@formio/js 5.6.0 → 5.7.0-api912.2
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.
- package/dist/formio.builder.css +5 -5
- package/dist/formio.builder.min.css +1 -1
- package/dist/formio.embed.js +1 -1
- package/dist/formio.embed.min.js +1 -1
- package/dist/formio.embed.min.js.LICENSE.txt +1 -1
- package/dist/formio.form.css +5 -5
- package/dist/formio.form.js +5218 -5191
- package/dist/formio.form.min.css +1 -1
- package/dist/formio.form.min.js +1 -1
- package/dist/formio.form.min.js.LICENSE.txt +3 -1
- package/dist/formio.full.css +5 -5
- package/dist/formio.full.js +6073 -6046
- package/dist/formio.full.min.css +1 -1
- package/dist/formio.full.min.js +1 -1
- package/dist/formio.full.min.js.LICENSE.txt +3 -1
- package/dist/formio.js +1215 -1188
- package/dist/formio.min.js +1 -1
- package/dist/formio.min.js.LICENSE.txt +3 -1
- package/dist/formio.utils.js +1106 -1079
- package/dist/formio.utils.min.js +1 -1
- package/dist/formio.utils.min.js.LICENSE.txt +3 -1
- package/lib/cjs/Embed.js +38 -25
- package/lib/cjs/Form.d.ts +8 -2
- package/lib/cjs/Form.js +1 -1
- package/lib/cjs/Formio.js +1 -1
- package/lib/cjs/PDF.d.ts +1 -0
- package/lib/cjs/PDF.js +21 -5
- package/lib/cjs/PDFBuilder.d.ts +1 -0
- package/lib/cjs/PDFBuilder.js +1 -0
- package/lib/cjs/Webform.d.ts +13 -1
- package/lib/cjs/Webform.js +79 -26
- package/lib/cjs/Wizard.d.ts +1 -1
- package/lib/cjs/Wizard.js +12 -6
- package/lib/cjs/components/Components.js +1 -5
- package/lib/cjs/components/_classes/component/Component.d.ts +14 -0
- package/lib/cjs/components/_classes/component/Component.js +33 -65
- package/lib/cjs/components/_classes/nested/NestedComponent.form.js +13 -0
- package/lib/cjs/components/_classes/nested/NestedComponent.js +10 -8
- package/lib/cjs/components/content/editForm/Content.edit.display.js +8 -0
- package/lib/cjs/components/currency/editForm/Currency.edit.display.js +20 -0
- package/lib/cjs/components/datagrid/DataGrid.js +2 -6
- package/lib/cjs/components/day/editForm/Day.edit.display.js +8 -0
- package/lib/cjs/components/editgrid/EditGrid.d.ts +1 -0
- package/lib/cjs/components/editgrid/EditGrid.js +22 -2
- package/lib/cjs/components/email/editForm/Email.edit.display.js +12 -0
- package/lib/cjs/components/fieldset/editForm/Fieldset.edit.display.js +8 -0
- package/lib/cjs/components/file/editForm/File.edit.file.js +1 -1
- package/lib/cjs/components/form/Form.js +21 -1
- package/lib/cjs/components/hidden/Hidden.d.ts +0 -1
- package/lib/cjs/components/hidden/Hidden.js +1 -1
- package/lib/cjs/components/hidden/editForm/Hidden.edit.display.js +8 -0
- package/lib/cjs/components/html/editForm/HTML.edit.display.js +8 -0
- package/lib/cjs/components/number/Number.d.ts +11 -0
- package/lib/cjs/components/number/Number.js +35 -0
- package/lib/cjs/components/number/editForm/Number.edit.display.js +12 -0
- package/lib/cjs/components/password/editForm/Password.edit.display.js +12 -0
- package/lib/cjs/components/phonenumber/PhoneNumber.form.js +8 -0
- package/lib/cjs/components/select/editForm/Select.edit.data.d.ts +1 -1
- package/lib/cjs/components/select/editForm/Select.edit.data.js +1 -0
- package/lib/cjs/components/tabs/editForm/Tabs.edit.display.js +8 -0
- package/lib/cjs/components/textarea/editForm/TextArea.edit.display.js +12 -0
- package/lib/cjs/components/url/editForm/Url.edit.display.js +12 -0
- package/lib/cjs/components/well/editForm/Well.edit.display.js +8 -0
- package/lib/cjs/package.json +1 -1
- package/lib/cjs/utils/formUtils.d.ts +3 -0
- package/lib/cjs/utils/formUtils.js +5 -2
- package/lib/cjs/utils/index.d.ts +3 -0
- package/lib/cjs/utils/utils.js +6 -18
- package/lib/mjs/Embed.js +37 -24
- package/lib/mjs/Form.d.ts +8 -2
- package/lib/mjs/Form.js +1 -1
- package/lib/mjs/Formio.js +1 -1
- package/lib/mjs/PDF.d.ts +1 -0
- package/lib/mjs/PDF.js +21 -5
- package/lib/mjs/PDFBuilder.d.ts +1 -0
- package/lib/mjs/PDFBuilder.js +1 -0
- package/lib/mjs/Webform.d.ts +13 -1
- package/lib/mjs/Webform.js +75 -24
- package/lib/mjs/Wizard.d.ts +1 -1
- package/lib/mjs/Wizard.js +12 -6
- package/lib/mjs/components/Components.js +1 -5
- package/lib/mjs/components/_classes/component/Component.d.ts +14 -0
- package/lib/mjs/components/_classes/component/Component.js +33 -65
- package/lib/mjs/components/_classes/nested/NestedComponent.form.js +13 -0
- package/lib/mjs/components/_classes/nested/NestedComponent.js +10 -8
- package/lib/mjs/components/content/editForm/Content.edit.display.js +8 -0
- package/lib/mjs/components/currency/editForm/Currency.edit.display.js +20 -0
- package/lib/mjs/components/datagrid/DataGrid.js +2 -6
- package/lib/mjs/components/day/editForm/Day.edit.display.js +8 -0
- package/lib/mjs/components/editgrid/EditGrid.d.ts +1 -0
- package/lib/mjs/components/editgrid/EditGrid.js +22 -2
- package/lib/mjs/components/email/editForm/Email.edit.display.js +12 -0
- package/lib/mjs/components/fieldset/editForm/Fieldset.edit.display.js +8 -0
- package/lib/mjs/components/file/editForm/File.edit.file.js +1 -1
- package/lib/mjs/components/form/Form.js +21 -1
- package/lib/mjs/components/hidden/Hidden.d.ts +0 -1
- package/lib/mjs/components/hidden/Hidden.js +1 -1
- package/lib/mjs/components/hidden/editForm/Hidden.edit.display.js +8 -0
- package/lib/mjs/components/html/editForm/HTML.edit.display.js +8 -0
- package/lib/mjs/components/number/Number.d.ts +11 -0
- package/lib/mjs/components/number/Number.js +34 -0
- package/lib/mjs/components/number/editForm/Number.edit.display.js +12 -0
- package/lib/mjs/components/password/editForm/Password.edit.display.js +12 -0
- package/lib/mjs/components/phonenumber/PhoneNumber.form.js +8 -0
- package/lib/mjs/components/select/editForm/Select.edit.data.d.ts +1 -1
- package/lib/mjs/components/select/editForm/Select.edit.data.js +1 -0
- package/lib/mjs/components/tabs/editForm/Tabs.edit.display.js +8 -0
- package/lib/mjs/components/textarea/editForm/TextArea.edit.display.js +12 -0
- package/lib/mjs/components/url/editForm/Url.edit.display.js +12 -0
- package/lib/mjs/components/well/editForm/Well.edit.display.js +8 -0
- package/lib/mjs/package.json +1 -1
- package/lib/mjs/utils/formUtils.d.ts +3 -0
- package/lib/mjs/utils/formUtils.js +2 -2
- package/lib/mjs/utils/index.d.ts +3 -0
- package/lib/mjs/utils/utils.js +6 -18
- package/package.json +2 -2
|
@@ -20,7 +20,9 @@
|
|
|
20
20
|
|
|
21
21
|
/*! @license DOMPurify 3.4.13 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.13/LICENSE */
|
|
22
22
|
|
|
23
|
-
/*!
|
|
23
|
+
/*! @license DOMPurify 3.4.14 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.14/LICENSE */
|
|
24
|
+
|
|
25
|
+
/*! formiojs v5.7.0-api912.2 | https://unpkg.com/formiojs@5.7.0-api912.2/LICENSE.txt */
|
|
24
26
|
|
|
25
27
|
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
|
|
26
28
|
|
package/lib/cjs/Embed.js
CHANGED
|
@@ -273,7 +273,6 @@ class Formio {
|
|
|
273
273
|
});
|
|
274
274
|
}
|
|
275
275
|
static init(element, options = {}, builder = false) {
|
|
276
|
-
var _b;
|
|
277
276
|
return __awaiter(this, void 0, void 0, function* () {
|
|
278
277
|
_a.cdn = new CDN_js_1.default(_a.config.cdn, _a.config.cdnUrls || {});
|
|
279
278
|
_a.config.libs = _a.config.libs || {
|
|
@@ -345,7 +344,10 @@ class Formio {
|
|
|
345
344
|
};
|
|
346
345
|
});
|
|
347
346
|
const id = _a.config.id || `formio-${Math.random().toString(36).substring(7)}`;
|
|
348
|
-
|
|
347
|
+
// Quill and CKEditor cannot run in the shadow DOM (https://github.com/quilljs/quill/issues/2021,
|
|
348
|
+
// https://github.com/ckeditor/ckeditor5/issues/15824), so fall back to the light DOM when the
|
|
349
|
+
// form contains one of them.
|
|
350
|
+
const hasShadowIncompatibleEditor = (components) => {
|
|
349
351
|
if (!Array.isArray(components)) {
|
|
350
352
|
return false;
|
|
351
353
|
}
|
|
@@ -354,16 +356,39 @@ class Formio {
|
|
|
354
356
|
if (!component || typeof component !== 'object') {
|
|
355
357
|
return false;
|
|
356
358
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
component.editor
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
359
|
+
if (component.type === 'textarea') {
|
|
360
|
+
// A textarea with `wysiwyg` set and no explicit `editor` defaults to CKEditor at render time.
|
|
361
|
+
const editor = component.editor || (component.wysiwyg ? 'ckeditor' : '');
|
|
362
|
+
if (['quill', 'ckeditor'].includes(editor)) {
|
|
363
|
+
return true;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
const children = (component.components || []).concat(((_b = component.columns) === null || _b === void 0 ? void 0 : _b.flatMap((column) => column.components || [])) || [], ((_c = component.rows) === null || _c === void 0 ? void 0 : _c.flatMap((row) => row.flatMap((cell) => cell.components || []))) || []);
|
|
367
|
+
return hasShadowIncompatibleEditor(children);
|
|
364
368
|
});
|
|
365
369
|
};
|
|
366
|
-
const
|
|
370
|
+
const shouldSkipShadowDom = () => __awaiter(this, void 0, void 0, function* () {
|
|
371
|
+
var _b;
|
|
372
|
+
if ((_b = _a.config.form) === null || _b === void 0 ? void 0 : _b.components) {
|
|
373
|
+
return hasShadowIncompatibleEditor(_a.config.form.components);
|
|
374
|
+
}
|
|
375
|
+
const formUrl = _a.config.src || (typeof _a.config.form === 'string' ? _a.config.form : '');
|
|
376
|
+
if (!formUrl) {
|
|
377
|
+
return false;
|
|
378
|
+
}
|
|
379
|
+
try {
|
|
380
|
+
const response = yield fetch(formUrl);
|
|
381
|
+
if (!response.ok) {
|
|
382
|
+
throw new Error(`Request failed with status ${response.status}`);
|
|
383
|
+
}
|
|
384
|
+
const form = yield response.json();
|
|
385
|
+
return hasShadowIncompatibleEditor(form === null || form === void 0 ? void 0 : form.components);
|
|
386
|
+
}
|
|
387
|
+
catch (err) {
|
|
388
|
+
_a.debug('Could not load the form to check for shadow DOM support', err);
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
});
|
|
367
392
|
// Create a new wrapper and add the element inside of a new wrapper.
|
|
368
393
|
let wrapper = _a.createElement('div', {
|
|
369
394
|
id: `${id}-wrapper`,
|
|
@@ -372,20 +397,8 @@ class Formio {
|
|
|
372
397
|
// If we include the libraries, then we will attempt to run this in shadow dom.
|
|
373
398
|
const useShadowDom = _a.config.includeLibs &&
|
|
374
399
|
!_a.config.noshadow &&
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
if (useShadowDom) {
|
|
378
|
-
wrapper = wrapper.attachShadow({
|
|
379
|
-
mode: 'open',
|
|
380
|
-
});
|
|
381
|
-
options.shadowRoot = wrapper;
|
|
382
|
-
// Due to an issue with quill not loading styles in the shadowdom, we need to add quill styles and js to the shadowdom
|
|
383
|
-
const quill = {
|
|
384
|
-
js: `${_a.cdn.quill}/quill.js`,
|
|
385
|
-
css: `${_a.cdn.quill}/quill.snow.css`,
|
|
386
|
-
};
|
|
387
|
-
yield _a.addLibrary(wrapper, quill, 'quill');
|
|
388
|
-
}
|
|
400
|
+
typeof wrapper.attachShadow === 'function' &&
|
|
401
|
+
!(yield shouldSkipShadowDom());
|
|
389
402
|
element.parentNode.removeChild(element);
|
|
390
403
|
wrapper.appendChild(element);
|
|
391
404
|
// If this is inside of shadow dom, then we need to add the styles and scripts to the shadow dom.
|
|
@@ -500,7 +513,7 @@ Formio.formioReady = new Promise((ready, reject) => {
|
|
|
500
513
|
_a._formioReady = ready;
|
|
501
514
|
_a._formioReadyReject = reject;
|
|
502
515
|
});
|
|
503
|
-
Formio.version = '5.
|
|
516
|
+
Formio.version = '5.7.0-api912.2';
|
|
504
517
|
// Create a report.
|
|
505
518
|
Formio.Report = {
|
|
506
519
|
create: (element, submission, options = {}) => __awaiter(void 0, void 0, void 0, function* () {
|
package/lib/cjs/Form.d.ts
CHANGED
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
* @property {number} [saveDraftThrottle] - The throttle for the save draft feature.
|
|
46
46
|
* @property {boolean} [readOnly] - Set this form to readOnly.
|
|
47
47
|
* @property {boolean} [noAlerts] - Disable the alerts dialog.
|
|
48
|
-
* @property {{[key: string]: string} | { translationsUrl: string }} [i18n] - The
|
|
48
|
+
* @property {{[key: string]: string} | { translationsUrl: string } | { resource: { form: string, codeComponent: string, mapComponent: string } }} [i18n] - The translations for this rendering: inline, a hosted file, or a Form.io language resource (one submission per language).
|
|
49
49
|
* @property {string} [template] - Custom logic for creation of elements.
|
|
50
50
|
* @property {boolean} [noDefaults] - Exclude default values from the settings.
|
|
51
51
|
* @property {any} [fileService] - The file service for this form.
|
|
@@ -198,12 +198,18 @@ export type FormOptions = {
|
|
|
198
198
|
*/
|
|
199
199
|
noAlerts?: boolean | undefined;
|
|
200
200
|
/**
|
|
201
|
-
* - The
|
|
201
|
+
* - The translations for this rendering: inline, a hosted file, or a Form.io language resource (one submission per language).
|
|
202
202
|
*/
|
|
203
203
|
i18n?: {
|
|
204
204
|
[key: string]: string;
|
|
205
205
|
} | {
|
|
206
206
|
translationsUrl: string;
|
|
207
|
+
} | {
|
|
208
|
+
resource: {
|
|
209
|
+
form: string;
|
|
210
|
+
codeComponent: string;
|
|
211
|
+
mapComponent: string;
|
|
212
|
+
};
|
|
207
213
|
} | undefined;
|
|
208
214
|
/**
|
|
209
215
|
* - Custom logic for creation of elements.
|
package/lib/cjs/Form.js
CHANGED
|
@@ -56,7 +56,7 @@ const utils_1 = __importDefault(require("./utils"));
|
|
|
56
56
|
* @property {number} [saveDraftThrottle] - The throttle for the save draft feature.
|
|
57
57
|
* @property {boolean} [readOnly] - Set this form to readOnly.
|
|
58
58
|
* @property {boolean} [noAlerts] - Disable the alerts dialog.
|
|
59
|
-
* @property {{[key: string]: string} | { translationsUrl: string }} [i18n] - The
|
|
59
|
+
* @property {{[key: string]: string} | { translationsUrl: string } | { resource: { form: string, codeComponent: string, mapComponent: string } }} [i18n] - The translations for this rendering: inline, a hosted file, or a Form.io language resource (one submission per language).
|
|
60
60
|
* @property {string} [template] - Custom logic for creation of elements.
|
|
61
61
|
* @property {boolean} [noDefaults] - Exclude default values from the settings.
|
|
62
62
|
* @property {any} [fileService] - The file service for this form.
|
package/lib/cjs/Formio.js
CHANGED
|
@@ -11,7 +11,7 @@ const CDN_1 = __importDefault(require("./CDN"));
|
|
|
11
11
|
const providers_1 = __importDefault(require("./providers"));
|
|
12
12
|
sdk_1.Formio.cdn = new CDN_1.default();
|
|
13
13
|
sdk_1.Formio.Providers = providers_1.default;
|
|
14
|
-
sdk_1.Formio.version = '5.
|
|
14
|
+
sdk_1.Formio.version = '5.7.0-api912.2';
|
|
15
15
|
CDN_1.default.defaultCDN = sdk_1.Formio.version.includes('rc')
|
|
16
16
|
? 'https://cdn.test-form.io'
|
|
17
17
|
: 'https://cdn.form.io';
|
package/lib/cjs/PDF.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export default class PDF extends Webform {
|
|
|
2
2
|
constructor(element: any, options: any);
|
|
3
3
|
components: any[];
|
|
4
4
|
init(): void;
|
|
5
|
+
forwardRefreshEventsToIframe(): void;
|
|
5
6
|
render(): any;
|
|
6
7
|
submitButton: any;
|
|
7
8
|
attachComponents(element: any, components: any, container: any): Promise<void>;
|
package/lib/cjs/PDF.js
CHANGED
|
@@ -19,10 +19,7 @@ const isTrustedIframeMessage = (event, form) => {
|
|
|
19
19
|
var _a;
|
|
20
20
|
const iframeWindow = (_a = form === null || form === void 0 ? void 0 : form.iframeElement) === null || _a === void 0 ? void 0 : _a.contentWindow;
|
|
21
21
|
const iframeOrigin = (form === null || form === void 0 ? void 0 : form.iframeElement) && getIframeOrigin(form.iframeElement);
|
|
22
|
-
return Boolean(iframeWindow &&
|
|
23
|
-
iframeOrigin &&
|
|
24
|
-
event.source === iframeWindow &&
|
|
25
|
-
event.origin === iframeOrigin);
|
|
22
|
+
return Boolean(iframeWindow && iframeOrigin && event.source === iframeWindow && event.origin === iframeOrigin);
|
|
26
23
|
};
|
|
27
24
|
class PDF extends Webform_1.default {
|
|
28
25
|
constructor(element, options) {
|
|
@@ -31,7 +28,9 @@ class PDF extends Webform_1.default {
|
|
|
31
28
|
this.components = [];
|
|
32
29
|
}
|
|
33
30
|
init() {
|
|
31
|
+
this.options.pdfShell = true;
|
|
34
32
|
super.init();
|
|
33
|
+
this.forwardRefreshEventsToIframe();
|
|
35
34
|
// Handle an iframe submission.
|
|
36
35
|
this.on('iframe-submission', (submission) => this.setValue(submission, {
|
|
37
36
|
fromIframe: true,
|
|
@@ -62,6 +61,17 @@ class PDF extends Webform_1.default {
|
|
|
62
61
|
// Re-emit pageEnd without the iframe- prefix for consumers tracking PDF scroll position.
|
|
63
62
|
this.on('iframe-pageEnd', (data) => this.emit('pageEnd', data), true);
|
|
64
63
|
}
|
|
64
|
+
// The iframe renders the components in its own realm with its own emitter, so an event they
|
|
65
|
+
// refresh on only reaches them across the bridge.
|
|
66
|
+
forwardRefreshEventsToIframe() {
|
|
67
|
+
const refreshEvents = new Set();
|
|
68
|
+
(0, utils_1.eachComponent)(this.component.components, (component) => {
|
|
69
|
+
if (component.refreshOnEvent) {
|
|
70
|
+
refreshEvents.add(component.refreshOnEvent);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
refreshEvents.forEach((event) => this.on(event, () => this.postMessage({ name: 'emit', data: event }), true));
|
|
74
|
+
}
|
|
65
75
|
render() {
|
|
66
76
|
this.submitButton = this.addComponent({
|
|
67
77
|
disabled: this.form.disableWizardSubmit,
|
|
@@ -318,7 +328,13 @@ if (typeof window !== 'undefined') {
|
|
|
318
328
|
if (eventData.compPath) {
|
|
319
329
|
const comp = form.getComponent(eventData.compPath);
|
|
320
330
|
if (comp) {
|
|
321
|
-
|
|
331
|
+
// Emit component instance for focus/blur events to match payload of those events on other forms
|
|
332
|
+
if (['focus', 'blur'].includes(eventData.name)) {
|
|
333
|
+
comp.emit(eventData.name, comp);
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
comp.emit(eventData.name, eventData.data);
|
|
337
|
+
}
|
|
322
338
|
}
|
|
323
339
|
}
|
|
324
340
|
else {
|
package/lib/cjs/PDFBuilder.d.ts
CHANGED
package/lib/cjs/PDFBuilder.js
CHANGED
package/lib/cjs/Webform.d.ts
CHANGED
|
@@ -293,8 +293,20 @@ declare class Webform extends NestedDataComponent {
|
|
|
293
293
|
/**
|
|
294
294
|
* Focus on selected component.
|
|
295
295
|
* @param {string} key - The key of selected component.
|
|
296
|
+
* @param {string} [componentKey] - The schema key of the component that produced the error, if known.
|
|
296
297
|
*/
|
|
297
|
-
focusOnComponent(key: string): void;
|
|
298
|
+
focusOnComponent(key: string, componentKey?: string | undefined): void;
|
|
299
|
+
/**
|
|
300
|
+
* Resolves the component that produced an error, to attach the error to it or to focus it from
|
|
301
|
+
* the error list. A checkbox with inputType 'radio' takes its `name` as its path, so several
|
|
302
|
+
* components can share `key`; the schema key of the component that produced the error tells them
|
|
303
|
+
* apart. The shared-path lookup is only consulted when `getComponent` picked another component,
|
|
304
|
+
* and only trusted when it finds the one with that schema key.
|
|
305
|
+
* @param {string} key - The path the error was reported at.
|
|
306
|
+
* @param {string} [componentKey] - The schema key of the component that produced the error, if known.
|
|
307
|
+
* @returns {any} - The component that produced the error, if found.
|
|
308
|
+
*/
|
|
309
|
+
getErrorComponent(key: string, componentKey?: string | undefined): any;
|
|
298
310
|
/**
|
|
299
311
|
* @returns {boolean} - Whether or not the draft submission is being edited
|
|
300
312
|
*/
|
package/lib/cjs/Webform.js
CHANGED
|
@@ -981,16 +981,19 @@ class Webform extends NestedDataComponent_1.default {
|
|
|
981
981
|
}
|
|
982
982
|
this.loadRefs(this.alert, { errorRef: 'multiple' });
|
|
983
983
|
if (this.refs.errorRef && this.refs.errorRef.length) {
|
|
984
|
-
this.refs.errorRef.forEach((el) => {
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
984
|
+
this.refs.errorRef.forEach((el, index) => {
|
|
985
|
+
var _a;
|
|
986
|
+
// The Nth link renders the Nth error; a custom template that reorders or filters the list
|
|
987
|
+
// fails this check, and the link then resolves by its key alone.
|
|
988
|
+
const listItem = (_a = options === null || options === void 0 ? void 0 : options.errors) === null || _a === void 0 ? void 0 : _a[index];
|
|
989
|
+
const isLinkForListItem = !!listItem && listItem.keyOrPath === el.dataset.componentKey;
|
|
990
|
+
const componentKey = isLinkForListItem ? listItem.componentKey : undefined;
|
|
991
|
+
const focusOnLinkedComponent = (e) => this.focusOnComponent(e.currentTarget.dataset.componentKey, componentKey);
|
|
992
|
+
this.addEventListener(el, 'click', focusOnLinkedComponent);
|
|
989
993
|
this.addEventListener(el, 'keydown', (e) => {
|
|
990
994
|
if (e.keyCode === 13) {
|
|
991
995
|
e.preventDefault();
|
|
992
|
-
|
|
993
|
-
this.focusOnComponent(key);
|
|
996
|
+
focusOnLinkedComponent(e);
|
|
994
997
|
}
|
|
995
998
|
});
|
|
996
999
|
});
|
|
@@ -1000,16 +1003,36 @@ class Webform extends NestedDataComponent_1.default {
|
|
|
1000
1003
|
/**
|
|
1001
1004
|
* Focus on selected component.
|
|
1002
1005
|
* @param {string} key - The key of selected component.
|
|
1006
|
+
* @param {string} [componentKey] - The schema key of the component that produced the error, if known.
|
|
1003
1007
|
*/
|
|
1004
|
-
focusOnComponent(key) {
|
|
1008
|
+
focusOnComponent(key, componentKey) {
|
|
1005
1009
|
if (key) {
|
|
1006
|
-
const component = this.
|
|
1010
|
+
const component = this.getErrorComponent(key, componentKey);
|
|
1007
1011
|
if (component) {
|
|
1008
1012
|
component.focus();
|
|
1009
1013
|
component.scrollIntoView();
|
|
1010
1014
|
}
|
|
1011
1015
|
}
|
|
1012
1016
|
}
|
|
1017
|
+
/**
|
|
1018
|
+
* Resolves the component that produced an error, to attach the error to it or to focus it from
|
|
1019
|
+
* the error list. A checkbox with inputType 'radio' takes its `name` as its path, so several
|
|
1020
|
+
* components can share `key`; the schema key of the component that produced the error tells them
|
|
1021
|
+
* apart. The shared-path lookup is only consulted when `getComponent` picked another component,
|
|
1022
|
+
* and only trusted when it finds the one with that schema key.
|
|
1023
|
+
* @param {string} key - The path the error was reported at.
|
|
1024
|
+
* @param {string} [componentKey] - The schema key of the component that produced the error, if known.
|
|
1025
|
+
* @returns {any} - The component that produced the error, if found.
|
|
1026
|
+
*/
|
|
1027
|
+
getErrorComponent(key, componentKey) {
|
|
1028
|
+
const component = this.getComponent(key);
|
|
1029
|
+
if (!componentKey || (component === null || component === void 0 ? void 0 : component.component.key) === componentKey) {
|
|
1030
|
+
return component;
|
|
1031
|
+
}
|
|
1032
|
+
// GOTCHA(G-FJS06)
|
|
1033
|
+
const componentWithKey = (0, utils_1.resolveInstanceAtPath)(this.componentsMap, key, componentKey);
|
|
1034
|
+
return (componentWithKey === null || componentWithKey === void 0 ? void 0 : componentWithKey.component.key) === componentKey ? componentWithKey : component;
|
|
1035
|
+
}
|
|
1013
1036
|
/**
|
|
1014
1037
|
* @returns {boolean} - Whether or not the draft submission is being edited
|
|
1015
1038
|
*/
|
|
@@ -1045,29 +1068,29 @@ class Webform extends NestedDataComponent_1.default {
|
|
|
1045
1068
|
return;
|
|
1046
1069
|
}
|
|
1047
1070
|
// Mark any components as invalid if in a custom message.
|
|
1048
|
-
const
|
|
1071
|
+
const errorsByComponent = new Map();
|
|
1049
1072
|
errors.forEach((err) => {
|
|
1050
|
-
var _a, _b;
|
|
1073
|
+
var _a, _b, _c;
|
|
1051
1074
|
const path = (0, utils_1.getStringFromComponentPath)(err.path) || ((_a = err.context) === null || _a === void 0 ? void 0 : _a.path) || ((_b = err.component) === null || _b === void 0 ? void 0 : _b.key);
|
|
1052
|
-
|
|
1053
|
-
|
|
1075
|
+
const component = path && this.getErrorComponent(path, (_c = err.component) === null || _c === void 0 ? void 0 : _c.key);
|
|
1076
|
+
if (!component) {
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
1079
|
+
if (!errorsByComponent.has(component)) {
|
|
1080
|
+
errorsByComponent.set(component, []);
|
|
1054
1081
|
}
|
|
1055
|
-
|
|
1082
|
+
errorsByComponent.get(component).push(err);
|
|
1056
1083
|
});
|
|
1057
1084
|
// Iterate through all of our component errors and apply them to the components.
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
component.serverErrors = errors.filter((err) => err.fromServer);
|
|
1063
|
-
component.setCustomValidity(errors, true);
|
|
1064
|
-
}
|
|
1065
|
-
}
|
|
1085
|
+
errorsByComponent.forEach((componentErrors, component) => {
|
|
1086
|
+
component.serverErrors = componentErrors.filter((err) => err.fromServer);
|
|
1087
|
+
component.setCustomValidity(componentErrors, true);
|
|
1088
|
+
});
|
|
1066
1089
|
const displayedErrors = [];
|
|
1067
1090
|
if (errors.length) {
|
|
1068
1091
|
errors = lodash_1.default.uniqBy(errors, (error) => { var _a, _b; return [error.message, (_a = error.component) === null || _a === void 0 ? void 0 : _a.id, (_b = error.context) === null || _b === void 0 ? void 0 : _b.path].join(); });
|
|
1069
1092
|
const createListItem = (message, index) => {
|
|
1070
|
-
var _a, _b, _c;
|
|
1093
|
+
var _a, _b, _c, _d;
|
|
1071
1094
|
const err = errors[index];
|
|
1072
1095
|
const messageFromIndex = !lodash_1.default.isUndefined(index) && errors && errors[index];
|
|
1073
1096
|
const keyOrPath = (messageFromIndex === null || messageFromIndex === void 0 ? void 0 : messageFromIndex.formattedKeyOrPath) ||
|
|
@@ -1083,6 +1106,7 @@ class Webform extends NestedDataComponent_1.default {
|
|
|
1083
1106
|
return {
|
|
1084
1107
|
message: (0, utils_1.unescapeHTML)(message),
|
|
1085
1108
|
keyOrPath: formattedKeyOrPath,
|
|
1109
|
+
componentKey: (_d = err.component) === null || _d === void 0 ? void 0 : _d.key,
|
|
1086
1110
|
};
|
|
1087
1111
|
};
|
|
1088
1112
|
errors.forEach(({ message, context, fromServer, component }, index) => {
|
|
@@ -1096,7 +1120,7 @@ class Webform extends NestedDataComponent_1.default {
|
|
|
1096
1120
|
// GOTCHA(G-FJS02)
|
|
1097
1121
|
// Only paint the alert from a subform when the root won't double paint it to avoid a painful flicker
|
|
1098
1122
|
if (this === this.root || !((_a = this.root) === null || _a === void 0 ? void 0 : _a.submitted)) {
|
|
1099
|
-
(_b = this.root) === null || _b === void 0 ? void 0 : _b.setAlert('danger', errorsList);
|
|
1123
|
+
(_b = this.root) === null || _b === void 0 ? void 0 : _b.setAlert('danger', errorsList, { errors: displayedErrors });
|
|
1100
1124
|
}
|
|
1101
1125
|
if (triggerEvent) {
|
|
1102
1126
|
this.emit('error', errors);
|
|
@@ -1517,7 +1541,7 @@ class Webform extends NestedDataComponent_1.default {
|
|
|
1517
1541
|
}
|
|
1518
1542
|
}
|
|
1519
1543
|
loadTranslations() {
|
|
1520
|
-
var _a;
|
|
1544
|
+
var _a, _b, _c;
|
|
1521
1545
|
// We only need a resolve since if translations cannot load, we still want to proceed and render the for
|
|
1522
1546
|
let translationsLoadResolve;
|
|
1523
1547
|
const promise = new Promise((resolve) => {
|
|
@@ -1526,9 +1550,16 @@ class Webform extends NestedDataComponent_1.default {
|
|
|
1526
1550
|
const translationsUrl = typeof ((_a = this.options.i18n) === null || _a === void 0 ? void 0 : _a.translationsUrl) === 'string'
|
|
1527
1551
|
? this.options.i18n.translationsUrl
|
|
1528
1552
|
: null;
|
|
1553
|
+
// Translations can also live in a Form.io resource, one submission per language.
|
|
1554
|
+
const languageResource = (_b = this.options.i18n) === null || _b === void 0 ? void 0 : _b.resource;
|
|
1555
|
+
const usesLanguageResource = Boolean(languageResource === null || languageResource === void 0 ? void 0 : languageResource.form);
|
|
1529
1556
|
if (translationsUrl) {
|
|
1530
1557
|
const url = this.sanitize(this.interpolate(translationsUrl, {}), this.shouldSanitizeValue);
|
|
1531
|
-
|
|
1558
|
+
// Simple CORS GET: skip Content-Type / token so static hosts need no preflight.
|
|
1559
|
+
Formio_1.Formio.makeStaticRequest(url, 'GET', null, {
|
|
1560
|
+
headers: { Accept: 'application/json' },
|
|
1561
|
+
noToken: true,
|
|
1562
|
+
})
|
|
1532
1563
|
.then((response) => {
|
|
1533
1564
|
let languages = response;
|
|
1534
1565
|
try {
|
|
@@ -1555,6 +1586,28 @@ class Webform extends NestedDataComponent_1.default {
|
|
|
1555
1586
|
translationsLoadResolve();
|
|
1556
1587
|
});
|
|
1557
1588
|
}
|
|
1589
|
+
else if (usesLanguageResource) {
|
|
1590
|
+
const { form: resourceId, codeComponent, mapComponent } = languageResource;
|
|
1591
|
+
const language = ((_c = this.i18next) === null || _c === void 0 ? void 0 : _c.originalLanguage) || this.options.language;
|
|
1592
|
+
const languageQuery = `data.${codeComponent}=${encodeURIComponent(language)}`;
|
|
1593
|
+
// The resource is addressed by id, so it needs the /form/ route — the bare
|
|
1594
|
+
// `{project}/{alias}` route resolves by path only and would 404 on an id.
|
|
1595
|
+
const url = `${Formio_1.Formio.getProjectUrl()}/form/${resourceId}/submission?${languageQuery}&limit=1`;
|
|
1596
|
+
Formio_1.Formio.makeStaticRequest(url, 'GET')
|
|
1597
|
+
.then((submissions) => {
|
|
1598
|
+
var _a, _b;
|
|
1599
|
+
const translations = (_b = (_a = submissions === null || submissions === void 0 ? void 0 : submissions[0]) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b[mapComponent];
|
|
1600
|
+
// No submission for this language just leaves the form in its default language.
|
|
1601
|
+
if (translations) {
|
|
1602
|
+
this.addLanguage(language, translations, true);
|
|
1603
|
+
}
|
|
1604
|
+
translationsLoadResolve();
|
|
1605
|
+
})
|
|
1606
|
+
.catch((err) => {
|
|
1607
|
+
console.warn(err);
|
|
1608
|
+
translationsLoadResolve();
|
|
1609
|
+
});
|
|
1610
|
+
}
|
|
1558
1611
|
else {
|
|
1559
1612
|
translationsLoadResolve();
|
|
1560
1613
|
}
|
package/lib/cjs/Wizard.d.ts
CHANGED
|
@@ -112,7 +112,7 @@ declare class Wizard extends Webform {
|
|
|
112
112
|
pageId(page: any): any;
|
|
113
113
|
onChange(flags: any, changed: any, modified: any, changes: any): void;
|
|
114
114
|
checkValidity(data: any, dirty: any, row: any, currentPageOnly: any, childErrors?: any[]): any;
|
|
115
|
-
focusOnComponent(key: any): void | Promise<void>;
|
|
115
|
+
focusOnComponent(key: any, componentKey: any): void | Promise<void>;
|
|
116
116
|
triggerButtonCaptcha(page: any): void;
|
|
117
117
|
}
|
|
118
118
|
declare namespace Wizard {
|
package/lib/cjs/Wizard.js
CHANGED
|
@@ -129,9 +129,15 @@ class Wizard extends Webform_1.default {
|
|
|
129
129
|
{ name: 'cancel', method: 'cancel' },
|
|
130
130
|
{ name: 'previous', method: 'prevPage' },
|
|
131
131
|
{ name: 'next', method: 'nextPage' },
|
|
132
|
-
{
|
|
132
|
+
{
|
|
133
|
+
name: 'submit',
|
|
134
|
+
method: 'submit',
|
|
135
|
+
args: [
|
|
136
|
+
false,
|
|
137
|
+
{
|
|
133
138
|
state: 'submitted',
|
|
134
|
-
}
|
|
139
|
+
},
|
|
140
|
+
],
|
|
135
141
|
},
|
|
136
142
|
].forEach((button) => {
|
|
137
143
|
if (this.hasButton(button.name)) {
|
|
@@ -1022,8 +1028,8 @@ class Wizard extends Webform_1.default {
|
|
|
1022
1028
|
get errors() {
|
|
1023
1029
|
return !this.isLastPage() && !this.submitted ? this.currentPage.errors : super.errors;
|
|
1024
1030
|
}
|
|
1025
|
-
focusOnComponent(key) {
|
|
1026
|
-
const component = this.
|
|
1031
|
+
focusOnComponent(key, componentKey) {
|
|
1032
|
+
const component = this.getErrorComponent(key, componentKey);
|
|
1027
1033
|
if (component) {
|
|
1028
1034
|
let topPanel = component.parent;
|
|
1029
1035
|
while (!(topPanel.parent instanceof Wizard)) {
|
|
@@ -1033,11 +1039,11 @@ class Wizard extends Webform_1.default {
|
|
|
1033
1039
|
if (pageIndex >= 0) {
|
|
1034
1040
|
const page = this.pages[pageIndex];
|
|
1035
1041
|
if (page && page !== this.currentPage) {
|
|
1036
|
-
return this.setPage(pageIndex).then(() => super.focusOnComponent(key));
|
|
1042
|
+
return this.setPage(pageIndex).then(() => super.focusOnComponent(key, componentKey));
|
|
1037
1043
|
}
|
|
1038
1044
|
}
|
|
1039
1045
|
}
|
|
1040
|
-
return super.focusOnComponent(key);
|
|
1046
|
+
return super.focusOnComponent(key, componentKey);
|
|
1041
1047
|
}
|
|
1042
1048
|
triggerButtonCaptcha(page) {
|
|
1043
1049
|
if (!page.components) {
|
|
@@ -68,11 +68,7 @@ class Components {
|
|
|
68
68
|
else {
|
|
69
69
|
comp = new Component_1.default(component, options, data);
|
|
70
70
|
}
|
|
71
|
-
|
|
72
|
-
comp.eachRootChildComponentsMap((map) => {
|
|
73
|
-
map[comp.path] = comp;
|
|
74
|
-
});
|
|
75
|
-
}
|
|
71
|
+
comp.registerComponentInstance();
|
|
76
72
|
// Reset the componentMatches on the root element if any new component is created.
|
|
77
73
|
let parent = comp.parent;
|
|
78
74
|
while (parent) {
|
|
@@ -171,6 +171,20 @@ declare class Component extends Element {
|
|
|
171
171
|
* @param {(map: object) => void} fn - Called once per root that exposes a `childComponentsMap`.
|
|
172
172
|
*/
|
|
173
173
|
eachRootChildComponentsMap(fn: (map: object) => void): void;
|
|
174
|
+
/**
|
|
175
|
+
* Registers this instance in every root's `childComponentsMap`. Several components can resolve
|
|
176
|
+
* to one data path — see `getSharedPathKey` in `@formio/core` for the rule this follows.
|
|
177
|
+
* @returns {void}
|
|
178
|
+
*/
|
|
179
|
+
registerComponentInstance(): void;
|
|
180
|
+
sharedPathKey: string | undefined;
|
|
181
|
+
/**
|
|
182
|
+
* Removes this instance from every root's `childComponentsMap`.
|
|
183
|
+
* @param {string} [path] - The path this instance was registered under, when it has since
|
|
184
|
+
* been re-keyed (a DataGrid row index change regenerates paths before unregistering).
|
|
185
|
+
* @returns {void}
|
|
186
|
+
*/
|
|
187
|
+
unregisterComponentInstance(path?: string | undefined): void;
|
|
174
188
|
/**
|
|
175
189
|
* Returns if the parent should conditionally clear.
|
|
176
190
|
*
|