@signal24/vue-foundation 3.6.0 → 3.7.0
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 +1 -1
- package/src/components/smart-select.vue +90 -68
package/package.json
CHANGED
|
@@ -49,6 +49,8 @@ export default {
|
|
|
49
49
|
props: [
|
|
50
50
|
'modelValue',
|
|
51
51
|
'options',
|
|
52
|
+
'prependOptions',
|
|
53
|
+
'appendOptions',
|
|
52
54
|
'preload',
|
|
53
55
|
'url',
|
|
54
56
|
'urlParams',
|
|
@@ -71,7 +73,7 @@ export default {
|
|
|
71
73
|
data() {
|
|
72
74
|
return {
|
|
73
75
|
isLoaded: false,
|
|
74
|
-
|
|
76
|
+
loadedOptions: [],
|
|
75
77
|
isSearching: false,
|
|
76
78
|
searchText: '',
|
|
77
79
|
selectedOption: null,
|
|
@@ -83,12 +85,11 @@ export default {
|
|
|
83
85
|
},
|
|
84
86
|
|
|
85
87
|
computed: {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
/**
|
|
89
|
+
* EFFECTIVE PROPS
|
|
90
|
+
*/
|
|
90
91
|
effectiveDisabled() {
|
|
91
|
-
return this.disabled || !this.
|
|
92
|
+
return this.disabled || !this.loadedOptions;
|
|
92
93
|
},
|
|
93
94
|
|
|
94
95
|
effectivePlaceholder() {
|
|
@@ -97,47 +98,6 @@ export default {
|
|
|
97
98
|
return this.placeholder || '';
|
|
98
99
|
},
|
|
99
100
|
|
|
100
|
-
effectiveOptions() {
|
|
101
|
-
let options = [...this.decoratedOptions];
|
|
102
|
-
|
|
103
|
-
if (this.isSearching) {
|
|
104
|
-
const strippedSearchText = this.searchText.trim().toLowerCase();
|
|
105
|
-
|
|
106
|
-
if (strippedSearchText.length) {
|
|
107
|
-
options = options.filter(option => option.searchContent.includes(strippedSearchText));
|
|
108
|
-
|
|
109
|
-
const escapedSearchText = this.searchText.escapeHtml().replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
110
|
-
const searchRe = new RegExp(`(${escapedSearchText})`, 'ig');
|
|
111
|
-
|
|
112
|
-
options = options.map(option => {
|
|
113
|
-
option = { ...option };
|
|
114
|
-
option.titleHtml = option.titleHtml.replace(searchRe, '<mark>$1</mark>');
|
|
115
|
-
if (option.subtitleHtml)
|
|
116
|
-
option.subtitleHtml = option.subtitleHtml.replace(searchRe, '<mark>$1</mark>');
|
|
117
|
-
return option;
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
if (this.shouldShowCreateOption) {
|
|
121
|
-
const hasExactMatch =
|
|
122
|
-
options.find(option => option.searchContent === strippedSearchText) !== undefined;
|
|
123
|
-
if (!hasExactMatch) {
|
|
124
|
-
options.push({
|
|
125
|
-
key: createSymbol,
|
|
126
|
-
titleHtml: 'Create <strong>' + this.searchText.trim() + '</strong>...'
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
} else if (this.nullTitle) {
|
|
132
|
-
options.unshift({
|
|
133
|
-
key: nullSymbol,
|
|
134
|
-
titleHtml: this.nullTitle
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return options;
|
|
139
|
-
},
|
|
140
|
-
|
|
141
101
|
effectiveIdKey() {
|
|
142
102
|
return this.idKey || 'id';
|
|
143
103
|
},
|
|
@@ -148,7 +108,7 @@ export default {
|
|
|
148
108
|
|
|
149
109
|
effectiveValueKey() {
|
|
150
110
|
if (this.valueKey) return this.valueKey;
|
|
151
|
-
if (this.
|
|
111
|
+
if (this.options && !Array.isArray(this.options)) return this.effectiveIdKey;
|
|
152
112
|
return undefined;
|
|
153
113
|
},
|
|
154
114
|
|
|
@@ -156,17 +116,28 @@ export default {
|
|
|
156
116
|
return this.noResultsText || 'No options match your search.';
|
|
157
117
|
},
|
|
158
118
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
: this.resolvedOptions;
|
|
119
|
+
/**
|
|
120
|
+
* OPTIONS GENERATION
|
|
121
|
+
*/
|
|
122
|
+
|
|
123
|
+
loadedOptionsArray() {
|
|
124
|
+
return this.arrayifyOptions(this.loadedOptions);
|
|
166
125
|
},
|
|
167
126
|
|
|
168
|
-
|
|
169
|
-
return this.
|
|
127
|
+
prependOptionsArray() {
|
|
128
|
+
return this.prependOptions ? this.arrayifyOptions(this.prependOptions) : [];
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
appendOptionsArray() {
|
|
132
|
+
return this.appendOptions ? this.arrayifyOptions(this.appendOptions) : [];
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
fullOptionsArray() {
|
|
136
|
+
return [...this.prependOptionsArray, ...this.loadedOptionsArray, ...this.appendOptionsArray];
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
optionsDescriptors() {
|
|
140
|
+
return this.fullOptionsArray.map((option, index) => {
|
|
170
141
|
const title = this.getOptionTitle(option);
|
|
171
142
|
const subtitle = this.getOptionSubtitle(option);
|
|
172
143
|
const strippedTitle = title ? title.text.trim().toLowerCase() : '';
|
|
@@ -190,6 +161,47 @@ export default {
|
|
|
190
161
|
ref: option
|
|
191
162
|
};
|
|
192
163
|
});
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
effectiveOptions() {
|
|
167
|
+
let options = [...this.optionsDescriptors];
|
|
168
|
+
|
|
169
|
+
if (this.isSearching) {
|
|
170
|
+
const strippedSearchText = this.searchText.trim().toLowerCase();
|
|
171
|
+
|
|
172
|
+
if (strippedSearchText.length) {
|
|
173
|
+
options = options.filter(option => option.searchContent.includes(strippedSearchText));
|
|
174
|
+
|
|
175
|
+
const escapedSearchText = this.searchText.escapeHtml().replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
176
|
+
const searchRe = new RegExp(`(${escapedSearchText})`, 'ig');
|
|
177
|
+
|
|
178
|
+
options = options.map(option => {
|
|
179
|
+
option = { ...option };
|
|
180
|
+
option.titleHtml = option.titleHtml.replace(searchRe, '<mark>$1</mark>');
|
|
181
|
+
if (option.subtitleHtml)
|
|
182
|
+
option.subtitleHtml = option.subtitleHtml.replace(searchRe, '<mark>$1</mark>');
|
|
183
|
+
return option;
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
if (this.shouldShowCreateOption) {
|
|
187
|
+
const hasExactMatch =
|
|
188
|
+
options.find(option => option.searchContent === strippedSearchText) !== undefined;
|
|
189
|
+
if (!hasExactMatch) {
|
|
190
|
+
options.push({
|
|
191
|
+
key: createSymbol,
|
|
192
|
+
titleHtml: 'Create <strong>' + this.searchText.trim() + '</strong>...'
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
} else if (this.nullTitle) {
|
|
198
|
+
options.unshift({
|
|
199
|
+
key: nullSymbol,
|
|
200
|
+
titleHtml: this.nullTitle
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return options;
|
|
193
205
|
}
|
|
194
206
|
},
|
|
195
207
|
|
|
@@ -201,7 +213,7 @@ export default {
|
|
|
201
213
|
},
|
|
202
214
|
|
|
203
215
|
options() {
|
|
204
|
-
this.
|
|
216
|
+
this.loadedOptions = this.options;
|
|
205
217
|
},
|
|
206
218
|
|
|
207
219
|
url() {
|
|
@@ -214,7 +226,7 @@ export default {
|
|
|
214
226
|
|
|
215
227
|
// data
|
|
216
228
|
|
|
217
|
-
|
|
229
|
+
optionsDescriptors() {
|
|
218
230
|
this.shouldDisplayOptions && setTimeout(this.highlightInitialOption, 0);
|
|
219
231
|
},
|
|
220
232
|
|
|
@@ -245,8 +257,7 @@ export default {
|
|
|
245
257
|
this.shouldShowCreateOption = this.$attrs['onCreateItem'] !== undefined;
|
|
246
258
|
|
|
247
259
|
if (this.options) {
|
|
248
|
-
this.
|
|
249
|
-
// this.buildDecoratedOptions();
|
|
260
|
+
this.loadedOptions = this.options;
|
|
250
261
|
this.isLoaded = true;
|
|
251
262
|
} else if (this.$isPropTruthy(this.preload)) {
|
|
252
263
|
this.performInitialLoad();
|
|
@@ -256,7 +267,9 @@ export default {
|
|
|
256
267
|
|
|
257
268
|
this.$watch('selectedOption', () => {
|
|
258
269
|
const newValue =
|
|
259
|
-
this.selectedOption && this.effectiveValueKey
|
|
270
|
+
this.selectedOption && this.effectiveValueKey
|
|
271
|
+
? this.selectedOption[this.effectiveValueKey]
|
|
272
|
+
: this.selectedOption;
|
|
260
273
|
newValue === this.modelValue || this.$emit('update:modelValue', newValue);
|
|
261
274
|
});
|
|
262
275
|
},
|
|
@@ -264,7 +277,7 @@ export default {
|
|
|
264
277
|
methods: {
|
|
265
278
|
async performInitialLoad() {
|
|
266
279
|
await this.reloadOptions();
|
|
267
|
-
this.$emit('optionsLoaded', this.
|
|
280
|
+
this.$emit('optionsLoaded', this.loadedOptions);
|
|
268
281
|
|
|
269
282
|
if (this.$isPropTruthy(this.remoteSearch)) {
|
|
270
283
|
this.$watch('searchText', debounce(this.reloadOptionsIfSearching, 250));
|
|
@@ -275,7 +288,7 @@ export default {
|
|
|
275
288
|
if (this.preload) return this.reloadOptions();
|
|
276
289
|
if (!this.isLoaded) return;
|
|
277
290
|
this.isLoaded = false;
|
|
278
|
-
this.
|
|
291
|
+
this.loadedOptions = [];
|
|
279
292
|
},
|
|
280
293
|
|
|
281
294
|
async reloadOptions() {
|
|
@@ -284,7 +297,7 @@ export default {
|
|
|
284
297
|
this.$isPropTruthy(this.remoteSearch) && this.searchText && (params.q = this.searchText);
|
|
285
298
|
|
|
286
299
|
const result = await this.$http.get(this.url, { params: params });
|
|
287
|
-
this.
|
|
300
|
+
this.loadedOptions = result.data;
|
|
288
301
|
this.isLoaded = true;
|
|
289
302
|
},
|
|
290
303
|
|
|
@@ -450,7 +463,7 @@ export default {
|
|
|
450
463
|
this.selectedOptionTitle = null;
|
|
451
464
|
this.$emit('createItem', createText);
|
|
452
465
|
} else {
|
|
453
|
-
const selectedDecoratedOption = this.
|
|
466
|
+
const selectedDecoratedOption = this.optionsDescriptors.find(
|
|
454
467
|
decoratedOption => decoratedOption.key == option.key
|
|
455
468
|
);
|
|
456
469
|
const realOption = selectedDecoratedOption.ref;
|
|
@@ -465,7 +478,7 @@ export default {
|
|
|
465
478
|
handleValueChanged() {
|
|
466
479
|
if (this.modelValue) {
|
|
467
480
|
if (this.effectiveValueKey) {
|
|
468
|
-
this.selectedOption = this.
|
|
481
|
+
this.selectedOption = this.fullOptionsArray.find(
|
|
469
482
|
option => option[this.effectiveValueKey] === this.modelValue
|
|
470
483
|
);
|
|
471
484
|
} else {
|
|
@@ -530,7 +543,16 @@ export default {
|
|
|
530
543
|
},
|
|
531
544
|
|
|
532
545
|
addRemoteOption(option) {
|
|
533
|
-
this.
|
|
546
|
+
this.loadedOptions.push(option);
|
|
547
|
+
},
|
|
548
|
+
|
|
549
|
+
arrayifyOptions(options) {
|
|
550
|
+
return Array.isArray(options)
|
|
551
|
+
? options
|
|
552
|
+
: Object.entries(options).map(entry => ({
|
|
553
|
+
[this.effectiveIdKey]: entry[0],
|
|
554
|
+
[this.effectiveTitleKey]: entry[1]
|
|
555
|
+
}));
|
|
534
556
|
}
|
|
535
557
|
}
|
|
536
558
|
};
|