neo.mjs 6.10.10 → 6.10.11
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/apps/portal/view/learn/ContentTreeList.mjs +24 -12
- package/apps/portal/view/learn/LivePreview.mjs +28 -11
- package/buildScripts/createAppMinimal.mjs +391 -0
- package/examples/ServiceWorker.mjs +2 -2
- package/examples/button/base/neo-config.json +2 -1
- package/examples/list/chip/neo-config.json +1 -2
- package/package.json +72 -70
- package/resources/data/deck/learnneo/data/theBeatles.json +22 -0
- package/resources/data/deck/learnneo/p/2023-10-14T19-25-08-153Z.md +29 -20
- package/resources/data/deck/learnneo/p/ComponentModels.md +116 -1
- package/resources/data/deck/learnneo/p/Config.md +157 -0
- package/resources/data/deck/learnneo/p/DescribingTheUI.md +67 -1
- package/resources/data/deck/learnneo/p/Earthquakes.md +214 -0
- package/resources/data/deck/learnneo/p/Events.md +142 -1
- package/resources/data/deck/learnneo/p/Extending.md +116 -1
- package/resources/data/deck/learnneo/p/References.md +126 -0
- package/resources/data/deck/learnneo/p/TestLivePreview.md +28 -6
- package/resources/data/deck/learnneo/t.json +5 -6
- package/resources/data/deck/training/p/2022-12-27T21-55-30-948Z.md +1 -1
- package/resources/data/deck/training/p/2022-12-27T22-23-55-083Z.md +1 -1
- package/resources/data/deck/training/p/2022-12-29T16-00-13-223Z.md +1 -1
- package/resources/data/deck/training/p/2022-12-29T18-34-25-826Z.md +1 -1
- package/resources/data/deck/training/p/2022-12-29T18-36-56-893Z.md +1 -1
- package/resources/data/deck/training/p/2022-12-31T18-43-56-338Z.md +1 -1
- package/resources/data/deck/training/p/2022-12-31T18-51-50-682Z.md +1 -1
- package/resources/data/deck/training/p/2022-12-31T18-54-04-176Z.md +1 -1
- package/resources/data/deck/training/p/2023-01-01T17-49-18-429Z.md +1 -1
- package/resources/data/deck/training/p/2023-01-01T21-23-17-716Z.md +1 -1
- package/resources/data/deck/training/p/2023-01-06T23-21-31-685Z.md +1 -1
- package/resources/data/deck/training/p/2023-01-06T23-34-13-897Z.md +2 -2
- package/resources/data/deck/training/p/2023-01-06T23-46-36-687Z.md +1 -1
- package/resources/data/deck/training/p/2023-01-08T01-24-21-088Z.md +1 -1
- package/resources/data/deck/training/p/2023-01-08T02-11-26-333Z.md +2 -2
- package/resources/data/deck/training/p/2023-01-14T00-40-27-784Z.md +2 -2
- package/resources/data/deck/training/p/2023-07-31T00-37-21-927Z.md +2 -2
- package/resources/data/deck/training/p/2023-10-14T19-25-08-153Z.md +3 -3
- package/resources/scss/src/apps/newwebsite/Viewport.scss +32 -0
- package/resources/scss/src/apps/portal/learn/ContentView.scss +20 -4
- package/resources/scss/src/apps/portal/learn/LivePreview.scss +8 -0
- package/resources/scss/src/component/Base.scss +13 -4
- package/resources/scss/src/form/field/Select.scss +2 -5
- package/resources/scss/src/form/field/Text.scss +0 -1
- package/resources/scss/src/list/Base.scss +47 -2
- package/resources/scss/src/list/Chip.scss +10 -4
- package/resources/scss/theme-dark/list/Base.scss +11 -10
- package/resources/scss/theme-light/list/Base.scss +11 -10
- package/resources/scss/theme-neo-light/design-tokens/Components.scss +3 -0
- package/resources/scss/theme-neo-light/list/Base.scss +1 -0
- package/src/DefaultConfig.mjs +3 -3
- package/src/component/Base.mjs +7 -0
- package/src/container/Base.mjs +6 -12
- package/src/core/Base.mjs +5 -2
- package/src/data/Model.mjs +7 -0
- package/src/data/RecordFactory.mjs +5 -4
- package/src/form/field/Base.mjs +11 -0
- package/src/form/field/Picker.mjs +0 -1
- package/src/form/field/Select.mjs +208 -257
- package/src/form/field/Text.mjs +3 -3
- package/src/form/field/trigger/Base.mjs +5 -6
- package/src/layout/Flexbox.mjs +23 -31
- package/src/layout/HBox.mjs +1 -1
- package/src/layout/VBox.mjs +1 -1
- package/src/list/Base.mjs +64 -31
- package/src/main/DomAccess.mjs +55 -28
- package/src/main/DomEvents.mjs +2 -1
- package/src/main/DomUtils.mjs +66 -0
- package/src/main/addon/Navigator.mjs +332 -0
- package/src/manager/DomEvent.mjs +2 -1
- package/src/selection/ListModel.mjs +46 -82
- package/src/selection/Model.mjs +56 -33
- package/src/util/Array.mjs +5 -2
- package/src/util/Function.mjs +31 -0
- package/src/util/String.mjs +9 -0
- package/src/vdom/Helper.mjs +1 -2
- package/test/components/app.mjs +4 -3
- package/test/components/files/component/ChipList.mjs +125 -0
- package/test/components/files/form/field/Select.mjs +177 -2
- package/test/components/siesta.js +34 -1
@@ -4,9 +4,11 @@ import List from '../../list/Base.mjs';
|
|
4
4
|
import Picker from './Picker.mjs';
|
5
5
|
import Store from '../../data/Store.mjs';
|
6
6
|
import VDomUtil from '../../util/VDom.mjs';
|
7
|
-
|
7
|
+
import { buffer } from '../../util/Function.mjs';
|
8
8
|
/**
|
9
|
-
* Provides a dropdown list to select one or multiple items
|
9
|
+
* Provides a dropdown list to select one or multiple items.
|
10
|
+
*
|
11
|
+
* Conforms to ARIA accessiblity standards outlines in https://www.w3.org/WAI/ARIA/apg/patterns/combobox/
|
10
12
|
* @class Neo.form.field.Select
|
11
13
|
* @extends Neo.form.field.Picker
|
12
14
|
*/
|
@@ -49,19 +51,16 @@ class Select extends Picker {
|
|
49
51
|
*/
|
50
52
|
forceSelection: false,
|
51
53
|
/**
|
52
|
-
* @member {String|Number|null}
|
54
|
+
* @member {String|Number|null} activeRecordId=null
|
53
55
|
*/
|
54
|
-
|
56
|
+
activeRecordId: null,
|
55
57
|
/**
|
56
58
|
* Additional used keys for the selection model
|
57
59
|
* @member {Object} keys
|
58
60
|
*/
|
59
61
|
keys: {
|
60
62
|
Down : 'onKeyDownDown',
|
61
|
-
|
62
|
-
Escape: 'onKeyDownEscape',
|
63
|
-
Right : 'onKeyDownRight',
|
64
|
-
Up : 'onKeyDownUp'
|
63
|
+
Escape: 'onKeyDownEscape'
|
65
64
|
},
|
66
65
|
/**
|
67
66
|
* @member {String|null} lastManualInput=null
|
@@ -88,9 +87,9 @@ class Select extends Picker {
|
|
88
87
|
*/
|
89
88
|
record_: null,
|
90
89
|
/**
|
91
|
-
* @member {String|null} role='
|
90
|
+
* @member {String|null} role='combobox'
|
92
91
|
*/
|
93
|
-
role: '
|
92
|
+
role: 'combobox',
|
94
93
|
/**
|
95
94
|
* @member {Neo.data.Store|null} store_=null
|
96
95
|
*/
|
@@ -117,7 +116,13 @@ class Select extends Picker {
|
|
117
116
|
* which you want to submit instead
|
118
117
|
* @member {Number|String} valueField='id'
|
119
118
|
*/
|
120
|
-
valueField: 'id'
|
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
|
121
126
|
}
|
122
127
|
|
123
128
|
/**
|
@@ -126,34 +131,10 @@ class Select extends Picker {
|
|
126
131
|
construct(config) {
|
127
132
|
super.construct(config);
|
128
133
|
|
129
|
-
|
130
|
-
|
131
|
-
me.list = Neo.create({
|
132
|
-
module : List,
|
133
|
-
appName : me.appName,
|
134
|
-
displayField : me.displayField,
|
135
|
-
itemRole : 'option',
|
136
|
-
parentId : me.id,
|
137
|
-
selectionModel: {stayInList: false},
|
138
|
-
store : me.store,
|
139
|
-
...me.listConfig
|
140
|
-
});
|
141
|
-
|
142
|
-
me.list.keys._keys.push(
|
143
|
-
{fn: 'onContainerKeyDownEnter', key: 'Enter', scope: me.id},
|
144
|
-
{fn: 'onContainerKeyDownEscape', key: 'Escape', scope: me.id}
|
145
|
-
);
|
146
|
-
|
147
|
-
me.list.on({
|
148
|
-
createItems : me.onListCreateItems,
|
149
|
-
itemClick : me.onListItemClick,
|
150
|
-
itemNavigate : me.onListItemNavigate,
|
151
|
-
selectPostLastItem: me.onSelectPostLastItem,
|
152
|
-
selectPreFirstItem: me.onSelectPreFirstItem,
|
153
|
-
scope : me
|
154
|
-
});
|
134
|
+
// Create buffered function to respond to input field mutation
|
135
|
+
this.filterOnInput = buffer(this.filterOnInput, this, this.filterDelay);
|
155
136
|
|
156
|
-
|
137
|
+
this.typeAhead && this.updateTypeAhead()
|
157
138
|
}
|
158
139
|
|
159
140
|
/**
|
@@ -162,23 +143,17 @@ class Select extends Picker {
|
|
162
143
|
* @param {Object} oldValue
|
163
144
|
* @protected
|
164
145
|
*/
|
165
|
-
afterSetRecord(value
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
valueField = me.valueField,
|
170
|
-
nodeId;
|
171
|
-
|
172
|
-
if (oldValue) {
|
173
|
-
nodeId = list?.getItemId(oldValue[valueField]);
|
146
|
+
afterSetRecord(value) {
|
147
|
+
if (this._picker?.isVisible) {
|
148
|
+
let me = this,
|
149
|
+
selectionModel = me.list?.selectionModel;
|
174
150
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
selectionModel?.select(nodeId);
|
151
|
+
if (value) {
|
152
|
+
selectionModel?.select(value);
|
153
|
+
}
|
154
|
+
else {
|
155
|
+
selectionModel.deselectAll();
|
156
|
+
}
|
182
157
|
}
|
183
158
|
}
|
184
159
|
|
@@ -224,19 +199,6 @@ class Select extends Picker {
|
|
224
199
|
this.rendered && this.updateTypeAhead()
|
225
200
|
}
|
226
201
|
|
227
|
-
/**
|
228
|
-
* Triggered after the value config got changed
|
229
|
-
* @param {Number|String|null} value
|
230
|
-
* @param {Number|String|null} oldValue
|
231
|
-
* @param {Boolean} preventFilter=false
|
232
|
-
* @protected
|
233
|
-
*/
|
234
|
-
afterSetValue(value, oldValue, preventFilter=false) {
|
235
|
-
!preventFilter && this.updateValue(true);
|
236
|
-
|
237
|
-
super.afterSetValue(value, oldValue)
|
238
|
-
}
|
239
|
-
|
240
202
|
/**
|
241
203
|
* Triggered before the listConfig config gets changed.
|
242
204
|
* @param {Object} value
|
@@ -317,7 +279,37 @@ class Select extends Picker {
|
|
317
279
|
* @returns {Neo.list.Base}
|
318
280
|
*/
|
319
281
|
createPickerComponent() {
|
320
|
-
|
282
|
+
const me = this;
|
283
|
+
|
284
|
+
me.list = Neo.create({
|
285
|
+
module : List,
|
286
|
+
appName : me.appName,
|
287
|
+
displayField : me.displayField,
|
288
|
+
role : 'listbox',
|
289
|
+
itemRole : 'option',
|
290
|
+
parentId : me.id,
|
291
|
+
navigator : {
|
292
|
+
eventSource : me.getInputElId()
|
293
|
+
},
|
294
|
+
selectionModel : {stayInList: false},
|
295
|
+
store : me.store,
|
296
|
+
...me.listConfig
|
297
|
+
});
|
298
|
+
me.getInputEl()['aria-controls'] = me.list.id;
|
299
|
+
|
300
|
+
me.list.addDomListeners({
|
301
|
+
neonavigate: {
|
302
|
+
fn : me.onListItemNavigate,
|
303
|
+
scope : me
|
304
|
+
}
|
305
|
+
});
|
306
|
+
me.list.selectionModel.on({
|
307
|
+
selectionChange : me.onListItemSelectionChange,
|
308
|
+
noChange : me.onListItemSelectionNoChange,
|
309
|
+
scope : me
|
310
|
+
})
|
311
|
+
|
312
|
+
return me.list;
|
321
313
|
}
|
322
314
|
|
323
315
|
/**
|
@@ -355,24 +347,6 @@ class Select extends Picker {
|
|
355
347
|
}
|
356
348
|
}
|
357
349
|
|
358
|
-
/**
|
359
|
-
* @param {Function} [callback]
|
360
|
-
*/
|
361
|
-
focusInputEl(callback) {
|
362
|
-
let me = this,
|
363
|
-
lastManualInput = me.lastManualInput;
|
364
|
-
|
365
|
-
me.updateTypeAheadValue(lastManualInput, true);
|
366
|
-
me.value = lastManualInput;
|
367
|
-
|
368
|
-
Neo.main.DomAccess.focus({
|
369
|
-
appName: me.appName,
|
370
|
-
id : me.getInputElId()
|
371
|
-
}).then(() => {
|
372
|
-
callback?.apply(me)
|
373
|
-
})
|
374
|
-
}
|
375
|
-
|
376
350
|
/**
|
377
351
|
* @returns {Object}
|
378
352
|
*/
|
@@ -407,35 +381,13 @@ class Select extends Picker {
|
|
407
381
|
return me.record?.[me.valueField] || me.value
|
408
382
|
}
|
409
383
|
|
410
|
-
|
411
|
-
|
412
|
-
* @protected
|
413
|
-
*/
|
414
|
-
handleKeyDownEnter(data) {
|
415
|
-
let me = this;
|
416
|
-
|
417
|
-
if (me.pickerIsMounted) {
|
418
|
-
me.selectListItem();
|
419
|
-
super.onKeyDownEnter(data)
|
420
|
-
} else {
|
421
|
-
super.onKeyDownEnter(data, me.selectListItem)
|
422
|
-
}
|
423
|
-
}
|
424
|
-
|
425
|
-
/**
|
426
|
-
* @param {Object} data
|
427
|
-
* @protected
|
428
|
-
*/
|
429
|
-
onContainerKeyDownEnter(data) {
|
430
|
-
this.hidePicker()
|
431
|
-
}
|
384
|
+
onConstructed() {
|
385
|
+
const inputEl = this.getInputEl();
|
432
386
|
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
onContainerKeyDownEscape(data) {
|
438
|
-
this.focusInputEl(this.hidePicker)
|
387
|
+
inputEl['aria-expanded'] = false
|
388
|
+
inputEl['aria-haspopup'] = 'listbox'
|
389
|
+
inputEl['aria-activedescendant'] = ''
|
390
|
+
super.onConstructed(...arguments);
|
439
391
|
}
|
440
392
|
|
441
393
|
/**
|
@@ -446,20 +398,45 @@ class Select extends Picker {
|
|
446
398
|
onFocusLeave(data) {
|
447
399
|
let me = this;
|
448
400
|
|
449
|
-
if (
|
450
|
-
me.
|
401
|
+
if (!me.record) {
|
402
|
+
if (me.forceSelection) {
|
403
|
+
me.value = me.forceSelection ? me.activeRecordId : null;
|
404
|
+
}
|
405
|
+
// If we exit without selecting a record, clear the filter input value.
|
406
|
+
else {
|
407
|
+
me.getInputEl().value = '';
|
408
|
+
}
|
409
|
+
}
|
410
|
+
|
411
|
+
// Clear any typeahead hint
|
412
|
+
me.updateTypeAheadValue('');
|
413
|
+
|
414
|
+
// The VDOM must not carry the empty string permanently. Only while clearing the value.
|
415
|
+
if (!me.record && !me.forceSelection) {
|
416
|
+
delete me.getInputEl().value;
|
451
417
|
}
|
452
418
|
|
453
419
|
super.onFocusLeave(data)
|
454
420
|
}
|
455
421
|
|
422
|
+
filterOnInput(data) {
|
423
|
+
if (data.value) {
|
424
|
+
this.doFilter(data.value);
|
425
|
+
}
|
426
|
+
else if (this.picker) {
|
427
|
+
this.picker?.hide();
|
428
|
+
}
|
429
|
+
}
|
430
|
+
|
456
431
|
/**
|
457
432
|
* @param {Object} data
|
458
433
|
* @protected
|
459
434
|
*/
|
460
435
|
onInputValueChange(data) {
|
461
|
-
super.
|
436
|
+
// We do not call super here. The value of the Select is *not* connected to the value
|
437
|
+
// typed into the input area. The input area is just a filter value to filter the list.
|
462
438
|
this.lastManualInput = data.value
|
439
|
+
this.filterOnInput(data);
|
463
440
|
}
|
464
441
|
|
465
442
|
/**
|
@@ -467,70 +444,43 @@ class Select extends Picker {
|
|
467
444
|
* @protected
|
468
445
|
*/
|
469
446
|
onKeyDownDown(data) {
|
470
|
-
this.
|
471
|
-
|
472
|
-
|
473
|
-
/**
|
474
|
-
* @param {Object} data
|
475
|
-
* @protected
|
476
|
-
*/
|
477
|
-
onKeyDownEnter(data) {
|
478
|
-
this.handleKeyDownEnter(data);
|
479
|
-
}
|
480
|
-
|
481
|
-
/**
|
482
|
-
* @param {Object} data
|
483
|
-
* @protected
|
484
|
-
*/
|
485
|
-
onKeyDownRight(data) {
|
486
|
-
let me = this,
|
487
|
-
oldValue, record;
|
488
|
-
|
489
|
-
if (me.hintRecordId) {
|
490
|
-
oldValue = me.value;
|
491
|
-
record = me.store.get(me.hintRecordId);
|
492
|
-
|
493
|
-
me.record = record;
|
494
|
-
me._value = record[me.displayField];
|
495
|
-
|
496
|
-
me.afterSetValue(me._value, oldValue)
|
447
|
+
if (!this.picker || this.picker?.hidden) {
|
448
|
+
this.onPickerTriggerClick();
|
497
449
|
}
|
498
450
|
}
|
499
451
|
|
500
|
-
|
501
|
-
|
502
|
-
* @protected
|
503
|
-
*/
|
504
|
-
onKeyDownUp(data) {
|
505
|
-
let me = this;
|
452
|
+
onPickerHiddenChange({ value }) {
|
453
|
+
const inputEl = this.getInputEl();
|
506
454
|
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
} else {
|
511
|
-
super.onKeyDownEnter(data, me.selectLastListItem)
|
455
|
+
super.onPickerHiddenChange(...arguments);
|
456
|
+
if (value) {
|
457
|
+
inputEl['aria-activedescendant'] = '';
|
512
458
|
}
|
459
|
+
inputEl['aria-expanded'] = !value;
|
460
|
+
this.update();
|
513
461
|
}
|
514
462
|
|
463
|
+
// TODO:
|
464
|
+
// When we are using a `Collection` as our `valueCollection`, and that `Collection` is the
|
465
|
+
// `items` of the List's `selectionModel`, then this will be `onValueCollectionChange`,
|
466
|
+
// a `mutate` listener on our own `valueCollection` which backs our `value` field which
|
467
|
+
// will be implemented by a getter which accesses `valueCollection`.
|
468
|
+
// This will become important for implementing multiSelect
|
515
469
|
/**
|
470
|
+
* @param {Object} selectionChangeEvent
|
471
|
+
* @param {Object[]} selectionChangeEvent.selection
|
516
472
|
* @protected
|
517
473
|
*/
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
*/
|
527
|
-
onListItemChange(record) {
|
528
|
-
let me = this,
|
529
|
-
displayField = me.displayField,
|
530
|
-
oldValue = me.value,
|
531
|
-
value = record[displayField];
|
474
|
+
onListItemSelectionChange({ selection }) {
|
475
|
+
if (selection?.length) {
|
476
|
+
const
|
477
|
+
me = this,
|
478
|
+
oldValue = me.value,
|
479
|
+
selected = selection[0],
|
480
|
+
record = typeof selected === 'string' ? me.store.get(me.list.getItemRecordId(selected)) : selected,
|
481
|
+
value = record[me.displayField];
|
532
482
|
|
533
|
-
|
483
|
+
me.hidePicker();
|
534
484
|
me.hintRecordId = null;
|
535
485
|
me.record = record;
|
536
486
|
me._value = value;
|
@@ -540,42 +490,36 @@ class Select extends Picker {
|
|
540
490
|
|
541
491
|
me.fire('select', {
|
542
492
|
record,
|
543
|
-
value
|
493
|
+
value
|
544
494
|
})
|
545
495
|
}
|
546
496
|
}
|
547
497
|
|
548
498
|
/**
|
549
|
-
*
|
550
|
-
*
|
499
|
+
* Selection was attempted to be changed but resulted in no action.
|
500
|
+
* For example clicking on already selected list item.
|
551
501
|
*/
|
552
|
-
|
553
|
-
this.
|
554
|
-
this.hidePicker()
|
502
|
+
onListItemSelectionNoChange() {
|
503
|
+
this.hidePicker();
|
555
504
|
}
|
556
505
|
|
557
506
|
/**
|
558
507
|
* @param {Object} record
|
559
508
|
* @protected
|
560
509
|
*/
|
561
|
-
onListItemNavigate(
|
562
|
-
|
563
|
-
|
510
|
+
onListItemNavigate({ activeItem, activeIndex }) {
|
511
|
+
if (activeIndex >= 0) {
|
512
|
+
const
|
513
|
+
me = this,
|
514
|
+
{ store } = me;
|
564
515
|
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
onSelectPostLastItem() {
|
569
|
-
this.record = null;
|
570
|
-
this.focusInputEl()
|
571
|
-
}
|
516
|
+
me.activeRecord = store.getAt(activeIndex)
|
517
|
+
me.activeRecordId = me.activeRecord[store.keyProperty || model.keyProperty]
|
518
|
+
me.getInputEl()['aria-activedescendant'] = activeItem;
|
572
519
|
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
onSelectPreFirstItem() {
|
577
|
-
this.record = null;
|
578
|
-
this.focusInputEl()
|
520
|
+
// Update typeahead hint (which updates DOM), or update DOM
|
521
|
+
me.typeAhead ? me.updateTypeAheadValue(me.lastManualInput) : me.update();
|
522
|
+
}
|
579
523
|
}
|
580
524
|
|
581
525
|
/**
|
@@ -614,33 +558,73 @@ class Select extends Picker {
|
|
614
558
|
let me = this;
|
615
559
|
|
616
560
|
if (!Neo.isNumber(index)) {
|
617
|
-
if (me.
|
618
|
-
index = me.store.indexOfKey(me.
|
561
|
+
if (me.activeRecordId) {
|
562
|
+
index = me.store.indexOfKey(me.activeRecordId);
|
619
563
|
} else {
|
620
564
|
index = 0;
|
621
565
|
}
|
622
566
|
}
|
623
567
|
|
624
568
|
me.list.selectItem(index);
|
625
|
-
|
569
|
+
}
|
570
|
+
|
571
|
+
onPickerTriggerClick() {
|
572
|
+
let me = this;
|
573
|
+
|
574
|
+
if (me.picker?.isVisible) {
|
575
|
+
me.picker.hidden = true;
|
576
|
+
}
|
577
|
+
else if (!me.readOnly && !me.disabled) {
|
578
|
+
me.doFilter(null)
|
579
|
+
}
|
626
580
|
}
|
627
581
|
|
628
582
|
/**
|
583
|
+
* All routes which expect to open the picker route through here. This updates the
|
584
|
+
* filter and ensures that the picker is visible and reflecting the state of the filter.
|
629
585
|
*
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
586
|
+
* Input event processing passes the current input field value in as the filter value.
|
587
|
+
*
|
588
|
+
* Invocation of the expand trigger passes `null` so as to clear filtering.
|
589
|
+
* @private
|
590
|
+
* @param {String}null} value The value to filter the picker by
|
591
|
+
*/
|
592
|
+
doFilter(value) {
|
593
|
+
let me = this,
|
594
|
+
filter = me.store.getFilter(me.displayField),
|
595
|
+
{
|
596
|
+
record,
|
597
|
+
picker
|
598
|
+
} = me;
|
634
599
|
|
635
|
-
if (
|
636
|
-
filter =
|
600
|
+
if (filter) {
|
601
|
+
filter.value = value;
|
602
|
+
}
|
637
603
|
|
638
|
-
|
639
|
-
|
604
|
+
// Filter resulting in something to show
|
605
|
+
if (me.store.getCount()) {
|
606
|
+
me.getPicker().hidden = false;
|
607
|
+
|
608
|
+
// List might not exist until the picker is created
|
609
|
+
const
|
610
|
+
{ list } = me,
|
611
|
+
{ selectionModel } = list;
|
612
|
+
|
613
|
+
// On show, set the active item to be the current selected record or the first
|
614
|
+
if (record) {
|
615
|
+
// We do not want to hear back about our own selection
|
616
|
+
selectionModel.suspendEvents = true;
|
617
|
+
selectionModel.select(record);
|
618
|
+
selectionModel.suspendEvents = false;
|
640
619
|
}
|
620
|
+
setTimeout(() => {
|
621
|
+
list.activeIndex = me.record || 0;
|
622
|
+
}, 100)
|
623
|
+
}
|
624
|
+
// Filtered down to nothing - hide picker if it has been created.
|
625
|
+
else if (picker) {
|
626
|
+
picker._hidden = true;
|
641
627
|
}
|
642
|
-
|
643
|
-
super.togglePicker()
|
644
628
|
}
|
645
629
|
|
646
630
|
/**
|
@@ -658,7 +642,7 @@ class Select extends Picker {
|
|
658
642
|
cls: ['neo-input-field-wrapper'],
|
659
643
|
cn : [{
|
660
644
|
tag : 'input',
|
661
|
-
autocomplete: '
|
645
|
+
autocomplete: 'off',
|
662
646
|
autocorrect : 'off',
|
663
647
|
cls : ['neo-textfield-input', 'neo-typeahead-input'],
|
664
648
|
disabled : true,
|
@@ -674,70 +658,37 @@ class Select extends Picker {
|
|
674
658
|
}
|
675
659
|
|
676
660
|
/**
|
677
|
-
* @param {String|null} [value=this.
|
661
|
+
* @param {String|null} [value=this.lastManualInput]
|
678
662
|
* @param {Boolean} [silent=false]
|
679
663
|
* @protected
|
680
664
|
*/
|
681
|
-
updateTypeAheadValue(value=this.
|
665
|
+
updateTypeAheadValue(value=this.lastManualInput, silent=false) {
|
682
666
|
let me = this,
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
inputHintEl = me.getInputHintEl(),
|
688
|
-
storeValue;
|
689
|
-
|
690
|
-
if (!me.record && value && value.length > 0) {
|
691
|
-
for (; i < len; i++) {
|
692
|
-
storeValue = store.items[i][me.displayField];
|
693
|
-
|
694
|
-
if (!Neo.isString(storeValue)) {
|
695
|
-
return;
|
696
|
-
}
|
697
|
-
|
698
|
-
if (storeValue.toLowerCase().indexOf(value.toLowerCase()) === 0) {
|
699
|
-
hasMatch = true;
|
700
|
-
break;
|
701
|
-
}
|
667
|
+
match = false,
|
668
|
+
{
|
669
|
+
store,
|
670
|
+
displayField
|
702
671
|
}
|
672
|
+
= me,
|
673
|
+
inputHintEl = me.getInputHintEl();
|
674
|
+
|
675
|
+
if (!me.record && value?.length > 0) {
|
676
|
+
const search = value.toLocaleLowerCase();
|
677
|
+
match = store.items.find(r => r[displayField]?.toLowerCase?.()?.startsWith(search));
|
703
678
|
|
704
|
-
if (
|
705
|
-
inputHintEl.value = value +
|
706
|
-
me.
|
679
|
+
if (match && inputHintEl) {
|
680
|
+
inputHintEl.value = value + match[displayField].substr(value.length);
|
681
|
+
me.activeRecord = match;
|
682
|
+
me.activeRecordId = match[store.keyProperty || store.model.keyProperty]
|
707
683
|
}
|
708
684
|
}
|
709
685
|
|
710
|
-
if (!
|
711
|
-
inputHintEl.value = null;
|
712
|
-
me.hintRecordId = null;
|
686
|
+
if (!match && inputHintEl) {
|
687
|
+
inputHintEl.value = me.activeRecord = me.activeRecordId = null;
|
713
688
|
}
|
714
689
|
|
715
690
|
!silent && me.update()
|
716
691
|
}
|
717
|
-
|
718
|
-
/**
|
719
|
-
* @param {Boolean} silent=false
|
720
|
-
* @protected
|
721
|
-
*/
|
722
|
-
updateValue(silent=false) {
|
723
|
-
let me = this,
|
724
|
-
displayField = me.displayField,
|
725
|
-
store = me.store,
|
726
|
-
value = me._value,
|
727
|
-
filter;
|
728
|
-
|
729
|
-
if (store && !Neo.isEmpty(store.filters)) {
|
730
|
-
filter = store.getFilter(displayField);
|
731
|
-
|
732
|
-
if (filter) {
|
733
|
-
filter.value = me.record?.[displayField] || value;
|
734
|
-
}
|
735
|
-
}
|
736
|
-
|
737
|
-
if (me.typeAhead && !me.picker?.containsFocus) {
|
738
|
-
me.updateTypeAheadValue(value, silent)
|
739
|
-
}
|
740
|
-
}
|
741
692
|
}
|
742
693
|
|
743
694
|
/**
|
package/src/form/field/Text.mjs
CHANGED
@@ -318,7 +318,7 @@ class Text extends Base {
|
|
318
318
|
* @protected
|
319
319
|
*/
|
320
320
|
afterSetAutoComplete(value, oldValue) {
|
321
|
-
this.changeInputElKey('autocomplete', value ? null : '
|
321
|
+
this.changeInputElKey('autocomplete', value ? null : 'off')
|
322
322
|
}
|
323
323
|
|
324
324
|
/**
|
@@ -1323,7 +1323,7 @@ class Text extends Base {
|
|
1323
1323
|
onInputValueChange(data) {
|
1324
1324
|
let me = this,
|
1325
1325
|
oldValue = me.value,
|
1326
|
-
value = data.value,
|
1326
|
+
value = data.value ? data.value.toString().trim() : me.emptyValue,
|
1327
1327
|
vnode = VNodeUtil.findChildVnode(me.vnode, {nodeName: 'input'});
|
1328
1328
|
|
1329
1329
|
if (vnode) {
|
@@ -1526,7 +1526,7 @@ class Text extends Base {
|
|
1526
1526
|
minLength = me.minLength,
|
1527
1527
|
required = me.required,
|
1528
1528
|
returnValue = true,
|
1529
|
-
value = me.value,
|
1529
|
+
value = me.value ? me.value.toString().trim() : me.emptyValue,
|
1530
1530
|
valueLength = value?.toString().length,
|
1531
1531
|
inputPattern = me.inputPattern,
|
1532
1532
|
isEmpty = value !== 0 && (!value || valueLength < 1),
|