formiojs
Version:
Common js library for client side interaction with <form.io>
1,403 lines (1,350 loc) • 65.4 kB
JavaScript
"use strict";
require("core-js/modules/es.object.define-property.js");
require("core-js/modules/es.object.set-prototype-of.js");
require("core-js/modules/es.object.get-prototype-of.js");
require("core-js/modules/es.reflect.construct.js");
require("core-js/modules/es.object.create.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.object.keys.js");
require("core-js/modules/es.object.get-own-property-descriptors.js");
require("core-js/modules/es.object.define-properties.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");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
require("core-js/modules/es.function.bind.js");
require("core-js/modules/es.array.index-of.js");
require("core-js/modules/es.regexp.exec.js");
require("core-js/modules/es.object.assign.js");
require("core-js/modules/web.timers.js");
require("core-js/modules/es.string.trim.js");
require("core-js/modules/es.array.concat.js");
require("core-js/modules/es.array.is-array.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.filter.js");
require("core-js/modules/es.parse-int.js");
require("core-js/modules/es.array.includes.js");
require("core-js/modules/es.string.includes.js");
require("core-js/modules/es.array.map.js");
require("core-js/modules/es.function.name.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 _lodash = _interopRequireDefault(require("lodash"));
var _moment = _interopRequireDefault(require("moment"));
var _compareVersions = _interopRequireDefault(require("compare-versions"));
var _EventEmitter = _interopRequireDefault(require("./EventEmitter"));
var _i18next = _interopRequireDefault(require("i18next"));
var _i18n = _interopRequireDefault(require("./i18n"));
var _Formio = require("./Formio");
var _nativePromiseOnly = _interopRequireDefault(require("native-promise-only"));
var _Components = _interopRequireDefault(require("./components/Components"));
var _NestedDataComponent2 = _interopRequireDefault(require("./components/_classes/nesteddata/NestedDataComponent"));
var _utils = require("./utils/utils");
var _formUtils = require("./utils/formUtils");
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 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 _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 _get() { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get.bind(); } 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 ? Object.setPrototypeOf.bind() : 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.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
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); }
// Initialize the available forms.
_Formio.GlobalFormio.forms = {};
// Allow people to register components.
_Formio.GlobalFormio.registerComponent = _Components["default"].setComponent;
function getIconSet(icons) {
if (icons === 'fontawesome') {
return 'fa';
}
return icons || '';
}
function getOptions(options) {
options = _lodash["default"].defaults(options, {
submitOnEnter: false,
iconset: getIconSet(options && options.icons ? options.icons : _Formio.GlobalFormio.icons),
i18next: _i18next["default"],
saveDraft: false,
alwaysDirty: false,
saveDraftThrottle: 5000,
display: 'form',
cdnUrl: _Formio.GlobalFormio.cdn.baseUrl
});
if (!options.events) {
options.events = new _EventEmitter["default"]();
}
return options;
}
/**
* Renders a Form.io form within the webpage.
*/
var Webform = /*#__PURE__*/function (_NestedDataComponent) {
_inherits(Webform, _NestedDataComponent);
var _super = _createSuper(Webform);
/**
* Creates a new Form instance.
*
* @param {Object} options - The options to create a new form instance.
* @param {boolean} options.saveDraft - Set this if you would like to enable the save draft feature.
* @param {boolean} options.saveDraftThrottle - The throttle for the save draft feature.
* @param {boolean} options.readOnly - Set this form to readOnly
* @param {boolean} options.noAlerts - Set to true to disable the alerts dialog.
* @param {boolean} options.i18n - The translation file for this rendering. @see https://github.com/formio/formio.js/blob/master/i18n.js
* @param {boolean} options.template - Provides a way to inject custom logic into the creation of every element rendered within the form.
*/
/* eslint-disable max-statements */
function Webform() {
var _this2;
_classCallCheck(this, Webform);
var element, options;
if (arguments[0] instanceof HTMLElement || arguments[1]) {
element = arguments[0];
options = arguments[1];
} else {
options = arguments[0];
}
_this2 = _super.call(this, null, getOptions(options));
_defineProperty(_assertThisInitialized(_this2), "executeShortcuts", function (event) {
var target = event.target;
if (!_this2.keyboardCatchableElement(target)) {
return;
}
var ctrl = event.ctrlKey || event.metaKey;
var keyCode = event.keyCode;
var _char = '';
if (65 <= keyCode && keyCode <= 90) {
_char = String.fromCharCode(keyCode);
} else if (keyCode === 13) {
_char = 'Enter';
} else if (keyCode === 27) {
_char = 'Esc';
}
_lodash["default"].each(_this2.shortcuts, function (shortcut) {
if (shortcut.ctrl && !ctrl) {
return;
}
if (shortcut.shortcut === _char) {
shortcut.element.click();
event.preventDefault();
}
});
});
_this2.element = element;
// Keep track of all available forms globally.
_Formio.GlobalFormio.forms[_this2.id] = _assertThisInitialized(_this2);
// Set the base url.
if (_this2.options.baseUrl) {
_Formio.GlobalFormio.setBaseUrl(_this2.options.baseUrl);
}
/**
* The i18n configuration for this component.
*/
var i18n = _i18n["default"];
if (options && options.i18n && !options.i18nReady) {
// Support legacy way of doing translations.
if (options.i18n.resources) {
i18n = options.i18n;
} else {
_lodash["default"].each(options.i18n, function (lang, code) {
if (code === 'options') {
_lodash["default"].merge(i18n, lang);
} else if (!i18n.resources[code]) {
// extend the default translations (validations, buttons etc.) in case they are not in the options.
i18n.resources[code] = {
translation: _lodash["default"].assign((0, _utils.fastCloneDeep)(_i18n["default"].resources.en.translation), lang)
};
} else {
_lodash["default"].assign(i18n.resources[code].translation, lang);
}
});
}
options.i18n = i18n;
options.i18nReady = true;
}
if (options && options.i18n) {
_this2.options.i18n = options.i18n;
} else {
_this2.options.i18n = i18n;
}
// Set the language.
if (_this2.options.language) {
_this2.options.i18n.lng = _this2.options.language;
}
/**
* The type of this element.
* @type {string}
*/
_this2.type = 'form';
_this2._src = '';
_this2._loading = false;
_this2._form = {};
_this2.draftEnabled = false;
_this2.savingDraft = true;
if (_this2.options.saveDraftThrottle) {
_this2.triggerSaveDraft = _lodash["default"].throttle(_this2.saveDraft.bind(_assertThisInitialized(_this2)), _this2.options.saveDraftThrottle);
} else {
_this2.triggerSaveDraft = _this2.saveDraft.bind(_assertThisInitialized(_this2));
}
_this2.customErrors = [];
/**
* Determines if this form should submit the API on submit.
* @type {boolean}
*/
_this2.nosubmit = false;
/**
* Determines if the form has tried to be submitted, error or not.
*
* @type {boolean}
*/
_this2.submitted = false;
/**
* Determines if the form is being submitted at the moment.
*
* @type {boolean}
*/
_this2.submitting = false;
/**
* The Formio instance for this form.
* @type {Formio}
*/
_this2.formio = null;
/**
* The loader HTML element.
* @type {HTMLElement}
*/
_this2.loader = null;
/**
* The alert HTML element
* @type {HTMLElement}
*/
_this2.alert = null;
/**
* Promise that is triggered when the submission is done loading.
* @type {Promise}
*/
_this2.onSubmission = null;
/**
* Determines if this submission is explicitly set.
* @type {boolean}
*/
_this2.submissionSet = false;
/**
* Promise that executes when the form is ready and rendered.
* @type {Promise}
*
* @example
* import Webform from 'formiojs/Webform';
* let form = new Webform(document.getElementById('formio'));
* form.formReady.then(() => {
* console.log('The form is ready!');
* });
* form.src = 'https://examples.form.io/example';
*/
_this2.formReady = new _nativePromiseOnly["default"](function (resolve, reject) {
/**
* Called when the formReady state of this form has been resolved.
*
* @type {function}
*/
_this2.formReadyResolve = resolve;
/**
* Called when this form could not load and is rejected.
*
* @type {function}
*/
_this2.formReadyReject = reject;
});
/**
* Promise that executes when the submission is ready and rendered.
* @type {Promise}
*
* @example
* import Webform from 'formiojs/Webform';
* let form = new Webform(document.getElementById('formio'));
* form.submissionReady.then(() => {
* console.log('The submission is ready!');
* });
* form.src = 'https://examples.form.io/example/submission/234234234234234243';
*/
_this2.submissionReady = new _nativePromiseOnly["default"](function (resolve, reject) {
/**
* Called when the formReady state of this form has been resolved.
*
* @type {function}
*/
_this2.submissionReadyResolve = resolve;
/**
* Called when this form could not load and is rejected.
*
* @type {function}
*/
_this2.submissionReadyReject = reject;
});
_this2.shortcuts = [];
// Set language after everything is established.
_this2.localize().then(function () {
_this2.language = _this2.options.language;
});
// See if we need to restore the draft from a user.
if (_this2.options.saveDraft) {
_this2.formReady.then(function () {
if (!_this2.options.skipDraftRestore) {
var user = _Formio.GlobalFormio.getUser();
// Only restore a draft if the submission isn't explicitly set.
if (user && !_this2.submissionSet) {
_this2.restoreDraft(user._id);
}
} else {
// Enable drafts
_this2.draftEnabled = true;
_this2.savingDraft = false;
}
});
}
_this2.component.clearOnHide = false;
// Ensure the root is set to this component.
_this2.root = _assertThisInitialized(_this2);
_this2.localRoot = _assertThisInitialized(_this2);
return _this2;
}
/* eslint-enable max-statements */
_createClass(Webform, [{
key: "language",
get: function get() {
return this.options.language;
},
set:
/**
* Sets the language for this form.
*
* @param lang
* @return {Promise}
*/
function set(lang) {
var _this3 = this;
this.options.language = lang;
if (this.i18next.language === lang) {
return;
}
try {
this.i18next.changeLanguage(lang, function (err) {
if (err) {
return;
}
_this3.rebuild();
_this3.emit('languageChanged');
});
} catch (err) {
return;
}
}
}, {
key: "emptyValue",
get: function get() {
return null;
}
}, {
key: "componentContext",
value: function componentContext() {
return this._data;
}
}, {
key: "componentComponents",
get: function get() {
return this.form.components;
}
}, {
key: "shadowRoot",
get: function get() {
return this.options.shadowRoot;
}
/**
* Add a language for translations
*
* @param code
* @param lang
* @param active
* @return {*}
*/
}, {
key: "addLanguage",
value: function addLanguage(code, lang) {
var active = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
var translations = _lodash["default"].assign((0, _utils.fastCloneDeep)(_i18n["default"].resources.en.translation), lang);
this.i18next.addResourceBundle(code, 'translation', translations, true, true);
if (active) {
this.language = code;
}
}
/**
* Perform the localization initialization.
* @returns {*}
*/
}, {
key: "localize",
value: function localize() {
var _this4 = this;
if (this.i18next.initialized) {
return _nativePromiseOnly["default"].resolve(this.i18next);
}
this.i18next.initialized = true;
return new _nativePromiseOnly["default"](function (resolve, reject) {
try {
_this4.i18next.init(_objectSpread(_objectSpread({}, _this4.options.i18n), {
compatibilityJSON: 'v3'
}), function (err) {
// Get language but remove any ;q=1 that might exist on it.
_this4.options.language = _this4.i18next.language.split(';')[0];
if (err) {
return reject(err);
}
resolve(_this4.i18next);
});
} catch (err) {
return reject(err);
}
});
}
}, {
key: "keyboardCatchableElement",
value: function keyboardCatchableElement(element) {
if (element.nodeName === 'TEXTAREA') {
return false;
}
if (element.nodeName === 'INPUT') {
return ['text', 'email', 'password'].indexOf(element.type) === -1;
}
return true;
}
}, {
key: "addShortcut",
value: function addShortcut(element, shortcut) {
if (!shortcut || !/^([A-Z]|Enter|Esc)$/i.test(shortcut)) {
return;
}
shortcut = _lodash["default"].capitalize(shortcut);
if (shortcut === 'Enter' || shortcut === 'Esc') {
// Restrict Enter and Esc only for buttons
if (element.tagName !== 'BUTTON') {
return;
}
this.shortcuts.push({
shortcut: shortcut,
element: element
});
} else {
this.shortcuts.push({
ctrl: true,
shortcut: shortcut,
element: element
});
}
}
}, {
key: "removeShortcut",
value: function removeShortcut(element, shortcut) {
if (!shortcut || !/^([A-Z]|Enter|Esc)$/i.test(shortcut)) {
return;
}
_lodash["default"].remove(this.shortcuts, {
shortcut: shortcut,
element: element
});
}
/**
* Get the embed source of the form.
*
* @returns {string}
*/
}, {
key: "src",
get: function get() {
return this._src;
}
/**
* Loads the submission if applicable.
*/,
set:
/**
* Set the Form source, which is typically the Form.io embed URL.
*
* @param {string} value - The value of the form embed url.
*
* @example
* import Webform from 'formiojs/Webform';
* let form = new Webform(document.getElementById('formio'));
* form.formReady.then(() => {
* console.log('The form is formReady!');
* });
* form.src = 'https://examples.form.io/example';
*/
function set(value) {
this.setSrc(value);
}
/**
* Get the embed source of the form.
*
* @returns {string}
*/
}, {
key: "loadSubmission",
value: function loadSubmission() {
var _this5 = this;
this.loadingSubmission = true;
if (this.formio.submissionId) {
this.onSubmission = this.formio.loadSubmission().then(function (submission) {
return _this5.setSubmission(submission);
}, function (err) {
return _this5.submissionReadyReject(err);
})["catch"](function (err) {
return _this5.submissionReadyReject(err);
});
} else {
this.submissionReadyResolve();
}
return this.submissionReady;
}
/**
* Set the src of the form renderer.
*
* @param value
* @param options
*/
}, {
key: "setSrc",
value: function setSrc(value, options) {
var _this6 = this;
if (this.setUrl(value, options)) {
this.nosubmit = false;
return this.formio.loadForm({
params: {
live: 1
}
}).then(function (form) {
var setForm = _this6.setForm(form);
_this6.loadSubmission();
return setForm;
})["catch"](function (err) {
console.warn(err);
_this6.formReadyReject(err);
});
}
return _nativePromiseOnly["default"].resolve();
}
}, {
key: "url",
get: function get() {
return this._src;
}
/**
* Sets the url of the form renderer.
*
* @param value
* @param options
*/,
set:
/**
* Set the form source but don't initialize the form and submission from the url.
*
* @param {string} value - The value of the form embed url.
*/
function set(value) {
this.setUrl(value);
}
/**
* Called when both the form and submission have been loaded.
*
* @returns {Promise} - The promise to trigger when both form and submission have loaded.
*/
}, {
key: "setUrl",
value: function setUrl(value, options) {
if (!value || typeof value !== 'string' || value === this._src) {
return false;
}
this._src = value;
this.nosubmit = true;
this.formio = this.options.formio = new _Formio.GlobalFormio(value, options);
if (this.type === 'form') {
// Set the options source so this can be passed to other components.
this.options.src = value;
}
return true;
}
}, {
key: "ready",
get: function get() {
var _this7 = this;
return this.formReady.then(function () {
return _get(_getPrototypeOf(Webform.prototype), "ready", _this7).then(function () {
return _this7.loadingSubmission ? _this7.submissionReady : true;
});
});
}
/**
* Returns if this form is loading.
*
* @returns {boolean} - TRUE means the form is loading, FALSE otherwise.
*/
}, {
key: "loading",
get: function get() {
return this._loading;
}
/**
* Set the loading state for this form, and also show the loader spinner.
*
* @param {boolean} loading - If this form should be "loading" or not.
*/,
set: function set(loading) {
if (this._loading !== loading) {
this._loading = loading;
if (!this.loader && loading) {
this.loader = this.ce('div', {
"class": 'loader-wrapper'
});
var spinner = this.ce('div', {
"class": 'loader text-center'
});
this.loader.appendChild(spinner);
}
/* eslint-disable max-depth */
if (this.loader) {
try {
if (loading) {
this.prependTo(this.loader, this.wrapper);
} else {
this.removeChildFrom(this.loader, this.wrapper);
}
} catch (err) {
// ingore
}
}
/* eslint-enable max-depth */
}
}
/**
* Sets the JSON schema for the form to be rendered.
*
* @example
* import Webform from 'formiojs/Webform';
* let form = new Webform(document.getElementById('formio'));
* form.setForm({
* components: [
* {
* type: 'textfield',
* key: 'firstName',
* label: 'First Name',
* placeholder: 'Enter your first name.',
* input: true
* },
* {
* type: 'textfield',
* key: 'lastName',
* label: 'Last Name',
* placeholder: 'Enter your last name',
* input: true
* },
* {
* type: 'button',
* action: 'submit',
* label: 'Submit',
* theme: 'primary'
* }
* ]
* });
*
* @param {Object} form - The JSON schema of the form @see https://examples.form.io/example for an example JSON schema.
* @param flags
* @returns {*}
*/
}, {
key: "setForm",
value: function setForm(form, flags) {
var _this$_form$component,
_this8 = this;
var isFormAlreadySet = this._form && ((_this$_form$component = this._form.components) === null || _this$_form$component === void 0 ? void 0 : _this$_form$component.length);
try {
var _this$parent, _this$parent$componen;
// Do not set the form again if it has been already set
if (isFormAlreadySet && JSON.stringify(this._form) === JSON.stringify(form)) {
return _nativePromiseOnly["default"].resolve();
}
// Create the form.
this._form = flags !== null && flags !== void 0 && flags.keepAsReference ? form : _lodash["default"].cloneDeep(form);
if (this.onSetForm) {
this.onSetForm(_lodash["default"].cloneDeep(this._form), form);
}
if ((_this$parent = this.parent) !== null && _this$parent !== void 0 && (_this$parent$componen = _this$parent.component) !== null && _this$parent$componen !== void 0 && _this$parent$componen.modalEdit) {
return _nativePromiseOnly["default"].resolve();
}
} catch (err) {
console.warn(err);
// If provided form is not a valid JSON object, do not set it too
return _nativePromiseOnly["default"].resolve();
}
// Allow the form to provide component overrides.
if (form && form.settings && form.settings.components) {
this.options.components = form.settings.components;
}
if (form && form.properties) {
this.options.properties = form.properties;
}
// Use the sanitize config from the form settings or the global sanitize config if it is not provided in the options
if (!this.options.sanitizeConfig && !this.builderMode) {
this.options.sanitizeConfig = _lodash["default"].get(form, 'settings.sanitizeConfig') || _lodash["default"].get(form, 'globalSettings.sanitizeConfig');
}
if ('schema' in form && (0, _compareVersions["default"])(form.schema, '1.x') > 0) {
this.ready.then(function () {
_this8.setAlert('alert alert-danger', 'Form schema is for a newer version, please upgrade your renderer. Some functionality may not work.');
});
}
// See if they pass a module, and evaluate it if so.
if (form && form.module) {
var formModule = null;
if (typeof form.module === 'string') {
try {
formModule = this.evaluate("return ".concat(form.module));
} catch (err) {
console.warn(err);
}
} else {
formModule = form.module;
}
if (formModule) {
_Formio.GlobalFormio.use(formModule);
// Since we got here after instantiation, we need to manually apply form options.
if (formModule.options && formModule.options.form) {
this.options = Object.assign(this.options, formModule.options.form);
}
}
}
this.initialized = false;
var rebuild = this.rebuild() || _nativePromiseOnly["default"].resolve();
return rebuild.then(function () {
_this8.emit('formLoad', form);
_this8.triggerCaptcha();
// Make sure to trigger onChange after a render event occurs to speed up form rendering.
setTimeout(function () {
_this8.onChange(flags);
_this8.formReadyResolve();
}, 0);
return _this8.formReady;
});
}
/**
* Gets the form object.
*
* @returns {Object} - The form JSON schema.
*/
}, {
key: "form",
get: function get() {
if (!this._form) {
this._form = {
components: []
};
}
return this._form;
}
/**
* Sets the form value.
*
* @alias setForm
* @param {Object} form - The form schema object.
*/,
set: function set(form) {
this.setForm(form);
}
/**
* Returns the submission object that was set within this form.
*
* @returns {Object}
*/
}, {
key: "submission",
get: function get() {
return this.getValue();
}
/**
* Sets the submission of a form.
*
* @example
* import Webform from 'formiojs/Webform';
* let form = new Webform(document.getElementById('formio'));
* form.src = 'https://examples.form.io/example';
* form.submission = {data: {
* firstName: 'Joe',
* lastName: 'Smith',
* email: 'joe@example.com'
* }};
*
* @param {Object} submission - The Form.io submission object.
*/,
set: function set(submission) {
this.setSubmission(submission);
}
/**
* Sets a submission and returns the promise when it is ready.
* @param submission
* @param flags
* @return {Promise.<TResult>}
*/
}, {
key: "setSubmission",
value: function setSubmission(submission) {
var _this9 = this;
var flags = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
flags = _objectSpread(_objectSpread({}, flags), {}, {
fromSubmission: _lodash["default"].has(flags, 'fromSubmission') ? flags.fromSubmission : true
});
return this.onSubmission = this.formReady.then(function (resolveFlags) {
if (resolveFlags) {
flags = _objectSpread(_objectSpread({}, flags), resolveFlags);
}
_this9.submissionSet = true;
_this9.triggerChange(flags);
_this9.emit('beforeSetSubmission', submission);
_this9.setValue(submission, flags);
return _this9.submissionReadyResolve(submission);
}, function (err) {
return _this9.submissionReadyReject(err);
})["catch"](function (err) {
return _this9.submissionReadyReject(err);
});
}
}, {
key: "handleDraftError",
value: function handleDraftError(errName, errDetails, restoreDraft) {
var errorMessage = _lodash["default"].trim("".concat(this.t(errName), " ").concat(errDetails || ''));
console.warn(errorMessage);
this.emit(restoreDraft ? 'restoreDraftError' : 'saveDraftError', errDetails || errorMessage);
}
/**
* Saves a submission draft.
*/
}, {
key: "saveDraft",
value: function saveDraft() {
var _this10 = this;
if (!this.draftEnabled) {
return;
}
if (!this.formio) {
this.handleDraftError('saveDraftInstanceError');
return;
}
if (!_Formio.GlobalFormio.getUser()) {
this.handleDraftError('saveDraftAuthError');
return;
}
var draft = (0, _utils.fastCloneDeep)(this.submission);
draft.state = 'draft';
if (!this.savingDraft && !this.submitting) {
this.emit('saveDraftBegin');
this.savingDraft = true;
this.formio.saveSubmission(draft).then(function (sub) {
// Set id to submission to avoid creating new draft submission
_this10.submission._id = sub._id;
_this10.savingDraft = false;
_this10.emit('saveDraft', sub);
})["catch"](function (err) {
_this10.savingDraft = false;
_this10.handleDraftError('saveDraftError', err);
});
}
}
/**
* Restores a draft submission based on the user who is authenticated.
*
* @param {userId} - The user id where we need to restore the draft from.
*/
}, {
key: "restoreDraft",
value: function restoreDraft(userId) {
var _this11 = this;
var formio = this.formio || this.options.formio;
if (!formio) {
this.handleDraftError('restoreDraftInstanceError', null, true);
return;
}
this.savingDraft = true;
formio.loadSubmissions({
params: {
state: 'draft',
owner: userId
}
}).then(function (submissions) {
if (submissions.length > 0 && !_this11.options.skipDraftRestore) {
var draft = (0, _utils.fastCloneDeep)(submissions[0]);
return _this11.setSubmission(draft).then(function () {
_this11.draftEnabled = true;
_this11.savingDraft = false;
_this11.emit('restoreDraft', draft);
});
}
// Enable drafts so that we can keep track of changes.
_this11.draftEnabled = true;
_this11.savingDraft = false;
_this11.emit('restoreDraft', null);
})["catch"](function (err) {
_this11.draftEnabled = true;
_this11.savingDraft = false;
_this11.handleDraftError('restoreDraftError', err, true);
});
}
}, {
key: "schema",
get: function get() {
var schema = (0, _utils.fastCloneDeep)(_lodash["default"].omit(this._form, ['components']));
schema.components = [];
this.eachComponent(function (component) {
return schema.components.push(component.schema);
});
return schema;
}
}, {
key: "mergeData",
value: function mergeData(_this, _that) {
_lodash["default"].mergeWith(_this, _that, function (thisValue, thatValue) {
if (Array.isArray(thisValue) && Array.isArray(thatValue) && thisValue.length !== thatValue.length) {
return thatValue;
}
});
}
}, {
key: "setValue",
value: function setValue(submission) {
var flags = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (!submission || !submission.data) {
submission = {
data: {}
};
}
// Metadata needs to be available before setValue
this._submission.metadata = submission.metadata || {};
this.editing = !!submission._id;
// Set the timezone in the options if available.
if (!this.options.submissionTimezone && submission.metadata && submission.metadata.timezone) {
this.options.submissionTimezone = submission.metadata.timezone;
}
var changed = _get(_getPrototypeOf(Webform.prototype), "setValue", this).call(this, submission.data, flags);
if (!flags.sanitize) {
this.mergeData(this.data, submission.data);
}
submission.data = this.data;
this._submission = submission;
return changed;
}
}, {
key: "getValue",
value: function getValue() {
if (!this._submission.data) {
this._submission.data = {};
}
if (this.viewOnly) {
return this._submission;
}
var submission = this._submission;
submission.data = this.data;
return this._submission;
}
/**
* Build the form.
*/
}, {
key: "init",
value: function init() {
var _this12 = this;
this._submission = this._submission || {
data: {}
};
// Remove any existing components.
if (this.components && this.components.length) {
this.destroyComponents();
this.components = [];
}
if (this.component) {
this.component.components = this.form ? this.form.components : [];
} else {
this.component = this.form;
}
this.component.type = 'form';
this.component.input = false;
this.addComponents();
this.on('submitButton', function (options) {
_this12.submit(false, options)["catch"](function (e) {
return e !== false && console.log(e);
});
}, true);
this.on('checkValidity', function (data) {
return _this12.checkValidity(data, true, data);
}, true);
this.on('requestUrl', function (args) {
return _this12.submitUrl(args.url, args.headers);
}, true);
this.on('resetForm', function () {
return _this12.resetValue();
}, true);
this.on('deleteSubmission', function () {
return _this12.deleteSubmission();
}, true);
this.on('refreshData', function () {
return _this12.updateValue();
}, true);
this.executeFormController();
return this.formReady;
}
}, {
key: "executeFormController",
value: function executeFormController() {
var _this13 = this;
// If no controller value or
// hidden and set to clearOnHide (Don't calculate a value for a hidden field set to clear when hidden)
if (!this.form || !this.form.controller || (!this.visible || this.component.hidden) && this.component.clearOnHide && !this.rootPristine) {
return false;
}
this.formReady.then(function () {
_this13.evaluate(_this13.form.controller, {
components: _this13.components,
instance: _this13
});
});
}
}, {
key: "destroy",
value: function destroy() {
var deleteFromGlobal = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
this.off('submitButton');
this.off('checkValidity');
this.off('requestUrl');
this.off('resetForm');
this.off('deleteSubmission');
this.off('refreshData');
if (deleteFromGlobal) {
this.emit('formDelete', this.id);
delete _Formio.GlobalFormio.forms[this.id];
}
return _get(_getPrototypeOf(Webform.prototype), "destroy", this).call(this);
}
}, {
key: "build",
value: function build(element) {
var _this14 = this;
if (element || this.element) {
return this.ready.then(function () {
element = element || _this14.element;
_get(_getPrototypeOf(Webform.prototype), "build", _this14).call(_this14, element);
});
}
return this.ready;
}
}, {
key: "getClassName",
value: function getClassName() {
var classes = 'formio-form';
if (this.options.readOnly) {
classes += ' formio-read-only';
}
return classes;
}
}, {
key: "render",
value: function render() {
return _get(_getPrototypeOf(Webform.prototype), "render", this).call(this, this.renderTemplate('webform', {
classes: this.getClassName(),
children: this.renderComponents()
}), this.builderMode ? 'builder' : 'form', true);
}
}, {
key: "redraw",
value: function redraw() {
// Don't bother if we have not built yet.
if (!this.element) {
return _nativePromiseOnly["default"].resolve();
}
this.clear();
this.setContent(this.element, this.render());
return this.attach(this.element);
}
}, {
key: "attach",
value: function attach(element) {
var _this15 = this;
this.element = element;
this.loadRefs(element, {
webform: 'single'
});
var childPromise = this.attachComponents(this.refs.webform);
this.addEventListener(document, 'keydown', this.executeShortcuts);
this.currentForm = this;
this.hook('attachWebform', element, this);
return childPromise.then(function () {
_this15.emit('render', _this15.element);
return _this15.setValue(_this15._submission, {
noUpdateEvent: true
});
});
}
}, {
key: "hasRequiredFields",
value: function hasRequiredFields() {
var result = false;
(0, _formUtils.eachComponent)(this.form.components, function (component) {
if (component.validate.required) {
result = true;
return true;
}
}, true);
return result;
}
}, {
key: "resetValue",
value: function resetValue() {
_lodash["default"].each(this.getComponents(), function (comp) {
return comp.resetValue();
});
this.setPristine(true);
this.onChange({
resetValue: true
});
}
/**
* Sets a new alert to display in the error dialog of the form.
*
* @param {string} type - The type of alert to display. "danger", "success", "warning", etc.
* @param {string} message - The message to show in the alert.
* @param {Object} options
*/
}, {
key: "setAlert",
value: function setAlert(type, message, options) {
var _this16 = this;
if (!type && this.submitted) {
if (this.alert) {
if (this.refs.errorRef && this.refs.errorRef.length) {
this.refs.errorRef.forEach(function (el) {
_this16.removeEventListener(el, 'click');
_this16.removeEventListener(el, 'keypress');
});
}
this.removeChild(this.alert);
this.alert = null;
}
return;
}
if (this.options.noAlerts) {
if (!message) {
this.emit('error', false);
}
return;
}
if (this.alert) {
try {
if (this.refs.errorRef && this.refs.errorRef.length) {
this.refs.errorRef.forEach(function (el) {
_this16.removeEventListener(el, 'click');
_this16.removeEventListener(el, 'keypress');
});
}
this.removeChild(this.alert);
this.alert = null;
} catch (err) {
// ignore
}
}
if (message) {
var attrs = {
"class": options && options.classes || "alert alert-".concat(type),
id: "error-list-".concat(this.id)
};
var templateOptions = {
message: message instanceof HTMLElement ? message.outerHTML : message,
attrs: attrs,
type: type
};
this.alert = (0, _utils.convertStringToHTMLElement)(this.renderTemplate('alert', templateOptions), "#".concat(attrs.id));
}
if (!this.alert) {
return;
}
this.loadRefs(this.alert, {
errorRef: 'multiple'
});
if (this.refs.errorRef && this.refs.errorRef.length) {
this.refs.errorRef.forEach(function (el) {
_this16.addEventListener(el, 'click', function (e) {
var key = e.currentTarget.dataset.componentKey;
_this16.focusOnComponent(key);
});
_this16.addEventListener(el, 'keydown', function (e) {
if (e.keyCode === 13) {
e.preventDefault();
var key = e.currentTarget.dataset.componentKey;
_this16.focusOnComponent(key);
}
});
});
}
this.prepend(this.alert);
}
/**
* Focus on selected component.
*
* @param {string} key - The key of selected component.
* @returns {*}
*/
}, {
key: "focusOnComponent",
value: function focusOnComponent(key) {
if (key) {
var component = this.getComponent(key);
if (component) {
component.focus();
}
}
}
/**
* Show the errors of this form within the alert dialog.
*
* @param {Object} error - An optional additional error to display along with the component errors.
* @returns {*}
*/
/* eslint-disable no-unused-vars */
}, {
key: "showErrors",
value: function showErrors(error, triggerEvent, onChange) {
var _this17 = this;
this.loading = false;
var errors = this.errors;
if (error) {
if (Array.isArray(error)) {
errors = errors.concat(error);
} else {
errors.push(error);
}
} else {
errors = _get(_getPrototypeOf(Webform.prototype), "errors", this);
}
errors = errors.concat(this.customErrors);
if (!errors.length) {
this.setAlert(false);
return;
}
// Mark any components as invalid if in a custom message.
errors.forEach(function (err) {
var _err$components = err.components,
components = _err$components === void 0 ? [] : _err$components;
if (err.component) {
components.push(err.component);
}
if (err.path) {
components.push(err.path);
}
components.forEach(function (path) {
var originalPath = _this17._parentPath + (0, _utils.getStringFromComponentPath)(path);
var component = _this17.getComponent(path, _lodash["default"].identity, originalPath);
if (err.fromServer) {
if (component.serverErrors) {
component.serverErrors.push(err);
} else {
component.serverErrors = [err];
}
}
var components = _lodash["default"].compact(Array.isArray(component) ? component : [component]);
components.forEach(function (component) {
return component.setCustomValidity(err.message, true);
});
});
});
var displayedErrors = [];
errors.forEach(function (err) {
if (err) {
var createListItem = function createListItem(message, index) {
var messageFromIndex = !_lodash["default"].isUndefined(index) && err.messages && err.messages[index];
var keyOrPath = messageFromIndex && messageFromIndex.formattedKeyOrPath || messageFromIndex.path || err.component && err.component.key || err.fromServer && err.path;
var formattedKeyOrPath = keyOrPath ? (0, _utils.getStringFromComponentPath)(keyOrPath) : '';
formattedKeyOrPath = _this17._parentPath + formattedKeyOrPath;
if (typeof err !== 'string' && !err.formattedKeyOrPath) {
err.formattedKeyOrPath = formattedKeyOrPath;
}
return {
message: (0, _utils.unescapeHTML)(message),
keyOrPath: formattedKeyOrPath
};
};
err.messages = _lodash["default"].uniqBy(err.messages, function (message) {
return message.message;
});
if (err.messages && err.messages.length) {
var component = err.component;
err.messages.forEach(function (_ref, index) {
var message = _ref.message,
context = _ref.context,
fromServer = _ref.fromServer;
var text = context !== null && context !== void 0 && context.hasLabel || fromServer ? _this17.t('alertMessage', {
message: _this17.t(message)
}) : _this17.t('alertMessageWithLabel', {
label: _this17.t(component.label),
message: _this17.t(message)
});
displayedErrors.push(createListItem(text, index));
});
} else if (err) {
var message = _lodash["default"].isObject(err) ? _this17.t('alertMessage', {
message: _this17.t(err.message || '')
}) : _this17.t('alertMessage', {
message: _this17.t(err)
});
displayedErrors.push(createListItem(message));
}
}
});
var errorsList = this.renderTemplate('errorsList', {
errors: displayedErrors
});
this.root.setAlert('danger', errorsList);
if (triggerEvent) {
this.emit('error', errors);
}
return errors;
}
/* eslint-enable no-unused-vars */
/**
* Called when the submission has completed, or if the submission needs to be sent to an external library.
*
* @param {Object} submission - The submission object.
* @param {boolean} saved - Whether or not this submission was saved to the server.
* @returns {object} - The submission object.
*/
}, {
key: "onSubmit",
value: function onSubmit(submission, saved) {
var _this$triggerSaveDraf;
this.loading = false;
this.submitting = false;
this.setPristine(true);
// We want to return the submitted submission and setValue will mutate the submission so cloneDeep it here.
this.setValue((0, _utils.fastCloneDeep)(submission), {
noValidate: true,