UNPKG

pagedjs

Version:

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

175 lines (136 loc) 3.99 kB
import EventEmitter from "event-emitter"; import Hook from "../utils/hook.js"; import Chunker from "../chunker/chunker.js"; import Polisher from "../polisher/polisher.js"; import { initializeHandlers, registerHandlers } from "../utils/handlers.js"; class Previewer { constructor(options) { // this.preview = this.getParams("preview") !== "false"; this.settings = options || {}; // Process styles this.polisher = new Polisher(false); // Chunk contents this.chunker = new Chunker(undefined, undefined, this.settings); // Hooks this.hooks = {}; this.hooks.beforePreview = new Hook(this); this.hooks.afterPreview = new Hook(this); // default size this.size = { width: { value: 8.5, unit: "in" }, height: { value: 11, unit: "in" }, format: undefined, orientation: undefined }; this.chunker.on("page", (page) => { this.emit("page", page); }); this.chunker.on("rendering", () => { this.emit("rendering", this.chunker); }); } initializeHandlers() { let handlers = initializeHandlers(this.chunker, this.polisher, this); handlers.on("size", (size) => { this.size = size; this.emit("size", size); }); handlers.on("atpages", (pages) => { this.atpages = pages; this.emit("atpages", pages); }); return handlers; } registerHandlers() { return registerHandlers.apply(registerHandlers, arguments); } getParams(name) { let param; let url = new URL(window.location); let params = new URLSearchParams(url.search); for(var pair of params.entries()) { if(pair[0] === name) { param = pair[1]; } } return param; } wrapContent() { // Wrap body in template tag let body = document.querySelector("body"); // Check if a template exists let template; template = body.querySelector(":scope > template[data-ref='pagedjs-content']"); if (!template) { // Otherwise create one template = document.createElement("template"); template.dataset.ref = "pagedjs-content"; template.innerHTML = body.innerHTML; body.innerHTML = ""; body.appendChild(template); } return template.content; } removeStyles(doc=document) { // Get all stylesheets const stylesheets = Array.from(doc.querySelectorAll("link[rel='stylesheet']:not([data-pagedjs-ignore], [media~='screen'])")); // Get inline styles const inlineStyles = Array.from(doc.querySelectorAll("style:not([data-pagedjs-inserted-styles], [data-pagedjs-ignore], [media~='screen'])")); const elements = [...stylesheets, ...inlineStyles]; return elements // preserve order .sort(function (element1, element2) { const position = element1.compareDocumentPosition(element2); if (position === Node.DOCUMENT_POSITION_PRECEDING) { return 1; } else if (position === Node.DOCUMENT_POSITION_FOLLOWING) { return -1; } return 0; }) // extract the href .map((element) => { if (element.nodeName === "STYLE") { const obj = {}; obj[window.location.href] = element.textContent; element.remove(); return obj; } if (element.nodeName === "LINK") { element.remove(); return element.href; } // ignore console.warn(`Unable to process: ${element}, ignoring.`); }); } async preview(content, stylesheets, renderTo) { await this.hooks.beforePreview.trigger(content, renderTo); if (!content) { content = this.wrapContent(); } if (!stylesheets) { stylesheets = this.removeStyles(); } this.polisher.setup(); this.handlers = this.initializeHandlers(); await this.polisher.add(...stylesheets); let startTime = performance.now(); // Render flow let flow = await this.chunker.flow(content, renderTo); let endTime = performance.now(); flow.performance = (endTime - startTime); flow.size = this.size; this.emit("rendered", flow); await this.hooks.afterPreview.trigger(flow.pages); return flow; } } EventEmitter(Previewer.prototype); export default Previewer;