neo.mjs 6.12.0 → 6.12.1
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/apps/ServiceWorker.mjs +2 -2
- package/examples/ServiceWorker.mjs +2 -2
- package/package.json +2 -2
- package/src/DefaultConfig.mjs +2 -2
- package/src/form/field/Select.mjs +115 -102
- package/src/list/Base.mjs +36 -10
- package/src/selection/ListModel.mjs +4 -2
package/apps/ServiceWorker.mjs
CHANGED
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "neo.mjs",
|
3
|
-
"version": "6.12.
|
3
|
+
"version": "6.12.1",
|
4
4
|
"description": "The webworkers driven UI framework",
|
5
5
|
"type": "module",
|
6
6
|
"repository": {
|
@@ -62,7 +62,7 @@
|
|
62
62
|
"url": "^0.11.3",
|
63
63
|
"webpack": "^5.90.1",
|
64
64
|
"webpack-cli": "^5.1.4",
|
65
|
-
"webpack-dev-server": "
|
65
|
+
"webpack-dev-server": "5.0.1",
|
66
66
|
"webpack-hook-plugin": "^1.0.7",
|
67
67
|
"webpack-node-externals": "^3.0.0"
|
68
68
|
},
|
package/src/DefaultConfig.mjs
CHANGED
@@ -236,12 +236,12 @@ const DefaultConfig = {
|
|
236
236
|
useVdomWorker: true,
|
237
237
|
/**
|
238
238
|
* buildScripts/injectPackageVersion.mjs will update this value
|
239
|
-
* @default '6.12.
|
239
|
+
* @default '6.12.1'
|
240
240
|
* @memberOf! module:Neo
|
241
241
|
* @name config.version
|
242
242
|
* @type String
|
243
243
|
*/
|
244
|
-
version: '6.12.
|
244
|
+
version: '6.12.1'
|
245
245
|
};
|
246
246
|
|
247
247
|
Object.assign(DefaultConfig, {
|
@@ -32,6 +32,10 @@ class Select extends Picker {
|
|
32
32
|
* @protected
|
33
33
|
*/
|
34
34
|
ntype: 'selectfield',
|
35
|
+
/**
|
36
|
+
* @member {String|Number|null} activeRecordId=null
|
37
|
+
*/
|
38
|
+
activeRecordId: null,
|
35
39
|
/**
|
36
40
|
* @member {String[]} baseCls=['neo-selectfield','neo-pickerfield','neo-textfield']
|
37
41
|
*/
|
@@ -40,6 +44,12 @@ class Select extends Picker {
|
|
40
44
|
* @member {String} displayField='name'
|
41
45
|
*/
|
42
46
|
displayField: 'name',
|
47
|
+
/**
|
48
|
+
* The millisecond time to delay between input field mutation and applying the input field's
|
49
|
+
* new value to the filter
|
50
|
+
* @member {Number} filterDelay=300
|
51
|
+
*/
|
52
|
+
filterDelay : 300,
|
43
53
|
/**
|
44
54
|
* @member {String} filterOperator_='like'
|
45
55
|
*/
|
@@ -50,10 +60,6 @@ class Select extends Picker {
|
|
50
60
|
* @member {Boolean} forceSelection=false
|
51
61
|
*/
|
52
62
|
forceSelection: false,
|
53
|
-
/**
|
54
|
-
* @member {String|Number|null} activeRecordId=null
|
55
|
-
*/
|
56
|
-
activeRecordId: null,
|
57
63
|
/**
|
58
64
|
* Additional used keys for the selection model
|
59
65
|
* @member {Object} keys
|
@@ -116,13 +122,7 @@ class Select extends Picker {
|
|
116
122
|
* which you want to submit instead
|
117
123
|
* @member {Number|String} valueField='id'
|
118
124
|
*/
|
119
|
-
valueField: 'id'
|
120
|
-
/**
|
121
|
-
* The millisecond time to delay between input field mutation and applying the input field's
|
122
|
-
* new value to the filter
|
123
|
-
* @member {Number} filterDelay=300
|
124
|
-
*/
|
125
|
-
filterDelay : 300
|
125
|
+
valueField: 'id'
|
126
126
|
}
|
127
127
|
|
128
128
|
/**
|
@@ -143,7 +143,7 @@ class Select extends Picker {
|
|
143
143
|
* @param {Object} oldValue
|
144
144
|
* @protected
|
145
145
|
*/
|
146
|
-
afterSetRecord(value) {
|
146
|
+
afterSetRecord(value, oldValue) {
|
147
147
|
if (this._picker?.isVisible) {
|
148
148
|
let me = this,
|
149
149
|
selectionModel = me.list?.selectionModel;
|
@@ -252,7 +252,7 @@ class Select extends Picker {
|
|
252
252
|
}
|
253
253
|
}
|
254
254
|
|
255
|
-
return ClassSystemUtil.beforeSetInstance(value, Store)
|
255
|
+
return ClassSystemUtil.beforeSetInstance(value, Store)
|
256
256
|
}
|
257
257
|
|
258
258
|
/**
|
@@ -305,16 +305,15 @@ class Select extends Picker {
|
|
305
305
|
module : List,
|
306
306
|
appName : me.appName,
|
307
307
|
displayField : me.displayField,
|
308
|
-
role : 'listbox',
|
309
308
|
itemRole : 'option',
|
309
|
+
navigator : {eventSource : me.getInputElId()},
|
310
310
|
parentId : me.id,
|
311
|
-
|
312
|
-
eventSource : me.getInputElId()
|
313
|
-
},
|
311
|
+
role : 'listbox',
|
314
312
|
selectionModel : {stayInList: false},
|
315
313
|
store : me.store,
|
316
314
|
...me.listConfig
|
317
315
|
});
|
316
|
+
|
318
317
|
me.getInputEl()['aria-controls'] = me.list.id;
|
319
318
|
|
320
319
|
me.list.addDomListeners({
|
@@ -323,15 +322,76 @@ class Select extends Picker {
|
|
323
322
|
scope : me
|
324
323
|
}
|
325
324
|
});
|
325
|
+
|
326
326
|
me.list.selectionModel.on({
|
327
|
-
selectionChange : me.onListItemSelectionChange,
|
328
327
|
noChange : me.onListItemSelectionNoChange,
|
328
|
+
selectionChange : me.onListItemSelectionChange,
|
329
329
|
scope : me
|
330
330
|
})
|
331
331
|
|
332
332
|
return me.list;
|
333
333
|
}
|
334
334
|
|
335
|
+
/**
|
336
|
+
* All routes which expect to open the picker route through here. This updates the
|
337
|
+
* filter and ensures that the picker is visible and reflecting the state of the filter.
|
338
|
+
*
|
339
|
+
* Input event processing passes the current input field value in as the filter value.
|
340
|
+
*
|
341
|
+
* Invocation of the expand trigger passes `null` so as to clear filtering.
|
342
|
+
* @private
|
343
|
+
* @param {String|null} value The value to filter the picker by
|
344
|
+
*/
|
345
|
+
doFilter(value) {
|
346
|
+
let me = this,
|
347
|
+
filter = me.store.getFilter(me.displayField),
|
348
|
+
{
|
349
|
+
record,
|
350
|
+
picker
|
351
|
+
} = me;
|
352
|
+
|
353
|
+
if (filter) {
|
354
|
+
filter.value = value;
|
355
|
+
}
|
356
|
+
|
357
|
+
// Filter resulting in something to show
|
358
|
+
if (me.store.getCount()) {
|
359
|
+
me.getPicker().hidden = false;
|
360
|
+
|
361
|
+
// List might not exist until the picker is created
|
362
|
+
const
|
363
|
+
{ list } = me,
|
364
|
+
{ selectionModel } = list;
|
365
|
+
|
366
|
+
// On show, set the active item to be the current selected record or the first
|
367
|
+
if (record) {
|
368
|
+
// We do not want to hear back about our own selection
|
369
|
+
selectionModel.suspendEvents = true;
|
370
|
+
selectionModel.select(record);
|
371
|
+
selectionModel.suspendEvents = false;
|
372
|
+
}
|
373
|
+
setTimeout(() => {
|
374
|
+
list.activeIndex = me.record || 0;
|
375
|
+
}, 100)
|
376
|
+
}
|
377
|
+
// Filtered down to nothing - hide picker if it has been created.
|
378
|
+
else if (picker) {
|
379
|
+
picker._hidden = true;
|
380
|
+
}
|
381
|
+
}
|
382
|
+
|
383
|
+
/**
|
384
|
+
* @param {Object} data
|
385
|
+
*/
|
386
|
+
filterOnInput(data) {
|
387
|
+
if (data.value) {
|
388
|
+
this.doFilter(data.value);
|
389
|
+
}
|
390
|
+
else if (this.picker) {
|
391
|
+
this.picker?.hide();
|
392
|
+
}
|
393
|
+
}
|
394
|
+
|
335
395
|
/**
|
336
396
|
* Overrides form.field.Base
|
337
397
|
* @param {*} value
|
@@ -383,7 +443,7 @@ class Select extends Picker {
|
|
383
443
|
|
384
444
|
/**
|
385
445
|
* Returns the first selected record or null
|
386
|
-
* returns {Object}
|
446
|
+
* @returns {Object}
|
387
447
|
*/
|
388
448
|
getRecord() {
|
389
449
|
let list = this.list,
|
@@ -401,13 +461,17 @@ class Select extends Picker {
|
|
401
461
|
return me.record?.[me.valueField] || me.value
|
402
462
|
}
|
403
463
|
|
464
|
+
/**
|
465
|
+
*
|
466
|
+
*/
|
404
467
|
onConstructed() {
|
405
468
|
const inputEl = this.getInputEl();
|
406
469
|
|
407
|
-
inputEl['aria-
|
408
|
-
inputEl['aria-
|
409
|
-
inputEl['aria-
|
410
|
-
|
470
|
+
inputEl['aria-activedescendant'] = '';
|
471
|
+
inputEl['aria-expanded'] = false;
|
472
|
+
inputEl['aria-haspopup'] = 'listbox';
|
473
|
+
|
474
|
+
super.onConstructed(...arguments)
|
411
475
|
}
|
412
476
|
|
413
477
|
/**
|
@@ -439,15 +503,6 @@ class Select extends Picker {
|
|
439
503
|
super.onFocusLeave(data)
|
440
504
|
}
|
441
505
|
|
442
|
-
filterOnInput(data) {
|
443
|
-
if (data.value) {
|
444
|
-
this.doFilter(data.value);
|
445
|
-
}
|
446
|
-
else if (this.picker) {
|
447
|
-
this.picker?.hide();
|
448
|
-
}
|
449
|
-
}
|
450
|
-
|
451
506
|
/**
|
452
507
|
* @param {Object} data
|
453
508
|
* @protected
|
@@ -469,17 +524,6 @@ class Select extends Picker {
|
|
469
524
|
}
|
470
525
|
}
|
471
526
|
|
472
|
-
onPickerHiddenChange({ value }) {
|
473
|
-
const inputEl = this.getInputEl();
|
474
|
-
|
475
|
-
super.onPickerHiddenChange(...arguments);
|
476
|
-
if (value) {
|
477
|
-
inputEl['aria-activedescendant'] = '';
|
478
|
-
}
|
479
|
-
inputEl['aria-expanded'] = !value;
|
480
|
-
this.update();
|
481
|
-
}
|
482
|
-
|
483
527
|
// TODO:
|
484
528
|
// When we are using a `Collection` as our `valueCollection`, and that `Collection` is the
|
485
529
|
// `items` of the List's `selectionModel`, then this will be `onValueCollectionChange`,
|
@@ -541,6 +585,34 @@ class Select extends Picker {
|
|
541
585
|
}
|
542
586
|
}
|
543
587
|
|
588
|
+
/**
|
589
|
+
* @param {Object} data
|
590
|
+
*/
|
591
|
+
onPickerHiddenChange({ value }) {
|
592
|
+
const inputEl = this.getInputEl();
|
593
|
+
|
594
|
+
super.onPickerHiddenChange(...arguments);
|
595
|
+
if (value) {
|
596
|
+
inputEl['aria-activedescendant'] = '';
|
597
|
+
}
|
598
|
+
inputEl['aria-expanded'] = !value;
|
599
|
+
this.update();
|
600
|
+
}
|
601
|
+
|
602
|
+
/**
|
603
|
+
*
|
604
|
+
*/
|
605
|
+
onPickerTriggerClick() {
|
606
|
+
let me = this;
|
607
|
+
|
608
|
+
if (me.picker?.isVisible) {
|
609
|
+
me.picker.hidden = true;
|
610
|
+
}
|
611
|
+
else if (!me.readOnly && !me.disabled) {
|
612
|
+
me.doFilter(null)
|
613
|
+
}
|
614
|
+
}
|
615
|
+
|
544
616
|
/**
|
545
617
|
* Selecting a record, if required
|
546
618
|
* @param {Object[]} items
|
@@ -587,65 +659,6 @@ class Select extends Picker {
|
|
587
659
|
me.list.selectItem(index);
|
588
660
|
}
|
589
661
|
|
590
|
-
onPickerTriggerClick() {
|
591
|
-
let me = this;
|
592
|
-
|
593
|
-
if (me.picker?.isVisible) {
|
594
|
-
me.picker.hidden = true;
|
595
|
-
}
|
596
|
-
else if (!me.readOnly && !me.disabled) {
|
597
|
-
me.doFilter(null)
|
598
|
-
}
|
599
|
-
}
|
600
|
-
|
601
|
-
/**
|
602
|
-
* All routes which expect to open the picker route through here. This updates the
|
603
|
-
* filter and ensures that the picker is visible and reflecting the state of the filter.
|
604
|
-
*
|
605
|
-
* Input event processing passes the current input field value in as the filter value.
|
606
|
-
*
|
607
|
-
* Invocation of the expand trigger passes `null` so as to clear filtering.
|
608
|
-
* @private
|
609
|
-
* @param {String}null} value The value to filter the picker by
|
610
|
-
*/
|
611
|
-
doFilter(value) {
|
612
|
-
let me = this,
|
613
|
-
filter = me.store.getFilter(me.displayField),
|
614
|
-
{
|
615
|
-
record,
|
616
|
-
picker
|
617
|
-
} = me;
|
618
|
-
|
619
|
-
if (filter) {
|
620
|
-
filter.value = value;
|
621
|
-
}
|
622
|
-
|
623
|
-
// Filter resulting in something to show
|
624
|
-
if (me.store.getCount()) {
|
625
|
-
me.getPicker().hidden = false;
|
626
|
-
|
627
|
-
// List might not exist until the picker is created
|
628
|
-
const
|
629
|
-
{ list } = me,
|
630
|
-
{ selectionModel } = list;
|
631
|
-
|
632
|
-
// On show, set the active item to be the current selected record or the first
|
633
|
-
if (record) {
|
634
|
-
// We do not want to hear back about our own selection
|
635
|
-
selectionModel.suspendEvents = true;
|
636
|
-
selectionModel.select(record);
|
637
|
-
selectionModel.suspendEvents = false;
|
638
|
-
}
|
639
|
-
setTimeout(() => {
|
640
|
-
list.activeIndex = me.record || 0;
|
641
|
-
}, 100)
|
642
|
-
}
|
643
|
-
// Filtered down to nothing - hide picker if it has been created.
|
644
|
-
else if (picker) {
|
645
|
-
picker._hidden = true;
|
646
|
-
}
|
647
|
-
}
|
648
|
-
|
649
662
|
/**
|
650
663
|
* @param {Boolean} [silent=false]
|
651
664
|
* @protected
|
package/src/list/Base.mjs
CHANGED
@@ -21,6 +21,7 @@ class Base extends Component {
|
|
21
21
|
*/
|
22
22
|
ntype: 'list',
|
23
23
|
/**
|
24
|
+
* Keeps track of the selected item index and allows bindings and programmatic changes
|
24
25
|
* @member {Number|null} activeIndex_=null
|
25
26
|
*/
|
26
27
|
activeIndex_: null,
|
@@ -63,6 +64,12 @@ class Base extends Component {
|
|
63
64
|
* @member {Object} dragZoneConfig=null
|
64
65
|
*/
|
65
66
|
dragZoneConfig: null,
|
67
|
+
/**
|
68
|
+
* Keeps track of the focussed item index and allows bindings and programmatic changes.
|
69
|
+
* You can either pass the index or the related record
|
70
|
+
* @member {Number|Object|null} focusIndex_=null
|
71
|
+
*/
|
72
|
+
focusIndex_: null,
|
66
73
|
/**
|
67
74
|
* In case we are using list item headers and want to bind list item indexes to e.g. a card layout
|
68
75
|
* for e.g. a sidenav, this config comes in handy.
|
@@ -178,15 +185,16 @@ class Base extends Component {
|
|
178
185
|
* @param {Number|null} oldValue
|
179
186
|
* @protected
|
180
187
|
*/
|
181
|
-
afterSetActiveIndex(value) {
|
182
|
-
let me
|
188
|
+
afterSetActiveIndex(value, oldValue) {
|
189
|
+
let me = this,
|
190
|
+
selectionModel = me.selectionModel;
|
183
191
|
|
184
192
|
if (Neo.isNumber(value)) {
|
193
|
+
selectionModel?.selectAt(value);
|
185
194
|
me.headerlessActiveIndex = me.getHeaderlessIndex(value)
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
Neo.main.addon.Navigator.navigateTo([me.getItemId(value[me.getKeyProperty()]), this.navigator])
|
195
|
+
} else if (Neo.isNumber(oldValue)) {
|
196
|
+
selectionModel.deselectAll();
|
197
|
+
me.headerlessActiveIndex = null
|
190
198
|
}
|
191
199
|
}
|
192
200
|
|
@@ -243,6 +251,22 @@ class Base extends Component {
|
|
243
251
|
}
|
244
252
|
}
|
245
253
|
|
254
|
+
/**
|
255
|
+
* Triggered after the focusIndex config got changed
|
256
|
+
* @param {Number|Object|null} value
|
257
|
+
* @param {Number|Object|null} oldValue
|
258
|
+
* @protected
|
259
|
+
*/
|
260
|
+
afterSetFocusIndex(value, oldValue) {
|
261
|
+
let me = this;
|
262
|
+
|
263
|
+
if (Neo.isNumber(value)) {
|
264
|
+
Neo.main.addon.Navigator.navigateTo([me.getHeaderlessIndex(value), me.navigator])
|
265
|
+
} else if (value) {
|
266
|
+
Neo.main.addon.Navigator.navigateTo([me.getItemId(value[me.getKeyProperty()]), me.navigator])
|
267
|
+
}
|
268
|
+
}
|
269
|
+
|
246
270
|
/**
|
247
271
|
* Triggered after the headerlessActiveIndex config got changed
|
248
272
|
* @param {Number} value
|
@@ -253,7 +277,7 @@ class Base extends Component {
|
|
253
277
|
let me = this;
|
254
278
|
|
255
279
|
if (Neo.isNumber(value)) {
|
256
|
-
me.activeIndex = me.store.getCount() ? value: null
|
280
|
+
me.activeIndex = me.store.getCount() ? me.getActiveIndex(value) : null
|
257
281
|
} else if (Neo.isNumber(oldValue)) {
|
258
282
|
me.activeIndex = null
|
259
283
|
}
|
@@ -755,14 +779,16 @@ class Base extends Component {
|
|
755
779
|
* @param {Number|String} item
|
756
780
|
*/
|
757
781
|
selectItem(item) {
|
758
|
-
|
782
|
+
let me = this;
|
783
|
+
|
784
|
+
if (!me.disableSelection) {
|
759
785
|
// Selecting index
|
760
786
|
if (Neo.isNumber(item)) {
|
761
|
-
|
787
|
+
me.selectionModel?.selectAt(item)
|
762
788
|
}
|
763
789
|
// Selecting record
|
764
790
|
else if (item) {
|
765
|
-
|
791
|
+
me.selectionModel?.selectAt(me.store.indexOf(item))
|
766
792
|
}
|
767
793
|
}
|
768
794
|
}
|
@@ -77,8 +77,10 @@ class ListModel extends Model {
|
|
77
77
|
{ view } = this,
|
78
78
|
{ store } = view;
|
79
79
|
|
80
|
-
data.record
|
81
|
-
view.
|
80
|
+
data.record = store.getAt(Math.min(data.activeIndex, store.getCount()));
|
81
|
+
view._focusIndex = store.indexOf(data.record); // silent update, no need to refocus
|
82
|
+
|
83
|
+
view.fire('itemNavigate', data)
|
82
84
|
}
|
83
85
|
|
84
86
|
/**
|