@kws3/ui 1.9.0 → 1.9.3
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/CHANGELOG.mdx +12 -0
- package/forms/AutoComplete.svelte +70 -57
- package/forms/select/MultiSelect.svelte +32 -26
- package/package.json +2 -3
- package/styles/Select.scss +1 -1
- package/utils/fuzzy.js +116 -0
- package/utils/fuzzysearch.js +38 -17
package/CHANGELOG.mdx
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## 1.9.3
|
|
2
|
+
- Bug fix with fuzzy.js initial config hoisting
|
|
3
|
+
|
|
4
|
+
## 1.9.2
|
|
5
|
+
- Bug fix with fuzzy.js and Vite prebundling
|
|
6
|
+
- Debounce fuzzy searches
|
|
7
|
+
- Expose `@kws3/ui/utils/fuzzysearch` as a reusable function
|
|
8
|
+
|
|
9
|
+
## 1.9.1
|
|
10
|
+
- `SearchableSelect` and `MultiSelect`: match colors of dropdown area to theme color when dropdown area is inside a `Portal`
|
|
11
|
+
- `AutoComplete`: match colors of dropdown area to theme color when dropdown area is inside a `Portal`
|
|
12
|
+
|
|
1
13
|
## 1.9.0
|
|
2
14
|
- Use new fuzzy algorithm for `AutoComplete`,`MultiSelect` and `SearchableSelect` component
|
|
3
15
|
- Add property `scoreThreshold` in `AutoComplete`,`MultiSelect` and `SearchableSelect` component to control search accuracy.
|
|
@@ -66,7 +66,9 @@ Default value: `<span>{option.label}</span>`
|
|
|
66
66
|
class="button is-paddingless delete is-medium is-loading" />
|
|
67
67
|
{/if}
|
|
68
68
|
{#if rootContainer}
|
|
69
|
-
<div
|
|
69
|
+
<div
|
|
70
|
+
class="kws-autocomplete is-{color || 'primary'}"
|
|
71
|
+
use:portal={dropdown_portal}>
|
|
70
72
|
<ul bind:this={dropdown} class="options" class:hidden={!show_options}>
|
|
71
73
|
{#each filtered_options as option}
|
|
72
74
|
<li
|
|
@@ -98,7 +100,7 @@ Default value: `<span>{option.label}</span>`
|
|
|
98
100
|
import { debounce } from "@kws3/ui/utils";
|
|
99
101
|
import { createEventDispatcher, onMount, tick } from "svelte";
|
|
100
102
|
import { createPopper } from "@popperjs/core";
|
|
101
|
-
import
|
|
103
|
+
import { fuzzysearch } from "../utils/fuzzysearch";
|
|
102
104
|
|
|
103
105
|
const sameWidthPopperModifier = {
|
|
104
106
|
name: "sameWidth",
|
|
@@ -223,7 +225,8 @@ Default value: `<span>{option.label}</span>`
|
|
|
223
225
|
filtered_options = [], //list of options filtered by search query
|
|
224
226
|
normalised_options = [], //list of options normalised
|
|
225
227
|
options_loading = false, //indictaes whether async search function is running
|
|
226
|
-
mounted = false
|
|
228
|
+
mounted = false, //indicates whether component is mounted
|
|
229
|
+
fuzzyOpts = {}; // fuzzy.js lib options
|
|
227
230
|
|
|
228
231
|
let list_text_size = {
|
|
229
232
|
small: "7",
|
|
@@ -260,38 +263,11 @@ Default value: `<span>{option.label}</span>`
|
|
|
260
263
|
}
|
|
261
264
|
|
|
262
265
|
function triggerSearch(filters) {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
let opts = [];
|
|
268
|
-
if (word) {
|
|
269
|
-
if (allow_fuzzy_match) {
|
|
270
|
-
opts = fuzzySearch(word, normalised_options);
|
|
271
|
-
} else {
|
|
272
|
-
opts = [...normalised_options].filter((item) => {
|
|
273
|
-
// filter out items that don't match `filter`
|
|
274
|
-
if (typeof item === "object" && item.value) {
|
|
275
|
-
return (
|
|
276
|
-
typeof item.value === "string" &&
|
|
277
|
-
item.value.toLowerCase().indexOf(word) > -1
|
|
278
|
-
);
|
|
279
|
-
}
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
cache[idx] = opts; // storing options to current index on cache
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
filtered_options = Object.values(cache) // get values from cache
|
|
288
|
-
.flat() // flatten array
|
|
289
|
-
.filter((v, i, self) => i === self.findIndex((t) => t.value === v.value)); // remove duplicates
|
|
290
|
-
|
|
291
|
-
if (highlighted_results && !allow_fuzzy_match) {
|
|
292
|
-
filtered_options = highlightMatches(filtered_options, filters);
|
|
266
|
+
if (allow_fuzzy_match) {
|
|
267
|
+
debouncedFuzzySearch(filters, [...normalised_options]);
|
|
268
|
+
} else {
|
|
269
|
+
searchInStrictMode(filters, [...normalised_options]);
|
|
293
270
|
}
|
|
294
|
-
setOptionsVisible(true);
|
|
295
271
|
}
|
|
296
272
|
|
|
297
273
|
function triggerExternalSearch(filters) {
|
|
@@ -325,14 +301,18 @@ Default value: `<span>{option.label}</span>`
|
|
|
325
301
|
modifiers: [sameWidthPopperModifier],
|
|
326
302
|
});
|
|
327
303
|
|
|
328
|
-
if (allow_fuzzy_match
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
304
|
+
if (allow_fuzzy_match) {
|
|
305
|
+
fuzzyOpts = {
|
|
306
|
+
analyzeSubTerms: true,
|
|
307
|
+
analyzeSubTermDepth: 10,
|
|
308
|
+
highlighting: {
|
|
309
|
+
after: "",
|
|
310
|
+
before: "",
|
|
311
|
+
},
|
|
312
|
+
};
|
|
333
313
|
if (highlighted_results) {
|
|
334
|
-
|
|
335
|
-
|
|
314
|
+
fuzzyOpts.highlighting.before = `<span class="h">`;
|
|
315
|
+
fuzzyOpts.highlighting.after = "</span>";
|
|
336
316
|
}
|
|
337
317
|
}
|
|
338
318
|
|
|
@@ -444,25 +424,58 @@ Default value: `<span>{option.label}</span>`
|
|
|
444
424
|
return v && v.trim() ? v.toLowerCase().trim().split(/\s+/) : [];
|
|
445
425
|
}
|
|
446
426
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
427
|
+
const debouncedFuzzySearch = debounce(searchInFuzzyMode, 200, false);
|
|
428
|
+
|
|
429
|
+
function searchInFuzzyMode(filters, options) {
|
|
430
|
+
let cache = {};
|
|
431
|
+
//TODO - can optimize more for very long lists
|
|
432
|
+
filters.forEach((word, idx) => {
|
|
433
|
+
// iterate over each word in the search query
|
|
434
|
+
let opts = [];
|
|
435
|
+
if (word) {
|
|
436
|
+
let result = fuzzysearch(word, options, {
|
|
437
|
+
search_key: "label",
|
|
438
|
+
scoreThreshold,
|
|
439
|
+
fuzzyOpts,
|
|
440
|
+
});
|
|
441
|
+
opts = result;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
cache[idx] = opts; // storing options to current index on cache
|
|
457
445
|
});
|
|
446
|
+
setFilteredOptions(cache);
|
|
447
|
+
}
|
|
458
448
|
|
|
459
|
-
|
|
460
|
-
let
|
|
449
|
+
function searchInStrictMode(filters, options) {
|
|
450
|
+
let cache = {};
|
|
451
|
+
filters.forEach((word, idx) => {
|
|
452
|
+
// iterate over each word in the search query
|
|
453
|
+
let opts = [];
|
|
454
|
+
if (word) {
|
|
455
|
+
opts = options.filter((item) => {
|
|
456
|
+
// filter out items that don't match `filter`
|
|
457
|
+
if (typeof item === "object" && item.value) {
|
|
458
|
+
return (
|
|
459
|
+
typeof item.value === "string" &&
|
|
460
|
+
item.value.toLowerCase().indexOf(word) > -1
|
|
461
|
+
);
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
}
|
|
461
465
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
);
|
|
466
|
+
cache[idx] = opts; // storing options to current index on cache
|
|
467
|
+
});
|
|
468
|
+
setFilteredOptions(cache, filters);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function setFilteredOptions(cache, filters) {
|
|
472
|
+
filtered_options = Object.values(cache) // get values from cache
|
|
473
|
+
.flat() // flatten array
|
|
474
|
+
.filter((v, i, self) => i === self.findIndex((t) => t.value === v.value)); // remove duplicates
|
|
465
475
|
|
|
466
|
-
|
|
476
|
+
if (highlighted_results && !allow_fuzzy_match) {
|
|
477
|
+
filtered_options = highlightMatches(filtered_options, filters);
|
|
478
|
+
}
|
|
479
|
+
setOptionsVisible(true);
|
|
467
480
|
}
|
|
468
481
|
</script>
|
|
@@ -120,7 +120,9 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
120
120
|
style={shouldShowClearAll ? "" : "display: none;"} />
|
|
121
121
|
{/if}
|
|
122
122
|
{#if rootContainer}
|
|
123
|
-
<div
|
|
123
|
+
<div
|
|
124
|
+
class="kws-searchableselect is-{color || 'primary'}"
|
|
125
|
+
use:portal={dropdown_portal}>
|
|
124
126
|
<ul
|
|
125
127
|
bind:this={dropdown}
|
|
126
128
|
class="options {single ? 'is-single' : 'is-multi'}"
|
|
@@ -162,7 +164,7 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
162
164
|
import { debounce } from "@kws3/ui/utils";
|
|
163
165
|
import { createEventDispatcher, onMount, tick } from "svelte";
|
|
164
166
|
import { createPopper } from "@popperjs/core";
|
|
165
|
-
import
|
|
167
|
+
import { fuzzysearch } from "../../utils/fuzzysearch";
|
|
166
168
|
|
|
167
169
|
const sameWidthPopperModifier = {
|
|
168
170
|
name: "sameWidth",
|
|
@@ -324,6 +326,7 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
324
326
|
searchText = "",
|
|
325
327
|
searching = false,
|
|
326
328
|
showOptions = false,
|
|
329
|
+
fuzzyOpts = {}, // fuzzy.js lib options
|
|
327
330
|
filteredOptions = [], //list of options filtered by search query
|
|
328
331
|
normalisedOptions = [], //list of options normalised
|
|
329
332
|
selectedOptions = [], //list of options that are selected
|
|
@@ -405,7 +408,7 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
405
408
|
debouncedTriggerSearch(filter);
|
|
406
409
|
} else {
|
|
407
410
|
if (allow_fuzzy_match) {
|
|
408
|
-
|
|
411
|
+
fuzzySearch(filter, [...normalisedOptions]);
|
|
409
412
|
} else {
|
|
410
413
|
filteredOptions = strictSearch(filter, [...normalisedOptions]);
|
|
411
414
|
}
|
|
@@ -414,7 +417,11 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
414
417
|
|
|
415
418
|
function updateActiveOption() {
|
|
416
419
|
if (
|
|
417
|
-
(activeOption &&
|
|
420
|
+
(activeOption &&
|
|
421
|
+
searching &&
|
|
422
|
+
!filteredOptions.some(
|
|
423
|
+
(fo) => fo[used_value_key] === activeOption[used_value_key]
|
|
424
|
+
)) ||
|
|
418
425
|
(!activeOption && searchText)
|
|
419
426
|
) {
|
|
420
427
|
activeOption = filteredOptions[0];
|
|
@@ -479,9 +486,15 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
479
486
|
modifiers: [sameWidthPopperModifier],
|
|
480
487
|
});
|
|
481
488
|
|
|
482
|
-
if (allow_fuzzy_match
|
|
483
|
-
|
|
484
|
-
|
|
489
|
+
if (allow_fuzzy_match) {
|
|
490
|
+
fuzzyOpts = {
|
|
491
|
+
analyzeSubTerms: true,
|
|
492
|
+
analyzeSubTermDepth: 10,
|
|
493
|
+
highlighting: {
|
|
494
|
+
after: "",
|
|
495
|
+
before: "",
|
|
496
|
+
},
|
|
497
|
+
};
|
|
485
498
|
}
|
|
486
499
|
|
|
487
500
|
//normalize value for single versus multiselect
|
|
@@ -714,27 +727,20 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
714
727
|
});
|
|
715
728
|
};
|
|
716
729
|
|
|
717
|
-
|
|
718
|
-
|
|
730
|
+
const fuzzySearch = debounce(searchInFuzzyMode, 200, false);
|
|
731
|
+
|
|
732
|
+
function searchInFuzzyMode(filter, options) {
|
|
733
|
+
if (!filter) {
|
|
734
|
+
filteredOptions = options;
|
|
735
|
+
return;
|
|
736
|
+
}
|
|
719
737
|
if (options.length) {
|
|
720
|
-
let
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
!item.score || (item.score && item.score < output.score)
|
|
725
|
-
? output.score
|
|
726
|
-
: item.score || 0;
|
|
727
|
-
return item;
|
|
738
|
+
let result = fuzzysearch(filter, options, {
|
|
739
|
+
search_key: used_search_key,
|
|
740
|
+
scoreThreshold,
|
|
741
|
+
fuzzyOpts,
|
|
728
742
|
});
|
|
729
|
-
|
|
730
|
-
let maxScore = Math.max(...OPTS.map((i) => i.score));
|
|
731
|
-
let calculatedLimit = maxScore - scoreThreshold;
|
|
732
|
-
|
|
733
|
-
OPTS = OPTS.filter(
|
|
734
|
-
(r) => r.score > (calculatedLimit > 0 ? calculatedLimit : 0)
|
|
735
|
-
).map((o) => o.original);
|
|
736
|
-
|
|
737
|
-
return OPTS;
|
|
743
|
+
filteredOptions = result;
|
|
738
744
|
}
|
|
739
745
|
}
|
|
740
746
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kws3/ui",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.3",
|
|
4
4
|
"description": "UI components for use with Svelte v3 applications.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -25,10 +25,9 @@
|
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"apexcharts": "3.33.2",
|
|
27
27
|
"flatpickr": "^4.5.2",
|
|
28
|
-
"fuzzy.js": "^0.1.0",
|
|
29
28
|
"svelte-portal": "^2.1.2",
|
|
30
29
|
"text-mask-core": "^5.1.2",
|
|
31
30
|
"tippy.js": "^6.3.1"
|
|
32
31
|
},
|
|
33
|
-
"gitHead": "
|
|
32
|
+
"gitHead": "c6a60f59d36f7bb3a6e4475c6c727c036d235581"
|
|
34
33
|
}
|
package/styles/Select.scss
CHANGED
|
@@ -187,7 +187,7 @@ $kws-select-options-z-index: $__modal-z + 1 !default;
|
|
|
187
187
|
$color-invert: nth($pair, 2);
|
|
188
188
|
$color-light: findLightColor($color);
|
|
189
189
|
$color-dark: findDarkColor($color);
|
|
190
|
-
.searchableselect {
|
|
190
|
+
.kws-searchableselect {
|
|
191
191
|
&.is-#{$name} {
|
|
192
192
|
border-color: $color;
|
|
193
193
|
&:focus-within {
|
package/utils/fuzzy.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fuzzy.js v0.1.0
|
|
3
|
+
* (c) 2016 Ben Ripkens
|
|
4
|
+
* @license: MIT
|
|
5
|
+
* @params
|
|
6
|
+
* term : haystack
|
|
7
|
+
* query : needle
|
|
8
|
+
* opts: {
|
|
9
|
+
* analyzeSubTerms,
|
|
10
|
+
* analyzeSubTermDepth
|
|
11
|
+
* highlighting
|
|
12
|
+
* }
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
*
|
|
16
|
+
* Adapted from fuzzy.js for @kws3/ui to work with vite prebundling
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/*
|
|
20
|
+
* Whether or not fuzzy.js should analyze sub-terms, i.e. also
|
|
21
|
+
* check term starting positions != 0.
|
|
22
|
+
*
|
|
23
|
+
* Example:
|
|
24
|
+
* Given the term 'Halleluja' and query 'luja'
|
|
25
|
+
*
|
|
26
|
+
* Fuzzy.js scores this combination with an 8, when analyzeSubTerms is
|
|
27
|
+
* set to false, as the following matching string will be calculated:
|
|
28
|
+
* Ha[l]lel[uja]
|
|
29
|
+
*
|
|
30
|
+
* If you activate sub temr analysis though, the query will reach a score
|
|
31
|
+
* of 10, as the matching string looks as following:
|
|
32
|
+
* Halle[luja]
|
|
33
|
+
*
|
|
34
|
+
* Naturally, the second version is more expensive than the first one.
|
|
35
|
+
* You should therefore configure how many sub terms you which to analyse.
|
|
36
|
+
* This can be configured through opts.analyzeSubTermDepth = 10.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
export default function fuzzy(term, query, opts = {}) {
|
|
40
|
+
let analyzeSubTerms = opts.analyzeSubTerms ? opts.analyzeSubTerms : false;
|
|
41
|
+
let analyzeSubTermDepth = opts.analyzeSubTermDepth
|
|
42
|
+
? opts.analyzeSubTermDepth
|
|
43
|
+
: 10;
|
|
44
|
+
let highlighting = opts.highlighting
|
|
45
|
+
? opts.highlighting
|
|
46
|
+
: {
|
|
47
|
+
before: "<em>",
|
|
48
|
+
after: "</em>",
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
let max = calcFuzzyScore(term, query, highlighting);
|
|
52
|
+
let termLength = term.length;
|
|
53
|
+
|
|
54
|
+
if (analyzeSubTerms) {
|
|
55
|
+
for (let i = 1; i < termLength && i < analyzeSubTermDepth; i++) {
|
|
56
|
+
let subTerm = term.substring(i);
|
|
57
|
+
let score = calcFuzzyScore(subTerm, query, highlighting);
|
|
58
|
+
if (score.score > max.score) {
|
|
59
|
+
// we need to correct 'term' and 'matchedTerm', as calcFuzzyScore
|
|
60
|
+
// does not now that it operates on a substring. Doing it only for
|
|
61
|
+
// new maximum score to save some performance.
|
|
62
|
+
score.term = term;
|
|
63
|
+
score.highlightedTerm = term.substring(0, i) + score.highlightedTerm;
|
|
64
|
+
max = score;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return max;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function calcFuzzyScore(term, query, highlighting) {
|
|
73
|
+
let score = 0;
|
|
74
|
+
let termLength = term.length;
|
|
75
|
+
let queryLength = query.length;
|
|
76
|
+
let _highlighting = "";
|
|
77
|
+
let ti = 0;
|
|
78
|
+
// -1 would not work as this would break the calculations of bonus
|
|
79
|
+
// points for subsequent character matches. Something like
|
|
80
|
+
// Number.MIN_VALUE would be more appropriate, but unfortunately
|
|
81
|
+
// Number.MIN_VALUE + 1 equals 1...
|
|
82
|
+
let previousMatchingCharacter = -2;
|
|
83
|
+
|
|
84
|
+
for (let qi = 0; qi < queryLength && ti < termLength; qi++) {
|
|
85
|
+
let qc = query.charAt(qi);
|
|
86
|
+
let lowerQc = qc.toLowerCase();
|
|
87
|
+
|
|
88
|
+
for (; ti < termLength; ti++) {
|
|
89
|
+
let tc = term.charAt(ti);
|
|
90
|
+
|
|
91
|
+
if (lowerQc === tc.toLowerCase()) {
|
|
92
|
+
score++;
|
|
93
|
+
|
|
94
|
+
if (previousMatchingCharacter + 1 === ti) {
|
|
95
|
+
score += 2;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
_highlighting += highlighting.before + tc + highlighting.after;
|
|
99
|
+
previousMatchingCharacter = ti;
|
|
100
|
+
ti++;
|
|
101
|
+
break;
|
|
102
|
+
} else {
|
|
103
|
+
_highlighting += tc;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
_highlighting += term.substring(ti, term.length);
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
score: score,
|
|
112
|
+
term: term,
|
|
113
|
+
query: query,
|
|
114
|
+
highlightedTerm: _highlighting,
|
|
115
|
+
};
|
|
116
|
+
}
|
package/utils/fuzzysearch.js
CHANGED
|
@@ -1,20 +1,41 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
continue outer;
|
|
1
|
+
import fuzzy from "./fuzzy.js";
|
|
2
|
+
|
|
3
|
+
export function fuzzysearch(needle, haystack, opts) {
|
|
4
|
+
let search_key = defaultValue(opts, "search_key", "value");
|
|
5
|
+
let scoreThreshold = defaultValue(opts, "scoreThreshold", 5);
|
|
6
|
+
let fuzzyOpts = opts.fuzzyOpts ? opts.fuzzyOpts : {};
|
|
7
|
+
|
|
8
|
+
let OPTS = haystack.map((option) => {
|
|
9
|
+
let item = { ...option };
|
|
10
|
+
item.original = { ...option };
|
|
11
|
+
if (typeof item === "object") {
|
|
12
|
+
if (!Array.isArray(search_key)) {
|
|
13
|
+
search_key = [search_key];
|
|
15
14
|
}
|
|
15
|
+
|
|
16
|
+
search_key.forEach((s_key) => {
|
|
17
|
+
if (`${s_key}` in item) {
|
|
18
|
+
let output = fuzzy(option[s_key], needle, fuzzyOpts);
|
|
19
|
+
item.original[s_key] = output.highlightedTerm;
|
|
20
|
+
item.score =
|
|
21
|
+
!item.score || (item.score && item.score < output.score)
|
|
22
|
+
? output.score
|
|
23
|
+
: item.score || 0;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
16
26
|
}
|
|
17
|
-
return
|
|
18
|
-
}
|
|
19
|
-
|
|
27
|
+
return item;
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
let maxScore = Math.max(...OPTS.map((i) => i.score));
|
|
31
|
+
let calculatedLimit = maxScore - scoreThreshold;
|
|
32
|
+
|
|
33
|
+
OPTS = OPTS.filter(
|
|
34
|
+
(r) => r.score > (calculatedLimit > 0 ? calculatedLimit : 0)
|
|
35
|
+
);
|
|
36
|
+
return OPTS.map((i) => i.original);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function defaultValue(opts, key, value) {
|
|
40
|
+
return opts && opts[key] ? opts[key] : value;
|
|
20
41
|
}
|