neo.mjs 5.4.8 → 5.4.10

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.
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='5.4.8'
23
+ * @member {String} version='5.4.10'
24
24
  */
25
- version: '5.4.8'
25
+ version: '5.4.10'
26
26
  }
27
27
 
28
28
  /**
@@ -5,6 +5,10 @@ Neo.overwrites = {
5
5
  Text: {
6
6
  labelPosition_ : 'inline',
7
7
  showOptionalText_: true
8
+ },
9
+ ZipCode: {
10
+ maxLength: 5,
11
+ minLength: 5
8
12
  }
9
13
  }
10
14
  }
@@ -1,5 +1,5 @@
1
1
  import FormPageContainer from '../FormPageContainer.mjs';
2
- import TextField from '../../../../src/form/field/Text.mjs';
2
+ import ZipCodeField from '../../../../src/form/field/ZipCode.mjs';
3
3
 
4
4
  /**
5
5
  * @class Form.view.pages.Page11
@@ -16,13 +16,15 @@ class Page11 extends FormPageContainer {
16
16
  * @member {Object[]} items
17
17
  */
18
18
  items: [{
19
- module : TextField,
20
- labelText: 'Page 11 Field 1',
21
- name : 'page11field1'
19
+ module : ZipCodeField,
20
+ labelText: 'Munich',
21
+ name : 'page11.field1',
22
+ required : true,
23
+ value : '80796'
22
24
  }, {
23
- module : TextField,
25
+ module : ZipCodeField,
24
26
  labelText: 'Page 11 Field 2',
25
- name : 'page11field2'
27
+ name : 'page11.field2'
26
28
  }]
27
29
  }
28
30
  }
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='5.4.8'
23
+ * @member {String} version='5.4.10'
24
24
  */
25
- version: '5.4.8'
25
+ version: '5.4.10'
26
26
  }
27
27
 
28
28
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "5.4.8",
3
+ "version": "5.4.10",
4
4
  "description": "The webworkers driven UI framework",
5
5
  "type": "module",
6
6
  "repository": {
@@ -47,19 +47,19 @@
47
47
  "autoprefixer": "^10.4.14",
48
48
  "chalk": "^5.2.0",
49
49
  "clean-webpack-plugin": "^4.0.0",
50
- "commander": "^10.0.0",
50
+ "commander": "^10.0.1",
51
51
  "cssnano": "^6.0.0",
52
52
  "envinfo": "^7.8.1",
53
53
  "fs-extra": "^11.1.1",
54
54
  "highlightjs-line-numbers.js": "^2.8.0",
55
- "inquirer": "^9.1.5",
55
+ "inquirer": "^9.2.0",
56
56
  "neo-jsdoc": "^1.0.1",
57
57
  "neo-jsdoc-x": "^1.0.5",
58
- "postcss": "^8.4.21",
59
- "sass": "^1.61.0",
60
- "webpack": "^5.78.0",
61
- "webpack-cli": "^5.0.1",
62
- "webpack-dev-server": "4.13.2",
58
+ "postcss": "^8.4.23",
59
+ "sass": "^1.62.0",
60
+ "webpack": "^5.80.0",
61
+ "webpack-cli": "^5.0.2",
62
+ "webpack-dev-server": "4.13.3",
63
63
  "webpack-hook-plugin": "^1.0.7",
64
64
  "webpack-node-externals": "^3.0.0"
65
65
  },
@@ -16,7 +16,7 @@
16
16
  {"id": 12, "cardIndex": 8, "isHeader": false, "isValid": null, "name": "HiddenFields"},
17
17
  {"id": 13, "cardIndex": 9, "isHeader": false, "isValid": null, "name": "SelectFields"},
18
18
  {"id": 14, "cardIndex": null, "isHeader": true, "isValid": null, "name": "4. Optional data"},
19
- {"id": 15, "cardIndex": 10, "isHeader": false, "isValid": null, "name": "Page 11"},
19
+ {"id": 15, "cardIndex": 10, "isHeader": false, "isValid": null, "name": "ZipCodeFields"},
20
20
  {"id": 16, "cardIndex": 11, "isHeader": false, "isValid": null, "name": "Page 12"},
21
21
  {"id": 17, "cardIndex": 12, "isHeader": false, "isValid": null, "name": "Page 13"},
22
22
  {"id": 18, "cardIndex": 13, "isHeader": false, "isValid": null, "name": "Page 14"}
@@ -63,21 +63,23 @@
63
63
  border-color: v(textfield-border-color-invalid);
64
64
  }
65
65
 
66
- .neo-label-wrapper {
67
- .neo-center-border, .neo-left-border, .neo-right-border {
68
- border-bottom-color: v(textfield-border-color-invalid);
69
- }
66
+ &.label-inline {
67
+ .neo-label-wrapper {
68
+ .neo-center-border, .neo-left-border, .neo-right-border {
69
+ border-bottom-color: v(textfield-border-color-invalid);
70
+ }
70
71
 
71
- .neo-left-border, .neo-right-border {
72
- border-top-color: v(textfield-border-color-invalid);
73
- }
72
+ .neo-left-border, .neo-right-border {
73
+ border-top-color: v(textfield-border-color-invalid);
74
+ }
74
75
 
75
- .neo-left-border {
76
- border-left-color: v(textfield-border-color-invalid);
77
- }
76
+ .neo-left-border {
77
+ border-left-color: v(textfield-border-color-invalid);
78
+ }
78
79
 
79
- .neo-right-border {
80
- border-right-color: v(textfield-border-color-invalid);
80
+ .neo-right-border {
81
+ border-right-color: v(textfield-border-color-invalid);
82
+ }
81
83
  }
82
84
  }
83
85
  }
@@ -237,12 +237,12 @@ const DefaultConfig = {
237
237
  useVdomWorker: true,
238
238
  /**
239
239
  * buildScripts/injectPackageVersion.mjs will update this value
240
- * @default '5.4.8'
240
+ * @default '5.4.10'
241
241
  * @memberOf! module:Neo
242
242
  * @name config.version
243
243
  * @type String
244
244
  */
245
- version: '5.4.8'
245
+ version: '5.4.10'
246
246
  };
247
247
 
248
248
  Object.assign(DefaultConfig, {
@@ -259,11 +259,11 @@ class Base extends CoreBase {
259
259
  */
260
260
  role_: null,
261
261
  /**
262
- * Set this to true for bulk updates.
263
- * Ensure to set it back to false afterwards.
264
- * @member {Boolean} silentVdomUpdate=false
262
+ * Set this to true for bulk updates. Ensure to set it back to false afterwards.
263
+ * Internally the value will get saved as a number to ensure that child methods won't stop the silent mode too early.
264
+ * @member {Boolean} silentVdomUpdate_=false
265
265
  */
266
- silentVdomUpdate: false,
266
+ silentVdomUpdate_: false,
267
267
  /**
268
268
  * Style attributes added to this vdom root. see: getVdomRoot()
269
269
  * @member {Object} style_=null
@@ -982,6 +982,21 @@ class Base extends CoreBase {
982
982
  return value;
983
983
  }
984
984
 
985
+ /**
986
+ * Triggered before the silentVdomUpdate config gets changed.
987
+ * @param {Boolean} value
988
+ * @param {Boolean} oldValue
989
+ * @returns {Number}
990
+ * @protected
991
+ */
992
+ beforeSetSilentVdomUpdate(value, oldValue) {
993
+ if (value === true) {
994
+ return Neo.isNumber(oldValue) ? (oldValue + 1) : 1
995
+ }
996
+
997
+ return (Neo.isNumber(oldValue) && oldValue > 0) ? (oldValue - 1) : 0
998
+ }
999
+
985
1000
  /**
986
1001
  * Changes the value of a vdom object attribute or removes it in case it has no value
987
1002
  * @param {String} key
@@ -78,9 +78,13 @@ class CheckBox extends Base {
78
78
  /**
79
79
  * In case the CheckBox does not belong to a group (multiple fields with the same name),
80
80
  * you can pass a custom value for the unchecked state.
81
- * @member {*} uncheckedValue=null
81
+ * @member {*} uncheckedValue=false
82
82
  */
83
- uncheckedValue: null,
83
+ uncheckedValue: false,
84
+ /**
85
+ * @member {Boolean|Number|String|null} value=true
86
+ */
87
+ value: true,
84
88
  /**
85
89
  * @member {String|null} valueLabelText_=null
86
90
  */
@@ -0,0 +1,30 @@
1
+ import Text from './Text.mjs';
2
+
3
+ /**
4
+ * An extended form.field.Text which uses an input type 'tel'
5
+ * @class Neo.form.field.Phone
6
+ * @extends Neo.form.field.Text
7
+ */
8
+ class Phone extends Text {
9
+ static config = {
10
+ /**
11
+ * @member {String} className='Neo.form.field.Phone'
12
+ * @protected
13
+ */
14
+ className: 'Neo.form.field.Phone',
15
+ /**
16
+ * @member {String} ntype='phonefield'
17
+ * @protected
18
+ */
19
+ ntype: 'phonefield',
20
+ /**
21
+ * Value for the inputType_ textfield config
22
+ * @member {String} inputType='tel'
23
+ */
24
+ inputType: 'tel'
25
+ }
26
+ }
27
+
28
+ Neo.applyClassConfig(Phone);
29
+
30
+ export default Phone;
@@ -74,12 +74,17 @@ class Text extends Base {
74
74
  */
75
75
  error_: null,
76
76
  /**
77
- * data passes maxLength, minLength & valueLength properties
77
+ * data passes inputPattern, maxLength, minLength & valueLength properties
78
+ * @member {Function} errorTextInputPattern=data=>`Input pattern violation: ${data.inputPattern}`
79
+ */
80
+ errorTextInputPattern: data => `Input pattern violation: ${data.inputPattern}`,
81
+ /**
82
+ * data passes inputPattern, maxLength, minLength & valueLength properties
78
83
  * @member {Function} errorTextMaxLength=data=>`Max length violation: ${valueLength} / ${maxLength}`
79
84
  */
80
85
  errorTextMaxLength: data => `Max length violation: ${data.valueLength} / ${data.maxLength}`,
81
86
  /**
82
- * data passes maxLength, minLength & valueLength properties
87
+ * data passes inputPattern, maxLength, minLength & valueLength properties
83
88
  * @member {Function} errorTextMinLength=data=>`Min length violation: ${data.valueLength} / ${data.minLength}`
84
89
  */
85
90
  errorTextMinLength: data => `Min length violation: ${data.valueLength} / ${data.minLength}`,
@@ -92,7 +97,7 @@ class Text extends Base {
92
97
  */
93
98
  hideLabel_: false,
94
99
  /**
95
- * @member {RegExp|null} inputPattern=null
100
+ * @member {RegExp|null} inputPattern_=null
96
101
  */
97
102
  inputPattern_: null,
98
103
  /**
@@ -330,7 +335,12 @@ class Text extends Base {
330
335
  * @protected
331
336
  */
332
337
  afterSetInputPattern(value, oldValue) {
338
+ if (value) {
339
+ value = value.toString();
340
+ value = value.substring(1, value.length - 1);
341
+ }
333
342
 
343
+ this.changeInputElKey('pattern', value);
334
344
  }
335
345
 
336
346
  /**
@@ -573,9 +583,15 @@ class Text extends Base {
573
583
  afterSetRequired(value, oldValue) {
574
584
  let me = this;
575
585
 
576
- me.validate(); // silent
577
- me.changeInputElKey('required', value ? value : null, true); // silent update
578
- me.labelText = me.labelText; // triggers a vdom update
586
+ me.silentVdomUpdate = true;
587
+
588
+ me.validate(false);
589
+ me.changeInputElKey('required', value ? value : null);
590
+ me.labelText = me.labelText; // apply the optional text if needed
591
+
592
+ me.silentVdomUpdate = false;
593
+
594
+ me.update()
579
595
  }
580
596
 
581
597
  /**
@@ -1122,21 +1138,16 @@ class Text extends Base {
1122
1138
  * @protected
1123
1139
  */
1124
1140
  onInputValueChange(data) {
1125
- let me = this,
1126
- value = data.value,
1127
- oldValue = me.value,
1128
- vnode = VNodeUtil.findChildVnode(me.vnode, {nodeName: 'input'});
1141
+ let me = this,
1142
+ value = data.value,
1143
+ vnode = VNodeUtil.findChildVnode(me.vnode, {nodeName: 'input'});
1129
1144
 
1130
1145
  if (vnode) {
1131
1146
  // required for validation -> revert a wrong user input
1132
1147
  vnode.vnode.attributes.value = value;
1133
1148
  }
1134
1149
 
1135
- if (me.inputPattern && !me.inputPattern.test(value) ) {
1136
- me.afterSetValue(oldValue, value);
1137
- } else if (value !== oldValue) {
1138
- me.value = value;
1139
- }
1150
+ me.value = value;
1140
1151
  }
1141
1152
 
1142
1153
  /**
@@ -1253,7 +1264,7 @@ class Text extends Base {
1253
1264
  isValid = !value || value === '';
1254
1265
 
1255
1266
  NeoArray[!isValid ? 'add' : 'remove'](cls, 'neo-invalid');
1256
- me[silent ? '_cls' : 'cls'] = cls;
1267
+ me.cls = cls;
1257
1268
 
1258
1269
  errorNode = VDomUtil.findVdomChild(me.vdom, {cls: 'neo-textfield-error'}).vdom;
1259
1270
 
@@ -1313,16 +1324,17 @@ class Text extends Base {
1313
1324
  * @returns {Boolean} Returns true in case there are no client-side errors
1314
1325
  */
1315
1326
  validate(silent=true) {
1316
- let me = this,
1317
- errorField = silent ? '_error' : 'error',
1318
- maxLength = me.maxLength,
1319
- minLength = me.minLength,
1320
- required = me.required,
1321
- returnValue = true,
1322
- value = me.value,
1323
- valueLength = value?.toString().length,
1324
- isEmpty = value !== 0 && (!value || valueLength < 1),
1325
- errorParam = {maxLength, minLength, valueLength},
1327
+ let me = this,
1328
+ errorField = silent ? '_error' : 'error',
1329
+ maxLength = me.maxLength,
1330
+ minLength = me.minLength,
1331
+ required = me.required,
1332
+ returnValue = true,
1333
+ value = me.value,
1334
+ valueLength = value?.toString().length,
1335
+ inputPattern = me.inputPattern,
1336
+ isEmpty = value !== 0 && (!value || valueLength < 1),
1337
+ errorParam = {inputPattern, maxLength, minLength, valueLength},
1326
1338
  errorText;
1327
1339
 
1328
1340
  if (!silent) {
@@ -1337,7 +1349,9 @@ class Text extends Base {
1337
1349
  me[errorField] = errorText;
1338
1350
  returnValue = false;
1339
1351
  }
1340
- } else if (required && isEmpty) {
1352
+ }
1353
+
1354
+ if (required && isEmpty) {
1341
1355
  me[errorField] = me.errorTextRequired;
1342
1356
  returnValue = false;
1343
1357
  } else if (Neo.isNumber(maxLength) && valueLength > maxLength) {
@@ -1350,6 +1364,11 @@ class Text extends Base {
1350
1364
  me[errorField] = me.errorTextMinLength(errorParam);
1351
1365
  returnValue = false;
1352
1366
  }
1367
+ } else if (inputPattern && !inputPattern.test(value)) {
1368
+ if (required || !isEmpty) {
1369
+ me[errorField] = me.errorTextInputPattern(errorParam);
1370
+ returnValue = false;
1371
+ }
1353
1372
  }
1354
1373
 
1355
1374
  if (returnValue) {
@@ -0,0 +1,26 @@
1
+ import Text from './Text.mjs';
2
+
3
+ /**
4
+ * An extended form.field.Text which uses an input pattern to limit the amount of character which users can enter.
5
+ * The first version will only support numbers. Feel free to open feature requests.
6
+ * @class Neo.form.field.ZipCode
7
+ * @extends Neo.form.field.Text
8
+ */
9
+ class ZipCode extends Text {
10
+ static config = {
11
+ /**
12
+ * @member {String} className='Neo.form.field.ZipCode'
13
+ * @protected
14
+ */
15
+ className: 'Neo.form.field.ZipCode',
16
+ /**
17
+ * @member {String} ntype='zipcodefield'
18
+ * @protected
19
+ */
20
+ ntype: 'zipcodefield'
21
+ }
22
+ }
23
+
24
+ Neo.applyClassConfig(ZipCode);
25
+
26
+ export default ZipCode;