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

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) 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 +853 -132
  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 +827 -136
  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 +4 -4
  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 +9 -6
  22. package/lib/cjs/components/_classes/component/Component.js +21 -7
  23. package/lib/cjs/components/_classes/component/fixtures/comp5.js +2 -2
  24. package/lib/cjs/components/_classes/list/ListComponent.js +5 -12
  25. package/lib/cjs/components/_classes/nested/NestedComponent.js +17 -9
  26. package/lib/cjs/components/columns/editForm/Columns.edit.display.js +1 -1
  27. package/lib/cjs/components/editgrid/EditGrid.js +11 -4
  28. package/lib/cjs/components/form/Form.js +3 -1
  29. package/lib/cjs/components/html/HTML.js +2 -2
  30. package/lib/cjs/components/html/fixtures/comp3.js +31 -0
  31. package/lib/cjs/components/html/fixtures/index.js +3 -1
  32. package/lib/cjs/components/radio/Radio.js +2 -1
  33. package/lib/cjs/components/radio/fixtures/comp10.js +23 -0
  34. package/lib/cjs/components/radio/fixtures/index.js +3 -1
  35. package/lib/cjs/components/recaptcha/ReCaptcha.js +3 -0
  36. package/lib/cjs/components/select/Select.js +84 -9
  37. package/lib/cjs/components/survey/Survey.js +10 -0
  38. package/lib/cjs/utils/conditionOperators/IsEqualTo.js +19 -1
  39. package/lib/cjs/utils/conditionOperators/IsNotEqualTo.js +4 -5
  40. package/lib/cjs/utils/utils.js +40 -2
  41. package/lib/mjs/Element.js +2 -2
  42. package/lib/mjs/Embed.js +9 -6
  43. package/lib/mjs/components/_classes/component/Component.js +24 -8
  44. package/lib/mjs/components/_classes/component/fixtures/comp5.js +2 -2
  45. package/lib/mjs/components/_classes/list/ListComponent.js +5 -12
  46. package/lib/mjs/components/_classes/nested/NestedComponent.js +17 -9
  47. package/lib/mjs/components/columns/editForm/Columns.edit.display.js +1 -1
  48. package/lib/mjs/components/editgrid/EditGrid.js +11 -4
  49. package/lib/mjs/components/form/Form.js +3 -1
  50. package/lib/mjs/components/html/HTML.js +2 -2
  51. package/lib/mjs/components/html/fixtures/comp3.js +29 -0
  52. package/lib/mjs/components/html/fixtures/index.js +2 -1
  53. package/lib/mjs/components/radio/Radio.js +2 -1
  54. package/lib/mjs/components/radio/fixtures/comp10.js +21 -0
  55. package/lib/mjs/components/radio/fixtures/index.js +2 -1
  56. package/lib/mjs/components/recaptcha/ReCaptcha.js +3 -0
  57. package/lib/mjs/components/select/Select.js +83 -10
  58. package/lib/mjs/components/survey/Survey.js +10 -0
  59. package/lib/mjs/utils/conditionOperators/IsEqualTo.js +18 -1
  60. package/lib/mjs/utils/conditionOperators/IsNotEqualTo.js +4 -5
  61. package/lib/mjs/utils/utils.js +35 -0
  62. package/package.json +2 -2
  63. 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
@@ -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
- if (Formio.config.includeLibs && (typeof wrapper.attachShadow === 'function') && !Formio.config.premium) {
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(wrapper, Formio.config.embedCSS || `${Formio.cdn.js}/formio.embed.css`);
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(wrapper, Formio.formioScript(Formio.config.script || `${Formio.cdn.js}/${renderer}.js`, builder), 'Formio', builder ? 'isBuilder' : 'isRenderer');
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(wrapper, Formio.config.libs[Formio.config.template], Formio.config.template);
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(wrapper, lib, name);
297
+ await Formio.addLibrary(libWrapper, lib, name);
295
298
  }
296
299
  }
297
- await Formio.addStyles(wrapper, Formio.formioScript(Formio.config.style || `${Formio.cdn.js}/${renderer}.css`, builder));
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
  }
@@ -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) {