@formio/js 5.0.0-rc.39 → 5.0.0-rc.41

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. package/dist/formio.builder.css +2 -2
  2. package/dist/formio.builder.min.css +1 -1
  3. package/dist/formio.embed.js +1 -1
  4. package/dist/formio.embed.min.js +1 -1
  5. package/dist/formio.embed.min.js.LICENSE.txt +1 -1
  6. package/dist/formio.form.css +2 -2
  7. package/dist/formio.form.js +5373 -2370
  8. package/dist/formio.form.min.css +1 -1
  9. package/dist/formio.form.min.js +1 -1
  10. package/dist/formio.form.min.js.LICENSE.txt +25 -7
  11. package/dist/formio.full.css +2 -2
  12. package/dist/formio.full.js +5715 -2704
  13. package/dist/formio.full.min.css +1 -1
  14. package/dist/formio.full.min.js +1 -1
  15. package/dist/formio.full.min.js.LICENSE.txt +25 -7
  16. package/dist/formio.js +143 -61
  17. package/dist/formio.min.js +1 -1
  18. package/dist/formio.min.js.LICENSE.txt +13 -1
  19. package/dist/formio.utils.js +149 -96
  20. package/dist/formio.utils.min.js +1 -1
  21. package/dist/formio.utils.min.js.LICENSE.txt +4 -4
  22. package/lib/cjs/Element.js +1 -0
  23. package/lib/cjs/Embed.js +121 -121
  24. package/lib/cjs/Webform.js +36 -13
  25. package/lib/cjs/WebformBuilder.js +4 -2
  26. package/lib/cjs/Wizard.js +6 -1
  27. package/lib/cjs/components/_classes/component/Component.js +33 -22
  28. package/lib/cjs/components/_classes/component/editForm/Component.edit.logic.js +1 -1
  29. package/lib/cjs/components/_classes/component/editForm/Component.edit.validation.js +8 -0
  30. package/lib/cjs/components/_classes/component/fixtures/comp5.js +2 -2
  31. package/lib/cjs/components/_classes/multivalue/Multivalue.js +2 -2
  32. package/lib/cjs/components/_classes/nested/NestedComponent.js +2 -2
  33. package/lib/cjs/components/address/fixtures/comp3.js +1 -1
  34. package/lib/cjs/components/builder.js +0 -2
  35. package/lib/cjs/components/button/Button.js +7 -1
  36. package/lib/cjs/components/datagrid/DataGrid.js +16 -3
  37. package/lib/cjs/components/datagrid/fixtures/comp-with-allow-calculate-override.js +68 -0
  38. package/lib/cjs/components/datagrid/fixtures/comp6.js +1 -1
  39. package/lib/cjs/components/datagrid/fixtures/index.js +5 -1
  40. package/lib/cjs/components/datagrid/fixtures/two-comp-with-allow-calculate-override.js +104 -0
  41. package/lib/cjs/components/editgrid/EditGrid.js +11 -4
  42. package/lib/cjs/components/editgrid/fixtures/formsWithEditGridAndConditions.js +923 -0
  43. package/lib/cjs/components/file/File.js +2 -2
  44. package/lib/cjs/components/file/editForm/File.edit.file.js +1 -1
  45. package/lib/cjs/components/form/Form.js +1 -1
  46. package/lib/cjs/components/html/HTML.js +11 -2
  47. package/lib/cjs/components/html/fixtures/index.js +1 -3
  48. package/lib/cjs/components/index.js +0 -2
  49. package/lib/cjs/components/recaptcha/ReCaptcha.js +46 -46
  50. package/lib/cjs/components/select/Select.js +3 -1
  51. package/lib/cjs/components/select/fixtures/comp20.js +46 -0
  52. package/lib/cjs/components/select/fixtures/comp21.js +106 -0
  53. package/lib/cjs/components/select/fixtures/index.js +5 -1
  54. package/lib/cjs/components/selectboxes/SelectBoxes.js +1 -1
  55. package/lib/cjs/components/textfield/TextField.js +63 -3
  56. package/lib/cjs/providers/storage/s3.js +5 -3
  57. package/lib/cjs/providers/storage/uploadAdapter.js +1 -1
  58. package/lib/cjs/providers/storage/url.js +19 -13
  59. package/lib/cjs/templates/Templates.js +4 -4
  60. package/lib/cjs/translations/en.js +10 -6
  61. package/lib/cjs/utils/Evaluator.js +1 -1
  62. package/lib/cjs/utils/conditionOperators/IsEqualTo.js +2 -2
  63. package/lib/cjs/utils/formUtils.js +3 -3
  64. package/lib/cjs/utils/utils.js +4 -19
  65. package/lib/cjs/widgets/CalendarWidget.js +1 -1
  66. package/lib/mjs/Element.js +1 -0
  67. package/lib/mjs/Embed.js +1 -2
  68. package/lib/mjs/FormBuilder.js +1 -2
  69. package/lib/mjs/Webform.js +36 -13
  70. package/lib/mjs/WebformBuilder.js +4 -2
  71. package/lib/mjs/Wizard.js +6 -1
  72. package/lib/mjs/builders/Builders.js +1 -2
  73. package/lib/mjs/components/Components.js +1 -2
  74. package/lib/mjs/components/_classes/component/Component.js +33 -24
  75. package/lib/mjs/components/_classes/component/editForm/Component.edit.logic.js +1 -1
  76. package/lib/mjs/components/_classes/component/editForm/Component.edit.validation.js +8 -0
  77. package/lib/mjs/components/_classes/component/fixtures/comp5.js +2 -2
  78. package/lib/mjs/components/_classes/multivalue/Multivalue.js +2 -2
  79. package/lib/mjs/components/_classes/nested/NestedComponent.js +2 -2
  80. package/lib/mjs/components/address/fixtures/comp3.js +1 -1
  81. package/lib/mjs/components/builder.js +0 -2
  82. package/lib/mjs/components/button/Button.js +7 -1
  83. package/lib/mjs/components/datagrid/DataGrid.js +15 -3
  84. package/lib/mjs/components/datagrid/fixtures/comp-with-allow-calculate-override.js +66 -0
  85. package/lib/mjs/components/datagrid/fixtures/comp6.js +1 -1
  86. package/lib/mjs/components/datagrid/fixtures/index.js +3 -1
  87. package/lib/mjs/components/datagrid/fixtures/two-comp-with-allow-calculate-override.js +102 -0
  88. package/lib/mjs/components/editgrid/EditGrid.js +11 -4
  89. package/lib/mjs/components/editgrid/fixtures/formsWithEditGridAndConditions.js +921 -0
  90. package/lib/mjs/components/file/File.js +2 -2
  91. package/lib/mjs/components/file/editForm/File.edit.file.js +1 -1
  92. package/lib/mjs/components/form/Form.js +1 -1
  93. package/lib/mjs/components/html/HTML.js +10 -2
  94. package/lib/mjs/components/html/fixtures/index.js +1 -2
  95. package/lib/mjs/components/index.js +0 -2
  96. package/lib/mjs/components/recaptcha/ReCaptcha.js +32 -43
  97. package/lib/mjs/components/select/Select.js +3 -1
  98. package/lib/mjs/components/select/fixtures/comp20.js +44 -0
  99. package/lib/mjs/components/select/fixtures/comp21.js +104 -0
  100. package/lib/mjs/components/select/fixtures/index.js +3 -1
  101. package/lib/mjs/components/selectboxes/SelectBoxes.js +1 -1
  102. package/lib/mjs/components/textfield/TextField.js +62 -3
  103. package/lib/mjs/displays/Displays.js +1 -2
  104. package/lib/mjs/licenses/Licenses.js +1 -2
  105. package/lib/mjs/providers/Providers.js +1 -2
  106. package/lib/mjs/providers/storage/s3.js +5 -3
  107. package/lib/mjs/providers/storage/uploadAdapter.js +1 -1
  108. package/lib/mjs/providers/storage/url.js +19 -13
  109. package/lib/mjs/templates/Templates.js +1 -1
  110. package/lib/mjs/translations/en.js +10 -6
  111. package/lib/mjs/utils/Evaluator.js +1 -1
  112. package/lib/mjs/utils/conditionOperators/IsEqualTo.js +2 -2
  113. package/lib/mjs/utils/formUtils.js +3 -3
  114. package/lib/mjs/utils/utils.js +2 -16
  115. package/lib/mjs/widgets/CalendarWidget.js +1 -1
  116. package/package.json +23 -22
  117. package/lib/cjs/components/html/fixtures/comp3.js +0 -31
  118. package/lib/cjs/components/resource/Resource.form.js +0 -16
  119. package/lib/cjs/components/resource/Resource.js +0 -39
  120. package/lib/cjs/components/resource/editForm/Resource.edit.display.js +0 -102
  121. package/lib/cjs/components/resource/fixtures/comp1.js +0 -30
  122. package/lib/cjs/components/resource/fixtures/comp2.js +0 -31
  123. package/lib/cjs/components/resource/fixtures/index.js +0 -10
  124. package/lib/mjs/components/html/fixtures/comp3.js +0 -29
  125. package/lib/mjs/components/resource/Resource.form.js +0 -10
  126. package/lib/mjs/components/resource/Resource.js +0 -33
  127. package/lib/mjs/components/resource/editForm/Resource.edit.display.js +0 -100
  128. package/lib/mjs/components/resource/fixtures/comp1.js +0 -28
  129. package/lib/mjs/components/resource/fixtures/comp2.js +0 -29
  130. 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,
@@ -15,7 +15,7 @@ class IsEqualTo extends ConditionOperator_1.default {
15
15
  }
16
16
  execute({ value, comparedValue, instance, conditionComponentPath }) {
17
17
  var _a;
18
- if (value && comparedValue && typeof value !== typeof comparedValue && lodash_1.default.isString(comparedValue)) {
18
+ if ((value || value === false) && comparedValue && typeof value !== typeof comparedValue && lodash_1.default.isString(comparedValue)) {
19
19
  try {
20
20
  comparedValue = JSON.parse(comparedValue);
21
21
  }
@@ -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.isString(comparedValue)) {
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;
@@ -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.escapeHTML = 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 = exports.observeOverload = void 0;
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, '&amp;')
458
- .replace(/</g, '&lt;')
459
- .replace(/>/g, '&gt;')
460
- .replace(/"/g, '&quot;')
461
- .replace(/'/g, '&#39;');
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
- sanitizeOptions.ALLOWED_URI_REGEXP = options.sanitizeConfig.allowedUriRegex;
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());
@@ -508,6 +508,7 @@ export default class Element {
508
508
  token: Formio.getToken({
509
509
  decode: true
510
510
  }),
511
+ options: this.options,
511
512
  config: this.root && this.root.form && this.root.form.config
512
513
  ? this.root.form.config
513
514
  : this.options?.formConfig
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;
@@ -366,7 +366,6 @@ class Formio {
366
366
  }
367
367
  };
368
368
  }
369
- export { Formio };
370
369
  CDN.defaultCDN = Formio.version.includes('rc') ? 'https://cdn.test-form.io' : 'https://cdn.form.io';
371
370
  export class Form {
372
371
  constructor(element, form, options) {
@@ -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
  *
@@ -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
- const user = Formio.getUser();
186
- // Only restore a draft if the submission isn't explicitly set.
187
- if (user && !this.submissionSet) {
188
- this.restoreDraft(user._id);
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
- console.warn(this.t('saveDraftInstanceError'));
666
+ this.handleDraftError('saveDraftInstanceError');
656
667
  return;
657
668
  }
658
669
  if (!Formio.getUser()) {
659
- console.warn(this.t('saveDraftAuthError'));
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
- console.warn(this.t('restoreDraftInstanceError'));
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.serverErrors || []);
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
- this.showErrors(errors);
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: false,
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
- const placeholderChar = this.placeholderChar;
2178
- value = conformToMask(value, this.defaultMask, { placeholderChar }).conformedValue;
2179
- if (!FormioUtils.matchInputMask(value, this.defaultMask)) {
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
  }
@@ -368,7 +368,7 @@ export default [
368
368
  {
369
369
  weight: 20,
370
370
  input: true,
371
- label: 'Schema Defenition',
371
+ label: 'Schema Definition',
372
372
  key: 'schemaDefinition',
373
373
  editor: 'ace',
374
374
  as: 'javascript',
@@ -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',
@@ -95,7 +95,7 @@ export default class Multivalue extends Field {
95
95
  if (this.refs.input && this.refs.input.length) {
96
96
  this.refs.input.forEach((input) => {
97
97
  if (input.mask) {
98
- input.mask.destroy();
98
+ input.mask.destroy ? input.mask.destroy() : input.mask.remove();
99
99
  }
100
100
  if (input.widget) {
101
101
  input.widget.destroy();
@@ -105,7 +105,7 @@ export default class Multivalue extends Field {
105
105
  if (this.refs.mask && this.refs.mask.length) {
106
106
  this.refs.mask.forEach((input) => {
107
107
  if (input.mask) {
108
- input.mask.destroy();
108
+ input.mask.destroy ? input.mask.destroy() : input.mask.remove();
109
109
  }
110
110
  });
111
111
  }
@@ -507,8 +507,8 @@ export default class NestedComponent extends Field {
507
507
  flags = flags || {};
508
508
  row = row || this.data;
509
509
  components = components && _.isArray(components) ? components : this.getComponents();
510
- super.checkData(data, flags, row);
511
- components.forEach((comp) => comp.checkData(data, flags, row));
510
+ super.checkData(data, { ...flags }, row);
511
+ components.forEach((comp) => comp.checkData(data, { ...flags }, row));
512
512
  }
513
513
  checkConditions(data, flags, row) {
514
514
  // check conditions of parent component first, because it may influence on visibility of it's children
@@ -12,7 +12,7 @@ export default {
12
12
  providerOptions: {
13
13
  params: {
14
14
  autocompleteOptions: {},
15
- key: 'AIzaSyBNL2e4MnmyPj9zN7SVAe428nCSLP1X144',
15
+ key: '',
16
16
  },
17
17
  },
18
18
  input: true,