Cannot register handlers/Hooks via registerHandlers
know: it is unclear how to interact with the printer
and page
object.
feel: encouraged to help and confident to be able to resolve the issue
do: provide a example of how to register handlers
Environment
I rendering html with react. Then using puppeteer to create a PDF. I am intending to superpower our reports with pagedjs to handle Table of Contents, header, footer, and inverting control of page layout to report users.
Problem
I am unclear on how to format a pagejsHandlers.js
module and register the javascript on the page
instance created by printer.render();
File structure
files
├── Body.jsx
├── styles.css
├── createPdf.js
├── script
│ └── pagedjsHandlers.js
Here are some things I have tried:
- Using the 'pagedjs' polyfill on my own puppeteer page instance.
const body = ReactDOMServer.renderToStaticMarkup(<Body {...props} />)
const browser = await puppeteer.launch(/*settings*/);
const page = await browser.newPage();
await page.setContent(body);
await page.addStyleTag({ path: 'styles.css' })
await page.addScriptTag({ url: hosted.pagedjs.polyfill });
await page.addScriptTag({ path: './script/pagedjsHandlers.js' });
await page.emulateMedia('print');
// content should be set
// depending on the form of pagedjsHandlers, I might get errors related to using 'import' statements, using `require`
// I get no errors if I use an IIFE
// In call runnable cases, checking content with
// const html = await page.content();
// await fs.writeFileSync('pagedJsOutput.html', html, 'utf8');
// child_process.exec(`open ${process.cwd()}/pagedJsOutput.html`);
Renders html where the javascript is in the html, but the hook did not run.
// render a pdf that has no TOC[pagedjsHandlers.js](/uploads/ff1f9fc0d4a6e1a23d2e44e5932ff204/pagedjsHandlers.js)
const fileBuffer = await page.pdf(options);
return fileBuffer;
- export a
handlers
class that extends Handler andregisterHandlers
before instantiatingPrinter
import handlers from './script/pagedjsHandlers.js'
import { registerHandlers } from 'pagedjs';
const body = ReactDOMServer.renderToStaticMarkup(<Body {...props} />)
registerHandlers(handlers);
const printer = new Printer(true, true, [])
const page = await printer.render({ html: body })
await page.addStyleTag({ path: 'styles.css' })
await page.emulateMedia('print');
const fileBuffer = await page.pdf(
{ html },
{
outlineTags: [], // needed or Reference Error
},
);
- create
pagedjsHandlers.js
as an IIFE, import and add in a script tag of apage
instance.
const body = ReactDOMServer.renderToStaticMarkup(<Body {...props} />)
const printer = new Printer(true, true, [])
const page = await printer.render({ html: body })
await page.addStyleTag({ path: 'styles.css' })
await page.addStyleTag({ path: './script/pagedjsHandlers.js' })
await page.emulateMedia('print');
const fileBuffer = await page.pdf(
{ html },
{
outlineTags: [], // needed or Reference Error
},
);
- create
pagedjsHandlers.js
as an IIFE and list the pathname in thenew Printer(headless, allowLocal, additionalScripts)
call.
const body = ReactDOMServer.renderToStaticMarkup(<Body {...props} />)
const printer = new Printer(true, true, ['./script/pagedjsHandlers.js'])
const page = await printer.render({ html: body })
await page.addStyleTag({ path: 'styles.css' })
await page.emulateMedia('print');
const fileBuffer = await page.pdf(
{ html },
{
outlineTags: [], // needed or Reference Error
},
);
- create a
printer.on('rendered')
and then try topage.evaluate()
theregisterHandlers
in the page context.
const body = ReactDOMServer.renderToStaticMarkup(<Body {...props} />)
const printer = new Printer(true, true, []);
const page = await printer.render({ html: body })
printer.on('rendered', () => {
page.evaluate(() => {
registerHandlers(handlers);
});
};
await page.addStyleTag({ path: 'styles.css' })
await page.emulateMedia('print');
const fileBuffer = await page.pdf(
{ html },
{
outlineTags: [], // needed or Reference Error
},
);
pagedjsHandlers.js varieties
- IIFE
'use strict';
(function() {
const Paged = require('pagedjs/dist/paged.js');
function createToc(config) {
const content = config.content;
const tocElement = config.tocElement;
const titleElements = config.titleElements;
let tocElementDiv = content.querySelector(tocElement);
let tocUl = document.createElement('ul');
tocUl.id = 'list-toc-generated';
tocElementDiv.appendChild(tocUl);
// add class to all title elements
let tocElementNbr = 0;
for (var i = 0; i < titleElements.length; i++) {
let titleHierarchy = i + 1;
let titleElement = content.querySelectorAll(titleElements[i]);
titleElement.forEach(function(element) {
// add classes to the element
element.classList.add('title-element');
element.setAttribute('data-title-level', titleHierarchy);
element.setAttribute(
'data-toc-title',
element.getAttribute('data-toc-title'),
);
// add id if doesn't exist
tocElementNbr++;
idElement = element.id;
if (idElement == '') {
element.id = 'title-element-' + tocElementNbr;
}
let newIdElement = element.id;
});
}
// create toc list
let tocElements = content.querySelectorAll('.title-element');
for (var i = 0; i < tocElements.length; i++) {
let tocElement = tocElements[i];
let tocNewLi = document.createElement('li');
tocNewLi.classList.add('toc-element');
tocNewLi.classList.add(
'toc-element-level-' + tocElement.dataset.titleLevel,
);
tocNewLi.classList.add('toc-h2');
tocNewLi.innerHTML =
'<a href="#' +
tocElement.id +
'">' +
tocElement.getAttribute('data-toc-title') +
'</a>';
tocUl.appendChild(tocNewLi);
}
}
class handlers extends Paged.Handler {
constructor(chunker, polisher, caller) {
super(chunker, polisher, caller);
}
beforeParsed(content) {
createToc({
content: content,
tocElement: '#toc',
titleElements: ['.toc-item'],
});
}
afterPreview(pages) {
debugger;
console.log('****** after preview called', pages);
const oldPages = document.querySelector('div.pagedjs_pages');
oldPages.remove();
const body = document.querySelector('body');
body.appendChild(pages);
const renderFlag = document.createElement('div');
renderFlag.setAttribute(id, 'rendered');
renderFlag.setAttribute(style, 'display: none');
body.appendChild(renderFlag);
}
beforeTreeParse(text, sheet) {
return new Promise((resolve, reject) => {
console.log(text, sheet);
resolve(text, sheet);
});
}
beforeTreeWalk(ast) {
return new Promise((resolve, reject) => {
console.log(ast);
resolve(ast);
});
}
afterTreeWalk(ast, sheet) {
return new Promise((resolve, reject) => {
console.log(ast, sheet);
resolve(ast, sheet);
});
}
onUrl(urlNode) {
return new Promise((resolve, reject) => {
console.log(urlNode);
resolve(urlNode);
});
}
onAtPage(atPageNode) {
return new Promise((resolve, reject) => {
console.log(atPageNode);
resolve(atPageNode);
});
}
onRule(ruleNode) {
return new Promise((resolve, reject) => {
console.log(ruleNode);
resolve(ruleNode);
});
}
onDeclaration(declarationNode, ruleNode) {
return new Promise((resolve, reject) => {
console.log(declarationNode, ruleNode);
resolve(declarationNode, ruleNode);
});
}
onContent(contentNode, declarationNode, ruleNode) {
return new Promise((resolve, reject) => {
console.log(contentNode, declarationNode, ruleNode);
resolve(contentNode, declarationNode, ruleNode);
});
}
}
Paged.registerHandlers(handlers);
})();
- as pagedjsHandlers.mjs
import { Handler, requireHandlers } from 'pagedjs';
function createToc(config) {
...body
}
class handlers extends Handler {
...body
}
registerHandlers(handlers);
- as pagedHandlers.js (using require)
const { Handler, requireHandlers } = require('pagedjs');
function createToc(config) {
...body
}
class handlers extends Handler {
...body
}
exports handlers = handlers;
I will post images and sample documents. Please note there is probably another unresolved issue that is causing the page to be fragmented in very odd ways. This issue is specifically trying to address the apparent inability to register handlers and hook into the lifecycle methods available on Paged.