diff --git a/Changelog.md b/Changelog.md index 79fe813aa7..9a393ad05c 100644 --- a/Changelog.md +++ b/Changelog.md @@ -29,7 +29,21 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - FIO-7146: formiojs-circleci-to-ghactions - FIO-6859: update-s3-to-accept-headers-from-signer-presign - FIO 7239: support for AWS S3 Multipart Upload - - FIO-7239: add polyfill and include token in abort and complete requests for multipart upload + - FIO-7239: add polyfill and include token in abort and complete requests for multipart upload2 + - FIO-7429: removed columns component settings(pull, offset, push) + - FIO-7466: Tooltips fix + - FIO-7355: fixed issue with HTML5 select flickering on initial click + - FIO-7530: added ability to pass onSetItems component setting as a string (needed for builder mode) + - FIO-7528: Revert FIO-4405: fixed an issue where walidation error displays with empty value even if it is not required (#4746) + - FIO-7547: Container hidden with conditional logic still appears in submission #5401 + - FIO-7550: Fixing choices css issue + - FIO-7074/FIO-7379: Fixes some issues caused by Wizzard was not always setting _data to submission data + - FIO-7208: Moved Tree component to the contrib library + - FIO-7406 Fixed plain Textarea interpolating data in readonly mode [#5396](https://github.com/formio/formio.js/pull/5383) + - FIO-7112: fixed issues with calendar widget display for value components in new simple conditionals ui + +### Changed + - Add capability for adding sanitize profiles through sanitizeConfig in options ## 5.0.0-rc.26 ### Changed diff --git a/gulpfile.js b/gulpfile.js index fa4b8277e3..d0bd609d64 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -75,7 +75,7 @@ gulp.task('styles-builder', function builderStyles() { }); gulp.task('styles-full', gulp.series('builder-fonts', function fullStyles() { return compileStyles([ - './node_modules/@formio/choices.js/public/assets/styles/choices.min.css', + './node_modules/@formio/choices.js/public/assets/styles/choices.css', './node_modules/tippy.js/dist/tippy.css', './node_modules/dialog-polyfill/dialog-polyfill.css', './node_modules/dragula/dist/dragula.css', diff --git a/src/Wizard.js b/src/Wizard.js index b514d19121..49f54eec5a 100644 --- a/src/Wizard.js +++ b/src/Wizard.js @@ -897,25 +897,23 @@ export default class Wizard extends Webform { } setValue(submission, flags = {}, ignoreEstablishment) { - this._submission = submission; - if ( - (flags && flags.fromSubmission && (this.options.readOnly || this.editMode) && !this.isHtmlRenderMode()) || - (flags && flags.fromSubmission && (this.prefixComps.length || this.suffixComps.length) && submission._id) || - (this.options.server && (this.prefixComps.length || this.suffixComps.length)) - ) { - this._data = submission.data; - } - - if (!ignoreEstablishment) { - this.establishPages(submission.data); - } const changed = this.getPages({ all: true }).reduce((changed, page) => { return this.setNestedValue(page, submission.data, flags, changed) || changed; }, false); + this.mergeData(this.data, submission.data); + if (changed) { this.pageFieldLogic(this.page); } + + submission.data = this.data; + this._submission = submission; + + if (!ignoreEstablishment) { + this.establishPages(submission.data); + } + this.setEditMode(submission); return changed; diff --git a/src/components/_classes/component/Component.js b/src/components/_classes/component/Component.js index c64abaa4eb..e03c56d624 100644 --- a/src/components/_classes/component/Component.js +++ b/src/components/_classes/component/Component.js @@ -211,7 +211,12 @@ export default class Component extends Element { return { operators: ['isEqual', 'isNotEqual', 'isEmpty', 'isNotEmpty'], valueComponent() { - return { type: 'textfield' }; + return { + type: 'textfield', + widget: { + type: 'input' + } + }; } }; } @@ -1223,7 +1228,7 @@ export default class Component extends Element { placement: 'right', zIndex: 10000, interactive: true, - content: this.t(tooltipText, { _userInput: true }), + content: this.t(this.sanitize(tooltipText), { _userInput: true }), }); } }); @@ -3321,8 +3326,6 @@ export default class Component extends Element { shouldSkipValidation(data, dirty, row) { const rules = [ - // Do not check custom validation for empty data if it is not required - () => this.component.validate.custom && !this.dataValue && !this.component.validate.required, // Force valid if component is read-only () => this.options.readOnly, // Do not check validations if component is not an input component. diff --git a/src/components/_classes/component/Component.unit.js b/src/components/_classes/component/Component.unit.js index 7726f1b97c..46606065f2 100644 --- a/src/components/_classes/component/Component.unit.js +++ b/src/components/_classes/component/Component.unit.js @@ -9,6 +9,7 @@ import { comp1 } from './fixtures'; import _merge from 'lodash/merge'; import comp3 from './fixtures/comp3'; import comp4 from './fixtures/comp4'; +import comp5 from './fixtures/comp5'; describe('Component', () => { it('Should create a Component', (done) => { @@ -356,4 +357,17 @@ describe('Component', () => { .catch(done); }); }); + + it('Should not execute code inside Tooltips/Description', (done) => { + const formElement = document.createElement('div'); + const form = new Webform(formElement); + + form.setForm(comp5).then(() => { + setTimeout(() => { + assert.equal(window._ee, undefined, 'Should not execute code inside Tooltips/Description'); + done(); + }, 200); + }) + .catch(done); + }); }); diff --git a/src/components/_classes/component/fixtures/comp5.js b/src/components/_classes/component/fixtures/comp5.js new file mode 100644 index 0000000000..68806c95d7 --- /dev/null +++ b/src/components/_classes/component/fixtures/comp5.js @@ -0,0 +1,24 @@ +export default { + type: 'form', + display: 'form', + components: [ + { + label: 'Text Field', + description: "", + tooltip: " { }, 100); }).catch(done); }); + + it('Should not set the default value when clearOnHide during the server-side validation', (done) => { + const form = _.cloneDeep(comp4); + const element = document.createElement('div'); + + Formio.createForm(element, form, { server: true, noDefaults: true }).then(form => { + form.setValue({ data: { checkbox: false } }, { + sanitize: true, + }, true); + + form.checkConditions(); + form.clearOnHide(); + + setTimeout(() => { + assert.deepEqual(form._data, { checkbox: false }, 'Should not add Container\'s key'); + done(); + }, 200); + }).catch(done); + }); }); diff --git a/src/components/container/fixtures/comp4.js b/src/components/container/fixtures/comp4.js new file mode 100644 index 0000000000..c48b94e359 --- /dev/null +++ b/src/components/container/fixtures/comp4.js @@ -0,0 +1,43 @@ +export default { + type: 'form', + display: 'form', + components: [ + { + label: 'Checkbox', + tableView: false, + key: 'checkbox', + type: 'checkbox', + input: true, + }, + { + label: 'Container', + tableView: false, + key: 'container', + conditional: { + show: true, + when: 'checkbox', + eq: 'true', + }, + type: 'container', + input: true, + components: [ + { + label: 'Text Field', + applyMaskOn: 'change', + tableView: true, + key: 'textField', + type: 'textfield', + input: true, + }, + ], + }, + { + type: 'button', + label: 'Submit', + key: 'submit', + disableOnInvalid: true, + input: true, + tableView: false, + }, + ], +}; diff --git a/src/components/container/fixtures/index.js b/src/components/container/fixtures/index.js index 63f18da5cf..f1a58d4b03 100644 --- a/src/components/container/fixtures/index.js +++ b/src/components/container/fixtures/index.js @@ -1,4 +1,5 @@ import comp1 from './comp1'; import comp2 from './comp2'; import comp3 from './comp3'; -export { comp1, comp2, comp3 }; +import comp4 from './comp4'; +export { comp1, comp2, comp3, comp4 }; diff --git a/src/components/index.js b/src/components/index.js index 5ec679e647..9df2ad255a 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -42,7 +42,6 @@ import TagsComponent from './tags/Tags'; import TextAreaComponent from './textarea/TextArea'; import TextFieldComponent from './textfield/TextField'; import TimeComponent from './time/Time'; -import TreeComponent from './tree/Tree'; import UnknownComponent from './unknown/Unknown'; import UrlComponent from './url/Url'; import WellComponent from './well/Well'; @@ -93,7 +92,6 @@ export default { textarea: TextAreaComponent, textfield: TextFieldComponent, time: TimeComponent, - tree: TreeComponent, unknown: UnknownComponent, url: UrlComponent, well: WellComponent, diff --git a/src/components/select/Select.js b/src/components/select/Select.js index 9e651ee580..d41a252c6d 100644 --- a/src/components/select/Select.js +++ b/src/components/select/Select.js @@ -400,8 +400,10 @@ export default class SelectComponent extends ListComponent { } // Allow js processing (needed for form builder) - if (this.component.onSetItems && typeof this.component.onSetItems === 'function') { - const newItems = this.component.onSetItems(this, items); + if (this.component.onSetItems) { + const newItems = typeof this.component.onSetItems === 'function' + ? this.component.onSetItems(this, items) + : this.evaluate(this.component.onSetItems, { items: items }, 'items'); if (newItems) { items = newItems; } @@ -943,7 +945,11 @@ export default class SelectComponent extends ListComponent { } this.focusableElement = input; - this.addEventListener(input, 'focus', () => this.update()); + + if (this.component.dataSrc === 'custom') { + this.addEventListener(input, 'focus', () => this.updateCustomItems()); + } + this.addEventListener(input, 'keydown', (event) => { const { key } = event; diff --git a/src/components/select/Select.unit.js b/src/components/select/Select.unit.js index e775fdde29..51bb3f06fa 100644 --- a/src/components/select/Select.unit.js +++ b/src/components/select/Select.unit.js @@ -42,7 +42,7 @@ describe('Select Component', () => { assert.equal(component.dataValue.value, 'a'); assert.equal(typeof component.dataValue , 'object'); done(); - }, 100); + }, 300); }); }); diff --git a/src/components/textarea/TextArea.js b/src/components/textarea/TextArea.js index bfe2ad4b12..3639aedafe 100644 --- a/src/components/textarea/TextArea.js +++ b/src/components/textarea/TextArea.js @@ -342,10 +342,10 @@ export default class TextAreaComponent extends TextFieldComponent { if (this.options.readOnly || this.disabled) { if (this.refs.input && this.refs.input[index]) { if (this.component.inputFormat === 'plain') { - this.refs.input[index].innerText = this.interpolate(value, {}, { noeval: true }); + this.refs.input[index].innerText = this.isPlain ? value : this.interpolate(value, {}, { noeval: true }); } else { - this.setContent(this.refs.input[index], this.interpolate(value, {}, { noeval: true }), this.shouldSanitizeValue); + this.setContent(this.refs.input[index], this.isPlain ? value : this.interpolate(value, {}, { noeval: true }), this.shouldSanitizeValue); } } } diff --git a/src/components/textfield/TextField.js b/src/components/textfield/TextField.js index 22f82c1f12..08871db25b 100644 --- a/src/components/textfield/TextField.js +++ b/src/components/textfield/TextField.js @@ -44,6 +44,12 @@ export default class TextFieldComponent extends Input { return { ...super.conditionOperatorsSettings, operators: [...super.conditionOperatorsSettings.operators, 'includes', 'notIncludes', 'endsWith', 'startsWith'], + valueComponent(classComp) { + return { + ...classComp, + type: 'textfield', + }; + } }; } diff --git a/src/components/tree/Node.js b/src/components/tree/Node.js deleted file mode 100644 index 58db7167b8..0000000000 --- a/src/components/tree/Node.js +++ /dev/null @@ -1,227 +0,0 @@ -import _ from 'lodash'; - -export default class Node { - constructor( - parent, - { - data = {}, - children = [], - } = {}, - { - checkNode, - createComponents, - isNew = true, - removeComponents, - parentPath = '' - } = {}, - ) { - this.parent = parent; - this.previousData = {}; - this.persistentData = _.cloneDeep(data); - this.new = isNew; - this.createComponents = createComponents; - this.checkNode = checkNode; - this.removeComponents = removeComponents; - this.revertAvailable = false; - this.editing = false; - this.collapsed = false; - this.components = []; - this.children = []; - this.parentPath = parentPath; - - this.resetData(); - this.children = children.map((child, index) => new Node(this, child, { - checkNode, - createComponents, - isNew: false, - removeComponents, - parentPath: this.getChildrenPath(index), - })); -} - - get value() { - return this.new - ? null // Check the special case for empty root node. - : { - data: _.cloneDeep(this.persistentData), - children: this.children.filter((child) => !child.new).map((child) => child.value), - }; - } - - get isRoot() { - return this.parent === null; - } - - get changing() { - return this.new || this.editing; - } - - get hasChangingChildren() { - return this.changin || this.children.some((child) => child.hasChangingChildren); - } - - get hasData() { - return !_.isEmpty(this.persistentData); - } - - get hasChildren() { - return Array.isArray(this.children) && this.children.length > 0; - } - - getChildrenPath(index) { - return this.parentPath ? `${this.parentPath}.children[${index}]` : ''; - } - - eachChild(iteratee) { - iteratee(this); - this.children.forEach((child) => child.eachChild(iteratee)); - return this; - } - - getComponents() { - return this.children.reduce( - (components, child) => components.concat(child.getComponents()), - this.components, - ); - } - - validateNode() { - let valid = true; - this.getComponents().forEach(comp => { - comp.setPristine(false); - valid &= comp.checkValidity(null, false, this.persistentData); - }); - return valid; - } - - addChild() { - if (this.new) { - return null; - } - - const child = new Node(this, {}, { - checkNode: this.checkNode, - createComponents: this.createComponents, - isNew: true, - removeComponents: this.removeComponents, - parentPath: this.getChildrenPath(this.children.length), - }); - this.children = this.children.concat(child); - return child; - } - - removeChild(childToRemove) { - if (!this.new) { - this.children = this.children.filter((child) => child !== childToRemove); - } - - return this; - } - - edit() { - if (this.new) { - return this; - } - - this.editing = true; - return this.resetData(); - } - - save() { - const isValid = this.validateNode(); - if (this.changing && isValid) { - if (this.new) { - this.new = false; - } - else { - this.editing = false; - this.revertAvailable = true; - } - this.commitData(); - } - - return isValid; - } - - cancel() { - if (this.new) { - this.remove(); - } - else if (this.editing) { - this.editing = false; - this.resetData(); - } - - return this; - } - - remove() { - this.parent.removeChild(this); - this.parent = null; - this.clearComponents(); - return this; - } - - revert() { - if (!this.revertAvailable) { - return this; - } - - this.data = this.previousData; - return this.commitData(); - } - - commitData() { - this.previousData = this.persistentData; - this.persistentData = _.cloneDeep(this.data); - this.clearComponents(); - return this; - } - - resetData() { - this.data = _.cloneDeep(this.persistentData); - this.updateComponentsContext(); - return this; - } - - updateComponentsContext() { - if (this.changing) { - this.instantiateComponents(); - } - else { - this.clearComponents(); - } - - return this; - } - - instantiateComponents() { - this.components = this.createComponents(this.data, this); - this.components.forEach((component) => { - if (this.parentPath) { - const path = this.calculateComponentPath(component); - component.path = path; - } - }); - this.checkNode(this); - } - - clearComponents() { - this.removeComponents(this.components); - this.components = []; - } - - /** - * Return a path of component's value. - * - * @param {Object} component - The component instance. - * @return {string} - The component's value path. - */ - calculateComponentPath(component) { - let path = ''; - if (component.component.key) { - path = `${this.parentPath}.data.${component.component.key}`; - } - return path; - } -} diff --git a/src/components/tree/Tree.form.js b/src/components/tree/Tree.form.js deleted file mode 100644 index 2fe5c9a19b..0000000000 --- a/src/components/tree/Tree.form.js +++ /dev/null @@ -1,15 +0,0 @@ -import componentEditForm from '../_classes/component/Component.form'; -import TreeEditData from './editForm/Tree.edit.data'; -import TreeDisplayData from './editForm/Tree.edit.display'; -export default function(...extend) { - return componentEditForm([ - { - key: 'display', - components: TreeDisplayData, - }, - { - key: 'data', - components: TreeEditData, - }, - ], ...extend); -} diff --git a/src/components/tree/Tree.js b/src/components/tree/Tree.js deleted file mode 100644 index 67a5e7c683..0000000000 --- a/src/components/tree/Tree.js +++ /dev/null @@ -1,520 +0,0 @@ -import _ from 'lodash'; -import Component from '../_classes/component/Component'; -import Components from '../Components'; -import NestedDataComponent from '../_classes/nesteddata/NestedDataComponent'; -import Node from './Node'; - -export default class TreeComponent extends NestedDataComponent { - static schema(...extend) { - return NestedDataComponent.schema({ - label: 'Tree', - key: 'tree', - type: 'tree', - clearOnHide: true, - input: true, - tree: true, - components: [], - multiple: false, - }, ...extend); - } - - static get builderInfo() { - return { - title: 'Tree', - icon: 'indent', - weight: 40, - documentation: '/userguide/form-building/data-components#tree', - showPreview: false, - schema: TreeComponent.schema(), - }; - } - - constructor(...args) { - super(...args); - this.type = 'tree'; - } - - get emptyValue() { - return {}; - } - - get viewComponents() { - if (!this.viewComponentsInstantiated) { - this.viewComponentsInstantiated = true; - this._viewComponents = this.createComponents({}); - } - - return this._viewComponents; - } - - init() { - if (this.builderMode) { - return super.init(); - } - - this.components = []; - this.componentOptions = { - ...this.options, - parent: this, - root: this.root || this, - }; - this.disabled = this.shouldDisabled; - this.setRoot(); - this.viewComponentsInstantiated = false; - this._viewComponents = []; - } - - get disabled() { - return super.disabled; - } - - set disabled(disabled) { - super.disabled = disabled; - this.viewComponents.forEach((component) => component.parentDisabled = disabled); - } - - get isDefaultValueComponent() { - return !!this.options.editComponent && !!this.options.editForm && this.component.key === 'defaultValue'; - } - - destroy(all = false) { - if (!this.builderMode) { - this.removeComponents(this._viewComponents, all); - } - super.destroy(all); - } - - createComponents(data, node) { - const components = this.componentComponents.map( - (component) => { - const componentInstance = Components.create(component, this.componentOptions, data); - componentInstance.init(); - componentInstance.parentDisabled = this.disabled; - return componentInstance; - }, - ); - - if (node) { - this.checkNode(this.data, node); - } - - return components; - } - - removeComponents(components, all = false) { - return components.map((component) => component.destroy(all)); - } - - render() { - if (this.builderMode) { - return super.render(); - } - - return super.render(this.renderTree(this.treeRoot)); - } - - renderTree(node = {}, odd = true) { - const childNodes = (node.hasChildren && !node.collapsed) - ? this.renderChildNodes(node.children, !odd) - : []; - const content = node.changing - ? this.renderEdit(node) - : this.renderView(node); - - return this.renderTemplate('tree', { - odd, - childNodes, - content, - node, - }); - } - - renderChildNodes(nodes = [], odd) { - return nodes.map((node) => this.renderTree(node, odd)); - } - - renderEdit(node = {}) { - return this.renderTemplate('treeEdit', { - children: this.renderComponents(node.components), - node, - }); - } - - renderView(node = {}) { - return this.renderTemplate('treeView', { - values: this.viewComponents.map((component) => { - component.data = node.data; - component.checkComponentConditions(node.data); - return component.getView(component.dataValue); - }), - nodeData: node.data, - node, - }); - } - - attach(element) { - if (this.builderMode) { - return super.attach(element); - } - - this.loadRefs(element, { - root: 'single', - }); - - return Promise.all([ - super.attach(element), - this.attachNode(this.refs.root, this.treeRoot), - ]); - } - - attachNode(element, node) { - if (!element) { - return Promise.resolve(); - } - - let componentsPromise = Promise.resolve(); - let childrenPromise = Promise.resolve(); - - node.refs = _.reduce( - element.children, - (refs, child) => ( - child.hasAttribute('ref') - ? { - ...refs, - [child.getAttribute('ref')]: child, - } - : refs - ), - {}, - ); - - if (node.refs.content) { - this.attachActions(node); - componentsPromise = this.attachComponents(node); - } - - if (node.refs.childNodes) { - childrenPromise = this.attachChildren(node); - } - - return Promise.all([ - componentsPromise, - childrenPromise, - ]); - } - - attachActions(node) { - if (!node.editing) { - this.loadRefs.call(node, node.refs.content, { - addChild: 'single', - editNode: 'single', - removeNode: 'single', - revertNode: 'single', - toggleNode: 'single', - }); - } - - //load refs correctly (if there is nested tree) - this.loadRefs.call(node, node.refs.content.children[0]?.children[1] || node.refs.content, { - cancelNode: 'single', - saveNode: 'single', - }); - - if (node.refs.addChild) { - this.addEventListener(node.refs.addChild, 'click', () => { - this.addChild(node); - }); - } - - if (node.refs.cancelNode) { - this.addEventListener(node.refs.cancelNode, 'click', () => { - this.cancelNode(node); - }); - } - - if (node.refs.editNode) { - this.addEventListener(node.refs.editNode, 'click', () => { - this.editNode(node); - }); - } - - if (node.refs.removeNode) { - this.addEventListener(node.refs.removeNode, 'click', () => { - this.removeNode(node); - }); - } - - if (node.refs.revertNode) { - this.addEventListener(node.refs.revertNode, 'click', () => { - this.revertNode(node); - }); - } - - if (node.refs.saveNode) { - this.addEventListener(node.refs.saveNode, 'click', () => { - this.saveNode(node); - }); - } - - if (node.refs.toggleNode) { - this.addEventListener(node.refs.toggleNode, 'click', () => { - this.toggleNode(node); - }); - } - } - - attachComponents(node, ...args) { - if (this.builderMode) { - return super.attachComponents.call(this, node, ...args); - } - - this.loadRefs.call(node, node.refs.content, { - nodeEdit: 'single', - }); - - return node.refs.nodeEdit - ? super.attachComponents(node.refs.nodeEdit, node.components) - : Promise.resolve(); - } - - attachChildren(node) { - const childElements = node.refs.childNodes.children; - - return Promise.all( - _.map( - childElements, - (childElement, index) => this.attachNode(childElement, node.children[index]), - ), - ); - } - - setValue(value, flags = {}) { - const changed = this.updateValue(value, flags); - this.setRoot(); - return changed; - } - - addChild(parent) { - if (this.options.readOnly || parent.new) { - return; - } - - this.hook('tree.addChild', { - parent, - component: this, - }, () => { - const child = parent.addChild(); - this.redraw(); - - return child; - }); - } - - cancelNode(node) { - if (this.options.readOnly) { - return; - } - - this.hook('tree.cancelNode', { - node, - component: this, - }, () => { - if (node.isRoot) { - if (node.persistentData && !_.isEmpty(node.persistentData)) { - node.cancel(); - this.redraw(); - } - else { - this.removeRoot(); - } - } - else { - node.cancel(); - this.redraw(); - } - - return node; - }); - } - - editNode(node) { - if (this.options.readOnly || node.new) { - return; - } - - this.hook('tree.editNode', { - node, - component: this, - }, () => { - node.edit(); - this.redraw(); - - return node; - }); - } - - removeNode(node) { - if (this.options.readOnly || node.new) { - return; - } - - this.hook('tree.removeNode', { - node, - component: this, - }, () => { - if (node.isRoot) { - this.removeRoot(); - } - else { - node.remove(); - this.updateTree(); - } - - return node; - }); - } - - revertNode(node) { - if (this.options.readOnly || !node.revertAvailable) { - return; - } - - this.hook('tree.revertNode', { - node, - component: this, - }, () => { - node.revert(); - this.updateTree(); - - return node; - }); - } - - saveNode(node) { - if (this.options.readOnly) { - return; - } - - this.hook('tree.saveNode', { - node, - component: this, - }, () => { - const isSaved = node.save(); - if (isSaved) { - this.updateTree(); - } - - return node; - }); - } - - toggleNode(node) { - this.hook('tree.toggleNode', { - node, - component: this, - }, () => { - node.collapsed = !node.collapsed; - this.redraw(); - - return node; - }); - } - - removeRoot() { - if (this.options.readOnly) { - return; - } - - this.dataValue = this.defaultValue; - this.setRoot(); - this.redraw(); - } - - setRoot() { - const value = this.getValue(); - this.treeRoot = new Node(null, value, { - isNew: this.builderMode ? true : !value.data, - createComponents: this.createComponents.bind(this), - checkNode: this.checkNode.bind(this, this.data), - removeComponents: this.removeComponents, - parentPath: this.isDefaultValueComponent ? (this.path || this.component.key) : null, - }); - this.hook('tree.setRoot', { - root: this.treeRoot, - component: this, - }); - this.redraw(); - } - - getValue() { - return this.dataValue || {}; - } - - updateTree() { - this.updateValue(this.treeRoot.value); - this.redraw(); - } - - checkData(data, flags, row) { - return this.checkNode(data, this.treeRoot, flags, row); - } - - checkNode(data, node, flags, row) { - return node.children.reduce( - (result, child) => this.checkNode(data, child, flags, row) && result, - super.checkData(data, flags, node.data, node.components) && !node.editing && !node.new, - ); - } - - getComponents() { - return this.treeRoot && (this.isDefaultValueComponent || (!this.isDefaultValueComponent && !this.builderMode)) - ? this.treeRoot.getComponents() - : super.getComponents(); - } - - getValueAsString(value, options) { - const getChildAsString = (value) => { - let result = (` -
${k} | -
- ${value.data[k]}
- - `)); - - if (value.children?.length !== 0) { - value.children?.forEach((v) => { - result += getChildAsString(v); - }); - } - - result += ` - |
-
---|