UNPKG

formiojs

Version:

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

714 lines (677 loc) • 24.8 kB
"use strict"; require("core-js/modules/es.object.define-property.js"); require("core-js/modules/es.symbol.iterator.js"); require("core-js/modules/es.array.iterator.js"); require("core-js/modules/es.string.iterator.js"); require("core-js/modules/web.dom-collections.iterator.js"); require("core-js/modules/es.weak-map.js"); require("core-js/modules/es.object.get-own-property-descriptor.js"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; require("core-js/modules/es.object.assign.js"); require("core-js/modules/es.array.concat.js"); require("core-js/modules/es.array.for-each.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.some.js"); require("core-js/modules/es.array.is-array.js"); require("core-js/modules/es.date.to-string.js"); require("core-js/modules/es.regexp.to-string.js"); require("core-js/modules/es.array.join.js"); require("core-js/modules/es.array.map.js"); require("core-js/modules/es.regexp.constructor.js"); require("core-js/modules/es.regexp.exec.js"); require("core-js/modules/es.array.index-of.js"); require("core-js/modules/es.string.replace.js"); require("core-js/modules/es.array.includes.js"); require("core-js/modules/es.string.includes.js"); require("core-js/modules/es.array.slice.js"); require("core-js/modules/es.symbol.to-primitive.js"); require("core-js/modules/es.date.to-primitive.js"); require("core-js/modules/es.symbol.js"); require("core-js/modules/es.symbol.description.js"); require("core-js/modules/es.number.constructor.js"); var _EventEmitter = _interopRequireDefault(require("./EventEmitter")); var _Formio = require("./Formio"); var FormioUtils = _interopRequireWildcard(require("./utils/utils")); var _i18next = _interopRequireDefault(require("i18next")); var _lodash = _interopRequireDefault(require("lodash")); var _moment = _interopRequireDefault(require("moment")); var _vanillaTextMask = _interopRequireDefault(require("@formio/vanilla-text-mask")); 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 _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); } 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, _toPropertyKey(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 _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } /** * The root component for all elements within the Form.io renderer. */ var Element = /*#__PURE__*/function () { function Element(options) { _classCallCheck(this, Element); /** * The options for this component. * @type {{}} */ this.options = Object.assign({ language: 'en', highlightErrors: true, componentErrorClass: 'formio-error-wrapper', componentWarningClass: 'formio-warning-wrapper', row: '', namespace: 'formio' }, options || {}); /** * The ID of this component. This value is auto-generated when the component is created, but * can also be provided from the component.id value passed into the constructor. * @type {string} */ this.id = FormioUtils.getRandomComponentId(); /** * An array of event handlers so that the destry command can deregister them. * @type {Array} */ this.eventHandlers = []; // Use the i18next that is passed in, otherwise use the global version. this.i18next = this.options.i18next || _i18next["default"]; /** * An instance of the EventEmitter class to handle the emitting and registration of events. * * @type {EventEmitter} */ this.events = options && options.events ? options.events : new _EventEmitter["default"](); this.defaultMask = null; /** * Conditional to show or hide helplinks in editForm * * @type {*|boolean} */ this.helplinks = this.options.helplinks === 'false' ? false : this.options.helplinks || 'https://help.form.io'; } /** * Register for a new event within this component. * * @example * let component = new BaseComponent({ * type: 'textfield', * label: 'First Name', * key: 'firstName' * }); * component.on('componentChange', (changed) => { * console.log('this element is changed.'); * }); * * * @param {string} event - The event you wish to register the handler for. * @param {function} cb - The callback handler to handle this event. */ _createClass(Element, [{ key: "on", value: function on(event, cb, internal) { var once = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; if (!this.events) { return; } var type = "".concat(this.options.namespace, ".").concat(event); // Store the component id in the handler so that we can determine which events are for this component. cb.id = this.id; cb.key = this.key; cb.internal = internal; // Register for this event. return this.events[once ? 'once' : 'on'](type, cb); } /** * Register for a new single-fire event within this component. * * @param {string} event - The event you wish to register the handler for. * @param {function} cb - The callback handler to handle this event. */ }, { key: "once", value: function once(event, cb, internal) { return this.on(event, cb, internal, true); } /** * Allow catching any event. * * @param cb * @returns {this} */ }, { key: "onAny", value: function onAny(cb) { if (!this.events) { return; } return this.events.onAny(cb); } /** * Removes the listener that will be fired when any event is emitted. * * @param cb * @returns {this} */ }, { key: "offAny", value: function offAny(cb) { if (!this.events) { return; } return this.events.offAny(cb); } /** * Removes a listener for a certain event. Not passing the 2nd arg will remove all listeners for that event. * * @param {string} event - The event you wish to register the handler for. * @param {function|undefined} cb - The callback handler to handle this event. */ }, { key: "off", value: function off(event, cb) { var _this = this; if (!this.events) { return; } var type = "".concat(this.options.namespace, ".").concat(event); this.events.listeners(type).forEach(function (listener) { // Ensure the listener is for this element if (!listener || listener.id !== _this.id) { return; } // If there is a given callback, only deal with the match if (cb && cb !== listener) { return; } _this.events.off(type, listener); }); } /** * Emit a new event. * * @param {string} event - The event to emit. * @param {Object} data - The data to emit with the handler. */ }, { key: "emit", value: function emit(event) { if (this.events) { var _this$events; for (var _len = arguments.length, data = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { data[_key - 1] = arguments[_key]; } (_this$events = this.events).emit.apply(_this$events, ["".concat(this.options.namespace, ".").concat(event)].concat(data)); } } /** * Check if the component has an event handler set up for the event. * * @param {string} event - The event name. * @returns {boolean} */ }, { key: "hasEventHandler", value: function hasEventHandler(event) { var _this2 = this; if (!this.events) { return false; } var type = "".concat(this.options.namespace, ".").concat(event); return this.events.listeners(type).some(function (listener) { if (!listener) { return false; } return listener.id === _this2.id || listener.key === _this2.key; }); } /** * Wrapper method to add an event listener to an HTML element. * * @param obj * The DOM element to add the event to. * @param type * The event name to add. * @param func * The callback function to be executed when the listener is triggered. * @param persistent * If this listener should persist beyond "destroy" commands. */ }, { key: "addEventListener", value: function addEventListener(obj, type, func, persistent, capture) { if (!obj) { return; } if (!persistent) { this.eventHandlers.push({ id: this.id, obj: obj, type: type, func: func }); } if ('addEventListener' in obj) { obj.addEventListener(type, func, !!capture); } else if ('attachEvent' in obj) { obj.attachEvent("on".concat(type), func); } return this; } /** * Remove an event listener from the object. * * @param obj * @param type */ }, { key: "removeEventListener", value: function removeEventListener(obj, type) { var _this3 = this; var func = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; var indexes = []; if (!obj) { return; } this.eventHandlers.forEach(function (handler, index) { if (handler.id === _this3.id && obj.removeEventListener && handler.type === type && (!func || handler.func === func)) { obj.removeEventListener(type, handler.func); indexes.push(index); } }); if (indexes.length) { _lodash["default"].pullAt(this.eventHandlers, indexes); } return this; } }, { key: "removeEventListeners", value: function removeEventListeners() { var _this4 = this; this.eventHandlers.forEach(function (handler) { if (_this4.id === handler.id && handler.type && handler.obj && handler.obj.removeEventListener) { handler.obj.removeEventListener(handler.type, handler.func); } }); this.eventHandlers = []; } }, { key: "removeAllEvents", value: function removeAllEvents(includeExternal) { var _this5 = this; _lodash["default"].each(this.events._events, function (events, type) { _lodash["default"].each(events, function (listener) { if (listener && _this5.id === listener.id && (includeExternal || listener.internal)) { _this5.events.off(type, listener); } }); }); } /** * Removes all event listeners attached to this component. */ }, { key: "destroy", value: function destroy() { this.removeEventListeners(); this.removeAllEvents(); } /** * Append an HTML DOM element to a container. * * @param element * @param container */ }, { key: "appendTo", value: function appendTo(element, container) { container === null || container === void 0 ? void 0 : container.appendChild(element); return this; } /** * Prepend an HTML DOM element to a container. * * @param {HTMLElement} element - The DOM element to prepend. * @param {HTMLElement} container - The DOM element that is the container of the element getting prepended. */ }, { key: "prependTo", value: function prependTo(element, container) { if (container) { if (container.firstChild) { try { container.insertBefore(element, container.firstChild); } catch (err) { console.warn(err); container.appendChild(element); } } else { container.appendChild(element); } } return this; } /** * Removes an HTML DOM element from its bounding container. * * @param {HTMLElement} element - The element to remove. * @param {HTMLElement} container - The DOM element that is the container of the element to remove. */ }, { key: "removeChildFrom", value: function removeChildFrom(element, container) { if (container && container.contains(element)) { try { container.removeChild(element); } catch (err) { console.warn(err); } } return this; } /** * Alias for document.createElement. * * @param {string} type - The type of element to create * @param {Object} attr - The element attributes to add to the created element. * @param {Various} children - Child elements. Can be a DOM Element, string or array of both. * * @return {HTMLElement} - The created element. */ }, { key: "ce", value: function ce(type, attr) { var children = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; // console.warn('Call to deprecated this.ce(). Dom elements should be created with templates, not manually with ce.'); // Create the element. var element = document.createElement(type); // Add attributes. if (attr) { this.attr(element, attr); } // Append the children. this.appendChild(element, children); return element; } /** * Append different types of children. * * @param child */ }, { key: "appendChild", value: function appendChild(element, child) { var _this6 = this; if (Array.isArray(child)) { child.forEach(function (oneChild) { return _this6.appendChild(element, oneChild); }); } else if (child instanceof HTMLElement || child instanceof Text) { element.appendChild(child); } else if (child) { element.appendChild(this.text(child.toString())); } return this; } /** * Creates a new input mask placeholder. * @param {HTMLElement} mask - The input mask. * @returns {string} - The placeholder that will exist within the input as they type. */ }, { key: "maskPlaceholder", value: function maskPlaceholder(mask) { var _this7 = this; return mask.map(function (_char) { return _char instanceof RegExp ? _this7.placeholderChar : _char; }).join(''); } }, { key: "placeholderChar", get: function get() { var _this$component; return ((_this$component = this.component) === null || _this$component === void 0 ? void 0 : _this$component.inputMaskPlaceholderChar) || '_'; } /** * Sets the input mask for an input. * * @param {HTMLElement} input - The html input to apply the mask to. * @param {String} inputMask - The input mask to add to this input. * @param {Boolean} usePlaceholder - Set the mask placeholder on the input. */ }, { key: "setInputMask", value: function setInputMask(input, inputMask, usePlaceholder) { if (input && inputMask) { var mask = FormioUtils.getInputMask(inputMask, this.placeholderChar); this.defaultMask = mask; try { //destroy previous mask if (input.mask) { input.mask.destroy(); } input.mask = (0, _vanillaTextMask["default"])({ inputElement: input, mask: mask, placeholderChar: this.placeholderChar, shadowRoot: this.root ? this.root.shadowRoot : null }); } catch (e) { // Don't pass error up, to prevent form rejection. // Internal bug of vanilla-text-mask on iOS (`selectionEnd`); console.warn(e); } if (mask.numeric) { input.setAttribute('pattern', '\\d*'); } if (usePlaceholder) { input.setAttribute('placeholder', this.maskPlaceholder(mask)); } } } /** * Translate a text using the i18n system. * * @param {string|Array<string>} text - The i18n identifier. * @param {Object} params - The i18n parameters to use for translation. */ }, { key: "t", value: function t(text) { var _this$i18next; for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { args[_key2 - 1] = arguments[_key2]; } return (_this$i18next = this.i18next).t.apply(_this$i18next, [text].concat(args)); } /** * Alias to create a text node. * @param text * @returns {Text} */ }, { key: "text", value: function text(_text) { return document.createTextNode(this.t(_text)); } /** * Adds an object of attributes onto an element. * @param {HtmlElement} element - The element to add the attributes to. * @param {Object} attr - The attributes to add to the input element. */ }, { key: "attr", value: function attr(element, _attr) { var _this8 = this; if (!element) { return; } _lodash["default"].each(_attr, function (value, key) { if (typeof value !== 'undefined') { if (key.indexOf('on') === 0) { // If this is an event, add a listener. _this8.addEventListener(element, key.substr(2).toLowerCase(), value); } else { // Otherwise it is just an attribute. element.setAttribute(key, value); } } }); } /** * Determines if an element has a class. * * Taken from jQuery https://j11y.io/jquery/#v=1.5.0&fn=jQuery.fn.hasClass */ }, { key: "hasClass", value: function hasClass(element, className) { if (!element) { return false; } // Allow templates to intercept. className = " ".concat(className, " "); return " ".concat(element.className, " ").replace(/[\n\t\r]/g, ' ').indexOf(className) > -1; } /** * Adds a class to a DOM element. * * @param element * The element to add a class to. * @param className * The name of the class to add. */ }, { key: "addClass", value: function addClass(element, className) { if (!element || !(element instanceof HTMLElement)) { return this; } // Allow templates to intercept. var classes = element.getAttribute('class'); if (!(classes !== null && classes !== void 0 && classes.includes(className))) { element.setAttribute('class', "".concat(classes, " ").concat(className)); } return this; } /** * Remove a class from a DOM element. * * @param element * The DOM element to remove the class from. * @param className * The name of the class that is to be removed. */ }, { key: "removeClass", value: function removeClass(element, className) { if (!element || !className || !(element instanceof HTMLElement)) { return this; } // Allow templates to intercept. var cls = element.getAttribute('class'); if (cls) { cls = cls.replace(new RegExp(" ".concat(className), 'g'), ''); element.setAttribute('class', cls); } return this; } /** * Empty's an HTML DOM element. * * @param {HTMLElement} element - The element you wish to empty. */ }, { key: "empty", value: function empty(element) { if (element) { while (element.firstChild) { element.removeChild(element.firstChild); } } } /** * Create an evaluation context for all script executions and interpolations. * * @param additional * @return {*} */ }, { key: "evalContext", value: function evalContext(additional) { var _this$options; return Object.assign({ _: _lodash["default"], utils: FormioUtils, util: FormioUtils, user: _Formio.GlobalFormio.getUser(), moment: _moment["default"], instance: this, self: this, token: _Formio.GlobalFormio.getToken({ decode: true }), config: this.root && this.root.form && this.root.form.config ? this.root.form.config : (_this$options = this.options) !== null && _this$options !== void 0 && _this$options.formConfig ? this.options.formConfig : {} }, additional, _lodash["default"].get(this.root, 'options.evalContext', {})); } /** * Performs an interpolation using the evaluation context of this component. * * @param string * @param data * @return {XML|string|*|void} */ }, { key: "interpolate", value: function interpolate(string, data) { var _this9 = this; var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; if (typeof string !== 'function' && (this.component.content || this.component.html) && !FormioUtils.Evaluator.templateSettings.interpolate.test(string)) { string = FormioUtils.translateHTMLTemplate(String(string), function (value) { return _this9.t(value); }); } return FormioUtils.interpolate(string, this.evalContext(data), options); } /** * Performs an evaluation using the evaluation context of this component. * * @param func * @param args * @param ret * @param tokenize * @return {*} */ }, { key: "evaluate", value: function evaluate(func, args, ret, tokenize) { return FormioUtils.evaluate(func, this.evalContext(args), ret, tokenize); } /** * Allow for options to hook into the functionality of this renderer. * @return {*} */ }, { key: "hook", value: function hook() { var name = arguments[0]; if (this.options && this.options.hooks && this.options.hooks[name]) { return this.options.hooks[name].apply(this, Array.prototype.slice.call(arguments, 1)); } else { // If this is an async hook instead of a sync. var fn = typeof arguments[arguments.length - 1] === 'function' ? arguments[arguments.length - 1] : null; if (fn) { return fn(null, arguments[1]); } else { return arguments[1]; } } } }]); return Element; }(); exports["default"] = Element;