From 737604e655a628c51d8a0147ef6452d7ac71cd6c Mon Sep 17 00:00:00 2001 From: Maharshi Patel Date: Mon, 1 Apr 2024 16:23:33 +0530 Subject: [PATCH 1/4] feat: add columns in dynamic containers This is continuation of the #205 PR. There are some issue with PDF generated by table component and I am working on it. I will update the PR once I fix the issue. --- .../jinja/macros/relative_containers.html | 15 +- .../js/print_designer/PropertiesPanelState.js | 2 +- .../components/base/BaseTable.vue | 1 + .../components/layout/AppCanvas.vue | 11 + .../js/print_designer/store/ElementStore.js | 469 ++++++++++++------ 5 files changed, 352 insertions(+), 146 deletions(-) diff --git a/print_designer/print_designer/page/print_designer/jinja/macros/relative_containers.html b/print_designer/print_designer/page/print_designer/jinja/macros/relative_containers.html index 6327524..87daf0e 100644 --- a/print_designer/print_designer/page/print_designer/jinja/macros/relative_containers.html +++ b/print_designer/print_designer/page/print_designer/jinja/macros/relative_containers.html @@ -1,7 +1,7 @@ {% from 'print_designer/page/print_designer/jinja/macros/render_element.html' import render_element with context %} -{% macro relative_containers(element, send_to_jinja) -%} -
{% if element.childrens %} {% for object in element.childrens %} @@ -9,4 +9,15 @@ {% endfor %} {% endif %}
+{%- endmacro %} + +{% macro relative_containers(element, send_to_jinja) -%} +
+ {% if element.childrens %} + {% for object in element.childrens %} + {{ relative_columns(object, send_to_jinja) }} + {% endfor %} + {% endif %} +
{%- endmacro %} \ No newline at end of file diff --git a/print_designer/public/js/print_designer/PropertiesPanelState.js b/print_designer/public/js/print_designer/PropertiesPanelState.js index 31ad16b..2a95ae0 100644 --- a/print_designer/public/js/print_designer/PropertiesPanelState.js +++ b/print_designer/public/js/print_designer/PropertiesPanelState.js @@ -447,7 +447,7 @@ export const createPropertiesPanel = () => { currentEl?.type === "table") || (currentEl.type === "text" && currentEl.isDynamic) ) { - return !currentEl.isElementOverlapping; + return true; } return false; }, diff --git a/print_designer/public/js/print_designer/components/base/BaseTable.vue b/print_designer/public/js/print_designer/components/base/BaseTable.vue index 5e48a9d..6f21eda 100644 --- a/print_designer/public/js/print_designer/components/base/BaseTable.vue +++ b/print_designer/public/js/print_designer/components/base/BaseTable.vue @@ -163,6 +163,7 @@ const { selectedColumn, selectedDynamicText, DOMRef, + isDynamicHeight, } = toRefs(props.object); watch( diff --git a/print_designer/public/js/print_designer/components/layout/AppCanvas.vue b/print_designer/public/js/print_designer/components/layout/AppCanvas.vue index 8d0f24d..4aa0711 100644 --- a/print_designer/public/js/print_designer/components/layout/AppCanvas.vue +++ b/print_designer/public/js/print_designer/components/layout/AppCanvas.vue @@ -644,4 +644,15 @@ watch( margin-right: calc(var(--print-margin-right) * -1); margin-bottom: calc(var(--print-margin-bottom) * -1); } +.relative-row { + background-color: transparent !important; + border: none !important; + z-index: 9999 !important; +} +.relative-column { + background-color: transparent !important; + border: none !important; + z-index: 9999 !important; + outline: 1px solid var(--primary) !important; +} diff --git a/print_designer/public/js/print_designer/store/ElementStore.js b/print_designer/public/js/print_designer/store/ElementStore.js index 06490b7..ff6d832 100644 --- a/print_designer/public/js/print_designer/store/ElementStore.js +++ b/print_designer/public/js/print_designer/store/ElementStore.js @@ -34,35 +34,54 @@ export const useElementStore = defineStore("ElementStore", { } return newElement; }, - async saveElements() { - const MainStore = useMainStore(); - if (this.checkIfAnyTableIsEmpty()) return; - - // Update the header and footer height with margin - MainStore.page.headerHeightWithMargin = - MainStore.page.headerHeight + MainStore.page.marginTop; - MainStore.page.footerHeightWithMargin = - MainStore.page.footerHeight + MainStore.page.marginBottom; + async computedLayoutForSave() { + const { headerRowElements, bodyRowElements, footerRowElements } = + await this.computeRowLayout(); + // check if any element is overlapping with header or footer and raise errors. + if (!this.handleHeaderFooterOverlapping(headerRowElements.flat())) return; + if (!this.handleHeaderFooterOverlapping(bodyRowElements.flat())) return; + if (!this.handleHeaderFooterOverlapping(footerRowElements.flat())) return; - const [headerElements, bodyElements, footerElements] = await this.computeLayout(); - if (!this.handleHeaderFooterOverlapping(headerElements.flat())) return; - if (!this.handleHeaderFooterOverlapping(bodyElements.flat())) return; - if (!this.handleHeaderFooterOverlapping(footerElements.flat())) return; - - const headerDimensions = this.computeElementDimensions(headerElements, "header"); - const bodyDimensions = this.computeElementDimensions(bodyElements, "body"); - const footerDimensions = this.computeElementDimensions(footerElements, "footer"); - - const header = this.cleanUpElementsForSave(headerElements, "header"); - const body = this.cleanUpElementsForSave(bodyElements, "body"); - const footer = this.cleanUpElementsForSave(footerElements, "footer"); - - if (!body) return; + // calculate dimensions for rows + const headerDimensions = this.computeRowElementDimensions(headerRowElements, "header"); + const bodyDimensions = this.computeRowElementDimensions(bodyRowElements, "body"); + const footerDimensions = this.computeRowElementDimensions(footerRowElements, "footer"); + // calculate columns inside rows and update dimensions to passed array + const headerColumnsInsideRows = await this.computeColumnLayout( + headerRowElements, + headerDimensions + ); + const bodyColumnsInsideRows = await this.computeColumnLayout( + bodyRowElements, + bodyDimensions + ); + const footerColumnsInsideRows = await this.computeColumnLayout( + footerRowElements, + footerDimensions + ); - const [cleanedBodyElements, bodyFonts] = body; - const [cleanedHeaderElements, headerFonts] = header || [[], null]; - const [cleanedFooterElements, footerFonts] = footer || [[], null]; + const headerFonts = []; + const bodyFonts = []; + const footerFonts = []; + // clean up elements for save + const cleanedHeaderElements = this.cleanUpElementsForSave( + headerColumnsInsideRows, + "header", + headerFonts + ); + const cleanedBodyElements = this.cleanUpElementsForSave( + bodyColumnsInsideRows, + "body", + bodyFonts + ); + const cleanedFooterElements = this.cleanUpElementsForSave( + footerColumnsInsideRows, + "footer", + footerFonts + ); + // update fonts in store + const MainStore = useMainStore(); MainStore.currentFonts.length = 0; MainStore.currentFonts.push( ...Object.keys({ @@ -71,6 +90,34 @@ export const useElementStore = defineStore("ElementStore", { ...(footerFonts || {}), }) ); + return { + header: { + layout: cleanedHeaderElements, + dimensions: headerDimensions, + }, + body: { + layout: cleanedBodyElements, + dimensions: bodyDimensions, + }, + footer: { + layout: cleanedFooterElements, + dimensions: footerDimensions, + }, + }; + }, + async saveElements() { + const MainStore = useMainStore(); + if (this.checkIfAnyTableIsEmpty()) return; + + // Update the header and footer height with margin + MainStore.page.headerHeightWithMargin = + MainStore.page.headerHeight + MainStore.page.marginTop; + MainStore.page.footerHeightWithMargin = + MainStore.page.footerHeight + MainStore.page.marginBottom; + const layout = await this.computedLayoutForSave(); + if (!layout) return; + const { header, body, footer } = layout; + const updatedPage = { ...MainStore.page }; const settingsForSave = { page: updatedPage, @@ -99,27 +146,15 @@ export const useElementStore = defineStore("ElementStore", { convertCsstoString(MainStore.printStyleSheet); const objectToSave = { - print_designer_header: JSON.stringify(cleanedHeaderElements[0]), - print_designer_body: JSON.stringify(cleanedBodyElements.flat()), - print_designer_after_table: null, - print_designer_footer: JSON.stringify(cleanedFooterElements[0]), + // flatten the layout array to 2 levels to remove row and column structure + print_designer_header: JSON.stringify(header.layout?.flat(2) || []), + print_designer_body: JSON.stringify(body.layout.flat(2)), + print_designer_footer: JSON.stringify(footer.layout?.flat(2) || []), print_designer_settings: JSON.stringify(settingsForSave), + print_designer_after_table: null, css: css, }; - const PrintFormatData = this.getPrintFormatData({ - header: { - elements: cleanedHeaderElements, - dimensions: headerDimensions, - }, - body: { - elements: cleanedBodyElements, - dimensions: bodyDimensions, - }, - footer: { - elements: cleanedFooterElements, - dimensions: footerDimensions, - }, - }); + const PrintFormatData = this.getPrintFormatData({ header, body, footer }); objectToSave.print_designer_print_format = PrintFormatData; @@ -149,54 +184,111 @@ export const useElementStore = defineStore("ElementStore", { } return false; }, - async computeLayout(element = null) { + async computeRowLayout(columnContainer = null, activeSection = null) { const MainStore = useMainStore(); - const elements = [...this.Elements].map((el, index) => { - return { - index, - startY: parseInt(el.startY), - endY: parseInt(el.startY + el.height), - element: el, - }; - }); - elements.sort((a, b) => { + if (!columnContainer) { + columnContainer = [...this.Elements].map((el, index) => { + return { + index, + startY: parseInt(el.startY), + endY: parseInt(el.startY + el.height), + startX: parseInt(el.startX), + endX: parseInt(el.startX + el.width), + element: el, + }; + }); + } + columnContainer.sort((a, b) => { return a.startY < b.startY ? -1 : 1; }); - const fullWidthElements = elements.filter( - (currentEl) => !currentEl.element.isElementOverlapping - ); - const headerContainer = []; - const bodyContainer = []; - const footerContainer = []; - const tempElementsArray = []; - elements.forEach((currentEl) => { - if (MainStore.page.headerHeight && currentEl.endY <= MainStore.page.headerHeight) { - headerContainer.push(currentEl); - } else if ( - MainStore.page.footerHeight && - currentEl.startY >= - MainStore.page.height - - MainStore.page.footerHeightWithMargin - - MainStore.page.marginTop - ) { - footerContainer.push(currentEl); - } else if ( - fullWidthElements.includes(currentEl) && - currentEl.element.isDynamicHeight - ) { - if (tempElementsArray.length) { - bodyContainer.push([...tempElementsArray]); + return columnContainer.reduce( + (computedLayout, currentEl) => { + let rows = computedLayout[activeSection || computedLayout.activeSection]; + if ( + !activeSection && + computedLayout.activeSection == "headerRowElements" && + currentEl.startY >= MainStore.page.headerHeight + ) { + // handle empty headerRowElements + rows.length == 0 && rows.push([]); + // change activeSection and rows to bodyRowElements + computedLayout.activeSection = "bodyRowElements"; + rows = computedLayout["bodyRowElements"]; } - bodyContainer.push([currentEl]); - tempElementsArray.length = 0; - } else { - tempElementsArray.push(currentEl); + if ( + !activeSection && + computedLayout.activeSection == "bodyRowElements" && + currentEl.startY >= + MainStore.page.height - + MainStore.page.marginTop - + MainStore.page.footerHeightWithMargin + ) { + // no need to handle empty bodyRowElements as it will throw error and never reach here + // change activeSection and rows to footerRowElements + computedLayout.activeSection = "footerRowElements"; + rows = computedLayout["footerRowElements"]; + } + if (rows.length == 0) { + rows.push([currentEl]); + return computedLayout; + } + + // replace with .at() after checking compatibility for our user base. + const lastRow = rows[rows.length - 1]; + const elementWithMaxEndY = lastRow[lastRow.length - 1]; + + if (currentEl.startY >= elementWithMaxEndY.endY) { + rows.push([currentEl]); + return computedLayout; + } + + if (currentEl.endY > elementWithMaxEndY.endY) { + lastRow.push(currentEl); + } else { + lastRow.splice(-1, 0, currentEl); + } + + return computedLayout; + }, + { + headerRowElements: [], + bodyRowElements: [], + footerRowElements: [], + activeSection: "headerRowElements", } + ); + }, + async computeColumnLayout(rows, rowDimensions) { + const columns = rows.map((elements) => { + elements.sort((a, b) => { + return a.startX < b.startX ? -1 : 1; + }); + return elements.reduce((columns, currentEl) => { + if (columns.length == 0) { + columns.push([currentEl]); + return columns; + } + // replace with .at() after checking compatibility for our user base. + const lastColumn = columns[columns.length - 1]; + const elementWithMaxEndX = lastColumn[lastColumn.length - 1]; + + if (currentEl.startX >= elementWithMaxEndX.endX) { + columns.push([currentEl]); + return columns; + } + if (currentEl.endX > elementWithMaxEndX.endX) { + lastColumn.push(currentEl); + } else { + lastColumn.splice(-1, 0, currentEl); + } + return columns; + }, []); }); - if (tempElementsArray.length) { - bodyContainer.push(tempElementsArray); - } - return [[headerContainer], bodyContainer, [footerContainer]]; + // sort elements inside columns by startY + columns.forEach((column) => column.sort((a, b) => (a.startY < b.startY ? -1 : 1))); + // This will add column dimensions under key columnDimensions inside bodyDimensions. + this.computeColumnElementDimensions(columns, rowDimensions); + return columns; }, handleHeaderFooterOverlapping(elements) { const MainStore = useMainStore(); @@ -252,7 +344,7 @@ export const useElementStore = defineStore("ElementStore", { return true; }, - computeElementDimensions(elements, containerType = "body") { + computeRowElementDimensions(elements, containerType = "body") { const dimensions = []; elements.reduce( (prevDimensions, container, index) => { @@ -265,10 +357,35 @@ export const useElementStore = defineStore("ElementStore", { dimensions.push(calculatedDimensions); return calculatedDimensions; }, - { top: 0, bottom: 0 } + { bottom: 0 } ); return dimensions; }, + computeColumnElementDimensions(rows, rowDimensions) { + const MainStore = useMainStore(); + rows.forEach((row, index) => { + const dimensions = []; + row.reduceRight( + (prevDimensions, container, index) => { + const calculatedDimensions = this.calculateWrapperElementDimensions( + prevDimensions, + container, + "column", + index + ); + dimensions.push(calculatedDimensions); + return calculatedDimensions; + }, + { + left: + MainStore.page.width - + MainStore.page.marginRight - + MainStore.page.marginLeft, + } + ); + rowDimensions[index]["columnDimensions"] = dimensions.reverse(); + }); + }, calculateWrapperElementDimensions(prevDimensions, children, containerType, index) { // basically returns lowest left - top highest right - bottom from all of the children elements const MainStore = useMainStore(); @@ -303,45 +420,49 @@ export const useElementStore = defineStore("ElementStore", { (offsetRect.top -= parentRect.top), (offsetRect.left -= parentRect.left); (offsetRect.right -= parentRect.left), (offsetRect.bottom -= parentRect.top); - if (containerType == "header") { + if (containerType == "header" && index == 0) { offsetRect.top = 0; - offsetRect.bottom = MainStore.page.headerHeight; } - // if its the first element then update top to header height - // also checking if element is below header ( just safe guard ) if (containerType == "body") { if (index == 0 && offsetRect.top >= MainStore.page.headerHeight) { offsetRect.top = MainStore.page.headerHeight; } - if (index != 0) { - offsetRect.top = prevDimensions.bottom; - } + } + if (containerType == "footer" && index == 0) { + offsetRect.top = + MainStore.page.height - + MainStore.page.footerHeightWithMargin - + MainStore.page.marginTop; + } + if (index != 0) { + offsetRect.top = prevDimensions.bottom; + } + if (containerType == "column") { + offsetRect.right = prevDimensions.left; } return offsetRect; }, - cleanUpElementsForSave(elements, type) { - if (this.checkIfPrintFormatIsEmpty(elements, type)) return; - const fontsArray = []; - const cleanedElements = []; - elements.forEach((container) => { - const cleanedContainer = []; - container.forEach((element) => { - let newElement = this.childrensSave(element.element, fontsArray); - newElement.classes = newElement.classes.filter( - (name) => ["inHeaderFooter", "overlappingHeaderFooter"].indexOf(name) == -1 - ); - if (element.type == "rectangle" && element.childrens.length) { - let childrensArray = element.childrens; - newElement.childrens = []; - childrensArray.forEach((el) => { - newElement.childrens.push(this.childrensSave(el, printFonts)); - }); - } - cleanedContainer.push(newElement); + cleanUpElementsForSave(rows, type, fontsArray = null) { + if (this.checkIfPrintFormatIsEmpty(rows, type)) return; + return rows.map((columns) => { + return columns.map((column) => { + return column.map((element) => { + let newElement = this.childrensSave(element.element, fontsArray); + newElement.classes = newElement.classes.filter( + (name) => + ["inHeaderFooter", "overlappingHeaderFooter"].indexOf(name) == -1 + ); + if (element.type == "rectangle" && element.childrens.length) { + let childrensArray = element.childrens; + newElement.childrens = []; + childrensArray.forEach((el) => { + newElement.childrens.push(this.childrensSave(el, printFonts)); + }); + } + return newElement; + }); }); - cleanedElements.push(cleanedContainer); }); - return [cleanedElements, fontsArray]; }, checkIfPrintFormatIsEmpty(elements, type) { const MainStore = useMainStore(); @@ -369,7 +490,7 @@ export const useElementStore = defineStore("ElementStore", { } return false; }, - childrensSave(element, printFonts) { + childrensSave(element, printFonts = null) { let saveEl = { ...element }; delete saveEl.DOMRef; delete saveEl.index; @@ -391,27 +512,42 @@ export const useElementStore = defineStore("ElementStore", { return saveEl; }, getPrintFormatData({ header, body, footer }) { - const headerElements = this.createWrapperElement( - header.elements, + const headerElements = this.createRowWrapperElement( + header.layout, header.dimensions, "header" ); - const bodyElements = this.createWrapperElement(body.elements, body.dimensions, "body"); - const footerElements = this.createWrapperElement( - footer.elements, + const bodyElements = this.createRowWrapperElement( + body.layout, + body.dimensions, + "body" + ); + const footerElements = this.createRowWrapperElement( + footer.layout, footer.dimensions, "footer" ); - return JSON.stringify({ + const data = JSON.stringify({ header: headerElements, body: bodyElements, footer: footerElements, }); + const layoutElements = [...headerElements, ...bodyElements, ...footerElements]; + this.Elements.push( + ...layoutElements.map((row) => { + row.childrens.map((column) => { + column.childrens = []; + }); + return this.childrensLoad(row); + }) + ); + return data; }, - createWrapperElement(containers, dimensions, containerType = "body") { + createRowWrapperElement(rows, dimensions, containerType = "body") { + if (!rows) return []; const MainStore = useMainStore(); - const wrapperContainers = { childrens: [] }; - containers.forEach((container, index) => { + const wrapperContainer = { childrens: [] }; + rows.forEach((row, index) => { const calculatedDimensions = dimensions[index]; const cordinates = { startY: calculatedDimensions.top, @@ -419,29 +555,64 @@ export const useElementStore = defineStore("ElementStore", { startX: 0, pageX: 0, }; - const wrapperRectangleEl = createRectangle(cordinates, wrapperContainers); - wrapperRectangleEl.height = calculatedDimensions.bottom - calculatedDimensions.top; + const wrapperRectangleEl = createRectangle(cordinates, wrapperContainer); wrapperRectangleEl.width = MainStore.page.width - MainStore.page.marginLeft - MainStore.page.marginRight; - wrapperRectangleEl.childrens = container; + wrapperRectangleEl.height = calculatedDimensions.bottom - calculatedDimensions.top; + wrapperRectangleEl.childrens = this.createColumnWrapperElement( + row, + calculatedDimensions.columnDimensions, + wrapperRectangleEl + ); + if (wrapperRectangleEl.childrens.some((el) => el.isDynamicHeight == true)) { + wrapperRectangleEl.isDynamicHeight = true; + } + wrapperRectangleEl.classes.push("relative-row"); + }); + return wrapperContainer.childrens.map((el) => this.childrensSave(el)); + }, + createColumnWrapperElement(row, dimensions, rowContainer = null) { + return row.map((column, index) => { + const calculatedDimensions = dimensions[index]; + if (index == 0) { + calculatedDimensions.left = 0; + } + const cordinates = { + startY: 0, // parentDimensions.top, + pageY: 0, + startX: calculatedDimensions.left, + pageX: calculatedDimensions.left, + }; + const wrapperRectangleEl = createRectangle(cordinates, rowContainer); + wrapperRectangleEl.width = calculatedDimensions.right - calculatedDimensions.left; + wrapperRectangleEl.height = rowContainer.height; + wrapperRectangleEl.childrens = column; if ( - containerType == "body" && wrapperRectangleEl.childrens.length == 1 && wrapperRectangleEl.childrens[0].isDynamicHeight == true ) { wrapperRectangleEl.isDynamicHeight = true; } wrapperRectangleEl.childrens.forEach((el) => { - el.startY -= cordinates.startY; - if (containerType == "header") { - el.startY += MainStore.page.marginTop; - } + el.startY -= rowContainer.startY; + el.startX -= cordinates.startX; + ["startX", "startY", "height", "width"].forEach((property) => { + if (typeof el[property] == "string") { + el[property] = parseFloat(el[property]); + } + el[property] = parseFloat(el[property].toFixed(3)); + }); }); - wrapperRectangleEl.style.backgroundColor = ""; + ["startX", "startY", "height", "width"].forEach((property) => { + wrapperRectangleEl[property] = parseFloat( + wrapperRectangleEl[property].toFixed(3) + ); + }); + wrapperRectangleEl.classes.push("relative-column"); + wrapperRectangleEl.relativeColumn = true; + return wrapperRectangleEl; }); - return wrapperContainers.childrens.map((el) => this.childrensSave(el)); }, - handleDynamicContent(element) { const MainStore = useMainStore(); if ( @@ -576,7 +747,8 @@ export const useElementStore = defineStore("ElementStore", { t.isPrimaryTable = t == tableEl; }); }, - // This is called to check if the element is overlapping with any other element + // This is called to check if the element is overlapping with any other element (row only) + // TODO: add column calculations isElementOverlapping(currentEl, elements = this.Elements) { const currentElIndex = currentEl.index || this.Elements.findIndex((el) => el === currentEl); @@ -588,13 +760,24 @@ export const useElementStore = defineStore("ElementStore", { if (index == currentElIndex) return false; const elStartY = parseInt(el.startY); const elEndY = el.endY || parseInt(el.startY + el.height); - if (currentStartY <= elStartY && elStartY <= currentEndY) { - return true; - } else if (currentStartY <= elEndY && elEndY <= currentEndY) { + if ( + currentStartY <= elStartY && + elStartY <= currentEndY && + !(currentStartY <= elEndY && elEndY <= currentEndY) + ) { return true; - } else if (elStartY <= currentStartY && currentStartY <= elEndY) { + } else if ( + !(currentStartY <= elStartY && elStartY <= currentEndY) && + currentStartY <= elEndY && + elEndY <= currentEndY + ) { return true; - } else if (elStartY <= currentEndY && currentEndY <= elEndY) { + } else if ( + elStartY <= currentStartY && + currentStartY <= elEndY && + elStartY <= currentEndY && + currentEndY <= elEndY + ) { return true; } else { return false; From 84af5555c10b7b01a40ed47ea36272ed81406c1f Mon Sep 17 00:00:00 2001 From: Maharshi Patel Date: Thu, 4 Apr 2024 21:50:42 +0530 Subject: [PATCH 2/4] chore: fix typo from merge conflict --- print_designer/public/js/print_designer/store/ElementStore.js | 1 + 1 file changed, 1 insertion(+) diff --git a/print_designer/public/js/print_designer/store/ElementStore.js b/print_designer/public/js/print_designer/store/ElementStore.js index fd344fb..1dc0e59 100644 --- a/print_designer/public/js/print_designer/store/ElementStore.js +++ b/print_designer/public/js/print_designer/store/ElementStore.js @@ -549,6 +549,7 @@ export const useElementStore = defineStore("ElementStore", { }, cleanUpElementsForSave(rows, type) { if (this.checkIfPrintFormatIsEmpty(rows, type)) return; + const MainStore = useMainStore(); const fontsObject = {}; switch (type) { case "header": From 0f1510788f32aead5fb5ca3d3250025dbd177212 Mon Sep 17 00:00:00 2001 From: Maharshi Patel Date: Fri, 5 Apr 2024 02:45:28 +0530 Subject: [PATCH 3/4] fix: printview and table header overlap issue wkhtmltopdf have issue with table header overlapping if it is inside a div with display: inline. wkhtmltopdf doesn't support flex but it has some old experimental support for https://developer.mozilla.org/en-US/docs/Web/CSS/box-align As it doesn't support proper implementation of flex it is not used anywhere in print designer. This PR uses display: -webkit-box; to fix the particular issue. hopefully can be used to add more features in the future. --- .../jinja/macros/relative_containers.html | 6 ++--- .../print_designer/jinja/macros/styles.html | 23 ++++++++++++++++++- .../print_designer/jinja/print_format.html | 4 +++- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/print_designer/print_designer/page/print_designer/jinja/macros/relative_containers.html b/print_designer/print_designer/page/print_designer/jinja/macros/relative_containers.html index 87daf0e..3204af7 100644 --- a/print_designer/print_designer/page/print_designer/jinja/macros/relative_containers.html +++ b/print_designer/print_designer/page/print_designer/jinja/macros/relative_containers.html @@ -1,7 +1,7 @@ {% from 'print_designer/page/print_designer/jinja/macros/render_element.html' import render_element with context %} {% macro relative_columns(element, send_to_jinja) -%} -
{% if element.childrens %} {% for object in element.childrens %} @@ -12,8 +12,8 @@ {%- endmacro %} {% macro relative_containers(element, send_to_jinja) -%} -
+
{% if element.childrens %} {% for object in element.childrens %} {{ relative_columns(object, send_to_jinja) }} diff --git a/print_designer/print_designer/page/print_designer/jinja/macros/styles.html b/print_designer/print_designer/page/print_designer/jinja/macros/styles.html index 0dcb4e8..7b479aa 100644 --- a/print_designer/print_designer/page/print_designer/jinja/macros/styles.html +++ b/print_designer/print_designer/page/print_designer/jinja/macros/styles.html @@ -24,6 +24,16 @@ margin: auto !important; } } + /* set margin to 0 for print (Ctrl + p) on client browsers + and remove margin container that was added for screen ( viewing ) */ + @media print { + .print-format { + margin: 0 !important; + } + .printview-header-margin { + display: none; + } + } .print-designer-container { position: absolute; } @@ -71,8 +81,19 @@ .flexDirectionColumn .baseSpanTag .valueSpanTag { display: block; } + /* https://github.com/wkhtmltopdf/wkhtmltopdf/issues/1522 */ + .relative-row { + display: -webkit-box; + display: -webkit-flex; + display: flex; + border-width: 0 !important; + } .relative-column { - margin-right: -4px; + border-width: 1px !important; + border-color: white !important; + } + * { + -webkit-box-sizing: border-box; } {% endmacro %} \ No newline at end of file diff --git a/print_designer/print_designer/page/print_designer/jinja/print_format.html b/print_designer/print_designer/page/print_designer/jinja/print_format.html index 485cb37..8624edb 100644 --- a/print_designer/print_designer/page/print_designer/jinja/print_format.html +++ b/print_designer/print_designer/page/print_designer/jinja/print_format.html @@ -11,12 +11,14 @@
+
+
{% if headerElement %}{{ render(pd_format.header, send_to_jinja) }}{%endif%}
{% if bodyElement %}{{ render(pd_format.body, send_to_jinja) }}{%endif%}