UNPKG

formiojs

Version:

Common js library for client side interaction with <form.io>

747 lines (632 loc) • 22.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; require("core-js/modules/es7.symbol.async-iterator"); require("core-js/modules/es6.symbol"); require("core-js/modules/es6.reflect.get"); require("core-js/modules/es7.array.includes"); require("core-js/modules/es6.string.includes"); require("core-js/modules/es6.array.iterator"); require("core-js/modules/es6.string.iterator"); require("core-js/modules/web.dom.iterable"); require("core-js/modules/es6.array.find-index"); var _lodash = _interopRequireDefault(require("lodash")); var _nativePromiseOnly = _interopRequireDefault(require("native-promise-only")); var _utils = require("../../utils/utils"); var _Base = _interopRequireDefault(require("../base/Base")); var _Components = _interopRequireDefault(require("../Components")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _get(target, property, receiver) { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get; } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(receiver); } return desc.value; }; } return _get(target, property, receiver || target); } function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } var NestedComponent = /*#__PURE__*/ function (_BaseComponent) { _inherits(NestedComponent, _BaseComponent); _createClass(NestedComponent, null, [{ key: "schema", value: function schema() { for (var _len = arguments.length, extend = new Array(_len), _key = 0; _key < _len; _key++) { extend[_key] = arguments[_key]; } return _Base.default.schema.apply(_Base.default, [{}].concat(extend)); } }]); function NestedComponent(component, options, data) { var _this; _classCallCheck(this, NestedComponent); _this = _possibleConstructorReturn(this, _getPrototypeOf(NestedComponent).call(this, component, options, data)); _this.type = 'components'; _this.components = []; _this.hidden = []; _this.collapsed = !!_this.component.collapsed; return _this; } _createClass(NestedComponent, [{ key: "build", value: function build(state, showLabel) { this.createElement(); if (showLabel) { this.createLabel(this.element); } this.addComponents(null, null, null, state); this.attachLogic(); } }, { key: "getComponents", value: function getComponents() { return this.components; } }, { key: "getAllComponents", value: function getAllComponents() { return this.getComponents().reduce(function (components, component) { var result = component; if (component && component.getAllComponents) { result = component.getAllComponents(); } return components.concat(result); }, []); } /** * Perform a deep iteration over every component, including those * within other container based components. * * @param {function} fn - Called for every component. */ }, { key: "everyComponent", value: function everyComponent(fn) { var components = this.getComponents(); _lodash.default.each(components, function (component, index) { if (fn(component, components, index) === false) { return false; } if (typeof component.everyComponent === 'function') { if (component.everyComponent(fn) === false) { return false; } } }); } /** * Perform an iteration over each component within this container component. * * @param {function} fn - Called for each component */ }, { key: "eachComponent", value: function eachComponent(fn) { _lodash.default.each(this.getComponents(), function (component, index) { if (fn(component, index) === false) { return false; } }); } /** * Returns a component provided a key. This performs a deep search within the * component tree. * * @param {string} key - The key of the component to retrieve. * @param {function} fn - Called with the component once found. * @return {Object} - The component that is located. */ }, { key: "getComponent", value: function getComponent(key, fn) { var comp = null; this.everyComponent(function (component, components) { if (component.component.key === key) { comp = component; if (fn) { fn(component, components); } return false; } }); return comp; } /** * Return a component provided the Id of the component. * * @param {string} id - The Id of the component. * @param {function} fn - Called with the component once it is retrieved. * @return {Object} - The component retrieved. */ }, { key: "getComponentById", value: function getComponentById(id, fn) { var comp = null; this.everyComponent(function (component, components) { if (component.id === id) { comp = component; if (fn) { fn(component, components); } return false; } }); return comp; } /** * Create a new component and add it to the components array. * * @param component * @param data */ }, { key: "createComponent", value: function createComponent(component, options, data, before, state) { options = options || this.options; data = data || this.data; var comp = _Components.default.create(component, options, data, true); comp.parent = this; comp.root = this.root || this; comp.build(state); comp.isBuilt = true; if (component.internal) { return comp; } if (before) { var index = _lodash.default.findIndex(this.components, { id: before.id }); if (index !== -1) { this.components.splice(index, 0, comp); } else { this.components.push(comp); } } else { this.components.push(comp); } return comp; } }, { key: "getContainer", value: function getContainer() { return this.element; } /** * Add a new component to the components array. * * @param {Object} component - The component JSON schema to add. * @param {HTMLElement} element - The DOM element to append this child to. * @param {Object} data - The submission data object to house the data for this component. * @param {HTMLElement} before - A DOM element to insert this element before. * @param {Boolean} noAdd - If this component should just be created and not added to this nested component. * @param {Object} state - The state of the component getting created. * @return {BaseComponent} - The created component instance. */ }, { key: "addComponent", value: function addComponent(component, element, data, before, noAdd, state) { element = element || this.getContainer(); data = data || this.data; var comp = this.createComponent(component, this.options, data, before ? before.component : null, state); if (noAdd) { return comp; } element = this.hook('addComponent', element, comp, this); var compElement = comp.getElement(); if (!compElement) { console.warn("Component ".concat(component.key, " has no element.")); return comp; } if (before) { element.insertBefore(compElement, before); } else { element.appendChild(compElement); } this.setHidden(comp); return comp; } /** * Remove a component from the components array. * * @param {BaseComponent} component - The component to remove from the components. * @param {Array<BaseComponent>} components - An array of components to remove this component from. */ }, { key: "removeComponent", value: function removeComponent(component, components) { components = components || this.components; var state = component.destroy(); var element = component.getElement(); if (element && element.parentNode) { this.removeChildFrom(element, element.parentNode); } _lodash.default.remove(components, { id: component.id }); return state; } /** * Removes a component provided the API key of that component. * * @param {string} key - The API key of the component to remove. * @param {function} fn - Called once the component is removed. * @return {null} */ }, { key: "removeComponentByKey", value: function removeComponentByKey(key, fn) { var _this2 = this; var comp = this.getComponent(key, function (component, components) { _this2.removeComponent(component, components); if (fn) { fn(component, components); } }); if (!comp) { if (fn) { fn(null); } return null; } } /** * Removes a component provided the Id of the component. * * @param {string} id - The Id of the component to remove. * @param {function} fn - Called when the component is removed. * @return {null} */ }, { key: "removeComponentById", value: function removeComponentById(id, fn) { var _this3 = this; var comp = this.getComponentById(id, function (component, components) { _this3.removeComponent(component, components); if (fn) { fn(component, components); } }); if (!comp) { if (fn) { fn(null); } return null; } } }, { key: "addComponents", /** * * @param element * @param data */ value: function addComponents(element, data, options, state) { var _this4 = this; element = element || this.getContainer(); data = data || this.data; options = options || this.options; state = state || {}; if (options.components) { this.components = options.components; } else { var components = this.hook('addComponents', this.componentComponents, this) || []; components.forEach(function (component) { var compState = {}; if (state && state.components && state.components[component.key]) { compState = state.components[component.key]; } _this4.addComponent(component, element, data, null, null, compState); }); } } }, { key: "updateValue", value: function updateValue(flags) { return this.components.reduce(function (changed, comp) { return comp.updateValue(flags) || changed; }, false); } }, { key: "hasChanged", value: function hasChanged() { return false; } /** * A more performant way to check the conditions, calculations, and validity of * a submission once it has been changed. * * @param data * @param flags */ }, { key: "checkData", value: function checkData(data, flags) { flags = flags || {}; var valid = true; if (flags.noCheck) { return; } // Update the value. var changed = this.updateValue({ noUpdateEvent: true }); // Iterate through all components and check conditions, and calculate values. this.getComponents().forEach(function (comp) { changed |= comp.calculateValue(data, { noUpdateEvent: true }); comp.checkConditions(data); if (!flags.noValidate) { valid &= comp.checkValidity(data); } }); // Trigger the change if the values changed. if (changed) { this.triggerChange(flags); } // Return if the value is valid. return valid; } }, { key: "checkConditions", value: function checkConditions(data) { this.getComponents().forEach(function (comp) { return comp.checkConditions(data); }); return _get(_getPrototypeOf(NestedComponent.prototype), "checkConditions", this).call(this, data); } }, { key: "clearOnHide", value: function clearOnHide(show) { _get(_getPrototypeOf(NestedComponent.prototype), "clearOnHide", this).call(this, show); this.getComponents().forEach(function (component) { return component.clearOnHide(show); }); } }, { key: "show", value: function show(_show) { var shown = _get(_getPrototypeOf(NestedComponent.prototype), "show", this).call(this, _show); var forceShow = this.options.show && this.options.show[this.component.key]; var forceHide = this.options.hide && this.options.hide[this.component.key]; if (forceShow || forceHide) { this.getComponents().forEach(function (component) { if (forceShow) { component.show(true); } else if (forceHide) { component.show(false); } }); } // If hiding a nested component, clear all errors below. if (!shown) { this.getAllComponents().forEach(function (component) { component.error = ''; }); } return shown; } /** * Allow components to hook into the next page trigger to perform their own logic. * * @return {*} */ }, { key: "beforeNext", value: function beforeNext() { return _nativePromiseOnly.default.all(this.getComponents().map(function (comp) { return comp.beforeNext(); })); } /** * Allow components to hook into the submission to provide their own async data. * * @return {*} */ }, { key: "beforeSubmit", value: function beforeSubmit() { return _nativePromiseOnly.default.all(this.getComponents().map(function (comp) { return comp.beforeSubmit(); })); } }, { key: "calculateValue", value: function calculateValue(data, flags) { // Do not iterate into children and calculateValues if this nested component is conditionally hidden. if (!this.conditionallyVisible()) { return false; } return this.getComponents().reduce(function (changed, comp) { return comp.calculateValue(data, flags) || changed; }, _get(_getPrototypeOf(NestedComponent.prototype), "calculateValue", this).call(this, data, flags)); } }, { key: "isValid", value: function isValid(data, dirty) { return this.getComponents().reduce(function (valid, comp) { return comp.isValid(data, dirty) && valid; }, _get(_getPrototypeOf(NestedComponent.prototype), "isValid", this).call(this, data, dirty)); } }, { key: "checkValidity", value: function checkValidity(data, dirty) { if (!(0, _utils.checkCondition)(this.component, data, this.data, this.root ? this.root._form : {}, this)) { this.setCustomValidity(''); return true; } return this.getComponents().reduce(function (check, comp) { return comp.checkValidity(data, dirty) && check; }, _get(_getPrototypeOf(NestedComponent.prototype), "checkValidity", this).call(this, data, dirty)); } }, { key: "setPristine", value: function setPristine(pristine) { _get(_getPrototypeOf(NestedComponent.prototype), "setPristine", this).call(this, pristine); this.getComponents().forEach(function (comp) { return comp.setPristine(pristine); }); } /** * Destroys this component. * * @param state */ }, { key: "destroy", value: function destroy() { var state = _get(_getPrototypeOf(NestedComponent.prototype), "destroy", this).call(this) || {}; this.destroyComponents(state); return state; } }, { key: "destroyComponents", value: function destroyComponents(state) { var _this5 = this; state = state || {}; state.components = state.components || {}; var components = this.components.slice(); components.forEach(function (comp) { var compState = _this5.removeComponent(comp, _this5.components); if (comp.key && compState) { state.components[comp.key] = compState; } }); this.components = []; this.hidden = []; return state; } }, { key: "setHidden", value: function setHidden(component) { if (component.component.hidden || this.hidden && this.hidden.includes(component.key) || !component.conditionallyVisible()) { component.show(false, true); } } }, { key: "hideComponents", value: function hideComponents(hidden) { var _this6 = this; this.hidden = hidden; this.eachComponent(function (component) { return _this6.setHidden(component); }); } }, { key: "getValue", value: function getValue() { return this.data; } }, { key: "resetValue", value: function resetValue() { this.getComponents().forEach(function (comp) { return comp.resetValue(); }); _lodash.default.unset(this.data, this.key); this.setPristine(true); } }, { key: "setNestedValue", value: function setNestedValue(component, value, flags, changed) { if (component.type === 'button') { return false; } if (component.type === 'components') { return component.setValue(value, flags) || changed; } else if (value && component.hasValue(value)) { return component.setValue(_lodash.default.get(value, component.key), flags) || changed; } else { flags.noValidate = true; return component.setValue(component.defaultValue, flags) || changed; } } }, { key: "setValue", value: function setValue(value, flags) { var _this7 = this; if (!value) { return false; } flags = this.getFlags.apply(this, arguments); return this.getComponents().reduce(function (changed, component) { return _this7.setNestedValue(component, value, flags, changed); }, false); } }, { key: "setCollapseHeader", value: function setCollapseHeader(header) { var _this8 = this; if (this.component.collapsible) { this.addClass(header, 'formio-clickable'); this.addEventListener(header, 'click', function () { return _this8.toggleCollapse(); }); } } }, { key: "setCollapsed", value: function setCollapsed(element) { if (!this.component.collapsible || this.options.builder) { return; } var container = element || this.getContainer(); if (this.collapsed) { container.setAttribute('hidden', true); container.style.visibility = 'hidden'; } else { container.removeAttribute('hidden'); container.style.visibility = 'visible'; } } }, { key: "toggleCollapse", value: function toggleCollapse() { this.collapsed = !this.collapsed; this.setCollapsed(); } }, { key: "defaultSchema", get: function get() { return NestedComponent.schema(); } }, { key: "schema", get: function get() { var schema = _get(_getPrototypeOf(NestedComponent.prototype), "schema", this); schema.components = []; this.eachComponent(function (component) { return schema.components.push(component.schema); }); return schema; } }, { key: "componentComponents", get: function get() { return this.component.components; } }, { key: "disabled", set: function set(disabled) { this.components.forEach(function (component) { return component.disabled = disabled; }); } }, { key: "errors", get: function get() { return this.getAllComponents().reduce(function (errors, comp) { return errors.concat(comp.errors || []); }, []); } }, { key: "dataReady", get: function get() { return _nativePromiseOnly.default.all(this.getComponents().map(function (component) { return component.dataReady; })); } }]); return NestedComponent; }(_Base.default); exports.default = NestedComponent;