formiojs
Version:
Common js library for client side interaction with <form.io>
655 lines (564 loc) • 18.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
require("core-js/modules/es6.function.name");
require("core-js/modules/es6.object.assign");
require("core-js/modules/es6.regexp.replace");
require("core-js/modules/es6.regexp.constructor");
require("core-js/modules/es6.regexp.to-string");
require("core-js/modules/web.dom.iterable");
var _eventemitter = _interopRequireDefault(require("eventemitter2"));
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("vanilla-text-mask"));
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: 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, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
/**
* Root component for all elements within the renderer.
*/
var Component =
/*#__PURE__*/
function () {
function Component(options, id) {
_classCallCheck(this, Component);
/**
* The options for this component.
* @type {{}}
*/
this.options = _lodash.default.assign({
language: 'en',
highlightErrors: true,
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 = 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({
wildcard: false,
maxListeners: 0
});
/**
* All of the input masks associated with this component.
* @type {Array}
*/
this.inputMasks = [];
}
/**
* 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.
* @param {boolean} internal - If this event is an "internal" event and should get removed when destroyed.
* This parameter is necessary because any external "on" bindings should be persistent even through internal
* redraw events which will call the "destroy" methods.
*/
_createClass(Component, [{
key: "on",
value: function on(event, cb, internal) {
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.internal = internal; // Register for this event.
return this.events.on(type, cb);
}
/**
* Removes all listeners for a certain event.
*
* @param event
*/
}, {
key: "off",
value: function off(event) {
var _this = this;
if (!this.events) {
return;
}
var type = "".concat(this.options.namespace, ".").concat(event); // Iterate through all the internal events.
_lodash.default.each(this.events.listeners(type), function (listener) {
// Ensure this event is for this component.
if (listener && listener.id === _this.id) {
// Turn off this event handler.
_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, data) {
if (this.events) {
this.events.emit("".concat(this.options.namespace, ".").concat(event), data);
}
}
/**
* 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) {
if (!persistent) {
this.eventHandlers.push({
id: this.id,
obj: obj,
type: type,
func: func
});
}
if ('addEventListener' in obj) {
obj.addEventListener(type, func, false);
} else if ('attachEvent' in obj) {
obj.attachEvent("on".concat(type), func);
}
}
/**
* Remove an event listener from the object.
*
* @param obj
* @param type
*/
}, {
key: "removeEventListener",
value: function removeEventListener(obj, type) {
var _this2 = this;
var indexes = [];
_lodash.default.each(this.eventHandlers, function (handler, index) {
if (handler.id === _this2.id && obj.removeEventListener && handler.type === type) {
obj.removeEventListener(type, handler.func);
indexes.push(index);
}
});
if (indexes.length) {
_lodash.default.pullAt(this.eventHandlers, indexes);
}
}
/**
* Removes all event listeners attached to this component.
*/
}, {
key: "destroy",
value: function destroy() {
var _this3 = this;
_lodash.default.each(this.events._events, function (events, type) {
_lodash.default.each(events, function (listener) {
if (listener && _this3.id === listener.id && listener.internal) {
_this3.events.off(type, listener);
}
});
});
_lodash.default.each(this.eventHandlers, function (handler) {
if (_this3.id === handler.id && handler.type && handler.obj && handler.obj.removeEventListener) {
handler.obj.removeEventListener(handler.type, handler.func);
}
}); // Destroy the input masks.
this.inputMasks.forEach(function (mask) {
return mask.destroy();
});
this.inputMasks = [];
}
/**
* Append an HTML DOM element to a container.
*
* @param element
* @param container
*/
}, {
key: "appendTo",
value: function appendTo(element, container) {
if (container) {
container.appendChild(element);
}
}
/**
* 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);
}
}
}
/**
* 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);
}
}
}
/**
* 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;
// 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 _this4 = this;
if (Array.isArray(child)) {
child.forEach(function (oneChild) {
_this4.appendChild(element, oneChild);
});
} else if (child instanceof HTMLElement || child instanceof Text) {
element.appendChild(child);
} else if (child) {
element.appendChild(this.text(child.toString()));
}
}
/**
* 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) {
return mask.map(function (char) {
return char instanceof RegExp ? '_' : char;
}).join('');
}
/**
* 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} placeholder - Set the mask placeholder on the input.
*/
}, {
key: "setInputMask",
value: function setInputMask(input, inputMask, placeholder) {
if (input && inputMask) {
var mask = FormioUtils.getInputMask(inputMask);
this._inputMask = mask;
input.mask = (0, _vanillaTextMask.default)({
inputElement: input,
mask: mask
});
if (mask.numeric) {
input.setAttribute('pattern', '\\d*');
}
if (placeholder) {
input.setAttribute('placeholder', this.maskPlaceholder(mask));
}
this.inputMasks.push(input.mask);
}
}
/**
* 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, params) {
params = params || {};
params.nsSeparator = '::';
params.keySeparator = '.|.';
params.pluralSeparator = '._.';
params.contextSeparator = '._.';
var translated = this.i18next.t(text, params);
return translated || text;
}
/**
* 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 _this5 = 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.
_this5.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;
}
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) {
return;
}
var classes = element.getAttribute('class');
if (!classes || classes.indexOf(className) === -1) {
element.setAttribute('class', "".concat(classes, " ").concat(className));
}
}
/**
* 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) {
return;
}
var cls = element.getAttribute('class');
if (cls) {
cls = cls.replace(new RegExp(" ".concat(className), 'g'), '');
element.setAttribute('class', cls);
}
}
/**
* 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);
}
}
}
/**
* Gets the classname for either Fontawesome or Bootstrap depending on their settings.
*
* @param name
* @param spinning
* @return {string}
*/
}, {
key: "iconClass",
value: function iconClass(name, spinning) {
if (!this.options.icons || this.options.icons === 'glyphicon') {
return spinning ? "glyphicon glyphicon-".concat(name, " glyphicon-spin") : "glyphicon glyphicon-".concat(name);
}
switch (name) {
case 'save':
return 'fa fa-download';
case 'zoom-in':
return 'fa fa-search-plus';
case 'zoom-out':
return 'fa fa-search-minus';
case 'question-sign':
return 'fa fa-question-circle';
case 'remove-circle':
return 'fa fa-times-circle-o';
case 'new-window':
return 'fa fa-window-restore';
default:
return spinning ? "fa fa-".concat(name, " fa-spin") : "fa fa-".concat(name);
}
}
/**
* Returns an HTMLElement icon element.
*
* @param {string} name - The name of the icon to retrieve.
* @returns {HTMLElement} - The icon element.
*/
}, {
key: "getIcon",
value: function getIcon(name) {
return this.ce('i', {
class: this.iconClass(name)
});
}
/**
* Create an evaluation context for all script executions and interpolations.
*
* @param additional
* @return {*}
*/
}, {
key: "evalContext",
value: function evalContext(additional) {
return Object.assign({
_: _lodash.default,
utils: FormioUtils,
util: FormioUtils,
moment: _moment.default,
instance: this
}, additional);
}
/**
* 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) {
return FormioUtils.interpolate(string, this.evalContext(data));
}
/**
* 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 Component;
}();
exports.default = Component;