@formio/js 5.1.0-dev.5976.b0f317d → 5.1.0-dev.5976.f61da27

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 (95) hide show
  1. package/dist/formio.builder.css +11 -11
  2. package/dist/formio.builder.min.css +1 -1
  3. package/dist/formio.form.css +11 -11
  4. package/dist/formio.form.js +30 -30
  5. package/dist/formio.form.min.css +1 -1
  6. package/dist/formio.form.min.js +1 -1
  7. package/dist/formio.form.min.js.LICENSE.txt +1 -1
  8. package/dist/formio.full.css +11 -11
  9. package/dist/formio.full.js +36 -36
  10. package/dist/formio.full.min.css +1 -1
  11. package/dist/formio.full.min.js +1 -1
  12. package/dist/formio.full.min.js.LICENSE.txt +1 -1
  13. package/dist/formio.js +3 -3
  14. package/dist/formio.min.js +1 -1
  15. package/dist/formio.utils.js +1 -1
  16. package/dist/formio.utils.min.js +1 -1
  17. package/lib/cjs/Form.d.ts +2 -4
  18. package/lib/cjs/Form.js +3 -1
  19. package/lib/cjs/PDFBuilder.js +2 -2
  20. package/lib/cjs/Webform.d.ts +5 -2
  21. package/lib/cjs/Webform.js +31 -16
  22. package/lib/cjs/WebformBuilder.d.ts +1 -0
  23. package/lib/cjs/WebformBuilder.js +14 -3
  24. package/lib/cjs/Wizard.js +2 -1
  25. package/lib/cjs/WizardBuilder.js +14 -1
  26. package/lib/cjs/components/Components.d.ts +3 -0
  27. package/lib/cjs/components/_classes/component/Component.js +12 -2
  28. package/lib/cjs/components/_classes/component/editForm/Component.edit.conditional.js +1 -1
  29. package/lib/cjs/components/_classes/component/editForm/Component.edit.data.d.ts +37 -0
  30. package/lib/cjs/components/_classes/component/editForm/Component.edit.data.js +13 -2
  31. package/lib/cjs/components/_classes/component/editForm/utils.d.ts +1 -0
  32. package/lib/cjs/components/_classes/component/editForm/utils.js +3 -0
  33. package/lib/cjs/components/_classes/nesteddata/NestedDataComponent.d.ts +1 -0
  34. package/lib/cjs/components/_classes/nesteddata/NestedDataComponent.js +3 -0
  35. package/lib/cjs/components/datetime/DateTime.d.ts +1 -1
  36. package/lib/cjs/components/datetime/DateTime.js +5 -5
  37. package/lib/cjs/components/day/Day.js +7 -5
  38. package/lib/cjs/components/file/File.js +2 -1
  39. package/lib/cjs/components/form/Form.d.ts +4 -2
  40. package/lib/cjs/components/form/Form.js +25 -10
  41. package/lib/cjs/components/form/editForm/Form.edit.data.js +1 -1
  42. package/lib/cjs/components/form/editForm/Form.edit.form.js +2 -2
  43. package/lib/cjs/components/select/Select.js +1 -1
  44. package/lib/cjs/components/select/editForm/Select.edit.data.js +2 -2
  45. package/lib/cjs/components/tags/Tags.d.ts +1 -1
  46. package/lib/cjs/components/tags/Tags.js +1 -1
  47. package/lib/cjs/providers/storage/googleDrive.js +3 -2
  48. package/lib/cjs/providers/storage/s3.js +3 -3
  49. package/lib/cjs/providers/storage/xhr.d.ts +1 -0
  50. package/lib/cjs/providers/storage/xhr.js +6 -1
  51. package/lib/cjs/utils/ChoicesWrapper.d.ts +1 -1
  52. package/lib/cjs/utils/ChoicesWrapper.js +1 -1
  53. package/lib/cjs/utils/utils.d.ts +2 -1
  54. package/lib/cjs/utils/utils.js +3 -2
  55. package/lib/cjs/widgets/CalendarWidget.js +0 -14
  56. package/lib/mjs/Form.d.ts +2 -4
  57. package/lib/mjs/Form.js +4 -2
  58. package/lib/mjs/PDFBuilder.js +2 -2
  59. package/lib/mjs/Webform.d.ts +5 -2
  60. package/lib/mjs/Webform.js +31 -16
  61. package/lib/mjs/WebformBuilder.d.ts +1 -0
  62. package/lib/mjs/WebformBuilder.js +13 -2
  63. package/lib/mjs/Wizard.js +2 -1
  64. package/lib/mjs/WizardBuilder.js +14 -1
  65. package/lib/mjs/components/Components.d.ts +3 -0
  66. package/lib/mjs/components/_classes/component/Component.js +12 -2
  67. package/lib/mjs/components/_classes/component/editForm/Component.edit.conditional.js +1 -1
  68. package/lib/mjs/components/_classes/component/editForm/Component.edit.data.d.ts +37 -0
  69. package/lib/mjs/components/_classes/component/editForm/Component.edit.data.js +13 -2
  70. package/lib/mjs/components/_classes/component/editForm/utils.d.ts +1 -0
  71. package/lib/mjs/components/_classes/component/editForm/utils.js +3 -0
  72. package/lib/mjs/components/_classes/nesteddata/NestedDataComponent.d.ts +1 -0
  73. package/lib/mjs/components/_classes/nesteddata/NestedDataComponent.js +3 -0
  74. package/lib/mjs/components/datetime/DateTime.d.ts +1 -1
  75. package/lib/mjs/components/datetime/DateTime.js +5 -5
  76. package/lib/mjs/components/day/Day.js +7 -5
  77. package/lib/mjs/components/file/File.js +2 -1
  78. package/lib/mjs/components/form/Form.d.ts +4 -2
  79. package/lib/mjs/components/form/Form.js +25 -10
  80. package/lib/mjs/components/form/editForm/Form.edit.data.js +1 -1
  81. package/lib/mjs/components/form/editForm/Form.edit.form.js +2 -2
  82. package/lib/mjs/components/select/Select.js +1 -0
  83. package/lib/mjs/components/select/editForm/Select.edit.data.js +2 -2
  84. package/lib/mjs/components/tags/Tags.d.ts +1 -1
  85. package/lib/mjs/components/tags/Tags.js +1 -1
  86. package/lib/mjs/providers/storage/googleDrive.js +3 -2
  87. package/lib/mjs/providers/storage/s3.js +3 -3
  88. package/lib/mjs/providers/storage/xhr.d.ts +1 -0
  89. package/lib/mjs/providers/storage/xhr.js +6 -1
  90. package/lib/mjs/utils/ChoicesWrapper.d.ts +1 -1
  91. package/lib/mjs/utils/ChoicesWrapper.js +1 -1
  92. package/lib/mjs/utils/utils.d.ts +2 -1
  93. package/lib/mjs/utils/utils.js +3 -2
  94. package/lib/mjs/widgets/CalendarWidget.js +0 -14
  95. package/package.json +2 -2
@@ -380,10 +380,11 @@ class FormComponent extends Component_1.default {
380
380
  /**
381
381
  * Create a subform instance.
382
382
  * @param {boolean} [fromAttach] - This function is being called from an `attach` method.
383
+ * @param {boolean} [beforeSubmit] - This function is being called from a `beforeSubmit` method.
383
384
  * @returns {*} - The subform instance.
384
385
  */
385
- createSubForm(fromAttach) {
386
- this.subFormReady = this.loadSubForm(fromAttach).then((form) => {
386
+ createSubForm(fromAttach, beforeSubmit) {
387
+ this.subFormReady = this.loadSubForm(fromAttach, beforeSubmit).then((form) => {
387
388
  if (!form) {
388
389
  return;
389
390
  }
@@ -440,11 +441,13 @@ class FormComponent extends Component_1.default {
440
441
  /**
441
442
  * Load the subform.
442
443
  * @param {boolean} fromAttach - This function is being called from an `attach` method.
444
+ * @param {boolean} beforeSubmit - This function is being called from a `beforeSubmit` method.
443
445
  * @returns {Promise} - The promise that resolves when the subform is loaded.
444
446
  */
445
- loadSubForm(fromAttach) {
447
+ loadSubForm(fromAttach, beforeSubmit) {
446
448
  var _a, _b, _c, _d, _e;
447
- if (this.builderMode || this.conditionallyHidden || (this.isSubFormLazyLoad() && !fromAttach)) {
449
+ const loadHiddenForm = beforeSubmit && !this.component.clearOnHide;
450
+ if (this.builderMode || (this.conditionallyHidden && !loadHiddenForm) || (this.isSubFormLazyLoad() && !fromAttach)) {
448
451
  return Promise.resolve();
449
452
  }
450
453
  if (this.hasLoadedForm && !this.isRevisionChanged &&
@@ -516,7 +519,7 @@ class FormComponent extends Component_1.default {
516
519
  * @returns {*|boolean} - TRUE if the subform should be submitted, FALSE if it should not.
517
520
  */
518
521
  get shouldSubmit() {
519
- return this.subFormReady && (!this.component.hasOwnProperty('reference') || this.component.reference) && !this.conditionallyHidden;
522
+ return this.subFormReady && (!this.component.hasOwnProperty('reference') || this.component.reference) && (!this.conditionallyHidden || !this.component.clearOnHide);
520
523
  }
521
524
  /**
522
525
  * Returns the data for the subform.
@@ -587,11 +590,23 @@ class FormComponent extends Component_1.default {
587
590
  this.dataValue = submission;
588
591
  return Promise.resolve(this.dataValue);
589
592
  }
590
- return this.submitSubForm(false)
591
- .then(() => {
592
- return this.dataValue;
593
- })
594
- .then(() => super.beforeSubmit());
593
+ // we need to load a hidden form (when clearOnHide is disabled) in order to get and submit (if needed) its data
594
+ const loadHiddenForm = !this.subForm && !this.component.clearOnHide;
595
+ if ((this.isSubFormLazyLoad() || loadHiddenForm) && !this.subFormLoading) {
596
+ return this.createSubForm(true, true)
597
+ .then(this.submitSubForm(false))
598
+ .then(() => {
599
+ return this.dataValue;
600
+ })
601
+ .then(() => super.beforeSubmit());
602
+ }
603
+ else {
604
+ return this.submitSubForm(false)
605
+ .then(() => {
606
+ return this.dataValue;
607
+ })
608
+ .then(() => super.beforeSubmit());
609
+ }
595
610
  }
596
611
  isSubFormLazyLoad() {
597
612
  var _a, _b;
@@ -11,7 +11,7 @@ exports.default = [
11
11
  {
12
12
  weight: 140,
13
13
  type: 'checkbox',
14
- label: 'Clear Value When Hidden',
14
+ label: 'Omit Value From Submission Data When Conditionally Hidden',
15
15
  key: 'clearOnHide',
16
16
  defaultValue: true,
17
17
  tooltip: 'When a field is hidden, clear the value.',
@@ -69,7 +69,7 @@ exports.default = [
69
69
  input: true,
70
70
  weight: 20,
71
71
  key: 'reference',
72
- label: 'Save as reference',
73
- tooltip: 'Using this option will save this field as a reference and link its value to the value of the origin record.'
72
+ label: 'Submit as reference',
73
+ tooltip: 'When "Submit as reference" is enabled, the form submission will be recorded against the Parent Form as well as the Child Form. When a submission recorded with "Submit as reference" is edited, the update is applied to each submission made against the Parent Form and Child Form.'
74
74
  }
75
75
  ];
@@ -770,7 +770,7 @@ class SelectComponent extends ListComponent_1.default {
770
770
  containerOuter: ['choices', 'form-group', 'formio-choices'],
771
771
  containerInner: this.transform('class', 'form-control ui fluid selection dropdown').split(' '),
772
772
  }, addItemText: false, allowHTML: true, placeholder: !!this.component.placeholder, placeholderValue: placeholderValue, noResultsText: this.t('noResultsFound'), noChoicesText: this.t('noChoices'), searchPlaceholderValue: this.t('typeToSearch'), shouldSort: false, position: (this.component.dropdown || 'auto'), searchEnabled: useSearch, searchChoices: !this.component.searchField, searchFields: lodash_1.default.get(this, 'component.searchFields', ['label']), shadowRoot: this.root ? this.root.shadowRoot : null, fuseOptions: this.component.useExactSearch
773
- ? Object.assign({ tokenize: true, matchAllTokens: true }, commonFuseOptions) : Object.assign({}, lodash_1.default.get(this, 'component.fuseOptions', {}), Object.assign({ include: 'score', threshold: lodash_1.default.get(this, 'component.selectThreshold', 0.3) }, commonFuseOptions)), valueComparer: lodash_1.default.isEqual, resetScrollPosition: false }, customOptions);
773
+ ? Object.assign({ tokenize: true, matchAllTokens: true }, commonFuseOptions) : Object.assign({}, lodash_1.default.get(this, 'component.fuseOptions', {}), Object.assign({ include: 'score', threshold: lodash_1.default.get(this, 'component.selectThreshold', 0.3) }, commonFuseOptions)), valueComparer: lodash_1.default.isEqual, resetScrollPosition: false, duplicateItemsAllowed: false }, customOptions);
774
774
  }
775
775
  /* eslint-disable max-statements */
776
776
  attach(element) {
@@ -641,8 +641,8 @@ exports.default = [
641
641
  input: true,
642
642
  weight: 25,
643
643
  key: 'reference',
644
- label: 'Save as reference',
645
- tooltip: 'Using this option will save this field as a reference and link its value to the value of the origin record.',
644
+ label: 'Submit as reference',
645
+ tooltip: 'Using this option will submit this field as a reference id and link its value to the value of the origin record.',
646
646
  conditional: {
647
647
  json: { '===': [{ var: 'data.dataSrc' }, 'resource'] },
648
648
  },
@@ -24,4 +24,4 @@ export default class TagsComponent extends Input {
24
24
  getValueAsString(value: any): any;
25
25
  }
26
26
  import Input from '../_classes/input/Input';
27
- import Choices from '@formio/choices.js';
27
+ import Choices from 'choices.js';
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const utils_1 = require("../../utils/utils");
7
7
  const Input_1 = __importDefault(require("../_classes/input/Input"));
8
- const choices_js_1 = __importDefault(require("@formio/choices.js"));
8
+ const choices_js_1 = __importDefault(require("choices.js"));
9
9
  class TagsComponent extends Input_1.default {
10
10
  static schema(...extend) {
11
11
  return Input_1.default.schema({
@@ -52,10 +52,11 @@ function googledrive(formio) {
52
52
  xhr.send(fd);
53
53
  }));
54
54
  },
55
- downloadFile(file) {
55
+ downloadFile(file, component) {
56
56
  const token = formio.getToken();
57
+ // Constructed the url with the fileId, fileName, displayImage, imageSize if applicable
57
58
  file.url =
58
- `${formio.formUrl}/storage/gdrive?fileId=${file.id}&fileName=${file.originalName}${token ? `&x-jwt-token=${token}` : ''}`;
59
+ `${formio.formUrl}/storage/gdrive?fileId=${file.id}&fileName=${file.originalName}${token ? `&x-jwt-token=${token}` : ''}${component.image ? '&displayImage=true' : ''}${component.imageSize ? `&imageSize=${component.imageSize}` : ''}`;
59
60
  return Promise.resolve(file);
60
61
  },
61
62
  deleteFile: function deleteFile(fileInfo) {
@@ -115,7 +115,7 @@ function s3(formio) {
115
115
  const { changeMessage } = multipart;
116
116
  changeMessage('Completing AWS S3 multipart upload...');
117
117
  const token = formio.getToken();
118
- const response = yield fetch(`${formio.formUrl}/storage/s3/multipart/complete`, {
118
+ const response = yield xhr_1.default.fetch(`${formio.formUrl}/storage/s3/multipart/complete`, {
119
119
  method: 'POST',
120
120
  headers: Object.assign({ 'Content-Type': 'application/json' }, (token ? { 'x-jwt-token': token } : {})),
121
121
  body: JSON.stringify({ parts, uploadId: serverResponse.uploadId, key: serverResponse.key })
@@ -134,7 +134,7 @@ function s3(formio) {
134
134
  abortMultipartUpload(serverResponse) {
135
135
  const { uploadId, key } = serverResponse;
136
136
  const token = formio.getToken();
137
- fetch(`${formio.formUrl}/storage/s3/multipart/abort`, {
137
+ xhr_1.default.fetch(`${formio.formUrl}/storage/s3/multipart/abort`, {
138
138
  method: 'POST',
139
139
  headers: Object.assign({ 'Content-Type': 'application/json' }, (token ? { 'x-jwt-token': token } : {})),
140
140
  body: JSON.stringify({ uploadId, key })
@@ -148,7 +148,7 @@ function s3(formio) {
148
148
  const start = i * partSize;
149
149
  const end = (i + 1) * partSize;
150
150
  const blob = i < urls.length ? file.slice(start, end) : file.slice(start);
151
- const promise = fetch(urls[i], {
151
+ const promise = xhr_1.default.fetch(urls[i], {
152
152
  method: 'PUT',
153
153
  headers,
154
154
  body: blob,
@@ -3,6 +3,7 @@ export default XHR;
3
3
  declare namespace XHR {
4
4
  function trim(text: any): any;
5
5
  function path(items: any): any;
6
+ function fetch(url: any, options: any): Promise<Response>;
6
7
  function upload(formio: any, type: any, xhrCallback: any, file: any, fileName: any, dir: any, progressCallback: any, groupPermissions: any, groupId: any, abortCallback: any, multipartOptions: any): Promise<any>;
7
8
  function makeXhrRequest(formio: any, xhrCallback: any, serverResponse: any, progressCallback: any, abortCallback: any): Promise<any>;
8
9
  }
@@ -14,6 +14,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.setXhrHeaders = void 0;
16
16
  const trim_1 = __importDefault(require("lodash/trim"));
17
+ const Formio_1 = require("../../Formio");
17
18
  const setXhrHeaders = (formio, xhr) => {
18
19
  const { headers } = formio.options;
19
20
  if (headers) {
@@ -36,13 +37,17 @@ const XHR = {
36
37
  path(items) {
37
38
  return items.filter(item => !!item).map(XHR.trim).join('/');
38
39
  },
40
+ fetch(url, options) {
41
+ options = Formio_1.Formio.pluginAlter('requestOptions', options, url);
42
+ return fetch(url, options);
43
+ },
39
44
  upload(formio, type, xhrCallback, file, fileName, dir, progressCallback, groupPermissions, groupId, abortCallback, multipartOptions) {
40
45
  return __awaiter(this, void 0, void 0, function* () {
41
46
  // make request to Form.io server
42
47
  const token = formio.getToken();
43
48
  let response;
44
49
  try {
45
- response = yield fetch(`${formio.formUrl}/storage/${type}`, {
50
+ response = yield XHR.fetch(`${formio.formUrl}/storage/${type}`, {
46
51
  method: 'POST',
47
52
  headers: Object.assign({ 'Accept': 'application/json', 'Content-Type': 'application/json; charset=UTF-8' }, (token ? { 'x-jwt-token': token } : {})),
48
53
  body: JSON.stringify({
@@ -14,4 +14,4 @@ declare class ChoicesWrapper extends Choices {
14
14
  showDropdown(...args: any[]): void;
15
15
  hideDropdown(...args: any[]): void;
16
16
  }
17
- import Choices from '@formio/choices.js';
17
+ import Choices from 'choices.js';
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
23
23
  return result;
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- const choices_js_1 = __importStar(require("@formio/choices.js"));
26
+ const choices_js_1 = __importStar(require("choices.js"));
27
27
  const ExtendedKeyCodeMap = Object.assign(Object.assign({}, choices_js_1.KeyCodeMap), { TAB_KEY: 9 });
28
28
  class ChoicesWrapper extends choices_js_1.default {
29
29
  constructor(...args) {
@@ -208,9 +208,10 @@ export function loadZones(url: string, timezone: string): Promise<any> | any;
208
208
  * @param {string|Date} value - The value to convert into a moment date.
209
209
  * @param {string} format - The format to convert the date to.
210
210
  * @param {string} timezone - The timezone to convert the date to.
211
+ * @param {object} options - The options object
211
212
  * @returns {Date} - The moment date object.
212
213
  */
213
- export function momentDate(value: string | Date, format: string, timezone: string): Date;
214
+ export function momentDate(value: string | Date, format: string, timezone: string, options: object): Date;
214
215
  /**
215
216
  * Format a date provided a value, format, and timezone object.
216
217
  * @param {string} timezonesUrl - The URL to load the timezone data from.
@@ -687,9 +687,10 @@ exports.loadZones = loadZones;
687
687
  * @param {string|Date} value - The value to convert into a moment date.
688
688
  * @param {string} format - The format to convert the date to.
689
689
  * @param {string} timezone - The timezone to convert the date to.
690
+ * @param {object} options - The options object
690
691
  * @returns {Date} - The moment date object.
691
692
  */
692
- function momentDate(value, format, timezone) {
693
+ function momentDate(value, format, timezone, options) {
693
694
  const momentDate = (0, moment_timezone_1.default)(value);
694
695
  if (!timezone) {
695
696
  return momentDate;
@@ -697,7 +698,7 @@ function momentDate(value, format, timezone) {
697
698
  if (timezone === 'UTC') {
698
699
  timezone = 'Etc/UTC';
699
700
  }
700
- if ((timezone !== currentTimezone() || (format && format.match(/\s(z$|z\s)/))) && moment_timezone_1.default.zonesLoaded) {
701
+ if ((timezone !== currentTimezone() || (format && format.match(/\s(z$|z\s)/))) && (moment_timezone_1.default.zonesLoaded || (options === null || options === void 0 ? void 0 : options.email))) {
701
702
  return momentDate.tz(timezone);
702
703
  }
703
704
  return momentDate;
@@ -93,8 +93,6 @@ class CalendarWidget extends InputWidget_1.default {
93
93
  this.settings.disableWeekends ? this.settings.disable.push(this.disableWeekends) : '';
94
94
  this.settings.disableWeekdays ? this.settings.disable.push(this.disableWeekdays) : '';
95
95
  this.settings.disableFunction ? this.settings.disable.push(this.disableFunction) : '';
96
- this.settings.wasDefaultValueChanged = false;
97
- this.settings.defaultValue = '';
98
96
  this.settings.manualInputValue = '';
99
97
  this.settings.isManuallyOverriddenValue = false;
100
98
  this.settings.currentValue = '';
@@ -115,10 +113,6 @@ class CalendarWidget extends InputWidget_1.default {
115
113
  this.calendar._input.value = this.settings.isManuallyOverriddenValue ? this.settings.manualInputValue : this.calendar.altInput.value;
116
114
  this.emit('update');
117
115
  }
118
- if (this.settings.wasDefaultValueChanged) {
119
- this.calendar._input.value = this.settings.defaultValue;
120
- this.settings.wasDefaultValueChanged = false;
121
- }
122
116
  if (this.calendar) {
123
117
  this.emit('blur');
124
118
  }
@@ -360,14 +354,6 @@ class CalendarWidget extends InputWidget_1.default {
360
354
  this.settings.currentValue = event.target.value;
361
355
  this.emit('update');
362
356
  }
363
- if (event.target.value === '' && this.calendar.selectedDates.length > 0) {
364
- this.settings.wasDefaultValueChanged = true;
365
- this.settings.defaultValue = event.target.value;
366
- this.calendar.clear();
367
- }
368
- else {
369
- this.settings.wasDefaultValueChanged = false;
370
- }
371
357
  });
372
358
  if (this.calendar.daysContainer) {
373
359
  this.calendar.daysContainer.addEventListener('click', () => {
package/lib/mjs/Form.d.ts CHANGED
@@ -48,7 +48,7 @@ export default class Form extends Element {
48
48
  * @property {number} [saveDraftThrottle] - The throttle for the save draft feature.
49
49
  * @property {boolean} [readOnly] - Set this form to readOnly.
50
50
  * @property {boolean} [noAlerts] - Disable the alerts dialog.
51
- * @property {{[key: string]: string}} [i18n] - The translation file for this rendering.
51
+ * @property {Record<string, Record<string, string>>} [i18n] - The translation file for this rendering.
52
52
  * @property {string} [template] - Custom logic for creation of elements.
53
53
  * @property {boolean} [noDefaults] - Exclude default values from the settings.
54
54
  * @property {any} [fileService] - The file service for this form.
@@ -117,9 +117,7 @@ export default class Form extends Element {
117
117
  /**
118
118
  * - The translation file for this rendering.
119
119
  */
120
- i18n?: {
121
- [key: string]: string;
122
- } | undefined;
120
+ i18n?: Record<string, Record<string, string>> | undefined;
123
121
  /**
124
122
  * - Custom logic for creation of elements.
125
123
  */
package/lib/mjs/Form.js CHANGED
@@ -51,7 +51,7 @@ export default class Form extends Element {
51
51
  * @property {number} [saveDraftThrottle] - The throttle for the save draft feature.
52
52
  * @property {boolean} [readOnly] - Set this form to readOnly.
53
53
  * @property {boolean} [noAlerts] - Disable the alerts dialog.
54
- * @property {{[key: string]: string}} [i18n] - The translation file for this rendering.
54
+ * @property {Record<string, Record<string, string>>} [i18n] - The translation file for this rendering.
55
55
  * @property {string} [template] - Custom logic for creation of elements.
56
56
  * @property {boolean} [noDefaults] - Exclude default values from the settings.
57
57
  * @property {any} [fileService] - The file service for this form.
@@ -350,7 +350,9 @@ export default class Form extends Element {
350
350
  this.form.display = display;
351
351
  this.instance.destroy();
352
352
  this.instance = this.create(display);
353
- return this.setForm(this.form);
353
+ return this.setForm(this.form).then(() => {
354
+ this.instance.emit('setDisplay', this.form.display);
355
+ });
354
356
  }
355
357
  empty() {
356
358
  if (this.element) {
@@ -294,7 +294,7 @@ export default class PDFBuilder extends WebformBuilder {
294
294
  height: schema.height,
295
295
  width: schema.width
296
296
  };
297
- if (!this.options.noNewEdit && !component.component.noNewEdit) {
297
+ if (!this.options.noNewEdit && !component.component.noNewEdit && this.hasEditTabs(component.type)) {
298
298
  this.editComponent(component.component, this.getParentContainer(component), isNew);
299
299
  }
300
300
  this.emit('updateComponent', component.component);
@@ -318,7 +318,7 @@ export default class PDFBuilder extends WebformBuilder {
318
318
  });
319
319
  this.webform.on('iframe-componentClick', schema => {
320
320
  const component = this.webform.getComponentById(schema.id);
321
- if (component) {
321
+ if (component && this.hasEditTabs(component.type)) {
322
322
  this.editComponent(component.component, this.getParentContainer(component));
323
323
  }
324
324
  }, true);
@@ -190,7 +190,10 @@ declare class Webform extends NestedDataComponent {
190
190
  get language(): string;
191
191
  root: this;
192
192
  localRoot: this;
193
+ beforeInit(): void;
194
+ executeFormController: any;
193
195
  get emptyValue(): null;
196
+ get shouldCallFormController(): any;
194
197
  get shadowRoot(): any;
195
198
  /**
196
199
  * Add a language for translations
@@ -360,7 +363,7 @@ declare class Webform extends NestedDataComponent {
360
363
  * @returns {Promise} - The promise that is triggered when the form is built.
361
364
  */
362
365
  init(): Promise<any>;
363
- executeFormController(): false | undefined;
366
+ _executeFormController(): void;
364
367
  build(element: any): Promise<any>;
365
368
  getClassName(): string;
366
369
  render(): string;
@@ -452,7 +455,7 @@ declare class Webform extends NestedDataComponent {
452
455
  */
453
456
  submit(before?: boolean, options?: any): Promise<any>;
454
457
  submitUrl(URL: any, headers: any): void;
455
- triggerCaptcha(): void;
458
+ triggerCaptcha(components?: null): void;
456
459
  _nosubmit: any;
457
460
  get conditions(): any;
458
461
  get variables(): any;
@@ -287,12 +287,24 @@ export default class Webform extends NestedDataComponent {
287
287
  this.localRoot = this;
288
288
  }
289
289
  /* eslint-enable max-statements */
290
+ beforeInit() {
291
+ this.executeFormController = _.once(this._executeFormController);
292
+ }
290
293
  get language() {
291
294
  return this.options.language;
292
295
  }
293
296
  get emptyValue() {
294
297
  return null;
295
298
  }
299
+ get shouldCallFormController() {
300
+ // If no controller value or
301
+ // hidden and set to clearOnHide (Don't calculate a value for a hidden field set to clear when hidden)
302
+ return (this.form &&
303
+ this.form.controller &&
304
+ !((!this.visible || this.component.hidden) &&
305
+ this.component.clearOnHide &&
306
+ !this.rootPristine));
307
+ }
296
308
  componentContext() {
297
309
  return this._data;
298
310
  }
@@ -902,19 +914,12 @@ export default class Webform extends NestedDataComponent {
902
914
  this.on('resetForm', () => this.resetValue(), true);
903
915
  this.on('deleteSubmission', () => this.deleteSubmission(), true);
904
916
  this.on('refreshData', () => this.updateValue(), true);
905
- this.executeFormController();
917
+ if (this.shouldCallFormController) {
918
+ this.executeFormController();
919
+ }
906
920
  return this.formReady;
907
921
  }
908
- executeFormController() {
909
- // If no controller value or
910
- // hidden and set to clearOnHide (Don't calculate a value for a hidden field set to clear when hidden)
911
- if (!this.form ||
912
- !this.form.controller ||
913
- ((!this.visible || this.component.hidden) &&
914
- this.component.clearOnHide &&
915
- !this.rootPristine)) {
916
- return false;
917
- }
922
+ _executeFormController() {
918
923
  this.formReady.then(() => {
919
924
  this.evaluate(this.form.controller, {
920
925
  components: this.components,
@@ -1529,18 +1534,28 @@ export default class Webform extends NestedDataComponent {
1529
1534
  return console.warn(message);
1530
1535
  }
1531
1536
  }
1532
- triggerCaptcha() {
1533
- if (!this || !this.components) {
1537
+ triggerCaptcha(components = null) {
1538
+ if (!this || !this.components || this.options.preview) {
1534
1539
  return;
1535
1540
  }
1536
1541
  const captchaComponent = [];
1537
- this.eachComponent((component) => {
1542
+ eachComponent(components || this.components, (component) => {
1538
1543
  if (/^(re)?captcha$/.test(component.type) && component.component.eventType === 'formLoad') {
1539
1544
  captchaComponent.push(component);
1540
1545
  }
1541
- });
1546
+ }, true);
1542
1547
  if (captchaComponent.length > 0) {
1543
- captchaComponent[0].verify(`${this.form.name ? this.form.name : 'form'}Load`);
1548
+ if (captchaComponent[0].component.provider === 'google' && components) {
1549
+ return;
1550
+ }
1551
+ if (this.parent) {
1552
+ this.parent.subFormReady.then(() => {
1553
+ captchaComponent[0].verify(`${this.form.name ? this.form.name : 'form'}Load`);
1554
+ });
1555
+ }
1556
+ else {
1557
+ captchaComponent[0].verify(`${this.form.name ? this.form.name : 'form'}Load`);
1558
+ }
1544
1559
  }
1545
1560
  }
1546
1561
  set nosubmit(value) {
@@ -123,6 +123,7 @@ export default class WebformBuilder extends Component {
123
123
  addBuilderGroup(name: any, group: any): void;
124
124
  updateBuilderGroup(name: any, group: any): void;
125
125
  generateKey(info: any): any;
126
+ hasEditTabs(type: any): boolean;
126
127
  }
127
128
  import Component from './components/_classes/component/Component';
128
129
  import Webform from './Webform';
@@ -115,7 +115,9 @@ export default class WebformBuilder extends Component {
115
115
  html,
116
116
  disableBuilderActions: self?.component?.disableBuilderActions,
117
117
  childComponent: component,
118
- design: self?.options?.design
118
+ design: self?.options?.design,
119
+ editJson: self?.options?.editJson,
120
+ editComponent: this.hasEditTabs(component.type)
119
121
  });
120
122
  };
121
123
  this.options.hooks.renderComponents = (html, { components, self }) => {
@@ -840,7 +842,11 @@ export default class WebformBuilder extends Component {
840
842
  parent.addChildComponent(info, element, target, source, sibling);
841
843
  }
842
844
  const componentInDataGrid = parent.type === 'datagrid';
843
- if (isNew && !this.options.noNewEdit && !info.noNewEdit && !(this.options.design && info.type === 'reviewpage')) {
845
+ if (isNew
846
+ && !this.options.noNewEdit
847
+ && !info.noNewEdit
848
+ && this.hasEditTabs(info.type)
849
+ && !(this.options.design && info.type === 'reviewpage')) {
844
850
  this.editComponent(info, target, isNew, null, null, { inDataGrid: componentInDataGrid });
845
851
  }
846
852
  // Only rebuild the parts needing to be rebuilt.
@@ -1619,4 +1625,9 @@ export default class WebformBuilder extends Component {
1619
1625
  info.placeholder ||
1620
1626
  info.type);
1621
1627
  }
1628
+ hasEditTabs(type) {
1629
+ const editTabs = getComponent(Components.components[type].editForm().components, 'tabs', true).components;
1630
+ const hiddenEditTabs = _.filter(_.get(this.options, `editForm.${type}`, []), 'ignore');
1631
+ return _.intersectionBy(editTabs, hiddenEditTabs, 'key').length !== editTabs.length;
1632
+ }
1622
1633
  }
package/lib/mjs/Wizard.js CHANGED
@@ -594,6 +594,7 @@ export default class Wizard extends Webform {
594
594
  }
595
595
  this.redraw().then(() => {
596
596
  this.checkData(this.submission.data);
597
+ this.triggerCaptcha(this.currentPanel.components);
597
598
  const errors = this.submitted ? this.validate(this.localData, { dirty: true }) : this.validateCurrentPage();
598
599
  if (this.alert) {
599
600
  this.showErrors(errors, true, true);
@@ -657,7 +658,7 @@ export default class Wizard extends Webform {
657
658
  return this.page - 1;
658
659
  }
659
660
  beforeSubmit() {
660
- const pages = this.getPages();
661
+ const pages = this.getPages({ all: true });
661
662
  return Promise.all(pages.map((page) => {
662
663
  page.options.beforeSubmit = true;
663
664
  return page.beforeSubmit();
@@ -255,10 +255,23 @@ export default class WizardBuilder extends WebformBuilder {
255
255
  if (component instanceof WizardBuilder) {
256
256
  return;
257
257
  }
258
+ if (!window.sessionStorage) {
259
+ return console.warn(this.t('sessionStorageSupportError'));
260
+ }
261
+ // If pasting after the Wizard's page, check if a full Wizard page was copied and pass it to addPage method
258
262
  if (this._form.components.find(comp => _.isEqual(component.component, comp))) {
259
- this.addPage(component);
263
+ const data = window.sessionStorage.getItem('formio.clipboard');
264
+ if (data) {
265
+ const schema = JSON.parse(data);
266
+ // If the copied component is not a Wizard's page, do nothing since we can't paste outside the panel in Wizard
267
+ if (schema.type !== 'panel') {
268
+ return;
269
+ }
270
+ this.addPage(schema);
271
+ }
260
272
  }
261
273
  else {
274
+ // If we are not trying to paster after the current Wizard's page, just pass it to the WebformBuilder
262
275
  return super.pasteComponent(component);
263
276
  }
264
277
  }
@@ -2,6 +2,7 @@ export default class Components {
2
2
  static _editFormUtils: {
3
3
  sortAndFilterComponents(components: any): any;
4
4
  unifyComponents(objValue: any, srcValue: any): any;
5
+ tokenVariableDescription(): string;
5
6
  logicVariablesTable(additional: any): {
6
7
  type: string;
7
8
  tag: string;
@@ -86,6 +87,7 @@ export default class Components {
86
87
  static set EditFormUtils(value: {
87
88
  sortAndFilterComponents(components: any): any;
88
89
  unifyComponents(objValue: any, srcValue: any): any;
90
+ tokenVariableDescription(): string;
89
91
  logicVariablesTable(additional: any): {
90
92
  type: string;
91
93
  tag: string;
@@ -169,6 +171,7 @@ export default class Components {
169
171
  static get EditFormUtils(): {
170
172
  sortAndFilterComponents(components: any): any;
171
173
  unifyComponents(objValue: any, srcValue: any): any;
174
+ tokenVariableDescription(): string;
172
175
  logicVariablesTable(additional: any): {
173
176
  type: string;
174
177
  tag: string;
@@ -161,6 +161,7 @@ export default class Component extends Element {
161
161
  properties: {},
162
162
  allowMultipleMasks: false,
163
163
  addons: [],
164
+ serverOverride: {},
164
165
  }, ...sources);
165
166
  }
166
167
  /**
@@ -418,6 +419,9 @@ export default class Component extends Element {
418
419
  // Allow anyone to hook into the component creation.
419
420
  this.hook('component');
420
421
  if (!this.options.skipInit) {
422
+ if (typeof this.beforeInit === 'function') {
423
+ this.beforeInit();
424
+ }
421
425
  this.init();
422
426
  }
423
427
  }
@@ -1264,7 +1268,7 @@ export default class Component extends Element {
1264
1268
  detach() {
1265
1269
  // First iterate through each ref and delete the component so there are no dangling component references.
1266
1270
  _.each(this.refs, (ref) => {
1267
- if (typeof ref === NodeList) {
1271
+ if (ref instanceof NodeList) {
1268
1272
  ref.forEach((elem) => {
1269
1273
  delete elem.component;
1270
1274
  });
@@ -1914,15 +1918,21 @@ export default class Component extends Element {
1914
1918
  }
1915
1919
  // Check advanced conditions (and cache the result)
1916
1920
  const isConditionallyHidden = this.checkConditionallyHidden(data, row) || this._parentConditionallyHidden;
1921
+ let shouldClear = false;
1917
1922
  if (isConditionallyHidden !== this._conditionallyHidden) {
1918
1923
  this._conditionallyHidden = isConditionallyHidden;
1919
- this.clearOnHide();
1924
+ shouldClear = true;
1920
1925
  }
1921
1926
  // Check visibility
1922
1927
  const visible = (this.hasCondition() ? !this.conditionallyHidden : !this.component.hidden);
1923
1928
  if (this.visible !== visible) {
1924
1929
  this.visible = visible;
1925
1930
  }
1931
+ // Wait for visibility to update for nested components, so the component state is up-to-date when
1932
+ // calling clearOnHide
1933
+ if (shouldClear) {
1934
+ this.clearOnHide();
1935
+ }
1926
1936
  return visible;
1927
1937
  }
1928
1938
  /**
@@ -45,6 +45,6 @@ export default [
45
45
  },
46
46
  EditFormUtils.javaScriptValue('Advanced Conditions', 'customConditional', 'conditional.json', 110, '<p>You must assign the <strong>show</strong> variable a boolean result.</p>' +
47
47
  '<p><strong>Note: Advanced Conditional logic will override the results of the Simple Conditional logic.</strong></p>' +
48
- '<h5>Example</h5><pre>show = !!data.showMe;</pre>', '<p><a href="https://help.form.io/userguide/form-building/logic-and-conditions" target="_blank" rel="noopener noreferrer">Click here for an example</a></p>')
48
+ '<h5>Example</h5><pre>show = !!data.showMe;</pre>', '<p><a href="https://help.form.io/userguide/form-building/logic-and-conditions" target="_blank" rel="noopener noreferrer">Click here for an example</a></p>', EditFormUtils.tokenVariableDescription())
49
49
  ];
50
50
  /* eslint-enable quotes, max-len */