@formio/js 5.0.0-rc.36 → 5.0.0-rc.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/fonts/bootstrap-icons.woff +0 -0
- package/dist/fonts/bootstrap-icons.woff2 +0 -0
- 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.js +854 -133
- package/dist/formio.form.min.js +1 -1
- package/dist/formio.form.min.js.LICENSE.txt +5 -3
- package/dist/formio.full.css +4 -4
- package/dist/formio.full.js +828 -137
- package/dist/formio.full.min.css +3 -3
- package/dist/formio.full.min.js +1 -1
- package/dist/formio.full.min.js.LICENSE.txt +5 -3
- package/dist/formio.js +5 -5
- package/dist/formio.min.js +1 -1
- package/dist/formio.min.js.LICENSE.txt +1 -1
- package/dist/formio.utils.js +25 -14
- package/dist/formio.utils.min.js +1 -1
- package/dist/formio.utils.min.js.LICENSE.txt +5 -3
- package/lib/cjs/Element.js +2 -2
- package/lib/cjs/Embed.js +19 -14
- package/lib/cjs/Formio.js +3 -0
- package/lib/cjs/components/_classes/component/Component.js +21 -7
- package/lib/cjs/components/_classes/component/fixtures/comp5.js +2 -2
- package/lib/cjs/components/_classes/list/ListComponent.js +5 -12
- package/lib/cjs/components/_classes/nested/NestedComponent.js +17 -9
- package/lib/cjs/components/columns/editForm/Columns.edit.display.js +1 -1
- package/lib/cjs/components/editgrid/EditGrid.js +11 -4
- package/lib/cjs/components/form/Form.js +3 -1
- package/lib/cjs/components/html/HTML.js +2 -2
- package/lib/cjs/components/html/fixtures/comp3.js +31 -0
- package/lib/cjs/components/html/fixtures/index.js +3 -1
- package/lib/cjs/components/radio/Radio.js +2 -1
- package/lib/cjs/components/radio/fixtures/comp10.js +23 -0
- package/lib/cjs/components/radio/fixtures/index.js +3 -1
- package/lib/cjs/components/recaptcha/ReCaptcha.js +3 -0
- package/lib/cjs/components/select/Select.js +84 -9
- package/lib/cjs/components/survey/Survey.js +10 -0
- package/lib/cjs/utils/conditionOperators/IsEqualTo.js +19 -1
- package/lib/cjs/utils/conditionOperators/IsNotEqualTo.js +4 -5
- package/lib/cjs/utils/utils.js +40 -2
- package/lib/mjs/Element.js +2 -2
- package/lib/mjs/Embed.js +17 -14
- package/lib/mjs/Formio.js +3 -0
- package/lib/mjs/components/_classes/component/Component.js +24 -8
- package/lib/mjs/components/_classes/component/fixtures/comp5.js +2 -2
- package/lib/mjs/components/_classes/list/ListComponent.js +5 -12
- package/lib/mjs/components/_classes/nested/NestedComponent.js +17 -9
- package/lib/mjs/components/columns/editForm/Columns.edit.display.js +1 -1
- package/lib/mjs/components/editgrid/EditGrid.js +11 -4
- package/lib/mjs/components/form/Form.js +3 -1
- package/lib/mjs/components/html/HTML.js +2 -2
- package/lib/mjs/components/html/fixtures/comp3.js +29 -0
- package/lib/mjs/components/html/fixtures/index.js +2 -1
- package/lib/mjs/components/radio/Radio.js +2 -1
- package/lib/mjs/components/radio/fixtures/comp10.js +21 -0
- package/lib/mjs/components/radio/fixtures/index.js +2 -1
- package/lib/mjs/components/recaptcha/ReCaptcha.js +3 -0
- package/lib/mjs/components/select/Select.js +83 -10
- package/lib/mjs/components/survey/Survey.js +10 -0
- package/lib/mjs/utils/conditionOperators/IsEqualTo.js +18 -1
- package/lib/mjs/utils/conditionOperators/IsNotEqualTo.js +4 -5
- package/lib/mjs/utils/utils.js +35 -0
- package/package.json +2 -2
- package/types/formio.d.ts +4 -0
@@ -3,7 +3,7 @@ import { Formio } from '../../Formio';
|
|
3
3
|
import ListComponent from '../_classes/list/ListComponent';
|
4
4
|
import Input from '../_classes/input/Input';
|
5
5
|
import Form from '../../Form';
|
6
|
-
import { getRandomComponentId, boolValue, isPromise, componentValueTypes, getComponentSavedTypes } from '../../utils/utils';
|
6
|
+
import { getRandomComponentId, boolValue, isPromise, componentValueTypes, getComponentSavedTypes, unescapeHTML, isSelectResourceWithObjectValue } from '../../utils/utils';
|
7
7
|
import Choices from '../../utils/ChoicesWrapper';
|
8
8
|
export default class SelectComponent extends ListComponent {
|
9
9
|
static schema(...extend) {
|
@@ -61,7 +61,19 @@ export default class SelectComponent extends ListComponent {
|
|
61
61
|
return {
|
62
62
|
...super.conditionOperatorsSettings,
|
63
63
|
valueComponent(classComp) {
|
64
|
-
|
64
|
+
const valueComp = { ...classComp, type: 'select' };
|
65
|
+
if (isSelectResourceWithObjectValue(classComp)) {
|
66
|
+
valueComp.reference = false;
|
67
|
+
valueComp.onSetItems = `
|
68
|
+
var templateKeys = utils.getItemTemplateKeys(component.template) || [];
|
69
|
+
items = _.map(items || [], i => {
|
70
|
+
var item = {};
|
71
|
+
_.each(templateKeys, k => _.set(item, k, _.get(i, k)));
|
72
|
+
return item;
|
73
|
+
})
|
74
|
+
`;
|
75
|
+
}
|
76
|
+
return valueComp;
|
65
77
|
}
|
66
78
|
};
|
67
79
|
}
|
@@ -120,6 +132,7 @@ export default class SelectComponent extends ListComponent {
|
|
120
132
|
this.itemsLoaded = new Promise((resolve) => {
|
121
133
|
this.itemsLoadedResolve = resolve;
|
122
134
|
});
|
135
|
+
this.shouldPositionDropdown = this.hasDataGridAncestor();
|
123
136
|
if (this.isHtmlRenderMode()) {
|
124
137
|
this.activate();
|
125
138
|
}
|
@@ -851,6 +864,11 @@ export default class SelectComponent extends ListComponent {
|
|
851
864
|
});
|
852
865
|
}
|
853
866
|
}
|
867
|
+
if (window && this.choices && this.shouldPositionDropdown) {
|
868
|
+
this.addEventListener(window.document, 'scroll', () => {
|
869
|
+
this.positionDropdown(true);
|
870
|
+
}, false, true);
|
871
|
+
}
|
854
872
|
this.focusableElement.setAttribute('tabIndex', tabIndex);
|
855
873
|
// If a search field is provided, then add an event listener to update items on search.
|
856
874
|
if (this.component.searchField) {
|
@@ -880,7 +898,10 @@ export default class SelectComponent extends ListComponent {
|
|
880
898
|
const updateComponent = (evt) => {
|
881
899
|
this.triggerUpdate(evt.detail.value);
|
882
900
|
};
|
883
|
-
this.addEventListener(input, 'search', _.debounce(
|
901
|
+
this.addEventListener(input, 'search', _.debounce((e) => {
|
902
|
+
updateComponent(e);
|
903
|
+
this.positionDropdown();
|
904
|
+
}, debounceTimeout));
|
884
905
|
this.addEventListener(input, 'stopSearch', () => this.triggerUpdate());
|
885
906
|
this.addEventListener(input, 'hideDropdown', () => {
|
886
907
|
if (this.choices && this.choices.input && this.choices.input.element) {
|
@@ -889,7 +910,15 @@ export default class SelectComponent extends ListComponent {
|
|
889
910
|
this.updateItems(null, true);
|
890
911
|
});
|
891
912
|
}
|
892
|
-
this.addEventListener(input, 'showDropdown', () =>
|
913
|
+
this.addEventListener(input, 'showDropdown', () => {
|
914
|
+
this.update();
|
915
|
+
this.positionDropdown();
|
916
|
+
});
|
917
|
+
if (this.shouldPositionDropdown) {
|
918
|
+
this.addEventListener(input, 'highlightChoice', () => {
|
919
|
+
this.positionDropdown();
|
920
|
+
});
|
921
|
+
}
|
893
922
|
if (this.choices && choicesOptions.placeholderValue && this.choices._isSelectOneElement) {
|
894
923
|
this.addPlaceholderItem(choicesOptions.placeholderValue);
|
895
924
|
this.addEventListener(input, 'removeItem', () => {
|
@@ -926,6 +955,44 @@ export default class SelectComponent extends ListComponent {
|
|
926
955
|
this.triggerUpdate();
|
927
956
|
return superAttach;
|
928
957
|
}
|
958
|
+
setDropdownPosition() {
|
959
|
+
const dropdown = this.choices?.dropdown?.element;
|
960
|
+
const container = this.choices?.containerOuter?.element;
|
961
|
+
if (!dropdown || !container) {
|
962
|
+
return;
|
963
|
+
}
|
964
|
+
const containerPosition = container.getBoundingClientRect();
|
965
|
+
const isFlipped = container.classList.contains('is-flipped');
|
966
|
+
_.assign(dropdown.style, {
|
967
|
+
top: `${isFlipped ? containerPosition.top - dropdown.offsetHeight : containerPosition.top + containerPosition.height}px`,
|
968
|
+
left: `${containerPosition.left}px`,
|
969
|
+
width: `${containerPosition.width}px`,
|
970
|
+
position: 'fixed',
|
971
|
+
bottom: 'unset',
|
972
|
+
right: 'unset',
|
973
|
+
});
|
974
|
+
}
|
975
|
+
hasDataGridAncestor(comp) {
|
976
|
+
comp = comp || this;
|
977
|
+
if (comp.inDataGrid || comp.type === 'datagrid') {
|
978
|
+
return true;
|
979
|
+
}
|
980
|
+
else if (comp.parent) {
|
981
|
+
return this.hasDataGridAncestor(comp.parent);
|
982
|
+
}
|
983
|
+
else {
|
984
|
+
return false;
|
985
|
+
}
|
986
|
+
}
|
987
|
+
positionDropdown(scroll) {
|
988
|
+
if (!this.shouldPositionDropdown || !this.choices || (!this.choices.dropdown?.isActive && scroll)) {
|
989
|
+
return;
|
990
|
+
}
|
991
|
+
this.setDropdownPosition();
|
992
|
+
this.itemsLoaded.then(() => {
|
993
|
+
this.setDropdownPosition();
|
994
|
+
});
|
995
|
+
}
|
929
996
|
get isLoadingAvailable() {
|
930
997
|
return !this.isScrollLoading && this.additionalResourcesAvailable;
|
931
998
|
}
|
@@ -1043,10 +1110,10 @@ export default class SelectComponent extends ListComponent {
|
|
1043
1110
|
}
|
1044
1111
|
return added;
|
1045
1112
|
}
|
1046
|
-
getValueAsString(data) {
|
1113
|
+
getValueAsString(data, options) {
|
1047
1114
|
return (this.component.multiple && Array.isArray(data))
|
1048
|
-
? data.map(this.asString
|
1049
|
-
: this.asString(data);
|
1115
|
+
? data.map((v) => this.asString(v, options)).join(', ')
|
1116
|
+
: this.asString(data, options);
|
1050
1117
|
}
|
1051
1118
|
getValue() {
|
1052
1119
|
// If the widget isn't active.
|
@@ -1398,7 +1465,7 @@ export default class SelectComponent extends ListComponent {
|
|
1398
1465
|
}
|
1399
1466
|
return this.component.data.values.map(value => ({ label: value.label, value: String(this.normalizeSingleValue(value.value)) }));
|
1400
1467
|
}
|
1401
|
-
asString(value) {
|
1468
|
+
asString(value, options = {}) {
|
1402
1469
|
value = value ?? this.getValue();
|
1403
1470
|
//need to convert values to strings to be able to compare values with available options that are strings
|
1404
1471
|
const convertToString = (data, valueProperty) => {
|
@@ -1448,9 +1515,15 @@ export default class SelectComponent extends ListComponent {
|
|
1448
1515
|
if (_.isString(value)) {
|
1449
1516
|
return value;
|
1450
1517
|
}
|
1518
|
+
const getTemplateValue = (v) => {
|
1519
|
+
const itemTemplate = this.itemTemplate(v);
|
1520
|
+
return options.csv && itemTemplate
|
1521
|
+
? unescapeHTML(itemTemplate)
|
1522
|
+
: itemTemplate;
|
1523
|
+
};
|
1451
1524
|
if (Array.isArray(value)) {
|
1452
1525
|
const items = [];
|
1453
|
-
value.forEach(item => items.push(
|
1526
|
+
value.forEach(item => items.push(getTemplateValue(item)));
|
1454
1527
|
if (this.component.dataSrc === 'resource' && items.length > 0) {
|
1455
1528
|
return items.join(', ');
|
1456
1529
|
}
|
@@ -1465,7 +1538,7 @@ export default class SelectComponent extends ListComponent {
|
|
1465
1538
|
return JSON.stringify(value);
|
1466
1539
|
}
|
1467
1540
|
return !_.isNil(value)
|
1468
|
-
?
|
1541
|
+
? getTemplateValue(value)
|
1469
1542
|
: '-';
|
1470
1543
|
}
|
1471
1544
|
detach() {
|
@@ -148,6 +148,16 @@ export default class SurveyComponent extends Field {
|
|
148
148
|
result += '</tbody></table>';
|
149
149
|
return result;
|
150
150
|
}
|
151
|
+
if (_.isPlainObject(value)) {
|
152
|
+
const { values = [], questions = [] } = this.component;
|
153
|
+
return _.isEmpty(value)
|
154
|
+
? ''
|
155
|
+
: _.map(value, (v, q) => {
|
156
|
+
const valueLabel = _.get(_.find(values, val => _.isEqual(val.value, v)), 'label', v);
|
157
|
+
const questionLabel = _.get(_.find(questions, quest => _.isEqual(quest.value, q)), 'label', q);
|
158
|
+
return `${questionLabel}: ${valueLabel}`;
|
159
|
+
}).join('; ');
|
160
|
+
}
|
151
161
|
return super.getValueAsString(value, options);
|
152
162
|
}
|
153
163
|
}
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import ConditionOperator from './ConditionOperator';
|
2
2
|
import _ from 'lodash';
|
3
|
+
import { getItemTemplateKeys, isSelectResourceWithObjectValue } from '../utils';
|
3
4
|
export default class IsEqualTo extends ConditionOperator {
|
4
5
|
static get operatorKey() {
|
5
6
|
return 'isEqual';
|
@@ -7,7 +8,7 @@ export default class IsEqualTo extends ConditionOperator {
|
|
7
8
|
static get displayedName() {
|
8
9
|
return 'Is Equal To';
|
9
10
|
}
|
10
|
-
execute({ value, comparedValue }) {
|
11
|
+
execute({ value, comparedValue, instance, conditionComponentPath }) {
|
11
12
|
if (value && comparedValue && typeof value !== typeof comparedValue && _.isString(comparedValue)) {
|
12
13
|
try {
|
13
14
|
comparedValue = JSON.parse(comparedValue);
|
@@ -15,6 +16,22 @@ export default class IsEqualTo extends ConditionOperator {
|
|
15
16
|
// eslint-disable-next-line no-empty
|
16
17
|
catch (e) { }
|
17
18
|
}
|
19
|
+
if (instance && instance.root) {
|
20
|
+
const conditionTriggerComponent = instance.root.getComponent(conditionComponentPath);
|
21
|
+
if (conditionTriggerComponent
|
22
|
+
&& isSelectResourceWithObjectValue(conditionTriggerComponent.component)
|
23
|
+
&& conditionTriggerComponent.component?.template) {
|
24
|
+
if (!value || !_.isPlainObject(value)) {
|
25
|
+
return false;
|
26
|
+
}
|
27
|
+
const { template, valueProperty } = conditionTriggerComponent.component;
|
28
|
+
if (valueProperty === 'data') {
|
29
|
+
value = { data: value };
|
30
|
+
comparedValue = { data: comparedValue };
|
31
|
+
}
|
32
|
+
return _.every(getItemTemplateKeys(template) || [], k => _.isEqual(_.get(value, k), _.get(comparedValue, k)));
|
33
|
+
}
|
34
|
+
}
|
18
35
|
//special check for select boxes
|
19
36
|
if (_.isObject(value) && comparedValue && _.isString(comparedValue)) {
|
20
37
|
return value[comparedValue];
|
@@ -1,13 +1,12 @@
|
|
1
|
-
import
|
2
|
-
|
3
|
-
export default class IsNotEqualTo extends ConditionOperator {
|
1
|
+
import IsEqualTo from './IsEqualTo';
|
2
|
+
export default class IsNotEqualTo extends IsEqualTo {
|
4
3
|
static get operatorKey() {
|
5
4
|
return 'isNotEqual';
|
6
5
|
}
|
7
6
|
static get displayedName() {
|
8
7
|
return 'Is Not Equal To';
|
9
8
|
}
|
10
|
-
execute(
|
11
|
-
return !
|
9
|
+
execute(options) {
|
10
|
+
return !super.execute(options);
|
12
11
|
}
|
13
12
|
}
|
package/lib/mjs/utils/utils.js
CHANGED
@@ -394,6 +394,21 @@ export function unescapeHTML(str) {
|
|
394
394
|
const doc = new window.DOMParser().parseFromString(str, 'text/html');
|
395
395
|
return doc.documentElement.textContent;
|
396
396
|
}
|
397
|
+
/**
|
398
|
+
* Escape HTML characters like <, >, & and etc.
|
399
|
+
* @param str
|
400
|
+
* @returns {string}
|
401
|
+
*/
|
402
|
+
export function escapeHTML(html) {
|
403
|
+
if (html) {
|
404
|
+
return html.replace(/&/g, '&')
|
405
|
+
.replace(/</g, '<')
|
406
|
+
.replace(/>/g, '>')
|
407
|
+
.replace(/"/g, '"')
|
408
|
+
.replace(/'/g, ''');
|
409
|
+
}
|
410
|
+
return '';
|
411
|
+
}
|
397
412
|
/**
|
398
413
|
* Make HTML element from string
|
399
414
|
* @param str
|
@@ -1407,3 +1422,23 @@ export const interpolateErrors = (component, errors, interpolateFn) => {
|
|
1407
1422
|
return { ...error, message: unescapeHTML(interpolateFn(toInterpolate, context)), context: { ...context } };
|
1408
1423
|
});
|
1409
1424
|
};
|
1425
|
+
export function getItemTemplateKeys(template) {
|
1426
|
+
const templateKeys = [];
|
1427
|
+
if (!template) {
|
1428
|
+
return templateKeys;
|
1429
|
+
}
|
1430
|
+
const keys = template.match(/({{\s*(.*?)\s*}})/g);
|
1431
|
+
if (keys) {
|
1432
|
+
keys.forEach((key) => {
|
1433
|
+
const propKey = key.match(/{{\s*item\.(.*?)\s*}}/);
|
1434
|
+
if (propKey && propKey.length > 1) {
|
1435
|
+
templateKeys.push(propKey[1]);
|
1436
|
+
}
|
1437
|
+
});
|
1438
|
+
}
|
1439
|
+
return templateKeys;
|
1440
|
+
}
|
1441
|
+
export function isSelectResourceWithObjectValue(comp = {}) {
|
1442
|
+
const { reference, dataSrc, valueProperty } = comp;
|
1443
|
+
return reference || (dataSrc === 'resource' && (!valueProperty || valueProperty === 'data'));
|
1444
|
+
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@formio/js",
|
3
|
-
"version": "5.0.0-rc.
|
3
|
+
"version": "5.0.0-rc.38",
|
4
4
|
"description": "JavaScript powered Forms with JSON Form Builder",
|
5
5
|
"main": "lib/cjs/index.js",
|
6
6
|
"exports": {
|
@@ -86,7 +86,7 @@
|
|
86
86
|
"dependencies": {
|
87
87
|
"@formio/bootstrap": "^3.0.0-rc.20",
|
88
88
|
"@formio/choices.js": "^10.2.0",
|
89
|
-
"@formio/core": "^2.0.0-rc.
|
89
|
+
"@formio/core": "^2.0.0-rc.6",
|
90
90
|
"@formio/text-mask-addons": "^3.8.0-formio.2",
|
91
91
|
"@formio/vanilla-text-mask": "^5.1.1-formio.1",
|
92
92
|
"abortcontroller-polyfill": "^1.7.5",
|
package/types/formio.d.ts
CHANGED
@@ -159,6 +159,10 @@ export declare class Formio {
|
|
159
159
|
* Stores all of the libraries lazy loaded with ```Formio.requireLibrary``` method.
|
160
160
|
*/
|
161
161
|
static libraries: any;
|
162
|
+
/**
|
163
|
+
* The Library license for this application.
|
164
|
+
*/
|
165
|
+
static license: string;
|
162
166
|
/**
|
163
167
|
* A direct interface to the Form.io fetch polyfill.
|
164
168
|
*/
|