UNPKG

pagedjs

Version:

Chunks up a document into paged media flows and applies print styles

172 lines (144 loc) 4.98 kB
import Handler from "../handler.js"; import csstree from "css-tree"; import { displayedElementAfter, displayedElementBefore, needsPageBreak } from "../../utils/dom.js"; class Breaks extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.breaks = {}; } onDeclaration(declaration, dItem, dList, rule) { let property = declaration.property; if (property === "page") { let children = declaration.value.children.first(); let value = children.name; let selector = csstree.generate(rule.ruleNode.prelude); let name = value; let breaker = { property: property, value: value, selector: selector, name: name }; selector.split(",").forEach((s) => { if (!this.breaks[s]) { this.breaks[s] = [breaker]; } else { this.breaks[s].push(breaker); } }); dList.remove(dItem); } if (property === "break-before" || property === "break-after" || property === "page-break-before" || property === "page-break-after" ) { let child = declaration.value.children.first(); let value = child.name; let selector = csstree.generate(rule.ruleNode.prelude); if (property === "page-break-before") { property = "break-before"; } else if (property === "page-break-after") { property = "break-after"; } let breaker = { property: property, value: value, selector: selector }; selector.split(",").forEach((s) => { if (!this.breaks[s]) { this.breaks[s] = [breaker]; } else { this.breaks[s].push(breaker); } }); // Remove from CSS -- handle right / left in module dList.remove(dItem); } } afterParsed(parsed) { this.processBreaks(parsed, this.breaks); } processBreaks(parsed, breaks) { for (let b in breaks) { // Find elements let elements = parsed.querySelectorAll(b); // Add break data for (var i = 0; i < elements.length; i++) { for (let prop of breaks[b]) { if (prop.property === "break-after") { let nodeAfter = displayedElementAfter(elements[i], parsed); elements[i].setAttribute("data-break-after", prop.value); if (nodeAfter) { nodeAfter.setAttribute("data-previous-break-after", prop.value); } } else if (prop.property === "break-before") { let nodeBefore = displayedElementBefore(elements[i], parsed); // Breaks are only allowed between siblings, not between a box and its container. // If we cannot find a node before we should not break! // https://drafts.csswg.org/css-break-3/#break-propagation if (nodeBefore) { if (prop.value === "page" && needsPageBreak(elements[i], nodeBefore)) { // we ignore this explicit page break because an implicit page break is already needed continue; } elements[i].setAttribute("data-break-before", prop.value); nodeBefore.setAttribute("data-next-break-before", prop.value); } } else if (prop.property === "page") { elements[i].setAttribute("data-page", prop.value); let nodeAfter = displayedElementAfter(elements[i], parsed); if (nodeAfter) { nodeAfter.setAttribute("data-after-page", prop.value); } } else { elements[i].setAttribute("data-" + prop.property, prop.value); } } } } } mergeBreaks(pageBreaks, newBreaks) { for (let b in newBreaks) { if (b in pageBreaks) { pageBreaks[b] = pageBreaks[b].concat(newBreaks[b]); } else { pageBreaks[b] = newBreaks[b]; } } return pageBreaks; } addBreakAttributes(pageElement, page) { let before = pageElement.querySelector("[data-break-before]"); let after = pageElement.querySelector("[data-break-after]"); let previousBreakAfter = pageElement.querySelector("[data-previous-break-after]"); if (before) { if (before.dataset.splitFrom) { page.splitFrom = before.dataset.splitFrom; pageElement.setAttribute("data-split-from", before.dataset.splitFrom); } else if (before.dataset.breakBefore && before.dataset.breakBefore !== "avoid") { page.breakBefore = before.dataset.breakBefore; pageElement.setAttribute("data-break-before", before.dataset.breakBefore); } } if (after && after.dataset) { if (after.dataset.splitTo) { page.splitTo = after.dataset.splitTo; pageElement.setAttribute("data-split-to", after.dataset.splitTo); } else if (after.dataset.breakAfter && after.dataset.breakAfter !== "avoid") { page.breakAfter = after.dataset.breakAfter; pageElement.setAttribute("data-break-after", after.dataset.breakAfter); } } if (previousBreakAfter && previousBreakAfter.dataset) { if (previousBreakAfter.dataset.previousBreakAfter && previousBreakAfter.dataset.previousBreakAfter !== "avoid") { page.previousBreakAfter = previousBreakAfter.dataset.previousBreakAfter; } } } afterPageLayout(pageElement, page) { this.addBreakAttributes(pageElement, page); } } export default Breaks;