-
Notifications
You must be signed in to change notification settings - Fork 75
Page break #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Hi! I suppose your are using interactive .vue templates for your pages. In this case I cannot touch or change the content managed by Vue (i.e. separate it over several pages) because then Vue would be lost and the pages would be no more interactive. So the only choice you have is not using Vue and writing your plain HTML in the You can however make JavaScript interactivity using HTML tags with attribute |
Actually I'm not rendering components anymore because I read this comment in issue #5 . So I returned my code to a plain HTML. However, the page break is still not done. The content looks weird. The content should be broken into the red dashed, but it continues behind the second page. |
Can you send the HTML? |
<template>
<div class="main">
<!-- Top bar -->
<vue-file-toolbar-menu :content="menu" class="bar" />
<!-- Document editor -->
<vue-document-editor
class="editor"
ref="editor"
v-model:content="content"
:overlay="overlay"
:display="display"
:zoom="zoom"
:page_margins="page_margins"
/>
</div>
</template>
<script>
import {ref} from 'vue';
import VueDocumentEditor from 'vue-document-editor'
import VueFileToolbarMenu from 'vue-file-toolbar-menu';
//Mixins
import CurrencyMixin from '../../Mixins/CurrencyMixin'
//Aux
import {maskCnpj, maskCpf} from "../../helpers";
import moment from "moment";
export default {
name: "Print",
data() {
return {
content: [``]
display: `vertical`,
page_margins: "45mm 10mm",
zoom: 0.8,
mounted: false,
}
},
mixins: [
CurrencyMixin
],
props: ['order'],
mounted() {
this.content[0] = `
<div contenteditable="false">
<h3 class="mt-4 mb-4 text-center uppercase">Orçamento</h3>
<table>
<thead>
<tr>
<td class="text-left bg-gray-100">DADOS DO CLIENTE</td>
<td class="text-right">OUTROS DADOS</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-gray-100">
<div><b>${this.order.customer.type === 'physical' ? 'Nome Completo' : 'Razão Social'}:</b> ${this.order.customer.type === 'physical' ? this.order.customer.name : this.order.brand}</div>
<div><b>Endereço:</b> ${this.order.customer.address}, ${this.order.customer.number}</div>
<div><b>Bairro/CEP:</b> ${this.order.customer.neighborhood}, ${this.order.customer.postal_code}</div>
<div><b>Cidade:</b> ${this.order.customer.city.name}/${this.order.customer.city.state.acronym}</div>
<div><b>E-mail:</b> ${this.order.customer.email}</div>
<div><b>Telefone:</b> (XX) XXXX-XXXX</div>
</td>
<td style="min-width: 250px; text-align:right">
<div><b>Lorem Ipsum is simply dummy:</b> ${this.order.distancia_instalacao_entrega}km</div>
</td>
</tr>
</tbody>
</table>
<section>
<h3 class="mt-4 text-center uppercase">Lorem Ipsum is simply dummy</h3>
<table>
<thead>
<tr>
<td colspan="2" class="cabecalho">Lorem Ipsum is simply dummy</td>
</tr>
<tr>
<td class="bg-gray-100">MEDIDAS</td>
<td style="text-align:right">MATERIAIS</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-gray-100">
<div><b>Lorem Ipsum is simply dummy:</b> m²</div>
<div>
<b>Observações:</b><br>
</div>
</td>
<td style="min-width: 250px; text-align:right">
<div>Lorem Ipsum is simply dummy: <b>R$ 2.255.64</b></div>
<div>Lorem Ipsum is simply dummy: <b>R$ 2.255.64</b></div>
</td>
</tr>
</tbody>
</table>
</section>
<section>
<h3 class="mt-4 text-center uppercase">Peças Simples</h3>
<table>
<thead>
<tr>
<td colspan="2" class="cabecalho">Cozinha</td>
</tr>
<tr>
<td class="bg-gray-100">MEDIDAS</td>
<td style="text-align:right">MATERIAIS</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-gray-100">
<div><b>Lorem Ipsum is simply dummy:</b> m²</div>
<div><b>Lorem Ipsum is simply dummy:</b> m</div>
<div><b>Lorem Ipsum is simply dummy:</b> m</div>
<div>
<b>Observações:</b><br>
</div>
</td>
<td style="min-width: 250px; text-align:right">
<div>Lorem Ipsum is simply dummy: <b>R$ 2.255.64</b></div>
<div>Lorem Ipsum is simply dummy: <b>R$ 2.255.64</b></div>
</td>
</tr>
</tbody>
</table>
</section>
<section>
<h3 class="mt-4 text-center uppercase">Lorem Ipsum is simply dummy</h3>
<table>
<thead>
<tr>
<td colspan="2" class="cabecalho">Lorem Ipsum is simply dummy</td>
</tr>
<tr>
<td class="bg-gray-100">Lorem </td>
<td style="text-align:right">MATERIAIS</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-gray-100">
<div><b>Lorem Ipsum is simply dummy:</b></div>
<div><b>Lorem Ipsum is simply dummy:</b></div>
<div><b>Lorem Ipsum is simply dummy:</b></div>
<div><b>Lorem Ipsum is simply dummy:</b></div>
<div><b>Lorem Ipsum is simply dummy:</b></div>
<div><b>Lorem Ipsum is simply dummy:</b></div>
<div>
<b>Observações:</b><br>
</div>
</td>
<td style="min-width: 250px; text-align:right">
<div>What is Lorem Ipsum? <b>R$ 2.255.64</b></div>
<div>What is Lorem Ipsum? <b>R$ 2.255.64</b></div>
</td>
</tr>
</tbody>
</table>
</section>
<section>
<h3 class="mt-3 text-center uppercase">DESCRIMINAÇÃO DA NEGOCIAÇÃO</h3>
<ul>
<li>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum;</li>
<li>There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable;</li>
<li>Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old;</li>
<li>It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English;</li>
<li>The standard Lorem Ipsum passage, used since the 1500s;</li>
<li>But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?</li>
</ul>
</section>
</div>
</div>
`;
},
computed: {
menu () {
return [
{
text: "Imprimir",
title: "Imprimir",
icon: "print",
click: () => window.print()
}
];
}
},
methods: {
overlay (page, total) {
return `
<div style="position: absolute; bottom: 8mm; right: 10mm">Pág. ${page} de ${total}</div>
<div style="position: absolute; display: flex; align-items: center; justify-content: space-between; text-align: center; left: 0; top: 0; right: 0; padding: 10mm 15mm">
<div>
<img src="${this.$page.props.user.subscriber.logo}" style="width: 200px" alt="">
</div>
<div>
<span><b>${this.$page.props.user.subscriber.brand}</b></span><br>
<span>${this.$page.props.user.subscriber.name}</span><br>
<span>${this.$page.props.user.subscriber.type === 'legal' ? maskCnpj(this.$page.props.user.subscriber.document) : maskCpf(this.$page.props.user.subscriber.document)}</span><br>
<span>${this.$page.props.user.subscriber.email}</span><br>
<span>(XX) XXXX-XXXX</span>
</div>
<div class="flex flex-col justify-between self-stretch">
<h3>N° XXX</h3>
<span><b>Data:</b> ${moment(this.order.created_at).format('DD/MM/YYYY')}</span>
<span><b>Previsão Finalização:</b> ${this.order.expected_closing_date ?? ''}</span>
</div>
</div>
`;
}
},
async mounted() {
this.mounted = true;
},
created() {
// Initialize gesture flags
let start_zoom_gesture = false;
let start_dist_touch = false;
let start_zoom_touch = false;
// Manage ctrl+scroll zoom (or trackpad pinch)
window.addEventListener("wheel", (e) => {
if (e.ctrlKey) {
e.preventDefault();
this.zoom = Math.min(Math.max(this.zoom - e.deltaY * 0.01, this.zoom_min), this.zoom_max);
}
}, {passive: false});
// Manage trackpad pinch on Safari
window.addEventListener("gesturestart", (e) => {
e.preventDefault();
start_zoom_gesture = this.zoom;
});
window.addEventListener("gesturechange", (e) => {
e.preventDefault();
if (!start_zoom_touch) {
this.zoom = Math.min(Math.max(start_zoom_gesture * e.scale, this.zoom_min), this.zoom_max);
}
});
window.addEventListener("gestureend", () => {
start_zoom_gesture = false;
});
// Manage pinch to zoom for touch devices
window.addEventListener("touchstart", (e) => {
if (e.touches.length == 2) {
e.preventDefault();
start_dist_touch = Math.hypot(
e.touches[0].pageX - e.touches[1].pageX,
e.touches[0].pageY - e.touches[1].pageY
);
start_zoom_touch = this.zoom;
}
}, {passive: false});
window.addEventListener("touchmove", (e) => {
if (start_dist_touch && start_zoom_touch) {
e.preventDefault();
let zoom = start_zoom_touch * Math.hypot(
e.touches[0].pageX - e.touches[1].pageX,
e.touches[0].pageY - e.touches[1].pageY
) / start_dist_touch;
this.zoom = Math.min(Math.max(zoom, this.zoom_min), this.zoom_max);
}
}, {passive: false});
window.addEventListener("touchend", () => {
start_dist_touch = false;
start_zoom_touch = false;
}, {passive: false});
// Manage history undo/redo events
const manage_undo_redo = (e) => {
switch (e && e.inputType) {
case "historyUndo":
e.preventDefault();
e.stopPropagation();
this.undo();
break;
case "historyRedo":
e.preventDefault();
e.stopPropagation();
this.redo();
break;
}
}
window.addEventListener("beforeinput", manage_undo_redo);
window.addEventListener("input", manage_undo_redo); // in case of beforeinput event is not implemented (Firefox)
// If your component is susceptible to be destroyed, don't forget to
// use window.removeEventListener in the Vue.js beforeUnmount handler
},
components: {
VueDocumentEditor,
VueFileToolbarMenu
}
}
</script>
<style>
html {
height: 100%;
}
body {
margin: 0;
/*font-family: Avenir, Helvetica, Arial, sans-serif;*/
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: black;
background: rgb(248, 249, 250);
}
::-webkit-scrollbar {
width: 16px;
height: 16px;
}
::-webkit-scrollbar-track, ::-webkit-scrollbar-corner {
display: none;
}
::-webkit-scrollbar-thumb {
background-color: rgba(0, 0, 0, 0.5);
border: 5px solid transparent;
border-radius: 16px;
background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover {
background-color: rgba(0, 0, 0, 0.8);
}
table {
width: 100%;
border-spacing: 0;
}
table td {
position: relative;
padding: 6px;
vertical-align: top;
}
table.order-table td {
vertical-align: middle;
}
table thead td {
font-weight: bold;
}
.cabecalho {
border-bottom: 1px solid #CCC;
text-align: center;
text-transform: uppercase;
}
table tbody td {
border-top: solid 1px #CCC;
}
input[type=number] {
border: none;
font-family: inherit;
font-size: inherit;
color: inherit;
background: rgba(200, 250, 230, 0.4);
padding: 6px;
}
@media print {
.hide-in-print {
display: none;
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type=number] {
-moz-appearance: textfield;
background: none;
}
}
.order {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
.left-btn {
position: absolute;
left: -40px;
top: 2px;
}
.left-btn:hover {
opacity: 0.6;
}
section {
margin-top: 15px;
}
h1, h2, h3, h4, h5, h6 {
font-size: revert;
font-weight: revert;
}
</style>
<style scoped>
.main {
width: fit-content;
min-width: 100%;
}
.bar {
position: sticky;
left: 0;
top: 0;
font-family: inherit;
width: calc(100vw - 16px);
z-index: 1000;
background: rgba(248, 249, 250, 0.8);
border-bottom: solid 1px rgb(248, 249, 250);
backdrop-filter: blur(10px);
--bar-button-active-color: #188038;
--bar-button-open-color: #188038;
--bar-button-active-bkg: #e6f4ea;
--bar-button-open-bkg: #e6f4ea;
}
</style> |
That's weird. I will do some more tests and report here. |
Hello @motla ! |
Hi @guilhermeagirardi Yes! It took me some time to understand what was going on... It was specific to Vue3. PS: I just noticed you simply had to write |
Hi @motla Thanks, it worked for me! |
Hello friends!
I need help.
I would like to use vue-document-editor to issue reports from my system. It has proven to be a great tool, but it has an issue in it that is giving me a headache, which is the page break.
When I generate my report, I don't know how long it will be, whether or not it will fit within a single page. So I would need the library to work on it automatically, separating what goes on one page or another.
Currently all the content is on one page in the view, and some things get messed up.
Does anyone know how to solve this problem?
Best Regards
The text was updated successfully, but these errors were encountered: