From d4b5711331e813cfad90cbcda428058f4f551f67 Mon Sep 17 00:00:00 2001 From: Daniel Kostro Date: Mon, 23 Mar 2026 11:13:16 +0100 Subject: [PATCH 1/4] Reapply "chore: update twig dependency" This reverts commit 2c5b97b72991b666b4a3c533834f15cc67be6fa4. --- package-lock.json | 58 +++++++++++++++++++++++++++++++++-------------- package.json | 2 +- rollup.config.mjs | 8 +++++++ 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index 51bfcb69f..9353807d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,7 @@ "semver": "^7.7.4", "smart-array-filter": "^5.0.0", "superagent": "^10.3.0", - "twig": "^1.17.1" + "twig": "^2.0.0" }, "devDependencies": { "@babel/types": "^7.29.0", @@ -7009,12 +7009,12 @@ } }, "node_modules/locutus": { - "version": "2.0.39", - "resolved": "https://registry.npmjs.org/locutus/-/locutus-2.0.39.tgz", - "integrity": "sha512-v2iub44UtGpbIv+pFkkYhZ+JsbIM0bJsQcQ1+VayUNGVA/YhM8+CkBiRACcpuuE9Q0xI1pgNzGNwzZDCp1MCww==", + "version": "3.0.24", + "resolved": "https://registry.npmjs.org/locutus/-/locutus-3.0.24.tgz", + "integrity": "sha512-ErfAZ82Q2RNuk3NPDliKG7f5kc3E/hHh/vz17TAGCyctqao2xoFkNKrkyfHYMFXG1mNQt14kJJ1yPDKm6p3SkQ==", "license": "MIT", "engines": { - "node": ">= 10", + "node": ">= 22", "yarn": ">= 1" } }, @@ -9526,33 +9526,57 @@ } }, "node_modules/twig": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/twig/-/twig-1.17.1.tgz", - "integrity": "sha512-atxccyr/BHtb1gPMA7Lvki0OuU17XBqHsNH9lzDHt9Rr1293EVZOosSZabEXz/DPVikIW8ZDqSkEddwyJnQN2w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/twig/-/twig-2.0.0.tgz", + "integrity": "sha512-XKeIPEdmyEhM+HV8wB/6KIijnS+KHKSQaXH35lDFi2kTpEKJV3Ms5ksFbt89iNRgumfLIVqmVRh80MNWw/Hisw==", "license": "BSD-2-Clause", "dependencies": { "@babel/runtime": "^7.8.4", - "locutus": "^2.0.11", - "minimatch": "3.0.x", + "locutus": "^3.0.9", + "minimatch": "^10", "walk": "2.3.x" }, "bin": { "twigjs": "bin/twigjs" }, "engines": { - "node": ">=10" + "node": ">=20" + } + }, + "node_modules/twig/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/twig/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, "node_modules/twig/node_modules/minimatch": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", - "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", - "license": "ISC", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^5.0.2" }, "engines": { - "node": "*" + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/type-check": { diff --git a/package.json b/package.json index fbbd75456..220d4c685 100644 --- a/package.json +++ b/package.json @@ -108,7 +108,7 @@ "semver": "^7.7.4", "smart-array-filter": "^5.0.0", "superagent": "^10.3.0", - "twig": "^1.17.1" + "twig": "^2.0.0" }, "volta": { "node": "22.22.1" diff --git a/rollup.config.mjs b/rollup.config.mjs index 2f3bfe3b5..3d7df7f74 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -104,6 +104,14 @@ export default [ plugins, }, { + onwarn(warning, warn) { + if(warning.code === 'EVAL') { + // Prevent huge warning with minified input + warn({...warning, frame: ''}) + } else { + warn(warning); + } + }, input: 'node_modules/twig/twig.min.js', output: { file: 'src/browserified/twig/twig.js', From e5b840cb26ef28b3e06411dada78b657fc129f99 Mon Sep 17 00:00:00 2001 From: Daniel Kostro Date: Mon, 23 Mar 2026 11:41:03 +0100 Subject: [PATCH 2/4] refactor: define twig requirejs paths --- src/init.js | 2 ++ src/lib/twigjs/twig.js | 2 +- src/modules/types/display/template-twig/view.js | 2 +- src/modules/types/science/chemistry/periodic_table/view.js | 2 +- src/src/util/typerenderer.js | 2 +- src/src/util/ui.js | 2 +- 6 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/init.js b/src/init.js index e8730f3a5..b98a7db63 100644 --- a/src/init.js +++ b/src/init.js @@ -57,6 +57,8 @@ require.config({ sprintf: 'components/sprintf/dist/sprintf.min', superagent: 'browserified/superagent/index', threejs: 'components/threejs/build/three.min', + twig: 'browserified/twig/twig', + twig_extended: 'lib/twigjs/twig', uri: 'components/uri.js/src', 'web-animations': 'components/web-animations-js/web-animations.min', x2js: 'components/x2js/xml2json.min', diff --git a/src/lib/twigjs/twig.js b/src/lib/twigjs/twig.js index e8443a19d..f8eeda445 100644 --- a/src/lib/twigjs/twig.js +++ b/src/lib/twigjs/twig.js @@ -1,7 +1,7 @@ 'use strict'; define([ - 'browserified/twig/twig', + 'twig', 'src/util/typerenderer', 'src/util/util', ], function(Twig, Renderer, Util) { diff --git a/src/modules/types/display/template-twig/view.js b/src/modules/types/display/template-twig/view.js index 9e9f6821a..efcc5769f 100644 --- a/src/modules/types/display/template-twig/view.js +++ b/src/modules/types/display/template-twig/view.js @@ -3,7 +3,7 @@ define([ 'jquery', 'modules/default/defaultview', - 'lib/twigjs/twig', + 'twig_extended', 'src/util/debug', 'src/util/api', 'lodash', diff --git a/src/modules/types/science/chemistry/periodic_table/view.js b/src/modules/types/science/chemistry/periodic_table/view.js index 58efa145e..f03c678ba 100644 --- a/src/modules/types/science/chemistry/periodic_table/view.js +++ b/src/modules/types/science/chemistry/periodic_table/view.js @@ -2,7 +2,7 @@ define([ 'modules/default/defaultview', - 'lib/twigjs/twig', + 'twig_extended', 'src/util/debug', 'src/util/colorbar', 'src/util/color', diff --git a/src/src/util/typerenderer.js b/src/src/util/typerenderer.js index d3c3039b6..bc353cab6 100644 --- a/src/src/util/typerenderer.js +++ b/src/src/util/typerenderer.js @@ -443,7 +443,7 @@ define([ functions.object = {}; functions.object.init = async function () { - functions.object.twig = await asyncRequire('lib/twigjs/twig'); + functions.object.twig = await asyncRequire('twig_extended'); }; functions.object.toscreen = function ($element, value, root, options = {}) { const { twig, twigVariableName, toJSON } = options; diff --git a/src/src/util/ui.js b/src/src/util/ui.js index 5ee46a670..7d9d5e50b 100644 --- a/src/src/util/ui.js +++ b/src/src/util/ui.js @@ -14,7 +14,7 @@ define([ 'src/util/typerenderer', 'forms/button', 'src/util/Form', - 'lib/twigjs/twig', + 'twig', 'notifyjs', ], function (Util, Debug, Traversing, _, $, Renderer, Button, Form, Twig) { // On load add the style for the progress notification From 656052a7be88a719408fb3cd8635e43ddb3f15a5 Mon Sep 17 00:00:00 2001 From: Daniel Kostro Date: Mon, 23 Mar 2026 11:41:54 +0100 Subject: [PATCH 3/4] fixup: adapt rollup config to allow build to work --- package-lock.json | 136 +++++++++++++++++++++++++++++++++++++++++++--- package.json | 2 + rollup.config.mjs | 12 +++- 3 files changed, 141 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9353807d0..3dd669446 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "visualizer", - "version": "3.3.0", + "version": "4.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "visualizer", - "version": "3.3.0", + "version": "4.0.1", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -48,9 +48,11 @@ }, "devDependencies": { "@babel/types": "^7.29.0", + "@rollup/plugin-babel": "^7.0.0", "@rollup/plugin-commonjs": "^29.0.0", "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^16.0.3", + "@rollup/plugin-terser": "^1.0.0", "@types/node": "^24.10.13", "add-stream": "^1.0.0", "bower": "^1.8.14", @@ -1871,6 +1873,17 @@ "node": ">=6.0.0" } }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", @@ -1923,6 +1936,33 @@ "@noble/hashes": "^1.1.5" } }, + "node_modules/@rollup/plugin-babel": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-7.0.0.tgz", + "integrity": "sha512-NS2+P7v80N3MQqehZEjgpaFb9UyX3URNMW/zvoECKGo4PY4DvJfQusTI7BX/Ks+CPvtTfk3TqcR6S9VYBi/C+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@rollup/pluginutils": "^5.0.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "@types/babel__core": "^7.1.9", + "rollup": "^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "@types/babel__core": { + "optional": true + }, + "rollup": { + "optional": true + } + } + }, "node_modules/@rollup/plugin-commonjs": { "version": "29.0.0", "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-29.0.0.tgz", @@ -2019,6 +2059,29 @@ } } }, + "node_modules/@rollup/plugin-terser": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-1.0.0.tgz", + "integrity": "sha512-FnCxhTBx6bMOYQrar6C8h3scPt8/JwIzw3+AJ2K++6guogH5fYaIFia+zZuhqv0eo1RN7W1Pz630SyvLbDjhtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "serialize-javascript": "^7.0.3", + "smob": "^1.0.0", + "terser": "^5.17.4" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, "node_modules/@rollup/pluginutils": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", @@ -3436,6 +3499,12 @@ "node": ">=0.4.0" } }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, "node_modules/builtin-modules": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-5.0.0.tgz", @@ -8527,6 +8596,16 @@ "node": ">=10" } }, + "node_modules/serialize-javascript": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.0.4.tgz", + "integrity": "sha512-DuGdB+Po43Q5Jxwpzt1lhyFSYKryqoNjQSA9M92tyw0lyHIOur+XCalOUe0KTJpyqzT8+fQ5A0Jf7vCx/NKmIg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -8752,6 +8831,16 @@ "lodash.escaperegexp": "^4.1.2" } }, + "node_modules/smob": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.6.1.tgz", + "integrity": "sha512-KAkBqZl3c2GvNgNhcoyJae1aKldDW0LO279wF9bk1PnluRTETKBq0WyzRXxEhoQLk56yHaOY4JCBEKDuJIET5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -8762,6 +8851,17 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "node_modules/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", @@ -8895,12 +8995,6 @@ "node": ">=0.4.0" } }, - "node_modules/static-module/node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "license": "MIT" - }, "node_modules/static-module/node_modules/concat-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", @@ -9287,6 +9381,32 @@ "node": ">=8" } }, + "node_modules/terser": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.1.tgz", + "integrity": "sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, "node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", diff --git a/package.json b/package.json index 220d4c685..ed1f5b665 100644 --- a/package.json +++ b/package.json @@ -44,9 +44,11 @@ }, "devDependencies": { "@babel/types": "^7.29.0", + "@rollup/plugin-babel": "^7.0.0", "@rollup/plugin-commonjs": "^29.0.0", "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^16.0.3", + "@rollup/plugin-terser": "^1.0.0", "@types/node": "^24.10.13", "add-stream": "^1.0.0", "bower": "^1.8.14", diff --git a/rollup.config.mjs b/rollup.config.mjs index 3d7df7f74..a28333955 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -1,6 +1,8 @@ +import { babel } from '@rollup/plugin-babel'; import commonjs from '@rollup/plugin-commonjs'; import json from '@rollup/plugin-json'; import { nodeResolve } from '@rollup/plugin-node-resolve'; +import terser from '@rollup/plugin-terser'; import nodePolyfills from 'rollup-plugin-polyfill-node'; const plugins = [commonjs({}), json(), nodeResolve({ browser: true })]; @@ -118,6 +120,14 @@ export default [ format: 'umd', name: 'Twig', }, - plugins, + plugins: [...plugins, babel({ + presets: [[ + "@babel/preset-env", { + "targets": { + "ie": "11" + }, + } + ]], + }), terser()], }, ]; From 9c3edd8787725054a8bba03de11c8aa8b3877b33 Mon Sep 17 00:00:00 2001 From: Daniel Kostro Date: Mon, 23 Mar 2026 15:45:36 +0100 Subject: [PATCH 4/4] refactor!: move twig UI out of built entry path --- package-lock.json | 120 ----- package.json | 2 - rollup.config.mjs | 12 +- src/src/util/twig.js | 83 ++++ src/src/util/ui.js | 75 +-- testcase/data/twig-form-light/view.json | 606 +++++++++++++++++++----- testcase/data/twigRenderer/view.json | 6 +- 7 files changed, 564 insertions(+), 340 deletions(-) create mode 100644 src/src/util/twig.js diff --git a/package-lock.json b/package-lock.json index 3dd669446..69a3b87eb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,11 +48,9 @@ }, "devDependencies": { "@babel/types": "^7.29.0", - "@rollup/plugin-babel": "^7.0.0", "@rollup/plugin-commonjs": "^29.0.0", "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^16.0.3", - "@rollup/plugin-terser": "^1.0.0", "@types/node": "^24.10.13", "add-stream": "^1.0.0", "bower": "^1.8.14", @@ -1873,17 +1871,6 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", - "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" - } - }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", @@ -1936,33 +1923,6 @@ "@noble/hashes": "^1.1.5" } }, - "node_modules/@rollup/plugin-babel": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-7.0.0.tgz", - "integrity": "sha512-NS2+P7v80N3MQqehZEjgpaFb9UyX3URNMW/zvoECKGo4PY4DvJfQusTI7BX/Ks+CPvtTfk3TqcR6S9VYBi/C+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.18.6", - "@rollup/pluginutils": "^5.0.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "@types/babel__core": "^7.1.9", - "rollup": "^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "@types/babel__core": { - "optional": true - }, - "rollup": { - "optional": true - } - } - }, "node_modules/@rollup/plugin-commonjs": { "version": "29.0.0", "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-29.0.0.tgz", @@ -2059,29 +2019,6 @@ } } }, - "node_modules/@rollup/plugin-terser": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-1.0.0.tgz", - "integrity": "sha512-FnCxhTBx6bMOYQrar6C8h3scPt8/JwIzw3+AJ2K++6guogH5fYaIFia+zZuhqv0eo1RN7W1Pz630SyvLbDjhtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "serialize-javascript": "^7.0.3", - "smob": "^1.0.0", - "terser": "^5.17.4" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "rollup": "^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, "node_modules/@rollup/pluginutils": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", @@ -8596,16 +8533,6 @@ "node": ">=10" } }, - "node_modules/serialize-javascript": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.0.4.tgz", - "integrity": "sha512-DuGdB+Po43Q5Jxwpzt1lhyFSYKryqoNjQSA9M92tyw0lyHIOur+XCalOUe0KTJpyqzT8+fQ5A0Jf7vCx/NKmIg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=20.0.0" - } - }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -8831,16 +8758,6 @@ "lodash.escaperegexp": "^4.1.2" } }, - "node_modules/smob": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/smob/-/smob-1.6.1.tgz", - "integrity": "sha512-KAkBqZl3c2GvNgNhcoyJae1aKldDW0LO279wF9bk1PnluRTETKBq0WyzRXxEhoQLk56yHaOY4JCBEKDuJIET5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.0.0" - } - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -8851,17 +8768,6 @@ "node": ">=0.10.0" } }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, "node_modules/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", @@ -9381,32 +9287,6 @@ "node": ">=8" } }, - "node_modules/terser": { - "version": "5.46.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.1.tgz", - "integrity": "sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.15.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, - "license": "MIT" - }, "node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", diff --git a/package.json b/package.json index ed1f5b665..220d4c685 100644 --- a/package.json +++ b/package.json @@ -44,11 +44,9 @@ }, "devDependencies": { "@babel/types": "^7.29.0", - "@rollup/plugin-babel": "^7.0.0", "@rollup/plugin-commonjs": "^29.0.0", "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^16.0.3", - "@rollup/plugin-terser": "^1.0.0", "@types/node": "^24.10.13", "add-stream": "^1.0.0", "bower": "^1.8.14", diff --git a/rollup.config.mjs b/rollup.config.mjs index a28333955..3d7df7f74 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -1,8 +1,6 @@ -import { babel } from '@rollup/plugin-babel'; import commonjs from '@rollup/plugin-commonjs'; import json from '@rollup/plugin-json'; import { nodeResolve } from '@rollup/plugin-node-resolve'; -import terser from '@rollup/plugin-terser'; import nodePolyfills from 'rollup-plugin-polyfill-node'; const plugins = [commonjs({}), json(), nodeResolve({ browser: true })]; @@ -120,14 +118,6 @@ export default [ format: 'umd', name: 'Twig', }, - plugins: [...plugins, babel({ - presets: [[ - "@babel/preset-env", { - "targets": { - "ie": "11" - }, - } - ]], - }), terser()], + plugins, }, ]; diff --git a/src/src/util/twig.js b/src/src/util/twig.js new file mode 100644 index 000000000..4d62708b4 --- /dev/null +++ b/src/src/util/twig.js @@ -0,0 +1,83 @@ +'use strict'; + +define(['twig_extended', 'src/util/ui', 'src/util/Form'], function ( + Twig, + UI, + Form, +) { + const exports = {}; + exports.renderTwig = async function renderTwig(template, data) { + template = Twig.twig({ + data: DataObject.resurrect(template), + }); + var renderer = await template.renderAsync(DataObject.resurrect(data)); + const div = document.createElement('div'); + div.style = 'position: absolute; width: 1; height: 1; visibility: none'; + const body = document.querySelectorAll('body')[0]; + div.innerHTML = renderer.html; + body.append(div); + await renderer.render(); // we render the async typerenderer + const html = div.innerHTML; + div.remove(); + return html; + }; + + exports.form = function (divOrData, inputObject, opts) { + let $div; + opts = Object.assign({}, opts); + + if (opts.twig) { + var template = Twig.twig({ + data: DataObject.resurrect(divOrData), + }); + var render = template.renderAsync(DataObject.resurrect(opts.twig)); + render.render(); + $div = render.html; + } else { + $div = divOrData; + } + + return new Promise(function (resolve) { + const done = (name) => { + var obj = form.getData(true); + obj._clickedButton = name; + form.unbind(); + resolve(obj); + dialog.dialog('destroy'); + }; + + if (!$div.jquery) { + $div = $($div); + } + + var form = new Form($div); + if (inputObject) form.setData(inputObject); + + form.onSubmit((event) => { + done(event.target.name); + }); + + const dialogOptions = Object.assign({ buttons: {} }, opts.dialog, { + close() { + form.unbind(); + resolve(null); + dialog.dialog('destroy'); + }, + }); + + if (opts.buttonLabels) { + for (let i = 0; i < opts.buttonLabels.length; i++) { + const button = opts.buttonLabels[i]; + if (typeof button === 'string') { + dialogOptions.buttons[button] = () => done(button); + } else { + dialogOptions.buttons[button.label] = () => done(button.key); + } + } + } + var dialog = UI.dialog($div, dialogOptions); + }); + }; + + return exports; +}); diff --git a/src/src/util/ui.js b/src/src/util/ui.js index 7d9d5e50b..c295daca3 100644 --- a/src/src/util/ui.js +++ b/src/src/util/ui.js @@ -12,11 +12,8 @@ define([ 'lodash', 'jquery', 'src/util/typerenderer', - 'forms/button', - 'src/util/Form', - 'twig', 'notifyjs', -], function (Util, Debug, Traversing, _, $, Renderer, Button, Form, Twig) { +], function (Util, Debug, Traversing, _, $, Renderer) { // On load add the style for the progress notification $.notify.addStyle('inprogress', { html: `
    ${Util.getLoadingAnimation( @@ -115,76 +112,6 @@ define([ }); }; - exports.renderTwig = async function renderTwig(template, data) { - template = Twig.twig({ - data: DataObject.resurrect(template), - }); - var renderer = await template.renderAsync(DataObject.resurrect(data)); - const div = document.createElement('div'); - div.style = 'position: absolute; width: 1; height: 1; visibility: none'; - const body = document.querySelectorAll('body')[0]; - div.innerHTML = renderer.html; - body.append(div); - await renderer.render(); // we render the async typerenderer - const html = div.innerHTML; - div.remove(); - return html; - }; - - exports.form = function (div, inputObject, opts) { - opts = Object.assign({}, opts); - - if (opts.twig) { - var template = Twig.twig({ - data: DataObject.resurrect(div), - }); - var render = template.renderAsync(DataObject.resurrect(opts.twig)); - render.render(); - div = render.html; - } - - return new Promise(function (resolve) { - const done = (name) => { - var obj = form.getData(true); - obj._clickedButton = name; - form.unbind(); - resolve(obj); - dialog.dialog('destroy'); - }; - - if (!div.jquery) { - div = $(div); - } - - var form = new Form(div); - if (inputObject) form.setData(inputObject); - - form.onSubmit((event) => { - done(event.target.name); - }); - - const dialogOptions = Object.assign({ buttons: {} }, opts.dialog, { - close() { - form.unbind(); - resolve(null); - dialog.dialog('destroy'); - }, - }); - - if (opts.buttonLabels) { - for (let i = 0; i < opts.buttonLabels.length; i++) { - const button = opts.buttonLabels[i]; - if (typeof button === 'string') { - dialogOptions.buttons[button] = () => done(button); - } else { - dialogOptions.buttons[button.label] = () => done(button.key); - } - } - } - var dialog = exports.dialog(div, dialogOptions); - }); - }; - exports.chooseSearch = async function (list, options) { let _resolve; const promise = new Promise(function (resolve) { diff --git a/testcase/data/twig-form-light/view.json b/testcase/data/twig-form-light/view.json index 6b8e087ba..35915846f 100644 --- a/testcase/data/twig-form-light/view.json +++ b/testcase/data/twig-form-light/view.json @@ -1,5 +1,5 @@ { - "version": "2.154.1-0", + "version": "4.0.1", "grid": { "layers": { "Default layer": { @@ -17,23 +17,51 @@ "groups": { "group": [ { - "mode": ["html"], - "outputType": [null], - "btnvalue": ["Send script"], - "iseditable": [["editable"]], - "hasButton": [["button"]], - "variable": [[]], - "storeOnChange": [["store"]], - "debouncing": [250], + "mode": [ + "html" + ], + "outputType": [ + null + ], + "btnvalue": [ + "Send script" + ], + "iseditable": [ + [ + "editable" + ] + ], + "hasButton": [ + [ + "button" + ] + ], + "variable": [ + [] + ], + "storeOnChange": [ + [ + "store" + ] + ], + "debouncing": [ + 250 + ], "script": [ - "Title:
\n\n\n" + "
\n\n\n\n
" ] } ], "ace": [ { - "useSoftTabs": [["yes"]], - "tabSize": [4] + "useSoftTabs": [ + [ + "yes" + ] + ], + "tabSize": [ + 4 + ] } ] } @@ -51,15 +79,24 @@ "zIndex": 0, "display": true, "title": "", - "bgColor": [255, 255, 255, 0], + "bgColor": [ + 255, + 255, + 255, + 0 + ], "wrapper": true, "created": true, "name": "Default layer" } }, "id": 1, - "vars_in": [{}], - "actions_in": [{}], + "vars_in": [ + {} + ], + "actions_in": [ + {} + ], "vars_out": [ { "event": "onEditorChange", @@ -81,20 +118,33 @@ "icon": "", "action": "", "position": "begin", - "color": [100, 100, 100, 1] + "color": [ + 100, + 100, + 100, + 1 + ] } ] ], "common": [ { - "toolbar": [["Open Preferences"]] + "toolbar": [ + [ + "Open Preferences" + ] + ] } ] }, "css": [ { - "fontSize": [""], - "fontFamily": [""] + "fontSize": [ + "" + ], + "fontFamily": [ + "" + ] } ], "title": "" @@ -106,14 +156,36 @@ "groups": { "group": [ { - "editable": ["text"], - "expanded": [[]], - "storeObject": [["expand"]], - "displayValue": [[]], - "searchBox": [["search"]], - "sendButton": [["send"]], - "output": ["new"], - "storedObject": ["{\"title\":\"abfddc\",\"kind\":\"A\"}"] + "editable": [ + "text" + ], + "expanded": [ + [] + ], + "storeObject": [ + [ + "expand" + ] + ], + "displayValue": [ + [] + ], + "searchBox": [ + [ + "search" + ] + ], + "sendButton": [ + [ + "send" + ] + ], + "output": [ + "new" + ], + "storedObject": [ + "{\"title\":\"abfddc\",\"kind\":\"B\"}" + ] } ] } @@ -130,22 +202,31 @@ }, "zIndex": 0, "display": true, - "title": "Input", - "bgColor": [255, 255, 255, 0], + "title": "Input - Click send to update the form data", + "bgColor": [ + 255, + 255, + 255, + 0 + ], "wrapper": true, "created": true, "name": "Default layer" } }, "id": 2, - "vars_in": [{}], - "actions_in": [{}], + "vars_in": [ + {} + ], + "actions_in": [ + {} + ], "vars_out": [ { "event": "onObjectChange", "rel": "output", "jpath": [], - "name": "dataXXX" + "name": "data" } ], "actions_out": [ @@ -161,23 +242,36 @@ "icon": "", "action": "", "position": "begin", - "color": [100, 100, 100, 1] + "color": [ + 100, + 100, + 100, + 1 + ] } ] ], "common": [ { - "toolbar": [["Open Preferences"]] + "toolbar": [ + [ + "Open Preferences" + ] + ] } ] }, "css": [ { - "fontSize": [""], - "fontFamily": [""] + "fontSize": [ + "" + ], + "fontFamily": [ + "" + ] } ], - "title": "Input" + "title": "Input - Click send to update the form data" }, { "url": "modules/types/display/template-twig/", @@ -186,11 +280,28 @@ "groups": { "group": [ { - "selectable": [[]], - "template": [""], - "modifyInForm": [["yes"]], - "debouncing": [100], - "formOptions": [["keepFormValueIfDataUndefined"]] + "selectable": [ + [] + ], + "template": [ + "" + ], + "modifyInForm": [ + [ + "yes" + ] + ], + "debouncing": [ + 100 + ], + "formOptions": [ + [ + "keepFormValueIfDataUndefined" + ] + ], + "templateOptions": [ + null + ] } ] } @@ -208,7 +319,12 @@ "zIndex": 0, "display": true, "title": "", - "bgColor": [255, 255, 255, 0], + "bgColor": [ + 255, + 255, + 255, + 0 + ], "wrapper": true, "created": true, "name": "Default layer" @@ -225,7 +341,9 @@ "name": "data" } ], - "actions_in": [{}], + "actions_in": [ + {} + ], "vars_out": [ { "jpath": [] @@ -244,20 +362,33 @@ "icon": "", "action": "", "position": "begin", - "color": [100, 100, 100, 1] + "color": [ + 100, + 100, + 100, + 1 + ] } ] ], "common": [ { - "toolbar": [["Open Preferences"]] + "toolbar": [ + [ + "Open Preferences" + ] + ] } ] }, "css": [ { - "fontSize": [""], - "fontFamily": [""] + "fontSize": [ + "" + ], + "fontFamily": [ + "" + ] } ], "title": "" @@ -269,14 +400,34 @@ "groups": { "group": [ { - "editable": ["text"], - "expanded": [[]], - "storeObject": [["expand"]], - "displayValue": [[]], - "searchBox": [["search"]], - "sendButton": [[]], - "output": ["new"], - "storedObject": ["{\"title\":\"abfddc\",\"kind\":\"\"}"] + "editable": [ + "text" + ], + "expanded": [ + [] + ], + "storeObject": [ + [ + "expand" + ] + ], + "displayValue": [ + [] + ], + "searchBox": [ + [ + "search" + ] + ], + "sendButton": [ + [] + ], + "output": [ + "new" + ], + "storedObject": [ + "{\"title\":\"abfddc\",\"kind\":\"B\"}" + ] } ] } @@ -294,7 +445,12 @@ "zIndex": 0, "display": true, "title": "Output", - "bgColor": [255, 255, 255, 0], + "bgColor": [ + 255, + 255, + 255, + 0 + ], "wrapper": true, "created": true, "name": "Default layer" @@ -307,7 +463,9 @@ "name": "data" } ], - "actions_in": [{}], + "actions_in": [ + {} + ], "vars_out": [ { "jpath": [] @@ -326,20 +484,33 @@ "icon": "", "action": "", "position": "begin", - "color": [100, 100, 100, 1] + "color": [ + 100, + 100, + 100, + 1 + ] } ] ], "common": [ { - "toolbar": [["Open Preferences"]] + "toolbar": [ + [ + "Open Preferences" + ] + ] } ] }, "css": [ { - "fontSize": [""], - "fontFamily": [""] + "fontSize": [ + "" + ], + "fontFamily": [ + "" + ] } ], "title": "Output" @@ -351,13 +522,30 @@ "groups": { "group": [ { - "display": [["editor", "buttons"]], - "execOnLoad": [[]], - "asyncAwait": [["top"]], - "script": ["API.createData('data', undefined);"] + "display": [ + [ + "editor", + "buttons" + ] + ], + "execOnLoad": [ + [] + ], + "asyncAwait": [ + [ + "top" + ] + ], + "script": [ + "API.createData('data', undefined);" + ] } ], - "libs": [[{}]], + "libs": [ + [ + {} + ] + ], "buttons": [ [ { @@ -383,15 +571,24 @@ "zIndex": 0, "display": true, "title": "", - "bgColor": [255, 255, 255, 0], + "bgColor": [ + 255, + 255, + 255, + 0 + ], "wrapper": true, "created": true, "name": "Default layer" } }, "id": 5, - "vars_in": [{}], - "actions_in": [{}], + "vars_in": [ + {} + ], + "actions_in": [ + {} + ], "vars_out": [ { "jpath": [] @@ -410,20 +607,33 @@ "icon": "", "action": "", "position": "begin", - "color": [100, 100, 100, 1] + "color": [ + 100, + 100, + 100, + 1 + ] } ] ], "common": [ { - "toolbar": [["Open Preferences"]] + "toolbar": [ + [ + "Open Preferences" + ] + ] } ] }, "css": [ { - "fontSize": [""], - "fontFamily": [""] + "fontSize": [ + "" + ], + "fontFamily": [ + "" + ] } ], "title": "" @@ -435,15 +645,30 @@ "groups": { "group": [ { - "display": [["editor", "buttons"]], - "execOnLoad": [[]], - "asyncAwait": [["top"]], + "display": [ + [ + "editor", + "buttons" + ] + ], + "execOnLoad": [ + [] + ], + "asyncAwait": [ + [ + "top" + ] + ], "script": [ "const data = API.getData('data');\ndata.kind= \"\";\ndata.triggerChange();" ] } ], - "libs": [[{}]], + "libs": [ + [ + {} + ] + ], "buttons": [ [ { @@ -459,25 +684,34 @@ "layers": { "Default layer": { "position": { - "left": 4, - "top": 35 + "left": 0, + "top": 33 }, "size": { - "width": 40, - "height": 27 + "width": 47, + "height": 12 }, "zIndex": 0, "display": true, "title": "", - "bgColor": [255, 255, 255, 0], + "bgColor": [ + 255, + 255, + 255, + 0 + ], "wrapper": true, "created": true, "name": "Default layer" } }, "id": 6, - "vars_in": [{}], - "actions_in": [{}], + "vars_in": [ + {} + ], + "actions_in": [ + {} + ], "vars_out": [ { "jpath": [] @@ -496,28 +730,169 @@ "icon": "", "action": "", "position": "begin", - "color": [100, 100, 100, 1] + "color": [ + 100, + 100, + 100, + 1 + ] } ] ], "common": [ { - "toolbar": [["Open Preferences"]] + "toolbar": [ + [ + "Open Preferences" + ] + ] } ] }, "css": [ { - "fontSize": [""], - "fontFamily": [""] + "fontSize": [ + "" + ], + "fontFamily": [ + "" + ] } ], "title": "" + }, + { + "url": "modules/types/client_interaction/code_executor/", + "configuration": { + "sections": {}, + "groups": { + "group": [ + { + "display": [ + [ + "editor", + "buttons" + ] + ], + "execOnLoad": [ + [] + ], + "asyncAwait": [ + [ + "top" + ] + ], + "script": [ + "const template = API.getData('template');\nconst data = API.getData('data');\n\nif(template && data) {\n const result = await TwigUtil.form(template, data, {twig: {}, buttonLabels: ['Submit']});\n console.log('result', result);\n}" + ] + } + ], + "libs": [ + [ + { + "lib": "src/util/twig", + "alias": "TwigUtil" + } + ] + ], + "buttons": [ + [ + { + "name": "button1", + "label": "Execute", + "hide": [], + "disable": [] + } + ] + ] + } + }, + "layers": { + "Default layer": { + "position": { + "left": 0, + "top": 46 + }, + "size": { + "width": 47, + "height": 25 + }, + "zIndex": 0, + "display": true, + "title": "Twig dialog form", + "bgColor": [ + 255, + 255, + 255, + 0 + ], + "wrapper": true, + "created": true, + "name": "Default layer" + } + }, + "id": 7, + "vars_in": [ + {} + ], + "actions_in": [ + {} + ], + "vars_out": [ + { + "jpath": [] + } + ], + "actions_out": [ + { + "jpath": [] + } + ], + "toolbar": { + "custom": [ + [ + { + "title": "", + "icon": "", + "action": "", + "position": "begin", + "color": [ + 100, + 100, + 100, + 1 + ] + } + ] + ], + "common": [ + { + "toolbar": [ + [ + "Open Preferences" + ] + ] + } + ] + }, + "css": [ + { + "fontSize": [ + "" + ], + "fontFamily": [ + "" + ] + } + ], + "title": "Twig dialog form" } ], "variables": [ { - "jpath": [""] + "jpath": [ + "" + ] } ], "aliases": [ @@ -539,8 +914,12 @@ "groups": { "action": [ { - "name": [null], - "script": [null] + "name": [ + null + ], + "script": [ + null + ] } ] } @@ -560,48 +939,15 @@ } } ], - "custom_filters": [ - { - "sections": { - "modules": [ - { - "sections": {}, - "groups": { - "modules": [[{}]] - } - } - ], - "filtersLib": [ - { - "sections": {}, - "groups": { - "filters": [[{}]] - } - } - ], - "filters": [ - { - "sections": {}, - "groups": { - "filter": [ - { - "name": [null], - "script": [null] - } - ], - "libs": [[{}]] - } - } - ] - }, - "groups": {} - } - ], "actionfiles": [ { "sections": {}, "groups": { - "action": [[{}]] + "action": [ + [ + {} + ] + ] } } ] diff --git a/testcase/data/twigRenderer/view.json b/testcase/data/twigRenderer/view.json index 9968362f1..f46c26292 100644 --- a/testcase/data/twigRenderer/view.json +++ b/testcase/data/twigRenderer/view.json @@ -21,15 +21,15 @@ "execOnLoad": [[]], "asyncAwait": [["top"]], "script": [ - "const template = API.getData('template');\n\nconst data={\n a: 1\n}\n\nlet html = await UI.renderTwig(template, data);\n\n\n\nAPI.createData('html', html);\n\n" + "const template = API.getData('template');\n\nconst data={\n a: 1\n}\n\nlet html = await TwigUtil.renderTwig(template, data);\n\n\n\nAPI.createData('html', html);\n\n" ] } ], "libs": [ [ { - "lib": "src/util/ui", - "alias": "UI" + "lib": "src/util/twig", + "alias": "TwigUtil" } ] ],