formiojs
Version:
Common js library for client side interaction with <form.io>
1,467 lines (1,198 loc) • 128 kB
JavaScript
"use strict";
function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
require("core-js/modules/es.reflect.construct.js");
require("core-js/modules/es.reflect.get.js");
require("core-js/modules/es.object.get-own-property-descriptor.js");
require("core-js/modules/es.symbol.js");
require("core-js/modules/es.symbol.description.js");
require("core-js/modules/es.symbol.iterator.js");
require("core-js/modules/es.array.iterator.js");
require("core-js/modules/web.dom-collections.iterator.js");
require("core-js/modules/es.object.keys.js");
require("core-js/modules/es.object.get-own-property-descriptors.js");
require("core-js/modules/es.weak-map.js");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
require("core-js/modules/es.object.assign.js");
require("core-js/modules/es.function.name.js");
require("core-js/modules/es.regexp.flags.js");
require("core-js/modules/es.object.to-string.js");
require("core-js/modules/web.dom-collections.for-each.js");
require("core-js/modules/es.array.concat.js");
require("core-js/modules/es.array.includes.js");
require("core-js/modules/es.regexp.exec.js");
require("core-js/modules/es.string.split.js");
require("core-js/modules/es.string.includes.js");
require("core-js/modules/es.string.replace.js");
require("core-js/modules/es.string.starts-with.js");
require("core-js/modules/es.array.join.js");
require("core-js/modules/es.regexp.to-string.js");
require("core-js/modules/es.array.map.js");
require("core-js/modules/es.array.splice.js");
require("core-js/modules/es.array.filter.js");
require("core-js/modules/es.array.from.js");
require("core-js/modules/es.string.iterator.js");
require("core-js/modules/es.array.slice.js");
require("core-js/modules/es.object.get-prototype-of.js");
var _vanillaTextMask = require("@formio/vanilla-text-mask");
var _nativePromiseOnly = _interopRequireDefault(require("native-promise-only"));
var _tippy = _interopRequireDefault(require("tippy.js"));
var _lodash = _interopRequireDefault(require("lodash"));
var _ismobilejs = _interopRequireDefault(require("ismobilejs"));
var _Formio = require("../../../Formio");
var FormioUtils = _interopRequireWildcard(require("../../../utils/utils"));
var _Validator = _interopRequireDefault(require("../../../validator/Validator"));
var _Element2 = _interopRequireDefault(require("../../../Element"));
var _ComponentModal = _interopRequireDefault(require("../componentModal/ComponentModal"));
var _widgets = _interopRequireDefault(require("../../../widgets"));
var _addons = _interopRequireDefault(require("../../../addons"));
var _uploadAdapter = require("../../../providers/storage/uploadAdapter");
var _en = _interopRequireDefault(require("../../../translations/en"));
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
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); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
function _get() { 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(arguments.length < 3 ? target : receiver); } return desc.value; }; } return _get.apply(this, arguments); }
function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; }
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 } }); Object.defineProperty(subClass, "prototype", { writable: false }); 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); }
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } 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 _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
var isIEBrowser = FormioUtils.getBrowserInfo().ie;
var CKEDITOR_URL = isIEBrowser ? 'https://cdn.ckeditor.com/4.14.1/standard/ckeditor.js' : 'https://cdn.form.io/ckeditor/19.0.0/ckeditor.js';
var QUILL_URL = isIEBrowser ? 'https://cdn.quilljs.com/1.3.7' : 'https://cdn.quilljs.com/2.0.0-dev.3';
var QUILL_TABLE_URL = 'https://cdn.form.io/quill/quill-table.js';
var ACE_URL = 'https://cdn.form.io/ace/1.4.10/ace.js';
var Templates = _Formio.GlobalFormio.Templates;
if (!Templates) {
Templates = require('../../../templates/Templates').default;
}
/**
* This is the Component class
which all elements within the FormioForm derive from.
*/
var Component = /*#__PURE__*/function (_Element) {
_inherits(Component, _Element);
var _super = _createSuper(Component);
/* eslint-enable no-unused-vars */
/**
* Initialize a new Component.
*
* @param {Object} component - The component JSON you wish to initialize.
* @param {Object} options - The options for this component.
* @param {Object} data - The global data submission object this component will belong.
*/
/* eslint-disable max-statements */
function Component(component, options, data) {
var _this;
_classCallCheck(this, Component);
_this = _super.call(this, Object.assign({
renderMode: 'form',
attachMode: 'full',
noDefaults: false
}, options || {})); // Restore the component id.
if (component && component.id) {
_this.id = component.id;
}
/**
* Determines if this component has a condition assigned to it.
* @type {null}
* @private
*/
_this._hasCondition = null;
/**
* References to dom elements
*/
_this.refs = {}; // Allow global override for any component JSON.
if (component && _this.options.components && _this.options.components[component.type]) {
_lodash.default.merge(component, _this.options.components[component.type]);
}
/**
* Set the validator instance.
*/
_this.validator = _Validator.default;
/**
* The data path to this specific component instance.
*
* @type {string}
*/
_this.path = '';
/**
* The Form.io component JSON schema.
* @type {*}
*/
_this.component = _this.mergeSchema(component || {}); // Add the id to the component.
_this.component.id = _this.id; // Save off the original component to be used in logic.
_this.originalComponent = (0, FormioUtils.fastCloneDeep)(_this.component);
/**
* If the component has been attached
*/
_this.attached = false;
/**
* If the component has been rendered
*/
_this.rendered = false;
/**
* The data object in which this component resides.
* @type {*}
*/
_this._data = data || {};
/**
* The existing error that this component has.
* @type {string}
*/
_this.error = '';
/**
* Tool tip text after processing
* @type {string}
*/
_this.tooltip = '';
/**
* The row path of this component.
* @type {number}
*/
_this.row = _this.options.row;
/**
* Determines if this component is disabled, or not.
*
* @type {boolean}
*/
_this._disabled = (0, FormioUtils.boolValue)(_this.component.disabled) ? _this.component.disabled : false;
/**
* Points to the root component, usually the FormComponent.
*
* @type {Component}
*/
_this.root = _this.options.root;
_this.localRoot = _this.options.localRoot;
/**
* If this input has been input and provided value.
*
* @type {boolean}
*/
_this.pristine = true;
/**
* Points to the parent component.
*
* @type {Component}
*/
_this.parent = _this.options.parent;
_this.options.name = _this.options.name || 'data';
/**
* The validators that are assigned to this component.
* @type {[string]}
*/
_this.validators = ['required', 'minLength', 'maxLength', 'minWords', 'maxWords', 'custom', 'pattern', 'json', 'mask'];
_this._path = ''; // Nested forms don't have parents so we need to pass their path in.
_this._parentPath = _this.options.parentPath || ''; // Needs for Nextgen Rules Engine
_this.resetCaches();
/**
* Determines if this component is visible, or not.
*/
_this._parentVisible = _this.options.hasOwnProperty('parentVisible') ? _this.options.parentVisible : true;
_this._visible = _this._parentVisible && _this.conditionallyVisible(null, data);
_this._parentDisabled = false;
/**
* Used to trigger a new change in this component.
* @type {function} - Call to trigger a change in this component.
*/
var changes = [];
var lastChanged = null;
var triggerArgs = [];
var _triggerChange = _lodash.default.debounce(function () {
var _this2;
if (_this.root) {
_this.root.changing = false;
}
triggerArgs = [];
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
if (!args[1] && lastChanged) {
// Set the changed component if one isn't provided.
args[1] = lastChanged;
}
if (_lodash.default.isEmpty(args[0]) && lastChanged) {
// Set the flags if it is empty and lastChanged exists.
args[0] = lastChanged.flags;
}
lastChanged = null;
args[3] = changes;
var retVal = (_this2 = _this).onChange.apply(_this2, args);
changes = [];
return retVal;
}, 100);
_this.triggerChange = function () {
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
if (args[1]) {
// Make sure that during the debounce that we always track lastChanged component, even if they
// don't provide one later.
lastChanged = args[1];
changes.push(lastChanged);
}
if (_this.root) {
_this.root.changing = true;
}
if (args.length) {
triggerArgs = args;
}
return _triggerChange.apply(void 0, _toConsumableArray(triggerArgs));
};
/**
* Used to trigger a redraw event within this component.
*
* @type {Function}
*/
_this.triggerRedraw = _lodash.default.debounce(_this.redraw.bind(_assertThisInitialized(_this)), 100);
/**
* list of attached tooltips
* @type {Array}
*/
_this.tooltips = [];
/**
* List of attached addons
* @type {Array}
*/
_this.addons = []; // To force this component to be invalid.
_this.invalid = false;
if (_this.component) {
_this.type = _this.component.type;
if (_this.allowData && _this.key) {
_this.options.name += "[".concat(_this.key, "]"); // If component is visible or not set to clear on hide, set the default value.
if (_this.visible || !_this.component.clearOnHide) {
if (!_this.hasValue()) {
if (_this.shouldAddDefaultValue) {
_this.dataValue = _this.defaultValue;
}
} else {
// Ensure the dataValue is set.
/* eslint-disable no-self-assign */
_this.dataValue = _this.dataValue;
/* eslint-enable no-self-assign */
}
}
}
/**
* The element information for creating the input element.
* @type {*}
*/
_this.info = _this.elementInfo();
} // Allow anyone to hook into the component creation.
_this.hook('component');
if (!_this.options.skipInit) {
_this.init();
}
return _this;
}
/* eslint-enable max-statements */
_createClass(Component, [{
key: "data",
get: function get() {
return this._data;
},
set: function set(value) {
this._data = value;
}
}, {
key: "mergeSchema",
value: function mergeSchema() {
var component = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
return _lodash.default.defaultsDeep(component, this.defaultSchema);
} // Allow componets to notify when ready.
}, {
key: "ready",
get: function get() {
return _nativePromiseOnly.default.resolve(this);
}
}, {
key: "labelInfo",
get: function get() {
var label = {};
label.hidden = this.labelIsHidden();
label.className = '';
label.labelPosition = this.component.labelPosition;
label.tooltipClass = "".concat(this.iconClass('question-sign'), " text-muted");
var isPDFReadOnlyMode = this.parent && this.parent.form && this.parent.form.display === 'pdf' && this.options.readOnly;
if (this.hasInput && this.component.validate && (0, FormioUtils.boolValue)(this.component.validate.required) && !isPDFReadOnlyMode) {
label.className += ' field-required';
}
if (label.hidden) {
label.className += ' control-label--hidden';
}
if (this.info.attr.id) {
label.for = this.info.attr.id;
}
return label;
}
}, {
key: "init",
value: function init() {
var _this$component$addon,
_this3 = this;
this.disabled = this.shouldDisabled;
this._visible = this.conditionallyVisible(null, null);
if ((_this$component$addon = this.component.addons) !== null && _this$component$addon !== void 0 && _this$component$addon.length) {
this.component.addons.forEach(function (addon) {
return _this3.createAddon(addon);
});
}
}
}, {
key: "createAddon",
value: function createAddon(addonConfiguration) {
var _addonConfiguration$s;
var name = addonConfiguration.name;
if (!name) {
return;
}
var settings = ((_addonConfiguration$s = addonConfiguration.settings) === null || _addonConfiguration$s === void 0 ? void 0 : _addonConfiguration$s.data) || {};
var Addon = _addons.default[name];
var addon = null;
if (Addon) {
var supportedComponents = Addon.info.supportedComponents;
var supportsThisComponentType = !(supportedComponents !== null && supportedComponents !== void 0 && supportedComponents.length) || supportedComponents.indexOf(this.component.type) !== -1;
if (supportsThisComponentType) {
addon = new Addon(settings, this);
this.addons.push(addon);
} else {
console.warn("Addon ".concat(name, " does not support component of type ").concat(this.component.type, "."));
}
}
return addon;
}
}, {
key: "destroy",
value: function destroy() {
_get(_getPrototypeOf(Component.prototype), "destroy", this).call(this);
this.detach();
this.addons.forEach(function (addon) {
return addon.destroy();
});
}
}, {
key: "shouldDisabled",
get: function get() {
return this.options.readOnly || this.component.disabled || this.options.hasOwnProperty('disabled') && this.options.disabled[this.key];
}
}, {
key: "isInputComponent",
get: function get() {
return !this.component.hasOwnProperty('input') || this.component.input;
}
}, {
key: "allowData",
get: function get() {
return this.hasInput;
}
}, {
key: "hasInput",
get: function get() {
return this.isInputComponent || this.refs.input && this.refs.input.length;
}
}, {
key: "defaultSchema",
get: function get() {
return Component.schema();
}
}, {
key: "key",
get: function get() {
return _lodash.default.get(this.component, 'key', '');
}
}, {
key: "parentVisible",
get: function get() {
return this._parentVisible;
},
set: function set(value) {
this._parentVisible = value;
}
}, {
key: "parentDisabled",
get: function get() {
return this._parentDisabled;
}
/**
*
* @param value {boolean}
*/
,
set: function set(value) {
this._parentDisabled = value;
}
}, {
key: "visible",
get:
/**
*
* @returns {boolean}
*/
function get() {
// Show only if visibility changes or if we are in builder mode or if hidden fields should be shown.
if (this.builderMode || this.previewMode || this.options.showHiddenFields) {
return true;
}
if (this.options.hide && this.options.hide[this.component.key]) {
return false;
}
if (this.options.show && this.options.show[this.component.key]) {
return true;
}
return this._visible && this._parentVisible;
},
set: function set(value) {
if (this._visible !== value) {
this._visible = value;
this.clearOnHide();
this.redraw();
}
}
}, {
key: "currentForm",
get: function get() {
return this._currentForm;
},
set: function set(instance) {
this._currentForm = instance;
}
}, {
key: "fullMode",
get: function get() {
return this.options.attachMode === 'full';
}
}, {
key: "builderMode",
get: function get() {
return this.options.attachMode === 'builder';
}
}, {
key: "calculatedPath",
get: function get() {
console.error('component.calculatedPath was deprecated, use component.path instead.');
return this.path;
}
}, {
key: "labelPosition",
get: function get() {
return this.component.labelPosition;
}
}, {
key: "labelWidth",
get: function get() {
var width = this.component.labelWidth;
return width >= 0 ? width : 30;
}
}, {
key: "labelMargin",
get: function get() {
var margin = this.component.labelMargin;
return margin >= 0 ? margin : 3;
}
}, {
key: "isAdvancedLabel",
get: function get() {
return ['left-left', 'left-right', 'right-left', 'right-right'].includes(this.labelPosition);
}
}, {
key: "labelPositions",
get: function get() {
return this.labelPosition.split('-');
}
}, {
key: "skipInEmail",
get: function get() {
return false;
}
}, {
key: "rightDirection",
value: function rightDirection(direction) {
return direction === 'right';
}
}, {
key: "getLabelInfo",
value: function getLabelInfo() {
var isRightPosition = this.rightDirection(this.labelPositions[0]);
var isLeftPosition = this.labelPositions[0] === 'left';
var isRightAlign = this.rightDirection(this.labelPositions[1]);
var contentMargin = '';
if (this.component.hideLabel) {
var margin = this.labelWidth + this.labelMargin;
contentMargin = isRightPosition ? "margin-right: ".concat(margin, "%") : '';
contentMargin = isLeftPosition ? "margin-left: ".concat(margin, "%") : '';
}
var labelStyles = "\n flex: ".concat(this.labelWidth, ";\n ").concat(isRightPosition ? 'margin-left' : 'margin-right', ": ").concat(this.labelMargin, "%;\n ");
var contentStyles = "\n flex: ".concat(100 - this.labelWidth - this.labelMargin, ";\n ").concat(contentMargin, ";\n ").concat(this.component.hideLabel ? "max-width: ".concat(100 - this.labelWidth - this.labelMargin) : '', ";\n ");
return {
isRightPosition: isRightPosition,
isRightAlign: isRightAlign,
labelStyles: labelStyles,
contentStyles: contentStyles
};
}
/**
* Returns only the schema that is different from the default.
*
* @param schema
* @param defaultSchema
*/
}, {
key: "getModifiedSchema",
value: function getModifiedSchema(schema, defaultSchema, recursion) {
var _this4 = this;
var modified = {};
if (!defaultSchema) {
return schema;
}
_lodash.default.each(schema, function (val, key) {
if (!_lodash.default.isArray(val) && _lodash.default.isObject(val) && defaultSchema.hasOwnProperty(key)) {
var subModified = _this4.getModifiedSchema(val, defaultSchema[key], true);
if (!_lodash.default.isEmpty(subModified)) {
modified[key] = subModified;
}
} else if (_lodash.default.isArray(val)) {
if (val.length !== 0 && !_lodash.default.isEqual(val, defaultSchema[key])) {
modified[key] = val;
}
} else if (!recursion && key === 'type' || !recursion && key === 'key' || !recursion && key === 'label' || !recursion && key === 'input' || !recursion && key === 'tableView' || val !== '' && !defaultSchema.hasOwnProperty(key) || val !== '' && val !== defaultSchema[key] || defaultSchema[key] && val !== defaultSchema[key]) {
modified[key] = val;
}
});
return modified;
}
/**
* Returns the JSON schema for this component.
*/
}, {
key: "schema",
get: function get() {
return (0, FormioUtils.fastCloneDeep)(this.getModifiedSchema(_lodash.default.omit(this.component, 'id'), this.defaultSchema));
}
/**
* Returns true if component is inside DataGrid
*/
}, {
key: "isInDataGrid",
get: function get() {
return this.inDataGrid;
}
/**
* Translate a text using the i18n system.
*
* @param {string} text - The i18n identifier.
* @param {Object} params - The i18n parameters to use for translation.
*/
}, {
key: "t",
value: function t(text) {
var _get2;
var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (!text) {
return '';
} // Use _userInput: true to ignore translations from defaults
if (text in _en.default && params._userInput) {
return text;
}
params.data = this.rootValue;
params.row = this.data;
params.component = this.component;
for (var _len3 = arguments.length, args = new Array(_len3 > 2 ? _len3 - 2 : 0), _key3 = 2; _key3 < _len3; _key3++) {
args[_key3 - 2] = arguments[_key3];
}
return (_get2 = _get(_getPrototypeOf(Component.prototype), "t", this)).call.apply(_get2, [this, text, params].concat(args));
}
}, {
key: "labelIsHidden",
value: function labelIsHidden() {
return !this.component.label || (!this.isInDataGrid && this.component.hideLabel || this.isInDataGrid && !this.component.dataGridLabel || this.options.inputsOnly) && !this.builderMode;
}
}, {
key: "transform",
get: function get() {
return Templates.current.hasOwnProperty('transform') ? Templates.current.transform.bind(Templates.current) : function (type, value) {
return value;
};
}
}, {
key: "getTemplate",
value: function getTemplate(names, modes) {
modes = Array.isArray(modes) ? modes : [modes];
names = Array.isArray(names) ? names : [names];
if (!modes.includes('form')) {
modes.push('form');
}
var result = null;
if (this.options.templates) {
result = this.checkTemplate(this.options.templates, names, modes);
if (result) {
return result;
}
}
var frameworkTemplates = this.options.template ? Templates.templates[this.options.template] : Templates.current;
result = this.checkTemplate(frameworkTemplates, names, modes);
if (result) {
return result;
} // Default back to bootstrap if not defined.
var name = names[names.length - 1];
var templatesByName = Templates.defaultTemplates[name];
if (!templatesByName) {
return "Unknown template: ".concat(name);
}
var templateByMode = this.checkTemplateMode(templatesByName, modes);
if (templateByMode) {
return templateByMode;
}
return templatesByName.form;
}
}, {
key: "checkTemplate",
value: function checkTemplate(templates, names, modes) {
var _iterator = _createForOfIteratorHelper(names),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var name = _step.value;
var templatesByName = templates[name];
if (templatesByName) {
var templateByMode = this.checkTemplateMode(templatesByName, modes);
if (templateByMode) {
return templateByMode;
}
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
return null;
}
}, {
key: "checkTemplateMode",
value: function checkTemplateMode(templatesByName, modes) {
var _iterator2 = _createForOfIteratorHelper(modes),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var mode = _step2.value;
var templateByMode = templatesByName[mode];
if (templateByMode) {
return templateByMode;
}
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
return null;
}
}, {
key: "getFormattedTooltip",
value: function getFormattedTooltip(tooltipValue) {
var tooltip = this.interpolate(tooltipValue || '').replace(/(?:\r\n|\r|\n)/g, '<br />');
return tooltip ? this.t(tooltip, {
_userInput: true
}).replace(/"/g, '"') : '';
}
}, {
key: "isHtmlRenderMode",
value: function isHtmlRenderMode() {
return this.options.renderMode === 'html';
}
}, {
key: "renderTemplate",
value: function renderTemplate(name) {
var _this5 = this;
var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var modeOption = arguments.length > 2 ? arguments[2] : undefined;
// Need to make this fall back to form if renderMode is not found similar to how we search templates.
var mode = modeOption || this.options.renderMode || 'form';
data.component = this.component;
data.self = this;
data.options = this.options;
data.readOnly = this.options.readOnly;
data.iconClass = this.iconClass.bind(this);
data.size = this.size.bind(this);
data.t = this.t.bind(this);
data.transform = this.transform;
data.id = data.id || this.id;
data.key = data.key || this.key;
data.value = data.value || this.dataValue;
data.disabled = this.disabled;
data.builder = this.builderMode;
data.render = function () {
console.warn("Form.io 'render' template function is deprecated.\n If you need to render template (template A) inside of another template (template B),\n pass pre-compiled template A (use this.renderTemplate('template_A_name') as template context variable for template B");
return _this5.renderTemplate.apply(_this5, arguments);
};
data.label = this.labelInfo;
data.tooltip = this.getFormattedTooltip(this.component.tooltip); // Allow more specific template names
var names = ["".concat(name, "-").concat(this.component.type, "-").concat(this.key), "".concat(name, "-").concat(this.component.type), "".concat(name, "-").concat(this.key), "".concat(name)]; // Allow template alters.
return this.hook("render".concat(name.charAt(0).toUpperCase() + name.substring(1, name.length)), this.interpolate(this.getTemplate(names, mode), data), data, mode);
}
/**
* Sanitize an html string.
*
* @param string
* @returns {*}
*/
}, {
key: "sanitize",
value: function sanitize(dirty, forceSanitize, options) {
var _this$options;
// No need to sanitize when generating PDF'S since no users interact with the form.
if (!this.shouldSanitizeValue && !forceSanitize || this.options.pdf && !forceSanitize) {
return dirty;
}
return FormioUtils.sanitize(dirty, {
sanitizeConfig: _lodash.default.merge(((_this$options = this.options) === null || _this$options === void 0 ? void 0 : _this$options.sanitizeConfig) || {}, options || {})
});
}
/**
* Render a template string into html.
*
* @param template
* @param data
* @param actions
*
* @return {HTMLElement|String} - The created element or an empty string if template is not specified.
*/
}, {
key: "renderString",
value: function renderString(template, data) {
if (!template) {
return '';
} // Interpolate the template and populate
return this.interpolate(template, data);
}
}, {
key: "performInputMapping",
value: function performInputMapping(input) {
return input;
}
}, {
key: "widget",
get: function get() {
var _this$root;
var settings = this.component.widget;
if (settings && (_this$root = this.root) !== null && _this$root !== void 0 && _this$root.shadowRoot) {
settings.shadowRoot = this.root.shadowRoot;
}
var widget = settings && _widgets.default[settings.type] ? new _widgets.default[settings.type](settings, this.component, this) : null;
return widget;
}
}, {
key: "getBrowserLanguage",
value: function getBrowserLanguage() {
var nav = window.navigator;
var browserLanguagePropertyKeys = ['language', 'browserLanguage', 'systemLanguage', 'userLanguage'];
var language; // support for HTML 5.1 "navigator.languages"
if (Array.isArray(nav.languages)) {
for (var i = 0; i < nav.languages.length; i++) {
language = nav.languages[i];
if (language && language.length) {
return language.split(';')[0];
}
}
} // support for other well known properties in browsers
for (var _i = 0; _i < browserLanguagePropertyKeys.length; _i++) {
language = nav[browserLanguagePropertyKeys[_i]];
if (language && language.length) {
return language.split(';')[0];
}
}
return null;
}
/**
* Called before a next and previous page is triggered allowing the components
* to perform special functions.
*
* @return {*}
*/
}, {
key: "beforePage",
value: function beforePage() {
return _nativePromiseOnly.default.resolve(true);
}
}, {
key: "beforeNext",
value: function beforeNext() {
return this.beforePage(true);
}
/**
* Called before a submission is triggered allowing the components
* to perform special async functions.
*
* @return {*}
*/
}, {
key: "beforeSubmit",
value: function beforeSubmit() {
return _nativePromiseOnly.default.resolve(true);
}
/**
* Return the submission timezone.
*
* @return {*}
*/
}, {
key: "submissionTimezone",
get: function get() {
this.options.submissionTimezone = this.options.submissionTimezone || _lodash.default.get(this.root, 'options.submissionTimezone');
return this.options.submissionTimezone;
}
}, {
key: "loadRefs",
value: function loadRefs(element, refs) {
for (var ref in refs) {
var refType = refs[ref];
var isString = typeof refType === 'string';
var selector = isString && refType.includes('scope') ? ":scope > [ref=\"".concat(ref, "\"]") : "[ref=\"".concat(ref, "\"]");
if (isString && refType.startsWith('single')) {
this.refs[ref] = element.querySelector(selector);
} else {
this.refs[ref] = element.querySelectorAll(selector);
}
}
}
}, {
key: "setOpenModalElement",
value: function setOpenModalElement(template) {
this.componentModal.setOpenModalElement(template || this.getModalPreviewTemplate());
}
}, {
key: "getModalPreviewTemplate",
value: function getModalPreviewTemplate() {
var dataValue = this.component.type === 'password' ? this.dataValue.replace(/./g, '•') : this.dataValue;
var message = this.error ? {
level: 'error',
message: this.error.message
} : '';
return this.renderTemplate('modalPreview', {
previewText: this.getValueAsString(dataValue, {
modalPreview: true
}) || this.t('Click to set value'),
messages: message && this.renderTemplate('message', message)
});
}
}, {
key: "build",
value: function build(element) {
element = element || this.element;
this.empty(element);
this.setContent(element, this.render());
return this.attach(element);
}
}, {
key: "hasModalSaveButton",
get: function get() {
return true;
}
}, {
key: "render",
value: function render() {
var children = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "Unknown component: ".concat(this.component.type);
var topLevel = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var isVisible = this.visible;
this.rendered = true;
if (!this.builderMode && !this.previewMode && this.component.modalEdit) {
return _ComponentModal.default.render(this, {
visible: isVisible,
showSaveButton: this.hasModalSaveButton,
id: this.id,
classes: this.className,
styles: this.customStyle,
children: children
}, topLevel);
} else {
return this.renderTemplate('component', {
visible: isVisible,
id: this.id,
classes: this.className,
styles: this.customStyle,
children: children
}, topLevel);
}
}
}, {
key: "attachTooltips",
value: function attachTooltips(toolTipsRefs) {
var _this6 = this;
toolTipsRefs === null || toolTipsRefs === void 0 ? void 0 : toolTipsRefs.forEach(function (tooltip, index) {
if (tooltip) {
var tooltipAttribute = tooltip.getAttribute('data-tooltip');
var tooltipDataTitle = tooltip.getAttribute('data-title');
var tooltipText = _this6.interpolate(tooltipDataTitle || tooltipAttribute).replace(/(?:\r\n|\r|\n)/g, '<br />');
_this6.tooltips[index] = (0, _tippy.default)(tooltip, {
allowHTML: true,
trigger: 'mouseenter click focus',
placement: 'right',
zIndex: 10000,
interactive: true,
content: _this6.t(tooltipText, {
_userInput: true
})
});
}
});
}
}, {
key: "createComponentModal",
value: function createComponentModal(element, modalShouldBeOpened, currentValue) {
return new _ComponentModal.default(this, element, modalShouldBeOpened, currentValue);
}
}, {
key: "attach",
value: function attach(element) {
if (!this.builderMode && !this.previewMode && this.component.modalEdit) {
var modalShouldBeOpened = this.componentModal ? this.componentModal.isOpened : false;
var currentValue = modalShouldBeOpened ? this.componentModal.currentValue : this.dataValue;
var openModalTemplate = this.componentModal && modalShouldBeOpened ? this.componentModal.openModalTemplate : null;
this.componentModal = this.createComponentModal(element, modalShouldBeOpened, currentValue);
this.setOpenModalElement(openModalTemplate);
}
this.attached = true;
this.element = element;
element.component = this; // If this already has an id, get it from the dom. If SSR, it could be different from the initiated id.
if (this.element.id) {
this.id = this.element.id;
this.component.id = this.id;
}
this.loadRefs(element, {
messageContainer: 'single',
tooltip: 'multiple'
});
this.attachTooltips(this.refs.tooltip); // Attach logic.
this.attachLogic();
this.autofocus(); // Allow global attach.
this.hook('attachComponent', element, this); // Allow attach per component type.
var type = this.component.type;
if (type) {
this.hook("attach".concat(type.charAt(0).toUpperCase() + type.substring(1, type.length)), element, this);
}
this.restoreFocus();
this.addons.forEach(function (addon) {
return addon.attach(element);
});
return _nativePromiseOnly.default.resolve();
}
}, {
key: "restoreFocus",
value: function restoreFocus() {
var _this$root2, _this$root2$focusedCo;
var isFocused = ((_this$root2 = this.root) === null || _this$root2 === void 0 ? void 0 : (_this$root2$focusedCo = _this$root2.focusedComponent) === null || _this$root2$focusedCo === void 0 ? void 0 : _this$root2$focusedCo.path) === this.path;
if (isFocused) {
var _this$root$currentSel;
this.loadRefs(this.element, {
input: 'multiple'
});
this.focus((_this$root$currentSel = this.root.currentSelection) === null || _this$root$currentSel === void 0 ? void 0 : _this$root$currentSel.index);
this.restoreCaretPosition();
}
}
}, {
key: "addShortcut",
value: function addShortcut(element, shortcut) {
// Avoid infinite recursion.
if (!element || !this.root || this.root === this) {
return;
}
if (!shortcut) {
shortcut = this.component.shortcut;
}
this.root.addShortcut(element, shortcut);
}
}, {
key: "removeShortcut",
value: function removeShortcut(element, shortcut) {
// Avoid infinite recursion.
if (!element || this.root === this) {
return;
}
if (!shortcut) {
shortcut = this.component.shortcut;
}
this.root.removeShortcut(element, shortcut);
}
/**
* Remove all event handlers.
*/
}, {
key: "detach",
value: function detach() {
this.refs = {};
this.removeEventListeners();
this.detachLogic();
if (this.tooltip) {
this.tooltip.destroy();
}
}
}, {
key: "checkRefresh",
value: function checkRefresh(refreshData, changed, flags) {
var changePath = _lodash.default.get(changed, 'instance.path', false); // Don't let components change themselves.
if (changePath && this.path === changePath) {
return;
}
if (refreshData === 'data') {
this.refresh(this.data, changed, flags);
} else if (changePath && (0, FormioUtils.getComponentPath)(changed.instance) === refreshData && changed && changed.instance && // Make sure the changed component is not in a different "context". Solves issues where refreshOn being set
// in fields inside EditGrids could alter their state from other rows (which is bad).
this.inContext(changed.instance)) {
this.refresh(changed.value, changed, flags);
}
}
}, {
key: "checkRefreshOn",
value: function checkRefreshOn(changes) {
var _this7 = this;
var flags = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
changes = changes || [];
if (flags.noRefresh) {
return;
}
if (!changes.length && flags.changed) {
changes = [flags.changed];
}
var refreshOn = flags.fromBlur ? this.component.refreshOnBlur : this.component.refreshOn || this.component.redrawOn; // If they wish to refresh on a value, then add that here.
if (refreshOn) {
if (Array.isArray(refreshOn)) {
refreshOn.forEach(function (refreshData) {
return changes.forEach(function (changed) {
return _this7.checkRefresh(refreshData, changed, flags);
});
});
} else {
changes.forEach(function (changed) {
return _this7.checkRefresh(refreshOn, changed, flags);
});
}
}
}
/**
* Refreshes the component with a new value.
*
* @param value
*/
}, {
key: "refresh",
value: function refresh(value) {
if (this.hasOwnProperty('refreshOnValue')) {
this.refreshOnChanged = !_lodash.default.isEqual(value, this.refreshOnValue);
} else {
this.refreshOnChanged = true;
}
this.refreshOnValue = (0, FormioUtils.fastCloneDeep)(value);
if (this.refreshOnChanged) {
if (this.component.clearOnRefresh) {
this.setValue(null);
}
this.triggerRedraw();
}
}
/**
* Checks to see if a separate component is in the "context" of this component. This is determined by first checking
* if they share the same "data" object. It will then walk up the parent tree and compare its parents data objects
* with the components data and returns true if they are in the same context.
*
* Different rows of the same EditGrid, for example, are in different contexts.
*
* @param component
*/
}, {
key: "inContext",
value: function inContext(component) {
if (component.data === this.data) {
return true;
}
var parent = this.parent;
while (parent) {
if (parent.data === component.data) {
return true;
}
parent = parent.parent;
}
return false;
}
}, {
key: "viewOnly",
get: function get() {
return this.options.readOnly && this.options.viewAsHtml;
}
}, {
key: "createViewOnlyElement",
value: function createViewOnlyElement() {
this.element = this.ce('dl', {
id: this.id
});
if (this.element) {
// Ensure you can get the component info from the element.
this.element.component = this;
}
return this.element;
}
}, {
key: "defaultViewOnlyValue",
get: function get() {
return '-';
}
/**
* Uses the widget to determine the output string.
*
* @param value
* @return {*}
*/
}, {
key: "getWidgetValueAsString",
value: function getWidgetValueAsString(value, options) {
var _this8 = this;
var noInputWidget = !this.refs.input || !this.refs.input[0] || !this.refs.input[0].widget;
if (!value || noInputWidget) {
if (!this.widget || !value) {
return value;
} else {
return this.widget.getValueAsString(value);
}
}
if (Array.isArray(value)) {
var values = [];
value.forEach(function (val, index) {
var widget = _this8.refs.input[index] && _this8.refs.input[index].widget;
if (widget) {
values.push(widget.getValueAsString(val, options));
}
});
return values;
}
var widget = this.refs.input[0].widget;
return widget.getValueAsString(value, options);
}
}, {
key: "getValueAsString",
value: function getValueAsString(value, options) {
if (!value) {
return '';
}
value = this.getWidgetValueAsString(value, options);
if (Array.isArray(value)) {
return value.join(', ');
}
if (_lodash.default.isPlainObject(value)) {