From 7861cce06d0978c3493d7db03441cf7860cf665a Mon Sep 17 00:00:00 2001 From: Michael Wedl Date: Wed, 20 Dec 2023 09:55:41 +0100 Subject: [PATCH 1/4] Make script loading in design more reliable --- rendering/src/main.js | 45 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/rendering/src/main.js b/rendering/src/main.js index d6db506d9..6b0bc1af5 100644 --- a/rendering/src/main.js +++ b/rendering/src/main.js @@ -1,4 +1,4 @@ -import { createApp, compile, nextTick } from 'vue'; +import { createApp, compile } from 'vue'; import { generateCodeFrame } from '@vue/shared'; import ChartJsPluginDataLabels from 'chartjs-plugin-datalabels'; import Pagebreak from './components/Pagebreak.vue'; @@ -144,6 +144,8 @@ if (!window.RENDERING_COMPLETED) { data: () => ({ data: REPORT_DATA, _tickCount: 0, + _pendingPromises: [], + _observer: null, }), computed: { ...DEFAULT_COMPUTED, @@ -153,12 +155,43 @@ if (!window.RENDERING_COMPLETED) { ...DEFAULT_METHODS, ...REPORT_METHODS, }, + created() { + this._observer = new MutationObserver((mutationList) => { + for (const mutation of mutationList) { + if (mutation.type === 'childList') { + for (const node of mutation.addedNodes) { + if (node.nodeType === Node.ELEMENT_NODE && node.nodeName === 'SCRIPT') { + this._pendingPromises.push(new Promise((resolve, reject) => { + node.addEventListener('load', resolve); + node.addEventListener('error', reject); + })); + } + } + } + } + }); + this._observer.observe(document, { childList: true, subtree: true }); + }, + beforeUnmount() { + this._observer.disconnect(); + }, async mounted() { - // Wait some ticks before rendering is signaled as completed - // Allow multi-pass rendering (for e.g. table of contents) - await callForTicks(10, nextTick, () => { - this._tickCount += 1; - }) + const waitUntilFinished = async () => { + // Wait some ticks before rendering is signaled as completed + // Allow multi-pass rendering (for e.g. table of contents) + await callForTicks(10, () => { + this._tickCount += 1; + }); + // Wait for pending promises to finish + if (this._pendingPromises.length > 0) { + await Promise.allSettled(this._pendingPromises); + await callForTicks(10, () => { + this._tickCount += 1; + }); + } + } + await waitUntilFinished(); + window.RENDERING_COMPLETED = true; }, }); From 3f28d816bc85444245a4f86207b0b2aed403abe3 Mon Sep 17 00:00:00 2001 From: Michael Wedl Date: Wed, 20 Dec 2023 10:52:04 +0100 Subject: [PATCH 2/4] Provide vue helpers in template rendering --- .../reportcreator_api/tests/test_rendering.py | 2 ++ rendering/src/main.js | 17 ++++++----------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/api/src/reportcreator_api/tests/test_rendering.py b/api/src/reportcreator_api/tests/test_rendering.py index aa8548082..811cc87bd 100644 --- a/api/src/reportcreator_api/tests/test_rendering.py +++ b/api/src/reportcreator_api/tests/test_rendering.py @@ -80,6 +80,8 @@ def extract_html_part(self, html, start=None, end=None): ("{{ formatDate('2022-09-21', 'long', 'en-US') }}", "September 21, 2022"), ("{{ formatDate('2022-09-21', 'full', 'en-US') }}", "Wednesday, September 21, 2022"), ("{{ formatDate('2022-09-21', {year: '2-digit', month: 'narrow', day: '2-digit', numberingSystem: 'latn'}, 'en-US') }}", "S 21, 22"), + ("""
{{ helperFunction() }}
""", lambda self: f"
{self.project.data['title']} function
"), + ("""
{{ computedVar.value }}
""", lambda self: f"
{self.project.data['title']} computed
"), ]) def test_variables_rendering(self, template, html): if callable(html): diff --git a/rendering/src/main.js b/rendering/src/main.js index 6b0bc1af5..3ade36f4b 100644 --- a/rendering/src/main.js +++ b/rendering/src/main.js @@ -1,4 +1,4 @@ -import { createApp, compile } from 'vue'; +import vue, { createApp, compile, computed, ref } from 'vue'; import { generateCodeFrame } from '@vue/shared'; import ChartJsPluginDataLabels from 'chartjs-plugin-datalabels'; import Pagebreak from './components/Pagebreak.vue'; @@ -13,7 +13,6 @@ import Ref from './components/Ref.vue'; import { callForTicks } from './utils'; import lodash from 'lodash'; - // injected as global variables const REPORT_TEMPLATE = '
' + (window.REPORT_TEMPLATE || '') + '
'; const REPORT_DATA = window.REPORT_DATA || { report: {}, findings: [] }; @@ -59,20 +58,16 @@ const DEFAULT_COMPUTED = { count_info: this.findings_info.length, }; }, - lodash() { - return lodash; - }, chartjsPlugins() { return { DataLabels: ChartJsPluginDataLabels }; }, - window() { - return window; - }, - document() { - return document; - }, + lodash: () => lodash, + window: () => window, + document: () => document, + vue: () => vue, + computed: () => computed, }; const DEFAULT_METHODS = { From 97ddc3bb6b2ffeab93b0b9a9e8fee6e5c82cc0fa Mon Sep 17 00:00:00 2001 From: Michael Wedl Date: Wed, 20 Dec 2023 10:52:38 +0100 Subject: [PATCH 3/4] Document defining helper functions in vue --- docs/docs/designer/formatting-utils.md | 29 +++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/docs/docs/designer/formatting-utils.md b/docs/docs/designer/formatting-utils.md index 707ecb205..3b792f2ce 100755 --- a/docs/docs/designer/formatting-utils.md +++ b/docs/docs/designer/formatting-utils.md @@ -76,4 +76,31 @@ English (default): ... English (no commas, always "and"): ... German: ... French: ... -``` \ No newline at end of file +``` + + +## Helper Functions +It is possible to define helper functions and variables inside the Vue template language to reuse logic. +Setting variables only works for native DOM tag (e.g. `
`, ``, etc.), but not for Vue components (e.g. `