@formio/js 5.0.0-rc.36 → 5.0.0-rc.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/fonts/bootstrap-icons.woff +0 -0
  2. package/dist/fonts/bootstrap-icons.woff2 +0 -0
  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.js +854 -133
  7. package/dist/formio.form.min.js +1 -1
  8. package/dist/formio.form.min.js.LICENSE.txt +5 -3
  9. package/dist/formio.full.css +4 -4
  10. package/dist/formio.full.js +828 -137
  11. package/dist/formio.full.min.css +3 -3
  12. package/dist/formio.full.min.js +1 -1
  13. package/dist/formio.full.min.js.LICENSE.txt +5 -3
  14. package/dist/formio.js +5 -5
  15. package/dist/formio.min.js +1 -1
  16. package/dist/formio.min.js.LICENSE.txt +1 -1
  17. package/dist/formio.utils.js +25 -14
  18. package/dist/formio.utils.min.js +1 -1
  19. package/dist/formio.utils.min.js.LICENSE.txt +5 -3
  20. package/lib/cjs/Element.js +2 -2
  21. package/lib/cjs/Embed.js +19 -14
  22. package/lib/cjs/Formio.js +3 -0
  23. package/lib/cjs/components/_classes/component/Component.js +21 -7
  24. package/lib/cjs/components/_classes/component/fixtures/comp5.js +2 -2
  25. package/lib/cjs/components/_classes/list/ListComponent.js +5 -12
  26. package/lib/cjs/components/_classes/nested/NestedComponent.js +17 -9
  27. package/lib/cjs/components/columns/editForm/Columns.edit.display.js +1 -1
  28. package/lib/cjs/components/editgrid/EditGrid.js +11 -4
  29. package/lib/cjs/components/form/Form.js +3 -1
  30. package/lib/cjs/components/html/HTML.js +2 -2
  31. package/lib/cjs/components/html/fixtures/comp3.js +31 -0
  32. package/lib/cjs/components/html/fixtures/index.js +3 -1
  33. package/lib/cjs/components/radio/Radio.js +2 -1
  34. package/lib/cjs/components/radio/fixtures/comp10.js +23 -0
  35. package/lib/cjs/components/radio/fixtures/index.js +3 -1
  36. package/lib/cjs/components/recaptcha/ReCaptcha.js +3 -0
  37. package/lib/cjs/components/select/Select.js +84 -9
  38. package/lib/cjs/components/survey/Survey.js +10 -0
  39. package/lib/cjs/utils/conditionOperators/IsEqualTo.js +19 -1
  40. package/lib/cjs/utils/conditionOperators/IsNotEqualTo.js +4 -5
  41. package/lib/cjs/utils/utils.js +40 -2
  42. package/lib/mjs/Element.js +2 -2
  43. package/lib/mjs/Embed.js +17 -14
  44. package/lib/mjs/Formio.js +3 -0
  45. package/lib/mjs/components/_classes/component/Component.js +24 -8
  46. package/lib/mjs/components/_classes/component/fixtures/comp5.js +2 -2
  47. package/lib/mjs/components/_classes/list/ListComponent.js +5 -12
  48. package/lib/mjs/components/_classes/nested/NestedComponent.js +17 -9
  49. package/lib/mjs/components/columns/editForm/Columns.edit.display.js +1 -1
  50. package/lib/mjs/components/editgrid/EditGrid.js +11 -4
  51. package/lib/mjs/components/form/Form.js +3 -1
  52. package/lib/mjs/components/html/HTML.js +2 -2
  53. package/lib/mjs/components/html/fixtures/comp3.js +29 -0
  54. package/lib/mjs/components/html/fixtures/index.js +2 -1
  55. package/lib/mjs/components/radio/Radio.js +2 -1
  56. package/lib/mjs/components/radio/fixtures/comp10.js +21 -0
  57. package/lib/mjs/components/radio/fixtures/index.js +2 -1
  58. package/lib/mjs/components/recaptcha/ReCaptcha.js +3 -0
  59. package/lib/mjs/components/select/Select.js +83 -10
  60. package/lib/mjs/components/survey/Survey.js +10 -0
  61. package/lib/mjs/utils/conditionOperators/IsEqualTo.js +18 -1
  62. package/lib/mjs/utils/conditionOperators/IsNotEqualTo.js +4 -5
  63. package/lib/mjs/utils/utils.js +35 -0
  64. package/package.json +2 -2
  65. package/types/formio.d.ts +4 -0
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const ConditionOperator_1 = __importDefault(require("./ConditionOperator"));
7
7
  const lodash_1 = __importDefault(require("lodash"));
8
+ const utils_1 = require("../utils");
8
9
  class IsEqualTo extends ConditionOperator_1.default {
9
10
  static get operatorKey() {
10
11
  return 'isEqual';
@@ -12,7 +13,8 @@ class IsEqualTo extends ConditionOperator_1.default {
12
13
  static get displayedName() {
13
14
  return 'Is Equal To';
14
15
  }
15
- execute({ value, comparedValue }) {
16
+ execute({ value, comparedValue, instance, conditionComponentPath }) {
17
+ var _a;
16
18
  if (value && comparedValue && typeof value !== typeof comparedValue && lodash_1.default.isString(comparedValue)) {
17
19
  try {
18
20
  comparedValue = JSON.parse(comparedValue);
@@ -20,6 +22,22 @@ class IsEqualTo extends ConditionOperator_1.default {
20
22
  // eslint-disable-next-line no-empty
21
23
  catch (e) { }
22
24
  }
25
+ if (instance && instance.root) {
26
+ const conditionTriggerComponent = instance.root.getComponent(conditionComponentPath);
27
+ if (conditionTriggerComponent
28
+ && (0, utils_1.isSelectResourceWithObjectValue)(conditionTriggerComponent.component)
29
+ && ((_a = conditionTriggerComponent.component) === null || _a === void 0 ? void 0 : _a.template)) {
30
+ if (!value || !lodash_1.default.isPlainObject(value)) {
31
+ return false;
32
+ }
33
+ const { template, valueProperty } = conditionTriggerComponent.component;
34
+ if (valueProperty === 'data') {
35
+ value = { data: value };
36
+ comparedValue = { data: comparedValue };
37
+ }
38
+ return lodash_1.default.every((0, utils_1.getItemTemplateKeys)(template) || [], k => lodash_1.default.isEqual(lodash_1.default.get(value, k), lodash_1.default.get(comparedValue, k)));
39
+ }
40
+ }
23
41
  //special check for select boxes
24
42
  if (lodash_1.default.isObject(value) && comparedValue && lodash_1.default.isString(comparedValue)) {
25
43
  return value[comparedValue];
@@ -3,17 +3,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const ConditionOperator_1 = __importDefault(require("./ConditionOperator"));
7
- const lodash_1 = __importDefault(require("lodash"));
8
- class IsNotEqualTo extends ConditionOperator_1.default {
6
+ const IsEqualTo_1 = __importDefault(require("./IsEqualTo"));
7
+ class IsNotEqualTo extends IsEqualTo_1.default {
9
8
  static get operatorKey() {
10
9
  return 'isNotEqual';
11
10
  }
12
11
  static get displayedName() {
13
12
  return 'Is Not Equal To';
14
13
  }
15
- execute({ value, comparedValue }) {
16
- return !lodash_1.default.isEqual(value, comparedValue);
14
+ execute(options) {
15
+ return !super.execute(options);
17
16
  }
18
17
  }
19
18
  exports.default = IsNotEqualTo;
@@ -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.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.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;
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;
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,6 +447,22 @@ 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;
450
466
  /**
451
467
  * Make HTML element from string
452
468
  * @param str
@@ -1509,3 +1525,25 @@ const interpolateErrors = (component, errors, interpolateFn) => {
1509
1525
  });
1510
1526
  };
1511
1527
  exports.interpolateErrors = interpolateErrors;
1528
+ function getItemTemplateKeys(template) {
1529
+ const templateKeys = [];
1530
+ if (!template) {
1531
+ return templateKeys;
1532
+ }
1533
+ const keys = template.match(/({{\s*(.*?)\s*}})/g);
1534
+ if (keys) {
1535
+ keys.forEach((key) => {
1536
+ const propKey = key.match(/{{\s*item\.(.*?)\s*}}/);
1537
+ if (propKey && propKey.length > 1) {
1538
+ templateKeys.push(propKey[1]);
1539
+ }
1540
+ });
1541
+ }
1542
+ return templateKeys;
1543
+ }
1544
+ exports.getItemTemplateKeys = getItemTemplateKeys;
1545
+ function isSelectResourceWithObjectValue(comp = {}) {
1546
+ const { reference, dataSrc, valueProperty } = comp;
1547
+ return reference || (dataSrc === 'resource' && (!valueProperty || valueProperty === 'data'));
1548
+ }
1549
+ exports.isSelectResourceWithObjectValue = isSelectResourceWithObjectValue;
@@ -179,7 +179,7 @@ export default class Element {
179
179
  * @param persistent
180
180
  * If this listener should persist beyond "destroy" commands.
181
181
  */
182
- addEventListener(obj, type, func, persistent) {
182
+ addEventListener(obj, type, func, persistent, capture) {
183
183
  if (!obj) {
184
184
  return;
185
185
  }
@@ -187,7 +187,7 @@ export default class Element {
187
187
  this.eventHandlers.push({ id: this.id, obj, type, func });
188
188
  }
189
189
  if ('addEventListener' in obj) {
190
- obj.addEventListener(type, func, false);
190
+ obj.addEventListener(type, func, !!capture);
191
191
  }
192
192
  else if ('attachEvent' in obj) {
193
193
  obj.attachEvent(`on${type}`, func);
package/lib/mjs/Embed.js CHANGED
@@ -201,6 +201,22 @@ class Formio {
201
201
  }
202
202
  }
203
203
  }
204
+ static async addLoader(wrapper) {
205
+ wrapper.appendChild(Formio.createElement('div', {
206
+ 'class': 'formio-loader'
207
+ }, [{
208
+ tag: 'div',
209
+ attrs: {
210
+ class: 'loader-wrapper'
211
+ },
212
+ children: [{
213
+ tag: 'div',
214
+ attrs: {
215
+ class: 'loader text-center'
216
+ }
217
+ }]
218
+ }]));
219
+ }
204
220
  // eslint-disable-next-line max-statements
205
221
  static async init(element, options = {}, builder = false) {
206
222
  Formio.cdn = new CDN(Formio.config.cdn, Formio.config.cdnUrls || {});
@@ -244,20 +260,7 @@ class Formio {
244
260
  // Load the renderer styles.
245
261
  await Formio.addStyles(wrapper, Formio.config.embedCSS || `${Formio.cdn.js}/formio.embed.css`);
246
262
  // Add a loader.
247
- wrapper.appendChild(Formio.createElement('div', {
248
- 'class': 'formio-loader'
249
- }, [{
250
- tag: 'div',
251
- attrs: {
252
- class: 'loader-wrapper'
253
- },
254
- children: [{
255
- tag: 'div',
256
- attrs: {
257
- class: 'loader text-center'
258
- }
259
- }]
260
- }]));
263
+ Formio.addLoader(wrapper);
261
264
  const formioSrc = Formio.config.full ? 'formio.full' : 'formio.form';
262
265
  const renderer = Formio.config.debug ? formioSrc : `${formioSrc}.min`;
263
266
  Formio.FormioClass = await Formio.addScript(wrapper, Formio.formioScript(Formio.config.script || `${Formio.cdn.js}/${renderer}.js`, builder), 'Formio', builder ? 'isBuilder' : 'isRenderer');
package/lib/mjs/Formio.js CHANGED
@@ -104,4 +104,7 @@ FormioCore.Form = FormioEmbed.Form;
104
104
  FormioCore.FormBuilder = FormioEmbed.FormBuilder;
105
105
  FormioCore.use = FormioEmbed.use;
106
106
  FormioCore.createForm = FormioEmbed.createForm;
107
+ FormioCore.submitDone = FormioEmbed.submitDone;
108
+ FormioCore.addLibrary = FormioEmbed.addLibrary;
109
+ FormioCore.addLoader = FormioEmbed.addLoader;
107
110
  export { FormioCore as Formio };
@@ -3,7 +3,7 @@ import { conformToMask } from '@formio/vanilla-text-mask';
3
3
  import tippy from 'tippy.js';
4
4
  import _ from 'lodash';
5
5
  import isMobile from 'ismobilejs';
6
- import { processOne, processOneSync, validateProcess, validateProcessSync } from '@formio/core/process';
6
+ import { processOne, processOneSync, validateProcessInfo } from '@formio/core/process';
7
7
  import { Formio } from '../../../Formio';
8
8
  import * as FormioUtils from '../../../utils/utils';
9
9
  import { fastCloneDeep, boolValue, getComponentPath, isInsideScopingComponent, currentTimezone } from '../../../utils/utils';
@@ -819,7 +819,13 @@ export default class Component extends Element {
819
819
  renderTemplate(name, data = {}, modeOption) {
820
820
  // Need to make this fall back to form if renderMode is not found similar to how we search templates.
821
821
  const mode = modeOption || this.options.renderMode || 'form';
822
- data.component = this.component;
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
829
  data.self = this;
824
830
  data.options = this.options;
825
831
  data.readOnly = this.options.readOnly;
@@ -1030,12 +1036,12 @@ export default class Component extends Element {
1030
1036
  const tooltipText = this.interpolate(tooltipDataTitle || tooltipAttribute)
1031
1037
  .replace(/(?:\r\n|\r|\n)/g, '<br />');
1032
1038
  this.tooltips[index] = tippy(tooltip, {
1033
- allowHTML: true,
1039
+ allowHTML: false,
1034
1040
  trigger: 'mouseenter click focus',
1035
1041
  placement: 'right',
1036
1042
  zIndex: 10000,
1037
1043
  interactive: true,
1038
- content: this.t(this.sanitize(tooltipText), { _userInput: true }),
1044
+ content: this.t(tooltipText, { _userInput: true }),
1039
1045
  });
1040
1046
  }
1041
1047
  });
@@ -2574,7 +2580,7 @@ export default class Component extends Element {
2574
2580
  scope: validationScope,
2575
2581
  instance: this,
2576
2582
  processors: [
2577
- validateProcessSync
2583
+ validateProcessInfo
2578
2584
  ]
2579
2585
  });
2580
2586
  const errors = validationScope.errors;
@@ -2655,7 +2661,7 @@ export default class Component extends Element {
2655
2661
  instance: this,
2656
2662
  scope: { errors: [] },
2657
2663
  processors: [
2658
- async ? validateProcess : validateProcessSync
2664
+ validateProcessInfo
2659
2665
  ]
2660
2666
  };
2661
2667
  if (async) {
@@ -2684,7 +2690,12 @@ export default class Component extends Element {
2684
2690
  return this.validateComponent(data, row, flags).then((errors) => {
2685
2691
  allErrors.push(...errors);
2686
2692
  if (this.parent && this.parent.childErrors) {
2687
- this.parent.childErrors.push(...errors);
2693
+ if (errors.length) {
2694
+ this.parent.childErrors.push(...errors);
2695
+ }
2696
+ else {
2697
+ _.remove(this.parent.childErrors, (err) => err.component.key === this.component.key);
2698
+ }
2688
2699
  }
2689
2700
  this.showValidationErrors(errors, data, row, flags);
2690
2701
  return errors.length === 0;
@@ -2695,7 +2706,12 @@ export default class Component extends Element {
2695
2706
  this.showValidationErrors(errors, data, row, flags);
2696
2707
  allErrors.push(...errors);
2697
2708
  if (this.parent && this.parent.childErrors) {
2698
- this.parent.childErrors.push(...errors);
2709
+ if (errors.length) {
2710
+ this.parent.childErrors.push(...errors);
2711
+ }
2712
+ else {
2713
+ _.remove(this.parent.childErrors, (err) => err.component.key === this.component.key);
2714
+ }
2699
2715
  }
2700
2716
  return errors.length === 0;
2701
2717
  }
@@ -4,8 +4,8 @@ export default {
4
4
  components: [
5
5
  {
6
6
  label: 'Text Field',
7
- description: "<img <img src='https://somesite' onerror='var _ee = 2' >",
8
- tooltip: "<img src='https://somesite' onerror='var _ee = 1 >",
7
+ description: "<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',
@@ -1,6 +1,7 @@
1
1
  import Field from '../field/Field';
2
2
  import { Formio } from '../../../Formio';
3
3
  import _ from 'lodash';
4
+ import { getItemTemplateKeys } from '../../../utils/utils';
4
5
  export default class ListComponent extends Field {
5
6
  static schema(...extend) {
6
7
  return Field.schema({
@@ -43,18 +44,10 @@ export default class ListComponent extends Field {
43
44
  return true;
44
45
  }
45
46
  getTemplateKeys() {
46
- this.templateKeys = [];
47
- if (this.options.readOnly && this.component.template) {
48
- const keys = this.component.template.match(/({{\s*(.*?)\s*}})/g);
49
- if (keys) {
50
- keys.forEach((key) => {
51
- const propKey = key.match(/{{\s*item\.(.*?)\s*}}/);
52
- if (propKey && propKey.length > 1) {
53
- this.templateKeys.push(propKey[1]);
54
- }
55
- });
56
- }
57
- }
47
+ const template = this.component.template;
48
+ this.templateKeys = this.options.readOnly && template
49
+ ? getItemTemplateKeys(template)
50
+ : [];
58
51
  }
59
52
  get requestHeaders() {
60
53
  // Create the headers object.
@@ -582,6 +582,16 @@ export default class NestedComponent extends Field {
582
582
  components = components || this.component.components;
583
583
  data = data || this.rootValue;
584
584
  const { async, dirty, process } = flags;
585
+ const validationProcessorProcess = (context) => this.validationProcessor(context, flags);
586
+ const checkModalProcessorProcess = ({ instance, component, components }) => {
587
+ // If we just validated the last component, and there are errors from our parent, then we need to show a model of those errors.
588
+ if (instance &&
589
+ instance.parent &&
590
+ (component === components[components.length - 1]) &&
591
+ instance.parent.componentModal) {
592
+ instance.parent.checkModal(instance.parent.childErrors, dirty);
593
+ }
594
+ };
585
595
  const processorContext = {
586
596
  process: process || 'unknown',
587
597
  components,
@@ -589,15 +599,13 @@ export default class NestedComponent extends Field {
589
599
  data: data,
590
600
  scope: { errors: [] },
591
601
  processors: [
592
- (context) => this.validationProcessor(context, flags),
593
- ({ instance, component, components }) => {
594
- // If we just validated the last component, and there are errors from our parent, then we need to show a model of those errors.
595
- if (instance &&
596
- instance.parent &&
597
- (component === components[components.length - 1]) &&
598
- instance.parent.componentModal) {
599
- instance.parent.checkModal(instance.parent.childErrors, dirty);
600
- }
602
+ {
603
+ process: validationProcessorProcess,
604
+ processSync: validationProcessorProcess
605
+ },
606
+ {
607
+ process: checkModalProcessorProcess,
608
+ processSync: checkModalProcessorProcess
601
609
  }
602
610
  ]
603
611
  };
@@ -56,7 +56,7 @@ export default [
56
56
  key: 'columns',
57
57
  label: 'Column Properties',
58
58
  addAnother: 'Add Column',
59
- tooltip: 'The width, offset, push, and pull settings for each column.',
59
+ tooltip: 'The size and width settings for each column. One row is equal to 12. (e.g., a row with two columns spanning the entire page should be 6 and 6)',
60
60
  reorder: true,
61
61
  components: [
62
62
  {
@@ -467,7 +467,7 @@ export default class EditGridComponent extends NestedArrayComponent {
467
467
  ].forEach(({ className, event, action, }) => {
468
468
  const elements = row.getElementsByClassName(className);
469
469
  Array.prototype.forEach.call(elements, (element) => {
470
- if (this.options.readOnly && _.intersection(element.classList, ['editRow', 'removeRow']).length) {
470
+ if (this.options.pdf && _.intersection(element.classList, ['editRow', 'removeRow']).length) {
471
471
  element.style.display = 'none';
472
472
  }
473
473
  else {
@@ -599,6 +599,9 @@ export default class EditGridComponent extends NestedArrayComponent {
599
599
  const dataObj = {};
600
600
  const rowIndex = this.editRows.length;
601
601
  const editRow = this.createRow(dataObj, rowIndex);
602
+ if (editRow.state === EditRowState.New) {
603
+ this.emptyRow = fastCloneDeep(editRow.data);
604
+ }
602
605
  if (this.inlineEditMode) {
603
606
  this.triggerChange();
604
607
  }
@@ -669,7 +672,7 @@ export default class EditGridComponent extends NestedArrayComponent {
669
672
  }
670
673
  showDialog(rowIndex) {
671
674
  const editRow = this.editRows[rowIndex];
672
- if (_.isEqual(editRow.backup, editRow.data)) {
675
+ if (editRow.state === EditRowState.New ? _.isEqual(this.emptyRow, editRow.data) : _.isEqual(editRow.backup, editRow.data)) {
673
676
  return Promise.resolve();
674
677
  }
675
678
  const wrapper = this.ce('div', { ref: 'confirmationDialog' });
@@ -969,6 +972,7 @@ export default class EditGridComponent extends NestedArrayComponent {
969
972
  const editGridValue = _.get(rootValue, this.path, []);
970
973
  editGridValue[editRow.rowIndex] = editRow.data;
971
974
  _.set(rootValue, this.path, editGridValue);
975
+ const validationProcessorProcess = (context) => this.validationProcessor(context, { dirty, silentCheck });
972
976
  editRow.errors = processSync({
973
977
  components: fastCloneDeep(this.component.components).map((component) => {
974
978
  component.parentPath = `${this.path}[${editRow.rowIndex}]`;
@@ -980,7 +984,10 @@ export default class EditGridComponent extends NestedArrayComponent {
980
984
  instances: this.componentsMap,
981
985
  scope: { errors: [] },
982
986
  processors: [
983
- (context) => this.validationProcessor(context, { dirty, silentCheck })
987
+ {
988
+ process: validationProcessorProcess,
989
+ processSync: validationProcessorProcess
990
+ }
984
991
  ]
985
992
  }).errors;
986
993
  }
@@ -1070,7 +1077,7 @@ export default class EditGridComponent extends NestedArrayComponent {
1070
1077
  this.setCustomValidity(this.t(this.errorMessage('unsavedRowsError')), dirty);
1071
1078
  return false;
1072
1079
  }
1073
- const message = this.invalid || this.invalidMessage(data, dirty);
1080
+ const message = this.invalid || this.invalidMessage(data, dirty, false, row);
1074
1081
  if (allRowErrors.length && this.root?.submitted && !message) {
1075
1082
  this._errors = this.setCustomValidity(message, dirty);
1076
1083
  errors.push(...this._errors);
@@ -600,7 +600,9 @@ export default class FormComponent extends Component {
600
600
  const formId = submission.form || this.formObj.form || this.component.form;
601
601
  const submissionUrl = `${this.subForm.formio.formsUrl}/${formId}/submission/${submission._id}`;
602
602
  this.subForm.setUrl(submissionUrl, this.options);
603
- this.subForm.loadSubmission();
603
+ this.subForm.loadSubmission().catch((err) => {
604
+ console.error(`Unable to load subform submission ${submission._id}:`, err);
605
+ });
604
606
  }
605
607
  else {
606
608
  this.subForm.setValue(submission, flags);
@@ -38,13 +38,13 @@ export default class HTMLComponent extends Component {
38
38
  return ` ${this.component.content} `;
39
39
  }
40
40
  const submission = _.get(this.root, 'submission', {});
41
- const content = this.component.content ? this.interpolate(this.component.content, {
41
+ const content = this.component.content ? this.interpolate(this.sanitize(this.component.content, this.shouldSanitizeValue), {
42
42
  metadata: submission.metadata || {},
43
43
  submission: submission,
44
44
  data: this.rootValue,
45
45
  row: this.data
46
46
  }) : '';
47
- return this.sanitize(content, this.shouldSanitizeValue);
47
+ return content;
48
48
  }
49
49
  get singleTags() {
50
50
  return ['br', 'img', 'hr'];
@@ -0,0 +1,29 @@
1
+ export default {
2
+ type: 'form',
3
+ display: 'form',
4
+ components: [
5
+ {
6
+ label: 'HTML',
7
+ attrs: [
8
+ {
9
+ attr: '',
10
+ value: '',
11
+ },
12
+ ],
13
+ content: '<img src=1 onerror=alert("htmlContent")>',
14
+ refreshOnChange: false,
15
+ key: 'html',
16
+ type: 'htmlelement',
17
+ input: false,
18
+ tableView: false,
19
+ },
20
+ {
21
+ type: 'button',
22
+ label: 'Submit',
23
+ key: 'submit',
24
+ disableOnInvalid: true,
25
+ input: true,
26
+ tableView: false,
27
+ },
28
+ ],
29
+ };
@@ -1,3 +1,4 @@
1
1
  import comp1 from './comp1';
2
2
  import comp2 from './comp2';
3
- export { comp1, comp2 };
3
+ import comp3 from './comp3';
4
+ export { comp1, comp2, comp3 };
@@ -349,7 +349,8 @@ export default class RadioComponent extends ListComponent {
349
349
  if (value === this.emptyValue) {
350
350
  return value;
351
351
  }
352
- if (!isNaN(parseFloat(value)) && isFinite(value)) {
352
+ const isEquivalent = _.toString(value) === Number(value).toString();
353
+ if (!isNaN(parseFloat(value)) && isFinite(value) && isEquivalent) {
353
354
  value = +value;
354
355
  }
355
356
  if (value === 'true') {
@@ -0,0 +1,21 @@
1
+ export default {
2
+ 'label': 'Radio',
3
+ 'optionsLabelPosition': 'right',
4
+ 'inline': false,
5
+ 'tableView': false,
6
+ 'values': [
7
+ {
8
+ 'label': '01',
9
+ 'value': '01',
10
+ 'shortcut': ''
11
+ },
12
+ {
13
+ 'label': '1',
14
+ 'value': '1',
15
+ 'shortcut': ''
16
+ }
17
+ ],
18
+ 'key': 'radio',
19
+ 'type': 'radio',
20
+ 'input': true
21
+ };
@@ -7,4 +7,5 @@ import comp6 from './comp6';
7
7
  import comp7 from './comp7';
8
8
  import comp8 from './comp8';
9
9
  import comp9 from './comp9';
10
- export { comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9 };
10
+ import comp10 from './comp10';
11
+ export { comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10 };
@@ -52,6 +52,9 @@ export default class ReCaptchaComponent extends Component {
52
52
  createLabel() {
53
53
  return;
54
54
  }
55
+ get skipInEmail() {
56
+ return true;
57
+ }
55
58
  verify(actionName) {
56
59
  const siteKey = _get(this.root.form, 'settings.recaptcha.siteKey');
57
60
  if (!siteKey) {