@formio/js 5.0.0-rc.38 → 5.0.0-rc.40
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/formio.builder.css +2 -2
- package/dist/formio.builder.min.css +1 -1
- package/dist/formio.embed.js +1 -1
- package/dist/formio.embed.min.js +1 -1
- package/dist/formio.embed.min.js.LICENSE.txt +1 -1
- package/dist/formio.form.css +2 -2
- package/dist/formio.form.js +5335 -2376
- package/dist/formio.form.min.css +1 -1
- package/dist/formio.form.min.js +1 -1
- package/dist/formio.form.min.js.LICENSE.txt +23 -5
- package/dist/formio.full.css +2 -2
- package/dist/formio.full.js +5663 -2696
- package/dist/formio.full.min.css +1 -1
- package/dist/formio.full.min.js +1 -1
- package/dist/formio.full.min.js.LICENSE.txt +23 -5
- package/dist/formio.js +72 -62
- package/dist/formio.min.js +1 -1
- package/dist/formio.min.js.LICENSE.txt +1 -1
- package/dist/formio.utils.js +105 -96
- package/dist/formio.utils.min.js +1 -1
- package/dist/formio.utils.min.js.LICENSE.txt +4 -4
- package/lib/cjs/Element.js +1 -0
- package/lib/cjs/Embed.js +134 -131
- package/lib/cjs/Webform.js +36 -13
- package/lib/cjs/WebformBuilder.js +4 -2
- package/lib/cjs/Wizard.js +6 -1
- package/lib/cjs/components/_classes/component/Component.js +33 -22
- package/lib/cjs/components/_classes/component/editForm/Component.edit.logic.js +1 -1
- package/lib/cjs/components/_classes/component/editForm/Component.edit.validation.js +8 -0
- package/lib/cjs/components/_classes/component/fixtures/comp5.js +2 -2
- package/lib/cjs/components/_classes/multivalue/Multivalue.js +2 -2
- package/lib/cjs/components/_classes/nested/NestedComponent.js +2 -2
- package/lib/cjs/components/address/fixtures/comp3.js +1 -1
- package/lib/cjs/components/builder.js +0 -2
- package/lib/cjs/components/button/Button.js +7 -1
- package/lib/cjs/components/datagrid/DataGrid.js +16 -3
- package/lib/cjs/components/datagrid/fixtures/comp-with-allow-calculate-override.js +68 -0
- package/lib/cjs/components/datagrid/fixtures/comp6.js +1 -1
- package/lib/cjs/components/datagrid/fixtures/index.js +5 -1
- package/lib/cjs/components/datagrid/fixtures/two-comp-with-allow-calculate-override.js +104 -0
- package/lib/cjs/components/editgrid/EditGrid.js +11 -4
- package/lib/cjs/components/editgrid/fixtures/formsWithEditGridAndConditions.js +923 -0
- package/lib/cjs/components/file/File.js +2 -2
- package/lib/cjs/components/file/editForm/File.edit.file.js +1 -1
- package/lib/cjs/components/form/Form.js +1 -1
- package/lib/cjs/components/html/HTML.js +11 -2
- package/lib/cjs/components/html/fixtures/index.js +1 -3
- package/lib/cjs/components/index.js +0 -2
- package/lib/cjs/components/recaptcha/ReCaptcha.js +46 -46
- package/lib/cjs/components/select/Select.js +3 -1
- package/lib/cjs/components/select/fixtures/comp20.js +46 -0
- package/lib/cjs/components/select/fixtures/comp21.js +106 -0
- package/lib/cjs/components/select/fixtures/index.js +5 -1
- package/lib/cjs/components/selectboxes/SelectBoxes.js +1 -1
- package/lib/cjs/components/textfield/TextField.js +63 -3
- package/lib/cjs/providers/storage/s3.js +5 -3
- package/lib/cjs/providers/storage/uploadAdapter.js +1 -1
- package/lib/cjs/providers/storage/url.js +19 -13
- package/lib/cjs/providers/storage/util.js +2 -2
- package/lib/cjs/templates/Templates.js +4 -4
- package/lib/cjs/translations/en.js +10 -6
- package/lib/cjs/utils/Evaluator.js +1 -1
- package/lib/cjs/utils/conditionOperators/IsEqualTo.js +1 -1
- package/lib/cjs/utils/formUtils.js +3 -3
- package/lib/cjs/utils/utils.js +4 -19
- package/lib/cjs/widgets/CalendarWidget.js +1 -1
- package/lib/mjs/Element.js +1 -0
- package/lib/mjs/Embed.js +10 -8
- package/lib/mjs/FormBuilder.js +1 -2
- package/lib/mjs/Webform.js +36 -13
- package/lib/mjs/WebformBuilder.js +4 -2
- package/lib/mjs/Wizard.js +6 -1
- package/lib/mjs/builders/Builders.js +1 -2
- package/lib/mjs/components/Components.js +1 -2
- package/lib/mjs/components/_classes/component/Component.js +33 -24
- package/lib/mjs/components/_classes/component/editForm/Component.edit.logic.js +1 -1
- package/lib/mjs/components/_classes/component/editForm/Component.edit.validation.js +8 -0
- package/lib/mjs/components/_classes/component/fixtures/comp5.js +2 -2
- package/lib/mjs/components/_classes/multivalue/Multivalue.js +2 -2
- package/lib/mjs/components/_classes/nested/NestedComponent.js +2 -2
- package/lib/mjs/components/address/fixtures/comp3.js +1 -1
- package/lib/mjs/components/builder.js +0 -2
- package/lib/mjs/components/button/Button.js +7 -1
- package/lib/mjs/components/datagrid/DataGrid.js +15 -3
- package/lib/mjs/components/datagrid/fixtures/comp-with-allow-calculate-override.js +66 -0
- package/lib/mjs/components/datagrid/fixtures/comp6.js +1 -1
- package/lib/mjs/components/datagrid/fixtures/index.js +3 -1
- package/lib/mjs/components/datagrid/fixtures/two-comp-with-allow-calculate-override.js +102 -0
- package/lib/mjs/components/editgrid/EditGrid.js +11 -4
- package/lib/mjs/components/editgrid/fixtures/formsWithEditGridAndConditions.js +921 -0
- package/lib/mjs/components/file/File.js +2 -2
- package/lib/mjs/components/file/editForm/File.edit.file.js +1 -1
- package/lib/mjs/components/form/Form.js +1 -1
- package/lib/mjs/components/html/HTML.js +10 -2
- package/lib/mjs/components/html/fixtures/index.js +1 -2
- package/lib/mjs/components/index.js +0 -2
- package/lib/mjs/components/recaptcha/ReCaptcha.js +32 -43
- package/lib/mjs/components/select/Select.js +3 -1
- package/lib/mjs/components/select/fixtures/comp20.js +44 -0
- package/lib/mjs/components/select/fixtures/comp21.js +104 -0
- package/lib/mjs/components/select/fixtures/index.js +3 -1
- package/lib/mjs/components/selectboxes/SelectBoxes.js +1 -1
- package/lib/mjs/components/textfield/TextField.js +62 -3
- package/lib/mjs/displays/Displays.js +1 -2
- package/lib/mjs/licenses/Licenses.js +1 -2
- package/lib/mjs/providers/Providers.js +1 -2
- package/lib/mjs/providers/storage/s3.js +5 -3
- package/lib/mjs/providers/storage/uploadAdapter.js +1 -1
- package/lib/mjs/providers/storage/url.js +19 -13
- package/lib/mjs/templates/Templates.js +1 -1
- package/lib/mjs/translations/en.js +10 -6
- package/lib/mjs/utils/Evaluator.js +1 -1
- package/lib/mjs/utils/conditionOperators/IsEqualTo.js +1 -1
- package/lib/mjs/utils/formUtils.js +3 -3
- package/lib/mjs/utils/utils.js +2 -16
- package/lib/mjs/widgets/CalendarWidget.js +1 -1
- package/package.json +21 -20
- package/lib/cjs/components/html/fixtures/comp3.js +0 -31
- package/lib/cjs/components/resource/Resource.form.js +0 -16
- package/lib/cjs/components/resource/Resource.js +0 -39
- package/lib/cjs/components/resource/editForm/Resource.edit.display.js +0 -102
- package/lib/cjs/components/resource/fixtures/comp1.js +0 -30
- package/lib/cjs/components/resource/fixtures/comp2.js +0 -31
- package/lib/cjs/components/resource/fixtures/index.js +0 -10
- package/lib/mjs/components/html/fixtures/comp3.js +0 -29
- package/lib/mjs/components/resource/Resource.form.js +0 -10
- package/lib/mjs/components/resource/Resource.js +0 -33
- package/lib/mjs/components/resource/editForm/Resource.edit.display.js +0 -100
- package/lib/mjs/components/resource/fixtures/comp1.js +0 -28
- package/lib/mjs/components/resource/fixtures/comp2.js +0 -29
- package/lib/mjs/components/resource/fixtures/index.js +0 -3
@@ -16,7 +16,7 @@ exports.default = {
|
|
16
16
|
required: '{{field}} is required',
|
17
17
|
unique: '{{field}} must be unique',
|
18
18
|
array: '{{field}} must be an array',
|
19
|
-
array_nonempty: '{{field}} must be a non-empty array',
|
19
|
+
array_nonempty: '{{field}} must be a non-empty array', // eslint-disable-line camelcase
|
20
20
|
nonarray: '{{field}} must not be an array',
|
21
21
|
select: '{{field}} contains an invalid selection',
|
22
22
|
pattern: '{{field}} does not match the pattern {{pattern}}',
|
@@ -32,11 +32,11 @@ exports.default = {
|
|
32
32
|
minYear: '{{field}} should not contain year less than {{minYear}}',
|
33
33
|
minSelectedCount: 'You must select at least {{minCount}} items',
|
34
34
|
maxSelectedCount: 'You may only select up to {{maxCount}} items',
|
35
|
-
invalid_email: '{{field}} must be a valid email.',
|
36
|
-
invalid_url: '{{field}} must be a valid url.',
|
37
|
-
invalid_regex: '{{field}} does not match the pattern {{regex}}.',
|
38
|
-
invalid_date: '{{field}} is not a valid date.',
|
39
|
-
invalid_day: '{{field}} is not a valid day.',
|
35
|
+
invalid_email: '{{field}} must be a valid email.', // eslint-disable-line camelcase
|
36
|
+
invalid_url: '{{field}} must be a valid url.', // eslint-disable-line camelcase
|
37
|
+
invalid_regex: '{{field}} does not match the pattern {{regex}}.', // eslint-disable-line camelcase
|
38
|
+
invalid_date: '{{field}} is not a valid date.', // eslint-disable-line camelcase
|
39
|
+
invalid_day: '{{field}} is not a valid day.', // eslint-disable-line camelcase
|
40
40
|
invalidValueProperty: 'Invalid Value Property',
|
41
41
|
mask: '{{field}} does not match the mask.',
|
42
42
|
valueIsNotAvailable: '{{ field }} is an invalid value.',
|
@@ -64,9 +64,13 @@ exports.default = {
|
|
64
64
|
saveDraftInstanceError: 'Cannot save draft because there is no formio instance.',
|
65
65
|
saveDraftAuthError: 'Cannot save draft unless a user is authenticated.',
|
66
66
|
restoreDraftInstanceError: 'Cannot restore draft because there is no formio instance.',
|
67
|
+
saveDraftError: 'Unable to save draft.',
|
68
|
+
restoreDraftError: 'Unable to restore draft.',
|
67
69
|
time: 'Invalid time',
|
68
70
|
cancelButtonAriaLabel: 'Cancel button. Click to reset the form',
|
69
71
|
previousButtonAriaLabel: 'Previous button. Click to go back to the previous tab',
|
70
72
|
nextButtonAriaLabel: 'Next button. Click to go to the next tab',
|
71
73
|
submitButtonAriaLabel: 'Submit Form button. Click to submit the form',
|
74
|
+
reCaptchaTokenValidationError: 'ReCAPTCHA: Token validation error',
|
75
|
+
reCaptchaTokenNotSpecifiedError: 'ReCAPTCHA: Token is not specified in submission',
|
72
76
|
};
|
@@ -8,7 +8,7 @@ const string_hash_1 = __importDefault(require("string-hash"));
|
|
8
8
|
const utils_1 = require("@formio/core/utils");
|
9
9
|
const Evaluator = {
|
10
10
|
noeval: false,
|
11
|
-
protectedEval: false,
|
11
|
+
protectedEval: false, // This property can be customized only by plugins
|
12
12
|
cache: {},
|
13
13
|
templateSettings: utils_1.Evaluator.templateSettings,
|
14
14
|
evaluator: utils_1.Evaluator.evaluator,
|
@@ -39,7 +39,7 @@ class IsEqualTo extends ConditionOperator_1.default {
|
|
39
39
|
}
|
40
40
|
}
|
41
41
|
//special check for select boxes
|
42
|
-
if (lodash_1.default.isObject(value) && comparedValue && lodash_1.default.
|
42
|
+
if (lodash_1.default.isObject(value) && comparedValue && lodash_1.default.isBoolean(value[comparedValue])) {
|
43
43
|
return value[comparedValue];
|
44
44
|
}
|
45
45
|
return lodash_1.default.isEqual(value, comparedValue);
|
@@ -271,9 +271,9 @@ function generateFormChange(type, data) {
|
|
271
271
|
change = {
|
272
272
|
op: 'add',
|
273
273
|
key: data.component.key,
|
274
|
-
container: data.parent.key,
|
275
|
-
path: data.path,
|
276
|
-
index: data.index,
|
274
|
+
container: data.parent.key, // Parent component
|
275
|
+
path: data.path, // Path to container within parent component.
|
276
|
+
index: data.index, // Index of component in parent container.
|
277
277
|
component: data.component
|
278
278
|
};
|
279
279
|
break;
|
package/lib/cjs/utils/utils.js
CHANGED
@@ -30,8 +30,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
30
30
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
31
31
|
};
|
32
32
|
Object.defineProperty(exports, "__esModule", { value: true });
|
33
|
-
exports.withSwitch = exports.firstNonNil = exports.unfold = exports.bootstrapVersion = exports.uniqueKey = exports.iterateKey = exports.delay = exports.fieldData = exports.getCurrencyAffixes = exports.getNumberDecimalLimit = exports.getNumberSeparators = exports.matchInputMask = exports.unmaskValue = exports.getInputMask = exports.convertFormatToMask = exports.convertFormatToMoment = exports.convertFormatToFlatpickr = exports.getLocaleDateFormatInfo = exports.formatOffset = exports.formatDate = exports.momentDate = exports.loadZones = exports.shouldLoadZones = exports.zonesLoaded = exports.offsetDate = exports.currentTimezone = exports.isValidDate = exports.getDateSetting = exports.guid = exports.uniqueName = exports.convertStringToHTMLElement = exports.
|
34
|
-
exports.isSelectResourceWithObjectValue = exports.getItemTemplateKeys = exports.interpolateErrors = exports.getComponentSavedTypes = exports.componentValueTypes = exports._ = exports.getFocusableElements = exports.isInsideScopingComponent = exports.isPromise = exports.getDataParentComponent = exports.getComponentPath = exports.getComponentPathWithoutIndicies = exports.getBrowserInfo = exports.getIEBrowserVersion = exports.round = exports.getStringFromComponentPath = exports.isChildOf = exports.getArrayFromComponentPath = exports.isInputComponent = exports.interpolate = exports.Evaluator = exports.fastCloneDeep = exports.sanitize = exports.translateHTMLTemplate = exports.getContextButtons = exports.getContextComponents =
|
33
|
+
exports.observeOverload = exports.withSwitch = exports.firstNonNil = exports.unfold = exports.bootstrapVersion = exports.uniqueKey = exports.iterateKey = exports.delay = exports.fieldData = exports.getCurrencyAffixes = exports.getNumberDecimalLimit = exports.getNumberSeparators = exports.matchInputMask = exports.unmaskValue = exports.getInputMask = exports.convertFormatToMask = exports.convertFormatToMoment = exports.convertFormatToFlatpickr = exports.getLocaleDateFormatInfo = exports.formatOffset = exports.formatDate = exports.momentDate = exports.loadZones = exports.shouldLoadZones = exports.zonesLoaded = exports.offsetDate = exports.currentTimezone = exports.isValidDate = exports.getDateSetting = exports.guid = exports.uniqueName = exports.convertStringToHTMLElement = exports.unescapeHTML = exports.setActionProperty = exports.checkTrigger = exports.checkCondition = exports.checkJsonConditional = exports.checkCustomConditional = exports.getComponentActualValue = exports.checkSimpleConditional = exports.checkCalculated = exports.isMongoId = exports.boolValue = exports.getElementRect = exports.getPropertyValue = exports.getRandomComponentId = exports.evaluate = exports.moment = exports.ConditionOperators = exports.jsonLogic = void 0;
|
34
|
+
exports.isSelectResourceWithObjectValue = exports.getItemTemplateKeys = exports.interpolateErrors = exports.getComponentSavedTypes = exports.componentValueTypes = exports._ = exports.getFocusableElements = exports.isInsideScopingComponent = exports.isPromise = exports.getDataParentComponent = exports.getComponentPath = exports.getComponentPathWithoutIndicies = exports.getBrowserInfo = exports.getIEBrowserVersion = exports.round = exports.getStringFromComponentPath = exports.isChildOf = exports.getArrayFromComponentPath = exports.isInputComponent = exports.interpolate = exports.Evaluator = exports.fastCloneDeep = exports.sanitize = exports.translateHTMLTemplate = exports.getContextButtons = exports.getContextComponents = void 0;
|
35
35
|
const lodash_1 = __importDefault(require("lodash"));
|
36
36
|
exports._ = lodash_1.default;
|
37
37
|
const fetch_ponyfill_1 = __importDefault(require("fetch-ponyfill"));
|
@@ -447,22 +447,6 @@ function unescapeHTML(str) {
|
|
447
447
|
return doc.documentElement.textContent;
|
448
448
|
}
|
449
449
|
exports.unescapeHTML = unescapeHTML;
|
450
|
-
/**
|
451
|
-
* Escape HTML characters like <, >, & and etc.
|
452
|
-
* @param str
|
453
|
-
* @returns {string}
|
454
|
-
*/
|
455
|
-
function escapeHTML(html) {
|
456
|
-
if (html) {
|
457
|
-
return html.replace(/&/g, '&')
|
458
|
-
.replace(/</g, '<')
|
459
|
-
.replace(/>/g, '>')
|
460
|
-
.replace(/"/g, '"')
|
461
|
-
.replace(/'/g, ''');
|
462
|
-
}
|
463
|
-
return '';
|
464
|
-
}
|
465
|
-
exports.escapeHTML = escapeHTML;
|
466
450
|
/**
|
467
451
|
* Make HTML element from string
|
468
452
|
* @param str
|
@@ -1271,7 +1255,8 @@ function sanitize(string, options) {
|
|
1271
1255
|
}
|
1272
1256
|
// Allowd URI Regex
|
1273
1257
|
if (options.sanitizeConfig && options.sanitizeConfig.allowedUriRegex) {
|
1274
|
-
|
1258
|
+
const allowedUriRegex = options.sanitizeConfig.allowedUriRegex;
|
1259
|
+
sanitizeOptions.ALLOWED_URI_REGEXP = lodash_1.default.isString(allowedUriRegex) ? new RegExp(allowedUriRegex) : allowedUriRegex;
|
1275
1260
|
}
|
1276
1261
|
// Allow to extend the existing array of elements that are safe for URI-like values
|
1277
1262
|
if (options.sanitizeConfig && Array.isArray(options.sanitizeConfig.addUriSafeAttr) && options.sanitizeConfig.addUriSafeAttr.length > 0) {
|
@@ -446,7 +446,7 @@ class CalendarWidget extends InputWidget_1.default {
|
|
446
446
|
return (date, format) => {
|
447
447
|
// Only format this if this is the altFormat and the form is readOnly.
|
448
448
|
if (this.settings.readOnly && (format === this.settings.altFormat)) {
|
449
|
-
if (this.loadZones()) {
|
449
|
+
if (!this.settings.enableTime || this.loadZones()) {
|
450
450
|
return Flatpickr.formatDate(date, format);
|
451
451
|
}
|
452
452
|
const currentValue = new Date(this.getValue());
|
package/lib/mjs/Element.js
CHANGED
package/lib/mjs/Embed.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import CDN from './CDN.js';
|
2
|
-
class Formio {
|
2
|
+
export class Formio {
|
3
3
|
static FormioClass = null;
|
4
4
|
static baseUrl;
|
5
5
|
static projectUrl;
|
@@ -249,7 +249,8 @@ class Formio {
|
|
249
249
|
});
|
250
250
|
element.parentNode.insertBefore(wrapper, element);
|
251
251
|
// If we include the libraries, then we will attempt to run this in shadow dom.
|
252
|
-
|
252
|
+
const useShadowDom = Formio.config.includeLibs && (typeof wrapper.attachShadow === 'function');
|
253
|
+
if (useShadowDom) {
|
253
254
|
wrapper = wrapper.attachShadow({
|
254
255
|
mode: 'open'
|
255
256
|
});
|
@@ -257,13 +258,15 @@ class Formio {
|
|
257
258
|
}
|
258
259
|
element.parentNode.removeChild(element);
|
259
260
|
wrapper.appendChild(element);
|
261
|
+
// If this is inside of shadow dom, then we need to add the styles and scripts to the shadow dom.
|
262
|
+
const libWrapper = useShadowDom ? wrapper : document.body;
|
260
263
|
// Load the renderer styles.
|
261
|
-
await Formio.addStyles(
|
264
|
+
await Formio.addStyles(libWrapper, Formio.config.embedCSS || `${Formio.cdn.js}/formio.embed.css`);
|
262
265
|
// Add a loader.
|
263
266
|
Formio.addLoader(wrapper);
|
264
267
|
const formioSrc = Formio.config.full ? 'formio.full' : 'formio.form';
|
265
268
|
const renderer = Formio.config.debug ? formioSrc : `${formioSrc}.min`;
|
266
|
-
Formio.FormioClass = await Formio.addScript(
|
269
|
+
Formio.FormioClass = await Formio.addScript(libWrapper, Formio.formioScript(Formio.config.script || `${Formio.cdn.js}/${renderer}.js`, builder), 'Formio', builder ? 'isBuilder' : 'isRenderer');
|
267
270
|
Formio.FormioClass.cdn = Formio.cdn;
|
268
271
|
Formio.FormioClass.setBaseUrl(options.baseUrl || Formio.baseUrl || Formio.config.base);
|
269
272
|
Formio.FormioClass.setProjectUrl(options.projectUrl || Formio.projectUrl || Formio.config.project);
|
@@ -280,7 +283,7 @@ class Formio {
|
|
280
283
|
}
|
281
284
|
// Add libraries if they wish to include the libs.
|
282
285
|
if (Formio.config.template && Formio.config.includeLibs) {
|
283
|
-
await Formio.addLibrary(
|
286
|
+
await Formio.addLibrary(libWrapper, Formio.config.libs[Formio.config.template], Formio.config.template);
|
284
287
|
}
|
285
288
|
// Add the premium modules.
|
286
289
|
if (Formio.config.premium) {
|
@@ -291,10 +294,10 @@ class Formio {
|
|
291
294
|
for (const name in Formio.config.modules) {
|
292
295
|
const lib = Formio.config.modules[name];
|
293
296
|
lib.use = lib.use || true;
|
294
|
-
await Formio.addLibrary(
|
297
|
+
await Formio.addLibrary(libWrapper, lib, name);
|
295
298
|
}
|
296
299
|
}
|
297
|
-
await Formio.addStyles(
|
300
|
+
await Formio.addStyles(libWrapper, Formio.formioScript(Formio.config.style || `${Formio.cdn.js}/${renderer}.css`, builder));
|
298
301
|
if (Formio.config.before) {
|
299
302
|
await Formio.config.before(Formio.FormioClass, element, Formio.config);
|
300
303
|
}
|
@@ -363,7 +366,6 @@ class Formio {
|
|
363
366
|
}
|
364
367
|
};
|
365
368
|
}
|
366
|
-
export { Formio };
|
367
369
|
CDN.defaultCDN = Formio.version.includes('rc') ? 'https://cdn.test-form.io' : 'https://cdn.form.io';
|
368
370
|
export class Form {
|
369
371
|
constructor(element, form, options) {
|
package/lib/mjs/FormBuilder.js
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import { Formio } from './Formio';
|
2
2
|
import Builders from './builders';
|
3
3
|
import Form from './Form';
|
4
|
-
class FormBuilder extends Form {
|
4
|
+
export default class FormBuilder extends Form {
|
5
5
|
static options = {};
|
6
6
|
constructor(element, form, options) {
|
7
7
|
form = form || {};
|
@@ -18,7 +18,6 @@ class FormBuilder extends Form {
|
|
18
18
|
}
|
19
19
|
}
|
20
20
|
}
|
21
|
-
export default FormBuilder;
|
22
21
|
/**
|
23
22
|
* Factory that creates a new form builder based on the form parameter.
|
24
23
|
*
|
package/lib/mjs/Webform.js
CHANGED
@@ -182,11 +182,13 @@ export default class Webform extends NestedDataComponent {
|
|
182
182
|
this.language = this.i18next.language;
|
183
183
|
// See if we need to restore the draft from a user.
|
184
184
|
if (this.options.saveDraft && !this.options.skipDraftRestore) {
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
185
|
+
this.formReady.then(() => {
|
186
|
+
const user = Formio.getUser();
|
187
|
+
// Only restore a draft if the submission isn't explicitly set.
|
188
|
+
if (user && !this.submissionSet) {
|
189
|
+
this.restoreDraft(user._id);
|
190
|
+
}
|
191
|
+
});
|
190
192
|
}
|
191
193
|
this.component.clearOnHide = false;
|
192
194
|
// Ensure the root is set to this component.
|
@@ -531,6 +533,10 @@ export default class Webform extends NestedDataComponent {
|
|
531
533
|
if (form && form.properties) {
|
532
534
|
this.options.properties = form.properties;
|
533
535
|
}
|
536
|
+
// Use the sanitize config from the form settings or the global sanitize config if it is not provided in the options
|
537
|
+
if (!this.options.sanitizeConfig && !this.builderMode) {
|
538
|
+
this.options.sanitizeConfig = _.get(form, 'settings.sanitizeConfig') || _.get(form, 'globalSettings.sanitizeConfig');
|
539
|
+
}
|
534
540
|
if ('schema' in form && compareVersions(form.schema, '1.x') > 0) {
|
535
541
|
this.ready.then(() => {
|
536
542
|
this.setAlert('alert alert-danger', 'Form schema is for a newer version, please upgrade your renderer. Some functionality may not work.');
|
@@ -644,6 +650,11 @@ export default class Webform extends NestedDataComponent {
|
|
644
650
|
return this.submissionReadyResolve(submission);
|
645
651
|
}, (err) => this.submissionReadyReject(err)).catch((err) => this.submissionReadyReject(err));
|
646
652
|
}
|
653
|
+
handleDraftError(errName, errDetails, restoreDraft) {
|
654
|
+
const errorMessage = _.trim(`${this.t(errName)} ${errDetails || ''}`);
|
655
|
+
console.warn(errorMessage);
|
656
|
+
this.emit(restoreDraft ? 'restoreDraftError' : 'saveDraftError', errDetails || errorMessage);
|
657
|
+
}
|
647
658
|
/**
|
648
659
|
* Saves a submission draft.
|
649
660
|
*/
|
@@ -652,11 +663,11 @@ export default class Webform extends NestedDataComponent {
|
|
652
663
|
return;
|
653
664
|
}
|
654
665
|
if (!this.formio) {
|
655
|
-
|
666
|
+
this.handleDraftError('saveDraftInstanceError');
|
656
667
|
return;
|
657
668
|
}
|
658
669
|
if (!Formio.getUser()) {
|
659
|
-
|
670
|
+
this.handleDraftError('saveDraftAuthError');
|
660
671
|
return;
|
661
672
|
}
|
662
673
|
const draft = fastCloneDeep(this.submission);
|
@@ -669,6 +680,10 @@ export default class Webform extends NestedDataComponent {
|
|
669
680
|
this.submission._id = sub._id;
|
670
681
|
this.savingDraft = false;
|
671
682
|
this.emit('saveDraft', sub);
|
683
|
+
})
|
684
|
+
.catch(err => {
|
685
|
+
this.savingDraft = false;
|
686
|
+
this.handleDraftError('saveDraftError', err);
|
672
687
|
});
|
673
688
|
}
|
674
689
|
}
|
@@ -679,7 +694,7 @@ export default class Webform extends NestedDataComponent {
|
|
679
694
|
*/
|
680
695
|
restoreDraft(userId) {
|
681
696
|
if (!this.formio) {
|
682
|
-
|
697
|
+
this.handleDraftError('restoreDraftInstanceError', null, true);
|
683
698
|
return;
|
684
699
|
}
|
685
700
|
this.savingDraft = true;
|
@@ -701,6 +716,11 @@ export default class Webform extends NestedDataComponent {
|
|
701
716
|
this.draftEnabled = true;
|
702
717
|
this.savingDraft = false;
|
703
718
|
this.emit('restoreDraft', null);
|
719
|
+
})
|
720
|
+
.catch(err => {
|
721
|
+
this.draftEnabled = true;
|
722
|
+
this.savingDraft = false;
|
723
|
+
this.handleDraftError('restoreDraftError', err, true);
|
704
724
|
});
|
705
725
|
}
|
706
726
|
get schema() {
|
@@ -879,7 +899,7 @@ export default class Webform extends NestedDataComponent {
|
|
879
899
|
resetValue() {
|
880
900
|
_.each(this.getComponents(), (comp) => (comp.resetValue()));
|
881
901
|
this.setPristine(true);
|
882
|
-
this.onChange();
|
902
|
+
this.onChange({ resetValue: true });
|
883
903
|
}
|
884
904
|
/**
|
885
905
|
* Sets a new alert to display in the error dialog of the form.
|
@@ -985,7 +1005,7 @@ export default class Webform extends NestedDataComponent {
|
|
985
1005
|
if (!Array.isArray(errors)) {
|
986
1006
|
errors = [errors];
|
987
1007
|
}
|
988
|
-
errors = errors.concat(this.
|
1008
|
+
errors = errors.concat(this.customErrors);
|
989
1009
|
if (!errors.length) {
|
990
1010
|
this.setAlert(false);
|
991
1011
|
return;
|
@@ -1095,16 +1115,17 @@ export default class Webform extends NestedDataComponent {
|
|
1095
1115
|
error = this.normalizeError(error);
|
1096
1116
|
this.submitting = false;
|
1097
1117
|
this.setPristine(false);
|
1098
|
-
this.emit('submitError', error);
|
1118
|
+
this.emit('submitError', error || this.errors);
|
1099
1119
|
// Allow for silent cancellations (no error message, no submit button error state)
|
1100
1120
|
if (error && error.silent) {
|
1101
1121
|
this.emit('change', { isValid: true }, { silent: true });
|
1102
1122
|
return false;
|
1103
1123
|
}
|
1104
|
-
this.showErrors(error, true);
|
1124
|
+
const errors = this.showErrors(error, true);
|
1105
1125
|
if (this.root && this.root.alert) {
|
1106
1126
|
this.scrollIntoView(this.root.alert);
|
1107
1127
|
}
|
1128
|
+
return errors;
|
1108
1129
|
}
|
1109
1130
|
/**
|
1110
1131
|
* Trigger the change event for this form.
|
@@ -1128,7 +1149,9 @@ export default class Webform extends NestedDataComponent {
|
|
1128
1149
|
value.isValid = errors.length === 0;
|
1129
1150
|
this.loading = false;
|
1130
1151
|
if (this.submitted) {
|
1131
|
-
|
1152
|
+
// show server errors while they are not cleaned/fixed
|
1153
|
+
const nonComponentServerErrors = _.filter(this.serverErrors || [], err => !err.component && !err.path);
|
1154
|
+
this.showErrors(nonComponentServerErrors.length ? nonComponentServerErrors : null);
|
1132
1155
|
}
|
1133
1156
|
// See if we need to save the draft of the form.
|
1134
1157
|
if (modified && this.options.saveDraft) {
|
@@ -976,6 +976,7 @@ export default class WebformBuilder extends Component {
|
|
976
976
|
}
|
977
977
|
}
|
978
978
|
updateComponent(component, changed) {
|
979
|
+
const sanitizeConfig = _.get(this.webform, 'form.settings.sanitizeConfig') || _.get(this.webform, 'form.globalSettings.sanitizeConfig');
|
979
980
|
// Update the preview.
|
980
981
|
if (this.preview) {
|
981
982
|
this.preview.form = {
|
@@ -987,13 +988,14 @@ export default class WebformBuilder extends Component {
|
|
987
988
|
'autofocus',
|
988
989
|
'customConditional',
|
989
990
|
])],
|
990
|
-
config: this.options.formConfig || {}
|
991
|
+
config: this.options.formConfig || {},
|
992
|
+
sanitizeConfig,
|
991
993
|
};
|
992
994
|
const fieldsToRemoveDoubleQuotes = ['label', 'tooltip'];
|
993
995
|
this.preview.form.components.forEach(component => this.replaceDoubleQuotes(component, fieldsToRemoveDoubleQuotes));
|
994
996
|
const previewElement = this.componentEdit.querySelector('[ref="preview"]');
|
995
997
|
if (previewElement) {
|
996
|
-
this.setContent(previewElement, this.preview.render());
|
998
|
+
this.setContent(previewElement, this.preview.render(), null, sanitizeConfig);
|
997
999
|
this.preview.attach(previewElement);
|
998
1000
|
}
|
999
1001
|
}
|
package/lib/mjs/Wizard.js
CHANGED
@@ -711,7 +711,7 @@ export default class Wizard extends Webform {
|
|
711
711
|
if (this.enabledIndex) {
|
712
712
|
this.enabledIndex = 0;
|
713
713
|
}
|
714
|
-
this.onChange();
|
714
|
+
this.onChange({ resetValue: true });
|
715
715
|
this.redraw();
|
716
716
|
return this.page;
|
717
717
|
});
|
@@ -867,6 +867,11 @@ export default class Wizard extends Webform {
|
|
867
867
|
}
|
868
868
|
return super.redraw();
|
869
869
|
}
|
870
|
+
rebuild() {
|
871
|
+
const currentPage = this.page;
|
872
|
+
const setCurrentPage = () => this.setPage(currentPage);
|
873
|
+
return super.rebuild().then(setCurrentPage);
|
874
|
+
}
|
870
875
|
checkValidity(data, dirty, row, currentPageOnly, childErrors = []) {
|
871
876
|
if (!this.checkCondition(row, data)) {
|
872
877
|
this.setCustomValidity('');
|
@@ -2,7 +2,7 @@ import _ from 'lodash';
|
|
2
2
|
import pdf from '../PDFBuilder';
|
3
3
|
import webform from '../WebformBuilder';
|
4
4
|
import wizard from '../WizardBuilder';
|
5
|
-
class Builders {
|
5
|
+
export default class Builders {
|
6
6
|
static builders = {
|
7
7
|
pdf,
|
8
8
|
webform,
|
@@ -21,4 +21,3 @@ class Builders {
|
|
21
21
|
return Builders.builders;
|
22
22
|
}
|
23
23
|
}
|
24
|
-
export default Builders;
|
@@ -2,7 +2,7 @@ import Component from './_classes/component/Component';
|
|
2
2
|
import EditFormUtils from './_classes/component/editForm/utils';
|
3
3
|
import BaseEditForm from './_classes/component/Component.form';
|
4
4
|
import _ from 'lodash';
|
5
|
-
class Components {
|
5
|
+
export default class Components {
|
6
6
|
static _editFormUtils = EditFormUtils;
|
7
7
|
static _baseEditForm = BaseEditForm;
|
8
8
|
static set EditFormUtils(value) {
|
@@ -101,4 +101,3 @@ class Components {
|
|
101
101
|
return comp;
|
102
102
|
}
|
103
103
|
}
|
104
|
-
export default Components;
|
@@ -747,6 +747,7 @@ export default class Component extends Element {
|
|
747
747
|
return !this.component.label ||
|
748
748
|
((!this.isInDataGrid && this.component.hideLabel) ||
|
749
749
|
(this.isInDataGrid && !this.component.dataGridLabel) ||
|
750
|
+
this.options.floatingLabels ||
|
750
751
|
this.options.inputsOnly) && !this.builderMode;
|
751
752
|
}
|
752
753
|
transform(type, value) {
|
@@ -819,13 +820,7 @@ export default class Component extends Element {
|
|
819
820
|
renderTemplate(name, data = {}, modeOption) {
|
820
821
|
// Need to make this fall back to form if renderMode is not found similar to how we search templates.
|
821
822
|
const mode = modeOption || this.options.renderMode || 'form';
|
822
|
-
data.component =
|
823
|
-
...this.component,
|
824
|
-
};
|
825
|
-
// Escape HTML provided in component description and render it as a string instead
|
826
|
-
if (this.component.description) {
|
827
|
-
data.component.description = FormioUtils.escapeHTML(this.component.description);
|
828
|
-
}
|
823
|
+
data.component = this.component;
|
829
824
|
data.self = this;
|
830
825
|
data.options = this.options;
|
831
826
|
data.readOnly = this.options.readOnly;
|
@@ -1036,12 +1031,12 @@ export default class Component extends Element {
|
|
1036
1031
|
const tooltipText = this.interpolate(tooltipDataTitle || tooltipAttribute)
|
1037
1032
|
.replace(/(?:\r\n|\r|\n)/g, '<br />');
|
1038
1033
|
this.tooltips[index] = tippy(tooltip, {
|
1039
|
-
allowHTML:
|
1034
|
+
allowHTML: true,
|
1040
1035
|
trigger: 'mouseenter click focus',
|
1041
1036
|
placement: 'right',
|
1042
1037
|
zIndex: 10000,
|
1043
1038
|
interactive: true,
|
1044
|
-
content: this.t(tooltipText, { _userInput: true }),
|
1039
|
+
content: this.t(this.sanitize(tooltipText), { _userInput: true }),
|
1045
1040
|
});
|
1046
1041
|
}
|
1047
1042
|
});
|
@@ -1816,6 +1811,10 @@ export default class Component extends Element {
|
|
1816
1811
|
this.setElementInvalid(this.performInputMapping(element), false);
|
1817
1812
|
});
|
1818
1813
|
this.setInputWidgetErrorClasses(elements, hasErrors);
|
1814
|
+
// do not set error classes for hidden components
|
1815
|
+
if (!this.visible) {
|
1816
|
+
return;
|
1817
|
+
}
|
1819
1818
|
if (hasErrors) {
|
1820
1819
|
// Add error classes
|
1821
1820
|
elements.forEach((input) => {
|
@@ -1915,7 +1914,7 @@ export default class Component extends Element {
|
|
1915
1914
|
placeholder: this.t(this.component.placeholder, { _userInput: true }),
|
1916
1915
|
modules: {
|
1917
1916
|
toolbar: [
|
1918
|
-
[{ 'size': ['small', false, 'large', 'huge'] }],
|
1917
|
+
[{ 'size': ['small', false, 'large', 'huge'] }], // custom dropdown
|
1919
1918
|
[{ 'header': [1, 2, 3, 4, 5, 6, false] }],
|
1920
1919
|
[{ 'font': [] }],
|
1921
1920
|
['bold', 'italic', 'underline', 'strike', { 'script': 'sub' }, { 'script': 'super' }, 'clean'],
|
@@ -2174,10 +2173,12 @@ export default class Component extends Element {
|
|
2174
2173
|
defaultValue = this.getCustomDefaultValue(defaultValue);
|
2175
2174
|
const checkMask = (value) => {
|
2176
2175
|
if (typeof value === 'string') {
|
2177
|
-
|
2178
|
-
|
2179
|
-
|
2180
|
-
value
|
2176
|
+
if (this.component.type !== 'textfield') {
|
2177
|
+
const placeholderChar = this.placeholderChar;
|
2178
|
+
value = conformToMask(value, this.defaultMask, { placeholderChar }).conformedValue;
|
2179
|
+
if (!FormioUtils.matchInputMask(value, this.defaultMask)) {
|
2180
|
+
value = '';
|
2181
|
+
}
|
2181
2182
|
}
|
2182
2183
|
}
|
2183
2184
|
else {
|
@@ -2276,10 +2277,10 @@ export default class Component extends Element {
|
|
2276
2277
|
}
|
2277
2278
|
const input = this.performInputMapping(this.refs.input[index]);
|
2278
2279
|
const valueMaskInput = this.refs.valueMaskInput;
|
2279
|
-
if (valueMaskInput?.mask) {
|
2280
|
+
if (valueMaskInput?.mask && valueMaskInput.mask.textMaskInputElement) {
|
2280
2281
|
valueMaskInput.mask.textMaskInputElement.update(value);
|
2281
2282
|
}
|
2282
|
-
if (input.mask) {
|
2283
|
+
if (input.mask && input.mask.textMaskInputElement) {
|
2283
2284
|
input.mask.textMaskInputElement.update(value);
|
2284
2285
|
}
|
2285
2286
|
else if (input.widget && input.widget.setValue) {
|
@@ -2435,8 +2436,8 @@ export default class Component extends Element {
|
|
2435
2436
|
}
|
2436
2437
|
/* eslint-disable max-statements */
|
2437
2438
|
calculateComponentValue(data, flags, row) {
|
2438
|
-
// Skip value calculation for the component if we don't have entire form data set
|
2439
|
-
if (_.isUndefined(_.get(this, 'root.data'))) {
|
2439
|
+
// Skip value calculation for the component if we don't have entire form data set or in builder mode
|
2440
|
+
if (this.builderMode || _.isUndefined(_.get(this, 'root.data'))) {
|
2440
2441
|
return false;
|
2441
2442
|
}
|
2442
2443
|
// If no calculated value or
|
@@ -2444,10 +2445,16 @@ export default class Component extends Element {
|
|
2444
2445
|
const { clearOnHide } = this.component;
|
2445
2446
|
const shouldBeCleared = !this.visible && clearOnHide;
|
2446
2447
|
const allowOverride = _.get(this.component, 'allowCalculateOverride', false);
|
2448
|
+
if (shouldBeCleared) {
|
2449
|
+
// remove calculated value so that the value is recalculated once component becomes visible
|
2450
|
+
if (this.hasOwnProperty('calculatedValue') && allowOverride) {
|
2451
|
+
_.unset(this, 'calculatedValue');
|
2452
|
+
}
|
2453
|
+
return false;
|
2454
|
+
}
|
2447
2455
|
// Handle all cases when calculated values should not fire.
|
2448
2456
|
if ((this.options.readOnly && !this.options.pdf && !this.component.calculateValue) ||
|
2449
2457
|
!(this.component.calculateValue || this.component.calculateValueVariable) ||
|
2450
|
-
shouldBeCleared ||
|
2451
2458
|
(this.options.server && !this.component.calculateServer) ||
|
2452
2459
|
(flags.dataSourceInitialLoading && allowOverride)) {
|
2453
2460
|
return false;
|
@@ -2474,7 +2481,7 @@ export default class Component extends Element {
|
|
2474
2481
|
this.calculationLocked = true;
|
2475
2482
|
return false;
|
2476
2483
|
}
|
2477
|
-
const firstPass = (this.calculatedValue === undefined);
|
2484
|
+
const firstPass = (this.calculatedValue === undefined) || flags.resetValue;
|
2478
2485
|
if (firstPass) {
|
2479
2486
|
this.calculatedValue = null;
|
2480
2487
|
}
|
@@ -2488,6 +2495,7 @@ export default class Component extends Element {
|
|
2488
2495
|
}
|
2489
2496
|
// Check to ensure that the calculated value is different than the previously calculated value.
|
2490
2497
|
if (previousCalculatedValue && previousChanged && !calculationChanged) {
|
2498
|
+
this.calculatedValue = null;
|
2491
2499
|
return false;
|
2492
2500
|
}
|
2493
2501
|
if (flags.isReordered || !calculationChanged) {
|
@@ -2495,7 +2503,7 @@ export default class Component extends Element {
|
|
2495
2503
|
}
|
2496
2504
|
if (fromSubmission) {
|
2497
2505
|
// If we set value from submission and it differs from calculated one, set the calculated value to prevent overriding dataValue in the next pass
|
2498
|
-
this.calculatedValue = calculatedValue;
|
2506
|
+
this.calculatedValue = fastCloneDeep(calculatedValue);
|
2499
2507
|
return false;
|
2500
2508
|
}
|
2501
2509
|
// If this is the firstPass, and the dataValue is different than to the calculatedValue.
|
@@ -2504,7 +2512,7 @@ export default class Component extends Element {
|
|
2504
2512
|
return true;
|
2505
2513
|
}
|
2506
2514
|
}
|
2507
|
-
this.calculatedValue = calculatedValue;
|
2515
|
+
this.calculatedValue = fastCloneDeep(calculatedValue);
|
2508
2516
|
if (changed) {
|
2509
2517
|
if (!flags.noPristineChangeOnModified) {
|
2510
2518
|
this.pristine = false;
|
@@ -2921,6 +2929,7 @@ export default class Component extends Element {
|
|
2921
2929
|
return (this.component.protected || !this.component.persistent || (this.component.persistent === 'client-only'));
|
2922
2930
|
}
|
2923
2931
|
shouldSkipValidation(data, row, flags = {}) {
|
2932
|
+
const { validateWhenHidden = false } = this.component || {};
|
2924
2933
|
const rules = [
|
2925
2934
|
// Do not validate if the flags say not too.
|
2926
2935
|
() => flags.noValidate,
|
@@ -2931,9 +2940,9 @@ export default class Component extends Element {
|
|
2931
2940
|
// Check to see if we are editing and if so, check component persistence.
|
2932
2941
|
() => this.isValueHidden(),
|
2933
2942
|
// Force valid if component is hidden.
|
2934
|
-
() => !this.visible,
|
2943
|
+
() => !this.visible && !validateWhenHidden,
|
2935
2944
|
// Force valid if component is conditionally hidden.
|
2936
|
-
() => !this.checkCondition(row, data)
|
2945
|
+
() => !this.checkCondition(row, data) && !validateWhenHidden
|
2937
2946
|
];
|
2938
2947
|
return rules.some(pred => pred());
|
2939
2948
|
}
|
@@ -18,6 +18,14 @@ export default [
|
|
18
18
|
key: 'unique',
|
19
19
|
input: true
|
20
20
|
},
|
21
|
+
{
|
22
|
+
weight: 100,
|
23
|
+
type: 'checkbox',
|
24
|
+
label: 'Validate When Hidden',
|
25
|
+
tooltip: 'Validates the component when it is hidden/conditionally hidden. Vaildation errors are displayed in the error alert on the form submission.',
|
26
|
+
key: 'validateWhenHidden',
|
27
|
+
input: true
|
28
|
+
},
|
21
29
|
{
|
22
30
|
weight: 0,
|
23
31
|
type: 'select',
|
@@ -4,8 +4,8 @@ export default {
|
|
4
4
|
components: [
|
5
5
|
{
|
6
6
|
label: 'Text Field',
|
7
|
-
description: "<img src='https://somesite' onerror='var _ee = 2' >",
|
8
|
-
tooltip: "<img src='https://somesite' onerror='var _ee = 1
|
7
|
+
description: "<img <img src='https://somesite' onerror='var _ee = 2' >",
|
8
|
+
tooltip: "<img src='https://somesite' onerror='var _ee = 1 >",
|
9
9
|
applyMaskOn: 'change',
|
10
10
|
tableView: true,
|
11
11
|
key: 'textField',
|