Insert page-break after content for A4 page (example in practice.js)master
| import $ from 'jquery' | |||||
| const practice = () => { | |||||
| const v = $('div.fade'); | |||||
| // const v = $(':eq(0)'); // za root element | |||||
| const va = $('div.fade').children().toArray(); // gledamo div-fade kao root | |||||
| let i = 1, temp = 0; | |||||
| const divRootElement = document.createElement('div'); | |||||
| divRootElement.className = 'hello'; | |||||
| const divElementPageBreak = document.createElement('div'); | |||||
| divElementPageBreak.style.pageBreakBefore = "always"; | |||||
| va.forEach(element => { | |||||
| // 59.338582677165356 is sum of default top and bottom print margins | |||||
| // 842 is height in pixels for A4 format | |||||
| const razlika = element.clientHeight + temp - (i * 842 - 59.338582677165356); | |||||
| if (razlika < 0) { | |||||
| temp += element.clientHeight; | |||||
| divRootElement.append(element); | |||||
| } | |||||
| else if (razlika === 0) { | |||||
| i++; | |||||
| temp = 0; | |||||
| divRootElement.append(divElementPageBreak); | |||||
| } | |||||
| else { | |||||
| if (element.hasChildNodes && element.childNodes.length === 1) { | |||||
| const node = element.childNodes[0]; | |||||
| if (node.hasChildNodes && node.childNodes.length === 1) { | |||||
| const subNode = node.childNodes[0]; | |||||
| if (subNode.hasChildNodes) { | |||||
| const nodes = subNode.childNodes; | |||||
| for (let j = 0; j < nodes.length; j++) { | |||||
| const razlikaNodes = nodes[j].clientHeight + temp - (i * 842 - 59.338582677165356); | |||||
| if (razlikaNodes < 0) { | |||||
| temp += nodes[j].clientHeight; | |||||
| } | |||||
| else if (razlikaNodes === 0) { | |||||
| i++; | |||||
| temp = 0; | |||||
| divRootElement.append(nodes[j]); | |||||
| } | |||||
| else { | |||||
| if (nodes[j].hasChildNodes && nodes[j].childNodes.length > 1) { | |||||
| const subNodes = nodes[j].childNodes; | |||||
| for (let k = 0; k < subNodes.length; k++) { | |||||
| const razlikaSubNodes = subNodes[k].clientHeight + temp - (i * 842 - 59.338582677165356); | |||||
| if (razlikaSubNodes < 0) { | |||||
| temp += subNodes[k].clientHeight; | |||||
| divRootElement.append(subNodes[k]); | |||||
| } | |||||
| else { | |||||
| i++; | |||||
| temp = 0; | |||||
| divRootElement.append(divElementPageBreak); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| else if (element.hasChildNodes && element.childNodes.length > 1) { | |||||
| const nodes = element.childNodes; | |||||
| for (let i = 0; i < nodes.length; i++) { | |||||
| if (nodes[i].clientHeight + temp < (i * 842 - 59.338582677165356)) { | |||||
| temp += nodes[i].clientHeight; | |||||
| divElement.append(nodes[i]); | |||||
| } | |||||
| else { | |||||
| i++; | |||||
| temp = 0; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| }); | |||||
| $('div.fade').empty(); | |||||
| $('div.fade').append(divRootElement); | |||||
| // $('root').append(divRootElement); | |||||
| } | |||||
| export default practice; |
| z-index: 9999; | z-index: 9999; | ||||
| left:0; | left:0; | ||||
| top: 0; | top: 0; | ||||
| margin-bottom: 300px; | |||||
| } | } | ||||
| table { page-break-after:auto } | table { page-break-after:auto } | ||||
| tr { page-break-inside:avoid; page-break-after:auto } | tr { page-break-inside:avoid; page-break-after:auto } |
| @media print | @media print | ||||
| { | { | ||||
| table{ | |||||
| display: block; | |||||
| } | |||||
| /* demo */ | |||||
| .demo { | |||||
| height: 100vh; | |||||
| position: relative; | |||||
| } | |||||
| .demo::after { | |||||
| content: attr(title); | |||||
| position: absolute; | |||||
| left: 0; | |||||
| top: 0; | |||||
| padding: .25em .5em; | |||||
| background-color: rgba(255, 255, 255, .8); | |||||
| } | |||||
| .table-landscape | .table-landscape | ||||
| { | { | ||||
| transform: rotate(90deg); | |||||
| max-width: 100vh; | |||||
| max-height: 100vw; | |||||
| transform: translatex(calc(50vw - 50%)) translatey(calc(50vh - 50%)) rotate(90deg); | |||||
| /* transform: rotate(90deg); */ | |||||
| /* break-before: always; */ | |||||
| /* page-break-before: always; */ | |||||
| page-break-before: auto; | |||||
| } | } | ||||
| .demo { page-break-before:always } | |||||
| /* .demo table { page-break-inside:avoid; page-break-after:auto } */ | |||||
| .demo table { page-break-inside: always; } | |||||
| } | } |
| const url = ('https://localhost:7285/api/PDFGenerator/http%3A%2F%2Flocalhost%3A3000%2F%23%2Fdashboard'); | |||||
| async function modifyPdf(existingPdfBytes) { | |||||
| // const url = 'https://pdf-lib.js.org/assets/with_update_sections.pdf' | |||||
| // const existingPdfBytes = await fetch(url).then(res => res.arrayBuffer()) | |||||
| const pdfDoc = await PDFDocument.load(existingPdfBytes) | |||||
| const helveticaFont = await pdfDoc.embedFont(StandardFonts.Helvetica) | |||||
| const pages = pdfDoc.getPages() | |||||
| const firstPage = pages[0] | |||||
| const { width, height } = firstPage.getSize() | |||||
| firstPage.drawText('This text was added with JavaScript!', { | |||||
| x: 5, | |||||
| y: height / 2 + 300, | |||||
| size: 50, | |||||
| font: helveticaFont, | |||||
| color: rgb(0.95, 0.1, 0.1), | |||||
| rotate: degrees(-45), | |||||
| }) | |||||
| const pdfBytes = await pdfDoc.save() | |||||
| console.log(pdfBytes); | |||||
| } | |||||
| // modifyPdf(); | |||||
| let headers = new Headers(); | |||||
| headers.append('Content-Type', 'application/pdf'); | |||||
| fetch(url, { | |||||
| method: 'GET', | |||||
| headers: headers | |||||
| }) | |||||
| .then(async res => ({ | |||||
| filename: "donwload.pdf", | |||||
| blob: await res.blob() | |||||
| })) | |||||
| .then(resObj => { | |||||
| // It is necessary to create a new blob object with mime-type explicitly set for all browsers except Chrome, but it works for Chrome too. | |||||
| const newBlob = new Blob([resObj.blob], { type: 'application/pdf' }); | |||||
| const bytes = new Uint8Array(newBlob); | |||||
| //console.log(bytes); | |||||
| modifyPdf(bytes); | |||||
| // MS Edge and IE don't allow using a blob object directly as link href, instead it is necessary to use msSaveOrOpenBlob | |||||
| if (window.navigator && window.navigator.msSaveOrOpenBlob) { | |||||
| window.navigator.msSaveOrOpenBlob(newBlob); | |||||
| } else { | |||||
| // For other browsers: create a link pointing to the ObjectURL containing the blob. | |||||
| const objUrl = window.URL.createObjectURL(newBlob); | |||||
| let link = document.createElement('a'); | |||||
| link.href = objUrl; | |||||
| link.download = resObj.filename; | |||||
| link.click(); | |||||
| // For Firefox it is necessary to delay revoking the ObjectURL. | |||||
| setTimeout(() => { window.URL.revokeObjectURL(objUrl); }, 250); | |||||
| } | |||||
| }) | |||||
| .catch((error) => { | |||||
| console.log('DOWNLOAD ERROR', error); | |||||
| }); |