goodteditor-ui 1.0.98 → 1.0.100
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/package.json
CHANGED
|
@@ -28,6 +28,8 @@
|
|
|
28
28
|
</div>
|
|
29
29
|
</template>
|
|
30
30
|
<script>
|
|
31
|
+
import { debounce } from 'lodash';
|
|
32
|
+
|
|
31
33
|
const Size = {
|
|
32
34
|
NORMAL: { name: '', class: [] },
|
|
33
35
|
SMALL: { name: 'small', class: ['input-small'] }
|
|
@@ -65,6 +67,10 @@ export default {
|
|
|
65
67
|
type: Boolean,
|
|
66
68
|
default: false
|
|
67
69
|
},
|
|
70
|
+
debounce: {
|
|
71
|
+
type: Number,
|
|
72
|
+
default: 0
|
|
73
|
+
},
|
|
68
74
|
embedded: {
|
|
69
75
|
type: Boolean,
|
|
70
76
|
default: false
|
|
@@ -83,11 +89,35 @@ export default {
|
|
|
83
89
|
return Object.values(Size).find(({ name }) => name === size)?.class;
|
|
84
90
|
}
|
|
85
91
|
},
|
|
92
|
+
created() {
|
|
93
|
+
if (this.debounce > 0) {
|
|
94
|
+
const { emitInputDebounced } = this;
|
|
95
|
+
this.emitInputDebounced = debounce(emitInputDebounced.bind(this), this.debounce);
|
|
96
|
+
}
|
|
97
|
+
},
|
|
86
98
|
methods: {
|
|
99
|
+
/**
|
|
100
|
+
* @param {string} val
|
|
101
|
+
* @param {boolean} isDebounced
|
|
102
|
+
*/
|
|
103
|
+
emitInput(val = '', isDebounced = false) {
|
|
104
|
+
const { emitInputDebounced, emitInputOriginal } = this;
|
|
105
|
+
const method = isDebounced ? emitInputDebounced : emitInputOriginal;
|
|
106
|
+
method(val);
|
|
107
|
+
},
|
|
108
|
+
/**
|
|
109
|
+
* @param {string} val
|
|
110
|
+
*/
|
|
111
|
+
emitInputDebounced(val = '') {
|
|
112
|
+
/**
|
|
113
|
+
* @property {string} value
|
|
114
|
+
*/
|
|
115
|
+
this.emitInputOriginal(val);
|
|
116
|
+
},
|
|
87
117
|
/**
|
|
88
118
|
* @param {string} val
|
|
89
119
|
*/
|
|
90
|
-
|
|
120
|
+
emitInputOriginal(val = '') {
|
|
91
121
|
/**
|
|
92
122
|
* @property {string} value
|
|
93
123
|
*/
|
|
@@ -121,7 +151,7 @@ export default {
|
|
|
121
151
|
* @param {InputEvent} e
|
|
122
152
|
*/
|
|
123
153
|
onInput({ target }) {
|
|
124
|
-
this.emitInput(target.value);
|
|
154
|
+
this.emitInput(target.value, true);
|
|
125
155
|
},
|
|
126
156
|
/**
|
|
127
157
|
* @param {InputEvent} e
|
|
@@ -149,10 +179,9 @@ export default {
|
|
|
149
179
|
</script>
|
|
150
180
|
<style scoped lang="pcss">
|
|
151
181
|
.form-control--embedded .input {
|
|
182
|
+
background: transparent;
|
|
152
183
|
border: none;
|
|
153
184
|
outline: none;
|
|
154
|
-
padding-top: 0;
|
|
155
|
-
padding-bottom: 0;
|
|
156
185
|
min-height: initial;
|
|
157
186
|
}
|
|
158
187
|
</style>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** Любой объект или стандартная структура опции */
|
|
2
|
+
export type Option = { label: string; value: any } | any;
|
|
3
|
+
|
|
4
|
+
export interface OptionSettings {
|
|
5
|
+
valueField?: string;
|
|
6
|
+
labelField?: string;
|
|
7
|
+
/** поле, по которому перед группой опций,
|
|
8
|
+
* будет рисоваться хедер группы, когда оно меняется
|
|
9
|
+
* опции должны изначально быть отсортированы по группам
|
|
10
|
+
* */
|
|
11
|
+
groupField?: string | null;
|
|
12
|
+
disabledField?: string;
|
|
13
|
+
valueObjects?: boolean;
|
|
14
|
+
/** Функция для проверки значения опции */
|
|
15
|
+
valueOfOptionChecker?: (option: { label: string; value: any } | Record<string, any>) => boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface DropdownSettings {
|
|
19
|
+
class?: string | string[];
|
|
20
|
+
maxHeight?: string | null;
|
|
21
|
+
maxItems?: number;
|
|
22
|
+
itemHeight?: string | null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface SearchSettings {
|
|
26
|
+
minItems?: number;
|
|
27
|
+
debounce?: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type MultipleSettings = {
|
|
31
|
+
pin?: boolean;
|
|
32
|
+
hideOnSelect?: boolean;
|
|
33
|
+
};
|
|
@@ -10,16 +10,21 @@
|
|
|
10
10
|
<!--
|
|
11
11
|
@slot search slot
|
|
12
12
|
-->
|
|
13
|
-
<
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
13
|
+
<div v-if="hasSearch && popoverShow" class="ui-select-searchbar-wrapper">
|
|
14
|
+
<slot name="label-search" v-bind="{ search: searchQuery }">
|
|
15
|
+
<ui-searchbar
|
|
16
|
+
v-model="searchQuery"
|
|
17
|
+
v-bind="{
|
|
18
|
+
size,
|
|
19
|
+
embedded: true,
|
|
20
|
+
debounce: searchSettings.debounce
|
|
21
|
+
}"
|
|
22
|
+
tabindex="1"
|
|
23
|
+
class="w-100"
|
|
24
|
+
ref="searchbar"
|
|
25
|
+
@click.native.stop></ui-searchbar>
|
|
26
|
+
</slot>
|
|
27
|
+
</div>
|
|
23
28
|
<template v-else-if="multiple">
|
|
24
29
|
<template v-if="optionsSelected.length > 0">
|
|
25
30
|
<!--
|
|
@@ -34,7 +39,7 @@
|
|
|
34
39
|
v-bind="{
|
|
35
40
|
selected: optionsSelected,
|
|
36
41
|
deselectOption,
|
|
37
|
-
clear: clearOptions
|
|
42
|
+
clear: clearOptions,
|
|
38
43
|
}">
|
|
39
44
|
<slot
|
|
40
45
|
name="label-multiple"
|
|
@@ -101,7 +106,7 @@
|
|
|
101
106
|
@slot Reset state icon slot
|
|
102
107
|
-->
|
|
103
108
|
<slot
|
|
104
|
-
v-if="clear && optionsSelected.length > 0 && (
|
|
109
|
+
v-if="clear && optionsSelected.length > 0 && (hasSearch === false || popoverShow === false)"
|
|
105
110
|
name="icon-clear"
|
|
106
111
|
v-bind="{ clear: clearOptions }">
|
|
107
112
|
<i
|
|
@@ -117,7 +122,7 @@
|
|
|
117
122
|
-->
|
|
118
123
|
<slot name="icon-open" v-if="popoverShow">
|
|
119
124
|
<i
|
|
120
|
-
class="icon mdi mdi-chevron-up"
|
|
125
|
+
class="icon icon-toggle mdi mdi-chevron-up"
|
|
121
126
|
:class="{
|
|
122
127
|
'mdi-18px': size === '',
|
|
123
128
|
'h-auto w-auto': size === 'small'
|
|
@@ -128,7 +133,7 @@
|
|
|
128
133
|
-->
|
|
129
134
|
<slot name="icon-close" v-else>
|
|
130
135
|
<i
|
|
131
|
-
class="icon mdi mdi-chevron-down"
|
|
136
|
+
class="icon icon-toggle mdi mdi-chevron-down"
|
|
132
137
|
:class="{
|
|
133
138
|
'mdi-18px': size === '',
|
|
134
139
|
'h-auto w-auto': size === 'small'
|
|
@@ -187,7 +192,17 @@
|
|
|
187
192
|
selectOption,
|
|
188
193
|
deselectOption,
|
|
189
194
|
toggleOption
|
|
190
|
-
}"
|
|
195
|
+
}">
|
|
196
|
+
<slot
|
|
197
|
+
v-if="isShowGroup({ option, index })"
|
|
198
|
+
name="option:before-group"
|
|
199
|
+
v-bind="{
|
|
200
|
+
option,
|
|
201
|
+
index,
|
|
202
|
+
group: getOptionGroup(option)
|
|
203
|
+
}">
|
|
204
|
+
</slot>
|
|
205
|
+
</slot>
|
|
191
206
|
<!--
|
|
192
207
|
@slot option slot mode
|
|
193
208
|
@binding {Object} option option
|
|
@@ -218,13 +233,14 @@
|
|
|
218
233
|
toggleOption,
|
|
219
234
|
// legacy
|
|
220
235
|
optionIndex: index,
|
|
221
|
-
isOptionSelected: isOptionSelected(option)
|
|
236
|
+
isOptionSelected: isOptionSelected(option),
|
|
237
|
+
search: searchQuery
|
|
222
238
|
}">
|
|
223
239
|
<li
|
|
224
240
|
:class="{
|
|
225
241
|
active: isOptionSelected(option),
|
|
226
242
|
'bg-grey-lighter': index == cursorIndex,
|
|
227
|
-
disabled: isOptionDisabled(option)
|
|
243
|
+
'option-disabled': isOptionDisabled(option)
|
|
228
244
|
}"
|
|
229
245
|
:key="index"
|
|
230
246
|
:title="getOptionLabel(option)"
|
|
@@ -263,7 +279,9 @@
|
|
|
263
279
|
label: getOptionLabel(option),
|
|
264
280
|
index,
|
|
265
281
|
isSelected: isOptionSelected(option),
|
|
266
|
-
|
|
282
|
+
isDisabled: isOptionDisabled(option),
|
|
283
|
+
cursorIndex,
|
|
284
|
+
search: searchQuery
|
|
267
285
|
}">
|
|
268
286
|
{{ getOptionLabel(option) }}
|
|
269
287
|
</slot>
|
|
@@ -295,7 +313,8 @@
|
|
|
295
313
|
cursorIndex,
|
|
296
314
|
selectOption,
|
|
297
315
|
deselectOption,
|
|
298
|
-
toggleOption
|
|
316
|
+
toggleOption,
|
|
317
|
+
search: searchQuery
|
|
299
318
|
}"></slot>
|
|
300
319
|
</template>
|
|
301
320
|
<template #footer>
|
|
@@ -310,6 +329,7 @@
|
|
|
310
329
|
</template>
|
|
311
330
|
<style lang="less" scoped>
|
|
312
331
|
.ui-select {
|
|
332
|
+
position: relative;
|
|
313
333
|
display: inline-flex;
|
|
314
334
|
align-items: center;
|
|
315
335
|
|
|
@@ -320,7 +340,8 @@
|
|
|
320
340
|
flex: 1 0 0;
|
|
321
341
|
}
|
|
322
342
|
|
|
323
|
-
.icon-clear {
|
|
343
|
+
.icon-clear, .icon-toggle {
|
|
344
|
+
z-index: 1;
|
|
324
345
|
cursor: pointer;
|
|
325
346
|
}
|
|
326
347
|
|
|
@@ -336,20 +357,34 @@
|
|
|
336
357
|
}
|
|
337
358
|
}
|
|
338
359
|
|
|
339
|
-
&-searchbar {
|
|
340
|
-
|
|
341
|
-
|
|
360
|
+
&-searchbar-wrapper {
|
|
361
|
+
position: absolute;
|
|
362
|
+
top: 0;
|
|
363
|
+
left: 0;
|
|
364
|
+
width: 100%;
|
|
365
|
+
height: 100%;
|
|
366
|
+
display: flex;
|
|
367
|
+
align-items: center;
|
|
368
|
+
padding-right: var(--spacer6);
|
|
342
369
|
}
|
|
343
370
|
}
|
|
344
371
|
|
|
345
372
|
.ui-datalist {
|
|
346
|
-
.
|
|
373
|
+
.option-disabled, .option-disabled:hover {
|
|
374
|
+
background-color: transparent;
|
|
375
|
+
color: var(--color-grey-light);
|
|
376
|
+
cursor: not-allowed;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.active:hover:not(.disabled) {
|
|
347
380
|
background-color: var(--color-primary-hover);
|
|
348
381
|
}
|
|
382
|
+
|
|
349
383
|
&.multiple {
|
|
350
384
|
li + li {
|
|
351
385
|
border-top: 1px solid transparent;
|
|
352
386
|
}
|
|
387
|
+
|
|
353
388
|
.active + .active {
|
|
354
389
|
border-color: var(--color-primary-hover);
|
|
355
390
|
}
|
|
@@ -361,6 +396,7 @@
|
|
|
361
396
|
}
|
|
362
397
|
</style>
|
|
363
398
|
<script>
|
|
399
|
+
import { isEqual } from 'lodash';
|
|
364
400
|
import UiBadge from './Badge.vue';
|
|
365
401
|
import UiDatalist from './Datalist.vue';
|
|
366
402
|
import UiPopover from './Popover.vue';
|
|
@@ -370,24 +406,11 @@ import UiSearchbar from './Searchbar.vue';
|
|
|
370
406
|
import { Key } from './utils/Helpers';
|
|
371
407
|
|
|
372
408
|
/**
|
|
373
|
-
* @typedef {
|
|
374
|
-
*
|
|
375
|
-
*
|
|
376
|
-
*
|
|
377
|
-
*
|
|
378
|
-
* valueOfOptionChecker?: (option: { label: string, value: any } | Record<string, any>) => boolean
|
|
379
|
-
* }} OptionSettings
|
|
380
|
-
*
|
|
381
|
-
* @typedef {{
|
|
382
|
-
* class?: string|string[],
|
|
383
|
-
* maxHeight?: null|string,
|
|
384
|
-
* maxItems?: number,
|
|
385
|
-
* itemHeight?: null|string
|
|
386
|
-
* }} DropdownSettings
|
|
387
|
-
*
|
|
388
|
-
* @typedef {{
|
|
389
|
-
* pin?: boolean
|
|
390
|
-
* }} MultipleSettings
|
|
409
|
+
* @typedef {import('./Select').Option} Option
|
|
410
|
+
* @typedef {import('./Select').OptionSettings} OptionSettings
|
|
411
|
+
* @typedef {import('./Select').DropdownSettings} DropdownSettings
|
|
412
|
+
* @typedef {import('./Select').SearchSettings} SearchSettings
|
|
413
|
+
* @typedef {import('./Select').MultipleSettings} MultipleSettings
|
|
391
414
|
*/
|
|
392
415
|
|
|
393
416
|
/**
|
|
@@ -399,7 +422,6 @@ const DropdownSettingsDefault = {
|
|
|
399
422
|
maxItems: 5,
|
|
400
423
|
itemHeight: null
|
|
401
424
|
};
|
|
402
|
-
|
|
403
425
|
/**
|
|
404
426
|
* @type {OptionSettings}
|
|
405
427
|
*/
|
|
@@ -407,15 +429,23 @@ const OptionSettingsDefault = {
|
|
|
407
429
|
valueField: 'value',
|
|
408
430
|
labelField: 'label',
|
|
409
431
|
disabledField: 'disabled',
|
|
432
|
+
groupField: null,
|
|
410
433
|
valueObjects: false,
|
|
411
434
|
valueOfOptionChecker: null
|
|
412
435
|
};
|
|
413
|
-
|
|
414
436
|
/**
|
|
415
437
|
* @type {MultipleSettings}
|
|
416
438
|
*/
|
|
417
439
|
const MultipleSettingsDefault = {
|
|
418
|
-
pin: false
|
|
440
|
+
pin: false,
|
|
441
|
+
hideOnSelect: false
|
|
442
|
+
};
|
|
443
|
+
/**
|
|
444
|
+
* @type {SearchSettings}
|
|
445
|
+
*/
|
|
446
|
+
const SearchSettingsDefault = {
|
|
447
|
+
minItems: 5,
|
|
448
|
+
debounce: 0
|
|
419
449
|
};
|
|
420
450
|
|
|
421
451
|
export default {
|
|
@@ -465,31 +495,20 @@ export default {
|
|
|
465
495
|
},
|
|
466
496
|
/**
|
|
467
497
|
* Allow embedded search
|
|
468
|
-
* @type {import('vue').PropOptions<boolean |
|
|
469
|
-
* clear?: boolean,
|
|
470
|
-
* }>}
|
|
498
|
+
* @type {import('vue').PropOptions<boolean | SearchSettings>}
|
|
471
499
|
*/
|
|
472
500
|
search: {
|
|
473
501
|
type: [Boolean, Object],
|
|
474
502
|
default: false
|
|
475
503
|
},
|
|
476
504
|
/**
|
|
477
|
-
*
|
|
505
|
+
* Option-related settings
|
|
478
506
|
* @type {import('vue').PropOptions<OptionSettings>}
|
|
507
|
+
* @default {}
|
|
479
508
|
*/
|
|
480
509
|
option: {
|
|
481
510
|
type: Object,
|
|
482
|
-
default
|
|
483
|
-
return {
|
|
484
|
-
/*
|
|
485
|
-
valueField: 'value',
|
|
486
|
-
labelField: 'label',
|
|
487
|
-
disabledField: '',
|
|
488
|
-
valueObjects: false,
|
|
489
|
-
valueOfOptionChecker: null
|
|
490
|
-
*/
|
|
491
|
-
};
|
|
492
|
-
}
|
|
511
|
+
default: null
|
|
493
512
|
},
|
|
494
513
|
/**
|
|
495
514
|
* Defines whether 'value' is the option value field or option object
|
|
@@ -536,15 +555,11 @@ export default {
|
|
|
536
555
|
// DATALIST OPTIONS
|
|
537
556
|
/**
|
|
538
557
|
* Dropdown extra config options
|
|
539
|
-
* @type {import('vue').PropOptions<DropdownSettings>}
|
|
558
|
+
* @type {import('vue').PropOptions<DropdownSettings|null>}
|
|
540
559
|
*/
|
|
541
560
|
datalist: {
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
maxHeight: null,
|
|
545
|
-
maxItems: 5,
|
|
546
|
-
itemHeight: null
|
|
547
|
-
*/
|
|
561
|
+
type: Object,
|
|
562
|
+
default: null
|
|
548
563
|
},
|
|
549
564
|
/**
|
|
550
565
|
* Datalist css classes (optional)
|
|
@@ -576,12 +591,28 @@ export default {
|
|
|
576
591
|
},
|
|
577
592
|
data() {
|
|
578
593
|
return {
|
|
594
|
+
/**
|
|
595
|
+
* @type {any[]}
|
|
596
|
+
*/
|
|
579
597
|
optionsSelected: [],
|
|
580
598
|
dataListCursorIndex: -1,
|
|
581
599
|
searchQuery: ''
|
|
582
600
|
};
|
|
583
601
|
},
|
|
584
602
|
computed: {
|
|
603
|
+
/**
|
|
604
|
+
* @return {boolean}
|
|
605
|
+
*/
|
|
606
|
+
isSelectedRemovable() {
|
|
607
|
+
return this.readonly === false && this.disabled === false;
|
|
608
|
+
},
|
|
609
|
+
/**
|
|
610
|
+
* @return {boolean}
|
|
611
|
+
*/
|
|
612
|
+
hasSearch() {
|
|
613
|
+
const { search, searchSettings: { minItems }, options } = this;
|
|
614
|
+
return search !== false && options.length > minItems;
|
|
615
|
+
},
|
|
585
616
|
/**
|
|
586
617
|
* @return {object}
|
|
587
618
|
*/
|
|
@@ -592,12 +623,15 @@ export default {
|
|
|
592
623
|
}
|
|
593
624
|
return this.cssClass;
|
|
594
625
|
},
|
|
626
|
+
/**
|
|
627
|
+
* @return {string}
|
|
628
|
+
*/
|
|
595
629
|
selectedBadgeTheme() {
|
|
596
630
|
return this.disabled ? '' : 'primary';
|
|
597
631
|
},
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
632
|
+
/**
|
|
633
|
+
* @return {Option[]}
|
|
634
|
+
*/
|
|
601
635
|
optionsInternal() {
|
|
602
636
|
let {
|
|
603
637
|
searchQuery,
|
|
@@ -620,13 +654,13 @@ export default {
|
|
|
620
654
|
* @return {OptionSettings}
|
|
621
655
|
*/
|
|
622
656
|
optionSettings() {
|
|
623
|
-
const { labelField,
|
|
657
|
+
const { labelField, valueField, disabledField, valueObjects, valueOfOptionChecker, option } = this;
|
|
624
658
|
return {
|
|
625
659
|
...OptionSettingsDefault,
|
|
626
660
|
labelField,
|
|
627
|
-
|
|
661
|
+
valueField,
|
|
628
662
|
disabledField,
|
|
629
|
-
|
|
663
|
+
valueObjects,
|
|
630
664
|
valueOfOptionChecker,
|
|
631
665
|
...option
|
|
632
666
|
};
|
|
@@ -635,16 +669,33 @@ export default {
|
|
|
635
669
|
* @return {DropdownSettings & { size: string }}
|
|
636
670
|
*/
|
|
637
671
|
dropdownSettings() {
|
|
638
|
-
const { datalistCssClass,
|
|
672
|
+
const { datalistCssClass, datalist, size } = this;
|
|
639
673
|
return {
|
|
640
674
|
...DropdownSettingsDefault,
|
|
641
675
|
class: datalistCssClass,
|
|
642
|
-
maxItems,
|
|
643
|
-
itemHeight,
|
|
644
|
-
maxHeight,
|
|
645
676
|
size,
|
|
646
677
|
...datalist
|
|
647
678
|
};
|
|
679
|
+
},
|
|
680
|
+
/**
|
|
681
|
+
* @return {SearchSettings}
|
|
682
|
+
*/
|
|
683
|
+
searchSettings() {
|
|
684
|
+
const { search } = this;
|
|
685
|
+
return {
|
|
686
|
+
...SearchSettingsDefault,
|
|
687
|
+
...search
|
|
688
|
+
};
|
|
689
|
+
},
|
|
690
|
+
/**
|
|
691
|
+
* @return {MultipleSettings}
|
|
692
|
+
*/
|
|
693
|
+
multipleSettings() {
|
|
694
|
+
const { multiple } = this;
|
|
695
|
+
return {
|
|
696
|
+
...MultipleSettingsDefault,
|
|
697
|
+
...multiple
|
|
698
|
+
};
|
|
648
699
|
}
|
|
649
700
|
},
|
|
650
701
|
watch: {
|
|
@@ -659,12 +710,17 @@ export default {
|
|
|
659
710
|
},
|
|
660
711
|
popoverShow(isPopoverShown) {
|
|
661
712
|
this.$emit('options-toggle', isPopoverShown);
|
|
662
|
-
if (this.
|
|
713
|
+
if (this.hasSearch !== false) {
|
|
663
714
|
this.handleSearchbar(isPopoverShown);
|
|
664
715
|
}
|
|
665
716
|
}
|
|
666
717
|
},
|
|
667
718
|
methods: {
|
|
719
|
+
/**
|
|
720
|
+
* @param option
|
|
721
|
+
* @param modelItem
|
|
722
|
+
* @return {boolean}
|
|
723
|
+
*/
|
|
668
724
|
isValueOfOptionDefault(option, modelItem) {
|
|
669
725
|
const { valueObjects } = this.optionSettings;
|
|
670
726
|
const modelValue = valueObjects ? this.getOptionValue(modelItem) : modelItem;
|
|
@@ -773,6 +829,16 @@ export default {
|
|
|
773
829
|
getOptionIndex(option) {
|
|
774
830
|
return this.optionsInternal.indexOf(option);
|
|
775
831
|
},
|
|
832
|
+
/**
|
|
833
|
+
* @param {Option} option
|
|
834
|
+
* @return {any|null}
|
|
835
|
+
*/
|
|
836
|
+
getOptionGroup(option) {
|
|
837
|
+
const {
|
|
838
|
+
optionSettings: { groupField }
|
|
839
|
+
} = this;
|
|
840
|
+
return option == null ? null : option[groupField] ?? null;
|
|
841
|
+
},
|
|
776
842
|
/**
|
|
777
843
|
* @param {Option} option
|
|
778
844
|
* @return {boolean}
|
|
@@ -791,6 +857,9 @@ export default {
|
|
|
791
857
|
let disabled = option ? option[disabledField] : null;
|
|
792
858
|
return Boolean(disabled);
|
|
793
859
|
},
|
|
860
|
+
/**
|
|
861
|
+
* @return {function(): void}
|
|
862
|
+
*/
|
|
794
863
|
createOptionRollback() {
|
|
795
864
|
const optionsSelected = [...this.optionsSelected];
|
|
796
865
|
return () => {
|
|
@@ -803,18 +872,29 @@ export default {
|
|
|
803
872
|
* @param {Option} option
|
|
804
873
|
*/
|
|
805
874
|
selectOption(option) {
|
|
806
|
-
|
|
875
|
+
const {
|
|
876
|
+
multiple,
|
|
877
|
+
/**
|
|
878
|
+
* @type {MultipleSettings}
|
|
879
|
+
*/
|
|
880
|
+
multipleSettings,
|
|
881
|
+
readonly,
|
|
882
|
+
optionsSelected
|
|
883
|
+
} = this;
|
|
884
|
+
if (this.isOptionSelected(option)) {
|
|
807
885
|
return;
|
|
808
886
|
}
|
|
809
|
-
if (this.
|
|
887
|
+
if (readonly || this.isOptionDisabled(option)) {
|
|
810
888
|
return;
|
|
811
889
|
}
|
|
812
890
|
|
|
813
891
|
const rollback = this.createOptionRollback();
|
|
814
|
-
if (
|
|
815
|
-
|
|
892
|
+
if (multiple) {
|
|
893
|
+
optionsSelected.push(option);
|
|
816
894
|
} else {
|
|
817
895
|
this.optionsSelected = [option];
|
|
896
|
+
}
|
|
897
|
+
if (!multiple || multipleSettings.hideOnSelect) {
|
|
818
898
|
this.popoverShow = false;
|
|
819
899
|
}
|
|
820
900
|
|
|
@@ -824,16 +904,25 @@ export default {
|
|
|
824
904
|
* @param {Option} option
|
|
825
905
|
*/
|
|
826
906
|
deselectOption(option) {
|
|
827
|
-
const { multiple, readonly, optionsSelected } = this;
|
|
828
|
-
if (readonly) {
|
|
907
|
+
const { multiple, multipleSettings, readonly, optionsSelected } = this;
|
|
908
|
+
if (readonly || this.isOptionDisabled(option)) {
|
|
829
909
|
return;
|
|
830
910
|
}
|
|
831
|
-
if (!
|
|
832
|
-
this.popoverShow = false;
|
|
911
|
+
if (!this.isOptionSelected(option)) {
|
|
833
912
|
return;
|
|
834
913
|
}
|
|
914
|
+
|
|
835
915
|
const rollback = this.createOptionRollback();
|
|
836
|
-
|
|
916
|
+
if (multiple) {
|
|
917
|
+
this.optionsSelected = optionsSelected.toSpliced(optionsSelected.indexOf(option), 1);
|
|
918
|
+
} else {
|
|
919
|
+
this.optionsSelected = [];
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
if (!multiple || multipleSettings.hideOnSelect) {
|
|
923
|
+
this.popoverShow = false;
|
|
924
|
+
}
|
|
925
|
+
|
|
837
926
|
this.triggerModelChange(rollback);
|
|
838
927
|
},
|
|
839
928
|
/**
|
|
@@ -855,6 +944,10 @@ export default {
|
|
|
855
944
|
getDatalistRef() {
|
|
856
945
|
return this.$refs.datalist;
|
|
857
946
|
},
|
|
947
|
+
/**
|
|
948
|
+
*
|
|
949
|
+
* @param isPopoverShown
|
|
950
|
+
*/
|
|
858
951
|
handleSearchbar(isPopoverShown) {
|
|
859
952
|
if (!isPopoverShown) {
|
|
860
953
|
this.searchQuery = '';
|
|
@@ -864,6 +957,21 @@ export default {
|
|
|
864
957
|
this.$refs.searchbar.focus();
|
|
865
958
|
});
|
|
866
959
|
},
|
|
960
|
+
isShowGroup({ option, index }) {
|
|
961
|
+
const { groupField } = this.optionSettings;
|
|
962
|
+
if (groupField == null) {
|
|
963
|
+
return false;
|
|
964
|
+
}
|
|
965
|
+
if (index === 0) {
|
|
966
|
+
return true;
|
|
967
|
+
}
|
|
968
|
+
const { optionsInternal } = this;
|
|
969
|
+
const currentGroup = this.getOptionGroup(option);
|
|
970
|
+
const prevGroup = this.getOptionGroup(optionsInternal[index - 1]);
|
|
971
|
+
return isEqual(prevGroup, currentGroup) === false;
|
|
972
|
+
},
|
|
973
|
+
|
|
974
|
+
// EVENTS
|
|
867
975
|
onClick() {
|
|
868
976
|
const { popoverShow, optionsSelected } = this;
|
|
869
977
|
this.togglePopover();
|