diff --git a/source/app/metrics/index.mjs b/source/app/metrics/index.mjs index 36f2ee24..d2360620 100644 --- a/source/app/metrics/index.mjs +++ b/source/app/metrics/index.mjs @@ -24,7 +24,7 @@ export default async function metrics({login, q}, {graphql, rest, plugins, conf, //Initialization const pending = [] const {queries} = conf - const extras = {css:(conf.settings.extras?.css ?? conf.settings.extras?.default ? q["extras.css"] ?? "" : "")} + const extras = {css:(conf.settings.extras?.css ?? conf.settings.extras?.default) ? q["extras.css"] ?? "" : "", js:(conf.settings.extras?.js ?? conf.settings.extras?.default) ? q["extras.js"] ?? "" : ""} const data = {q, animated:true, large:false, base:{}, config:{}, errors:[], plugins:{}, computed:{}, extras} const imports = { plugins:Plugins, @@ -189,7 +189,7 @@ export default async function metrics({login, q}, {graphql, rest, plugins, conf, console.debug(`metrics/compute/${login} > verified SVG, no parsing errors found`) } //Resizing - const {resized, mime} = await imports.svg.resize(rendered, {paddings:q["config.padding"] || conf.settings.padding, convert:convert === "svg" ? null : convert}) + const {resized, mime} = await imports.svg.resize(rendered, {paddings:q["config.padding"] || conf.settings.padding, convert:convert === "svg" ? null : convert, js:extras.js || null}) rendered = resized //Result diff --git a/source/app/metrics/utils.mjs b/source/app/metrics/utils.mjs index 0ad27dbf..a845b26e 100644 --- a/source/app/metrics/utils.mjs +++ b/source/app/metrics/utils.mjs @@ -401,7 +401,7 @@ export const svg = { return {rendered, mime:"application/pdf"} }, /**Render and resize svg */ - async resize(rendered, {paddings, convert}) { + async resize(rendered, {paddings, convert, js}) { //Instantiate browser if needed if (!svg.resize.browser) { svg.resize.browser = await puppeteer.launch() @@ -425,7 +425,9 @@ export const svg = { console.debug("metrics/svg/resize > loading svg") const page = await svg.resize.browser.newPage() page.setViewport({width:980, height:980}) - page.on("console", ({_text:text}) => console.debug(`metrics/svg/resize > puppeteer > ${text}`)) + page + .on("console", message => console.debug(`metrics/svg/resize > puppeteer > ${message.text()}`)) + .on("pageerror", error => console.debug(`metrics/svg/resize > puppeteer > ${error.message}`)) await page.setContent(rendered, {waitUntil:["load", "domcontentloaded", "networkidle2"]}) console.debug("metrics/svg/resize > loaded svg successfully") await page.addStyleTag({content:"body { margin: 0; padding: 0; }"}) @@ -433,7 +435,18 @@ export const svg = { console.debug("metrics/svg/resize > resizing svg") let height, resized, width try { - ({resized, width, height} = await page.evaluate(async padding => { + ({resized, width, height} = await page.evaluate(async (padding, js) => { + //Execute user JavaScript if provided + if (js) { + try { + console.debug(`metrics/svg/resize > executing ${js}`) + await new Function("document", `return (async () => {${js}})()`)(document) //eslint-disable-line no-new-func + console.debug("metrics/svg/resize > successfully executed user javascript") + } + catch (error) { + console.debug(`an error occured while evaluating user js: ${error}`) + } + } //Disable animations const animated = !document.querySelector("svg").classList.contains("no-animations") if (animated) @@ -456,7 +469,7 @@ export const svg = { document.querySelector("svg").classList.remove("no-animations") //Result return {resized:new XMLSerializer().serializeToString(document.querySelector("svg")), height, width} - }, padding)) + }, padding, js)) } catch (error) { console.error(error) diff --git a/source/app/web/settings.example.json b/source/app/web/settings.example.json index cdbd9cf1..5ce7b907 100644 --- a/source/app/web/settings.example.json +++ b/source/app/web/settings.example.json @@ -28,6 +28,7 @@ "extras": { "default": false, "//": "Default extras state (advised to let 'false' unless in debug mode)", "css": false, "//": "Allow use of 'extras.css' option", + "js": false, "//": "Allow use of 'extras.js' option", "features": false, "//": "Enable extra features (advised to let 'false' on web instances)" }, "plugins.default": false, "//": "Default plugin state (advised to let 'false' unless in debug mode)", diff --git a/source/plugins/core/metadata.yml b/source/plugins/core/metadata.yml index 65f9b170..817373fe 100644 --- a/source/plugins/core/metadata.yml +++ b/source/plugins/core/metadata.yml @@ -175,6 +175,19 @@ inputs: type: string default: "" + extras_js: + extras: yes + description: | + Extra JavaScript + + Custom JavaScript that will be executed during puppeteer rendering. + Useful to avoid creating a new template just to tweak some content. + + Note that is it executed within puppeteer context and **not** *metrics* context. + It is run after transformations and optimizations, but just before resizing. + type: string + default: "" + config_timezone: description: | Timezone for dates