From 51aed98b0d08fe1298fd54e61a3f0475945790b3 Mon Sep 17 00:00:00 2001 From: Paola De Bartolo Date: Thu, 16 Jul 2026 11:41:57 -0300 Subject: [PATCH 1/3] chore(demo): add dynamic theme properties --- pom.xml | 3 ++- src/test/resources/META-INF/dynamic-theme.properties | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 src/test/resources/META-INF/dynamic-theme.properties diff --git a/pom.xml b/pom.xml index c3b174c..fd098c4 100644 --- a/pom.xml +++ b/pom.xml @@ -521,7 +521,8 @@ **/test/* **/integration/* **/DemoView.class - **/DemoLayout.class + **/DemoLayout.class + **/dynamic-theme.properties diff --git a/src/test/resources/META-INF/dynamic-theme.properties b/src/test/resources/META-INF/dynamic-theme.properties new file mode 100644 index 0000000..62d1f6f --- /dev/null +++ b/src/test/resources/META-INF/dynamic-theme.properties @@ -0,0 +1 @@ +theme=LUMO \ No newline at end of file From 5e67c1a337d7415fe1e61deb9f41dfea76e873e5 Mon Sep 17 00:00:00 2001 From: Paola De Bartolo Date: Thu, 16 Jul 2026 12:22:44 -0300 Subject: [PATCH 2/3] fix: replace broken json-digger bundle to support Vaadin 25.2 Close #97 --- pom.xml | 4 +- .../META-INF/frontend/fc-orgchart.js | 2 +- .../META-INF/frontend/json-digger.js | 416 ++++++++++++++++++ 3 files changed, 420 insertions(+), 2 deletions(-) create mode 100644 src/main/resources/META-INF/frontend/json-digger.js diff --git a/pom.xml b/pom.xml index fd098c4..37ce470 100644 --- a/pom.xml +++ b/pom.xml @@ -220,7 +220,9 @@ apache_v2 false - **/font-awesome.css + **/font-awesome.css + + **/json-digger.js diff --git a/src/main/resources/META-INF/frontend/fc-orgchart.js b/src/main/resources/META-INF/frontend/fc-orgchart.js index f685e03..af82aae 100644 --- a/src/main/resources/META-INF/frontend/fc-orgchart.js +++ b/src/main/resources/META-INF/frontend/fc-orgchart.js @@ -21,7 +21,7 @@ import {html, PolymerElement} from '@polymer/polymer/polymer-element.js'; import jQuery from "jquery"; import html2canvas from 'html2canvas'; -import JSONDigger from "json-digger/dist/json-digger.js"; +import JSONDigger from "./json-digger.js"; /** * `fc-orgchart` diff --git a/src/main/resources/META-INF/frontend/json-digger.js b/src/main/resources/META-INF/frontend/json-digger.js new file mode 100644 index 0000000..0915019 --- /dev/null +++ b/src/main/resources/META-INF/frontend/json-digger.js @@ -0,0 +1,416 @@ +/* + * Vendored copy of json-digger 2.0.2 (https://github.com/dabeng/json-helper). + * + * The published npm package cannot be consumed by Vaadin 25's Vite/esbuild + * frontend build: its source starts with an unused `const { node } = + * require("webpack");`, which makes the shipped `dist/json-digger.js` a webpack + * development bundle (built with the `eval` devtool) that inlines webpack's own + * internals. Under Vaadin 25.2 that bundle fails at runtime with + * "TypeError: memoize is not a function". As there is no fixed upstream + * release, the (dependency-free) class is vendored here verbatim, with only the + * stray `require("webpack")` removed and the export converted to an ES module. + * + * The `orgchart` library and OrgChart.updateNode rely on `window.JSONDigger`, + * so this module is imported by fc-orgchart.js and assigned to the global. + * + * Original work Copyright (c) dabeng, released under the MIT License: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +class JSONDigger { + constructor(datasource, idProp, childrenProp) { + this.ds = datasource; + this.id = idProp; + this.children = childrenProp; + } + + /* + * This method returns the first node in the JSON object that satisfies the provided id. + * If no node satisfies the provide id, null is returned. + */ + findNodeById (id) { + const _this = this; + + if (!id) { + return null; + } + + if (this.ds[_this.id] === id) { + return this.ds; + } + + function findNodeById (nodes, id) { + for (const node of nodes) { + if (node[_this.id] === id) { + return node; + } + if (node[_this.children]) { + const foundNode = findNodeById(node[_this.children], id); + if (foundNode) { + return foundNode; + } + } + } + return null; + } + + return findNodeById(this.ds[this.children], id); + } + + matchConditions (obj, conditions) { + var flag = true; + Object.keys(conditions).some(item => { + if (typeof conditions[item] === 'string' || typeof conditions[item] === 'number' || typeof conditions[item] === 'boolean') { + if (obj[item] !== conditions[item]) { + flag = false; + return true; + } + } else if (conditions[item] instanceof RegExp) { + if (!conditions[item].test(obj[item])) { + flag = false; + return true; + } + } else if (typeof conditions[item] === 'object') { + Object.keys(conditions[item]).some(subitem => { + switch (subitem) { + case '>': { + if (!(obj[item] > conditions[item][subitem])) { + flag = false; + return true; + } + break; + } + case '<': { + if (!(obj[item] < conditions[item][subitem])) { + flag = false; + return true; + } + break; + } + case '>=': { + if (!(obj[item] >= conditions[item][subitem])) { + flag = false; + return true; + } + break; + } + case '<=': { + if (!(obj[item] <= conditions[item][subitem])) { + flag = false; + return true; + } + break; + } + case '!==': { + if (!(obj[item] !== conditions[item][subitem])) { + flag = false; + return true; + } + break; + } + } + }); + if (!flag) { + return false; + } + } + }); + + return flag; + } + + /* + * This method returns the first node in the JSON object that satisfies the conditions. + * If no node satisfies the conditionas, null is returned. + */ + findOneNode (conditions) { + const _this = this; + + if (!conditions || !Object.keys(conditions).length) { + return null; + } + + if (this.matchConditions(this.ds, conditions)) { + return this.ds; + } + + function findOneNode (nodes, conditions) { + for (const node of nodes) { + if (_this.matchConditions(node, conditions)) { + return node; + } + if (node[_this.children]) { + const foundNode = findOneNode(node[_this.children], conditions); + if (foundNode !== null) { + return foundNode; + } + } + } + return null; + } + + return findOneNode(this.ds[this.children], conditions); + } + + findNodes (conditions) { + const _this = this; + + if (!conditions || !Object.keys(conditions).length) { + return []; + } + + let nodes = []; + + function findNodes(obj) { + if (_this.matchConditions(obj, conditions)) { + nodes.push(obj); + } + if (obj[_this.children]) { + for (const node of obj[_this.children]) { + findNodes(node); + } + } + } + + findNodes(this.ds); + + return nodes; + } + + findParent (id) { + const _this = this; + + if (!id) { + return null; + } + + if (this.ds[_this.children].some(node => node[_this.id] === id)) { + return this.ds; + } + + function findParent (nodes, id) { + for (const node of nodes) { + if (node[_this.children] && node[_this.children].some(node => node[_this.id] === id)) { + return node; + } + if (node[_this.children]) { + const foundNode = findParent(node[_this.children], id); + if (foundNode) { + return foundNode; + } + } + } + return null; + } + + return findParent(this.ds[this.children], id); + } + + findSiblings (id) { + const _this = this; + if (!id || this.ds[this.id] === id) { + return []; + } + + const parent = this.findParent(id); + return parent[_this.children].filter(node => node[_this.id] !== id); + } + + findAncestors (id) { + const _this = this; + + if (!id || id === _this.ds[_this.id]) { + return []; + } + + const nodes = []; + function findAncestors (id) { + const parent = _this.findParent(id); + if (parent) { + nodes.push(parent); + return findAncestors(parent[_this.id]); + } else { + return nodes.slice(0); + } + } + + return findAncestors(id); + } + + // validate the input parameters id and data(could be oject or array) + validateParams(id, data) { + if (!id + || !data + || (data.constructor !== Object && data.constructor !== Array) + || (data.constructor === Object && !Object.keys(data).length) + || (data.constructor === Array && !data.length) + || (data.constructor === Array + && data.length + && !data.every(item => item && item.constructor === Object && Object.keys(item).length))){ + return false; + } + return true; + } + + addChildren (id, data) { + if (!this.validateParams(id, data)) { + return false; + } + + const parent = this.findNodeById(id); + if (!parent) { + return false; + } + + if (data.constructor === Object) { + if (parent[this.children]) { + parent[this.children].push(data); + } else { + parent[this.children] = [data]; + } + } else { + if (parent[this.children]) { + parent[this.children].push(...data); + } else { + parent[this.children] = data; + } + } + return true; + } + + addSiblings (id, data) { + if (!this.validateParams(id, data)) { + return false; + } + + const parent = this.findParent(id); + if (!parent) { + return false; + } + + if (data.constructor === Object) { + parent[this.children].push(data); + } else { + parent[this.children].push(...data); + } + return true; + } + + addRoot (data) { + const _this = this; + if (!data || data.constructor !== Object || (data.constructor === Object && !Object.keys(data).length)) { + return false; + } + + this.ds[this.children] = [Object.assign({}, this.ds)]; + delete data[this.children]; + Object.keys(this.ds).filter(prop => prop !== this.children).forEach(prop => { + if (!data[prop]) { + delete this.ds[prop]; + } + }); + Object.assign(this.ds, data); + return true; + } + + updateNode (data) { + if (!data + || data.constructor !== Object + || (data.constructor === Object && !Object.keys(data).length) + || (data.constructor === Object && Object.keys(data).length && !data[this.id])) { + return false; + } + + const node = this.findNodeById(data[this.id]); + Object.assign(node, data); + return true; + } + + updateNodes (ids, data) { + if (!ids + || (ids.constructor === Array && !ids.length) + || !data + || data.constructor !== Object + || (data.constructor === Object && !Object.keys(data).length)) { + return false; + } + + for (const id of ids) { + data[this.id] = id; + if (!this.updateNode(data)) { + return false; + } + } + return true; + } + + // remove single node based on id + removeNode (id) { + const _this = this; + if (id === this.ds[this.id]) { + return false; + } + + const parent = this.findParent(id); + if (!parent) { + return false; + } + const index = parent[this.children].map(node => node[_this.id]).indexOf(id); + parent[this.children].splice(index, 1); + return true; + } + + // param could be single id, id array or conditions object + removeNodes (param) { + const _this = this; + if (!param + || (param.constructor === Array && !param.length) + || (param.constructor === Object && !Object.keys(param).length)) { + return false; + } + + // if passing in single id + if (param.constructor === String || param.constructor === Number) { + return this.removeNode(param); + } else if (param.constructor === Array) { // if passing in id array + for (const p of param) { + if(!this.removeNode(p)) { + return false; + } + } + return true; + } else { // if passing in conditions object + const nodes = this.findNodes(param); + if (!nodes.length) { + return false; + } + const ids = nodes.map(node => node[_this.id]); + for (const p of ids) { + if (!this.removeNode(p)) { + return false; + } + } + return true; + } + } + +}; + +export default JSONDigger; From aeda778959d0ca3e10c7b921349750e80ebfb45a Mon Sep 17 00:00:00 2001 From: Paola De Bartolo Date: Thu, 16 Jul 2026 12:23:18 -0300 Subject: [PATCH 3/3] build: bump v25 profile to Vaadin 25.2.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 37ce470..3373c52 100644 --- a/pom.xml +++ b/pom.xml @@ -558,7 +558,7 @@ 21 21 - 25.0.3 + 25.2.3 11.0.26 5.2.0