@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.
- 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 +853 -132
- 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 +827 -136
- 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 +4 -4
- 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 +9 -6
- 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 +9 -6
- 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.39",
|
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
|
*/
|