@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.
Files changed (65) hide show
  1. package/dist/fonts/bootstrap-icons.woff +0 -0
  2. package/dist/fonts/bootstrap-icons.woff2 +0 -0
  3. package/dist/formio.embed.js +1 -1
  4. package/dist/formio.embed.min.js +1 -1
  5. package/dist/formio.embed.min.js.LICENSE.txt +1 -1
  6. package/dist/formio.form.js +854 -133
  7. package/dist/formio.form.min.js +1 -1
  8. package/dist/formio.form.min.js.LICENSE.txt +5 -3
  9. package/dist/formio.full.css +4 -4
  10. package/dist/formio.full.js +828 -137
  11. package/dist/formio.full.min.css +3 -3
  12. package/dist/formio.full.min.js +1 -1
  13. package/dist/formio.full.min.js.LICENSE.txt +5 -3
  14. package/dist/formio.js +5 -5
  15. package/dist/formio.min.js +1 -1
  16. package/dist/formio.min.js.LICENSE.txt +1 -1
  17. package/dist/formio.utils.js +25 -14
  18. package/dist/formio.utils.min.js +1 -1
  19. package/dist/formio.utils.min.js.LICENSE.txt +5 -3
  20. package/lib/cjs/Element.js +2 -2
  21. package/lib/cjs/Embed.js +19 -14
  22. package/lib/cjs/Formio.js +3 -0
  23. package/lib/cjs/components/_classes/component/Component.js +21 -7
  24. package/lib/cjs/components/_classes/component/fixtures/comp5.js +2 -2
  25. package/lib/cjs/components/_classes/list/ListComponent.js +5 -12
  26. package/lib/cjs/components/_classes/nested/NestedComponent.js +17 -9
  27. package/lib/cjs/components/columns/editForm/Columns.edit.display.js +1 -1
  28. package/lib/cjs/components/editgrid/EditGrid.js +11 -4
  29. package/lib/cjs/components/form/Form.js +3 -1
  30. package/lib/cjs/components/html/HTML.js +2 -2
  31. package/lib/cjs/components/html/fixtures/comp3.js +31 -0
  32. package/lib/cjs/components/html/fixtures/index.js +3 -1
  33. package/lib/cjs/components/radio/Radio.js +2 -1
  34. package/lib/cjs/components/radio/fixtures/comp10.js +23 -0
  35. package/lib/cjs/components/radio/fixtures/index.js +3 -1
  36. package/lib/cjs/components/recaptcha/ReCaptcha.js +3 -0
  37. package/lib/cjs/components/select/Select.js +84 -9
  38. package/lib/cjs/components/survey/Survey.js +10 -0
  39. package/lib/cjs/utils/conditionOperators/IsEqualTo.js +19 -1
  40. package/lib/cjs/utils/conditionOperators/IsNotEqualTo.js +4 -5
  41. package/lib/cjs/utils/utils.js +40 -2
  42. package/lib/mjs/Element.js +2 -2
  43. package/lib/mjs/Embed.js +17 -14
  44. package/lib/mjs/Formio.js +3 -0
  45. package/lib/mjs/components/_classes/component/Component.js +24 -8
  46. package/lib/mjs/components/_classes/component/fixtures/comp5.js +2 -2
  47. package/lib/mjs/components/_classes/list/ListComponent.js +5 -12
  48. package/lib/mjs/components/_classes/nested/NestedComponent.js +17 -9
  49. package/lib/mjs/components/columns/editForm/Columns.edit.display.js +1 -1
  50. package/lib/mjs/components/editgrid/EditGrid.js +11 -4
  51. package/lib/mjs/components/form/Form.js +3 -1
  52. package/lib/mjs/components/html/HTML.js +2 -2
  53. package/lib/mjs/components/html/fixtures/comp3.js +29 -0
  54. package/lib/mjs/components/html/fixtures/index.js +2 -1
  55. package/lib/mjs/components/radio/Radio.js +2 -1
  56. package/lib/mjs/components/radio/fixtures/comp10.js +21 -0
  57. package/lib/mjs/components/radio/fixtures/index.js +2 -1
  58. package/lib/mjs/components/recaptcha/ReCaptcha.js +3 -0
  59. package/lib/mjs/components/select/Select.js +83 -10
  60. package/lib/mjs/components/survey/Survey.js +10 -0
  61. package/lib/mjs/utils/conditionOperators/IsEqualTo.js +18 -1
  62. package/lib/mjs/utils/conditionOperators/IsNotEqualTo.js +4 -5
  63. package/lib/mjs/utils/utils.js +35 -0
  64. package/package.json +2 -2
  65. 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
- return { ...classComp, type: 'select' };
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(updateComponent, debounceTimeout));
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', () => this.update());
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.bind(this)).join(', ')
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(this.itemTemplate(item)));
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
- ? this.itemTemplate(value)
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 ConditionOperator from './ConditionOperator';
2
- import _ from 'lodash';
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({ value, comparedValue }) {
11
- return !_.isEqual(value, comparedValue);
9
+ execute(options) {
10
+ return !super.execute(options);
12
11
  }
13
12
  }
@@ -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, '&amp;')
405
+ .replace(/</g, '&lt;')
406
+ .replace(/>/g, '&gt;')
407
+ .replace(/"/g, '&quot;')
408
+ .replace(/'/g, '&#39;');
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.36",
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.2",
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
  */