lucos_search_component 1.0.56 → 1.0.57
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/dist/index.js +53 -9
- package/example/index.html +1 -0
- package/package.json +1 -1
- package/web-components/lucos-search.js +53 -9
package/dist/index.js
CHANGED
|
@@ -5646,7 +5646,7 @@ var tomSelectStylesheet = "/**\n * tom-select.css (v2.5.2)\n * Copyright (c) con
|
|
|
5646
5646
|
|
|
5647
5647
|
class LucosSearchComponent extends HTMLSpanElement {
|
|
5648
5648
|
static get observedAttributes() {
|
|
5649
|
-
return ['data-api-key','data-types','data-exclude-types','data-no-lang','data-common'];
|
|
5649
|
+
return ['data-api-key','data-types','data-exclude-types','data-no-lang','data-common','data-preload'];
|
|
5650
5650
|
}
|
|
5651
5651
|
constructor() {
|
|
5652
5652
|
super();
|
|
@@ -5809,6 +5809,25 @@ class LucosSearchComponent extends HTMLSpanElement {
|
|
|
5809
5809
|
component._searchAbortController = abortController;
|
|
5810
5810
|
|
|
5811
5811
|
errorMessage.setAttribute('hidden', '');
|
|
5812
|
+
const commonSet = new Set((component._commonOptions || []).map(o => o.id));
|
|
5813
|
+
const noLang = component.noLangOption;
|
|
5814
|
+
const noLangIsCommon = noLang && commonSet.has(noLang.id);
|
|
5815
|
+
// When preloaded, filter locally instead of hitting Typesense
|
|
5816
|
+
if (component._preloadedOptions) {
|
|
5817
|
+
const q = query.toLowerCase();
|
|
5818
|
+
let results = q
|
|
5819
|
+
? component._preloadedOptions.filter(r =>
|
|
5820
|
+
r.pref_label.toLowerCase().includes(q) ||
|
|
5821
|
+
(r.labels && r.labels.some(l => l.toLowerCase().includes(q)))
|
|
5822
|
+
)
|
|
5823
|
+
: [...component._preloadedOptions];
|
|
5824
|
+
results = results.filter(r => !commonSet.has(r.id));
|
|
5825
|
+
this.clearOptions();
|
|
5826
|
+
if (component._commonOptions) component._commonOptions.forEach(opt => this.addOption(opt));
|
|
5827
|
+
if (noLang && !noLangIsCommon) results.unshift(noLang);
|
|
5828
|
+
callback(results);
|
|
5829
|
+
return;
|
|
5830
|
+
}
|
|
5812
5831
|
const queryParams = new URLSearchParams({
|
|
5813
5832
|
q: query,
|
|
5814
5833
|
});
|
|
@@ -5823,13 +5842,10 @@ class LucosSearchComponent extends HTMLSpanElement {
|
|
|
5823
5842
|
this.clearOptions();
|
|
5824
5843
|
// Remove common items from results to avoid duplication (they're always shown separately)
|
|
5825
5844
|
if (component._commonOptions) {
|
|
5826
|
-
|
|
5827
|
-
results = results.filter(r => !commonIds.has(r.id));
|
|
5845
|
+
results = results.filter(r => !commonSet.has(r.id));
|
|
5828
5846
|
component._commonOptions.forEach(opt => this.addOption(opt));
|
|
5829
5847
|
}
|
|
5830
|
-
const noLang = component.noLangOption;
|
|
5831
5848
|
// Don't add noLang as standalone if it's already covered by a common item
|
|
5832
|
-
const noLangIsCommon = noLang && component._commonOptions && component._commonOptions.some(o => o.id === noLang.id);
|
|
5833
5849
|
if (noLang && !noLangIsCommon) results.unshift(noLang);
|
|
5834
5850
|
callback(results);
|
|
5835
5851
|
} catch(err) {
|
|
@@ -5851,14 +5867,20 @@ class LucosSearchComponent extends HTMLSpanElement {
|
|
|
5851
5867
|
},
|
|
5852
5868
|
onFocus: function() {
|
|
5853
5869
|
this.clearOptions();
|
|
5870
|
+
const commonSet = new Set((component._commonOptions || []).map(o => o.id));
|
|
5854
5871
|
// Re-add common items first so they own any shared IDs (e.g. zxx in both data-no-lang and data-common)
|
|
5855
5872
|
if (component._commonOptions) {
|
|
5856
5873
|
component._commonOptions.forEach(opt => this.addOption(opt));
|
|
5857
5874
|
}
|
|
5858
5875
|
const noLang = component.noLangOption;
|
|
5859
5876
|
// Skip noLang if its ID is already a common item (would be silently discarded as a duplicate)
|
|
5860
|
-
|
|
5861
|
-
|
|
5877
|
+
if (noLang && !commonSet.has(noLang.id)) this.addOption(noLang);
|
|
5878
|
+
// Re-add preloaded options (excluding common items which are shown separately)
|
|
5879
|
+
if (component._preloadedOptions) {
|
|
5880
|
+
component._preloadedOptions
|
|
5881
|
+
.filter(opt => !commonSet.has(opt.id))
|
|
5882
|
+
.forEach(opt => this.addOption(opt));
|
|
5883
|
+
}
|
|
5862
5884
|
},
|
|
5863
5885
|
// On startup, update any existing options with latest data from search
|
|
5864
5886
|
onInitialize: async function() {
|
|
@@ -5887,9 +5909,25 @@ class LucosSearchComponent extends HTMLSpanElement {
|
|
|
5887
5909
|
this.addOptionGroup(family.code, { label: family.label });
|
|
5888
5910
|
});
|
|
5889
5911
|
}
|
|
5912
|
+
// Preload all matching options (after groups are registered so options slot correctly)
|
|
5913
|
+
if (component.hasAttribute("data-preload")) {
|
|
5914
|
+
const filterValue = component.getAttribute("data-types")
|
|
5915
|
+
? `type:=[${component.getAttribute("data-types")}]`
|
|
5916
|
+
: component.getAttribute("data-exclude_types")
|
|
5917
|
+
? `type:!=[${component.getAttribute("data-exclude_types")}]`
|
|
5918
|
+
: null;
|
|
5919
|
+
// per_page: 250 acts as an upper bound — data-preload is intended for finite datasets
|
|
5920
|
+
const preloadParams = new URLSearchParams({ q: '*', per_page: 250 });
|
|
5921
|
+
if (filterValue) preloadParams.set("filter_by", filterValue);
|
|
5922
|
+
const preloaded = await component.searchRequest(preloadParams);
|
|
5923
|
+
component._preloadedOptions = preloaded;
|
|
5924
|
+
const commonSet = new Set((component._commonOptions || []).map(o => o.id));
|
|
5925
|
+
preloaded.filter(r => !commonSet.has(r.id)).forEach(r => this.addOption(r));
|
|
5926
|
+
}
|
|
5890
5927
|
if (ids.length < 1) return;
|
|
5891
|
-
// Fetch real options from Typesense, excluding
|
|
5892
|
-
const
|
|
5928
|
+
// Fetch real options from Typesense, excluding synthetic/preloaded items
|
|
5929
|
+
const preloadedIds = component._preloadedOptions ? new Set(component._preloadedOptions.map(r => r.id)) : new Set();
|
|
5930
|
+
const excludeIds = new Set([...(noLang ? [noLang.id] : []), ...commonIds, ...preloadedIds]);
|
|
5893
5931
|
const idsToFetch = ids.filter(id => !excludeIds.has(id));
|
|
5894
5932
|
if (idsToFetch.length > 0) {
|
|
5895
5933
|
const searchParams = new URLSearchParams({
|
|
@@ -5912,6 +5950,12 @@ class LucosSearchComponent extends HTMLSpanElement {
|
|
|
5912
5950
|
if (ids.includes(opt.id)) this.updateOption(opt.id, opt);
|
|
5913
5951
|
});
|
|
5914
5952
|
}
|
|
5953
|
+
// Update any pre-selected preloaded items with fresh data
|
|
5954
|
+
if (component._preloadedOptions) {
|
|
5955
|
+
component._preloadedOptions.forEach(opt => {
|
|
5956
|
+
if (ids.includes(opt.id)) this.updateOption(opt.id, opt);
|
|
5957
|
+
});
|
|
5958
|
+
}
|
|
5915
5959
|
},
|
|
5916
5960
|
onItemSelect: function (item) {
|
|
5917
5961
|
// Tom-select prevents clicking on link in an item to work as normal, so force it here
|
package/example/index.html
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
<option selected>https://eolas.l42.eu/metadata/language/ain/</option>
|
|
15
15
|
</select></span>
|
|
16
16
|
<label for="search8">Languages grouped by family:</label><span is="lucos-search" data-api-key="${KEY_LUCOS_ARACHNE}" data-types="Language"><select id="search8"></select></span>
|
|
17
|
+
<label for="search10">Languages preloaded:</label><span is="lucos-search" data-api-key="${KEY_LUCOS_ARACHNE}" data-types="Language" data-preload><select id="search10"></select></span>
|
|
17
18
|
<label for="search9">Languages with common pinned:</label><span is="lucos-search" data-api-key="${KEY_LUCOS_ARACHNE}" data-types="Language" data-no-lang="No Language" data-common="https://eolas.l42.eu/metadata/language/en/,https://eolas.l42.eu/metadata/language/ga/,https://eolas.l42.eu/metadata/language/zxx/"><select id="search9"></select></span>
|
|
18
19
|
<label for="search6">Languages with no-lang option:</label><span is="lucos-search" data-api-key="${KEY_LUCOS_ARACHNE}" data-types="Language" data-no-lang="No Language"><select id="search6"></select></span>
|
|
19
20
|
<label for="search7">Languages with no-lang pre-selected:</label><span is="lucos-search" data-api-key="${KEY_LUCOS_ARACHNE}" data-types="Language" data-no-lang="No Language"><select id="search7" multiple><option selected>https://eolas.l42.eu/metadata/language/zxx/</option></select></span>
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@ import tomSelectStylesheet from 'tom-select/dist/css/tom-select.default.css';
|
|
|
3
3
|
|
|
4
4
|
class LucosSearchComponent extends HTMLSpanElement {
|
|
5
5
|
static get observedAttributes() {
|
|
6
|
-
return ['data-api-key','data-types','data-exclude-types','data-no-lang','data-common'];
|
|
6
|
+
return ['data-api-key','data-types','data-exclude-types','data-no-lang','data-common','data-preload'];
|
|
7
7
|
}
|
|
8
8
|
constructor() {
|
|
9
9
|
super();
|
|
@@ -166,6 +166,25 @@ class LucosSearchComponent extends HTMLSpanElement {
|
|
|
166
166
|
component._searchAbortController = abortController;
|
|
167
167
|
|
|
168
168
|
errorMessage.setAttribute('hidden', '');
|
|
169
|
+
const commonSet = new Set((component._commonOptions || []).map(o => o.id));
|
|
170
|
+
const noLang = component.noLangOption;
|
|
171
|
+
const noLangIsCommon = noLang && commonSet.has(noLang.id);
|
|
172
|
+
// When preloaded, filter locally instead of hitting Typesense
|
|
173
|
+
if (component._preloadedOptions) {
|
|
174
|
+
const q = query.toLowerCase();
|
|
175
|
+
let results = q
|
|
176
|
+
? component._preloadedOptions.filter(r =>
|
|
177
|
+
r.pref_label.toLowerCase().includes(q) ||
|
|
178
|
+
(r.labels && r.labels.some(l => l.toLowerCase().includes(q)))
|
|
179
|
+
)
|
|
180
|
+
: [...component._preloadedOptions];
|
|
181
|
+
results = results.filter(r => !commonSet.has(r.id));
|
|
182
|
+
this.clearOptions();
|
|
183
|
+
if (component._commonOptions) component._commonOptions.forEach(opt => this.addOption(opt));
|
|
184
|
+
if (noLang && !noLangIsCommon) results.unshift(noLang);
|
|
185
|
+
callback(results);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
169
188
|
const queryParams = new URLSearchParams({
|
|
170
189
|
q: query,
|
|
171
190
|
});
|
|
@@ -180,13 +199,10 @@ class LucosSearchComponent extends HTMLSpanElement {
|
|
|
180
199
|
this.clearOptions();
|
|
181
200
|
// Remove common items from results to avoid duplication (they're always shown separately)
|
|
182
201
|
if (component._commonOptions) {
|
|
183
|
-
|
|
184
|
-
results = results.filter(r => !commonIds.has(r.id));
|
|
202
|
+
results = results.filter(r => !commonSet.has(r.id));
|
|
185
203
|
component._commonOptions.forEach(opt => this.addOption(opt));
|
|
186
204
|
}
|
|
187
|
-
const noLang = component.noLangOption;
|
|
188
205
|
// Don't add noLang as standalone if it's already covered by a common item
|
|
189
|
-
const noLangIsCommon = noLang && component._commonOptions && component._commonOptions.some(o => o.id === noLang.id);
|
|
190
206
|
if (noLang && !noLangIsCommon) results.unshift(noLang);
|
|
191
207
|
callback(results);
|
|
192
208
|
} catch(err) {
|
|
@@ -208,14 +224,20 @@ class LucosSearchComponent extends HTMLSpanElement {
|
|
|
208
224
|
},
|
|
209
225
|
onFocus: function() {
|
|
210
226
|
this.clearOptions();
|
|
227
|
+
const commonSet = new Set((component._commonOptions || []).map(o => o.id));
|
|
211
228
|
// Re-add common items first so they own any shared IDs (e.g. zxx in both data-no-lang and data-common)
|
|
212
229
|
if (component._commonOptions) {
|
|
213
230
|
component._commonOptions.forEach(opt => this.addOption(opt));
|
|
214
231
|
}
|
|
215
232
|
const noLang = component.noLangOption;
|
|
216
233
|
// Skip noLang if its ID is already a common item (would be silently discarded as a duplicate)
|
|
217
|
-
|
|
218
|
-
|
|
234
|
+
if (noLang && !commonSet.has(noLang.id)) this.addOption(noLang);
|
|
235
|
+
// Re-add preloaded options (excluding common items which are shown separately)
|
|
236
|
+
if (component._preloadedOptions) {
|
|
237
|
+
component._preloadedOptions
|
|
238
|
+
.filter(opt => !commonSet.has(opt.id))
|
|
239
|
+
.forEach(opt => this.addOption(opt));
|
|
240
|
+
}
|
|
219
241
|
},
|
|
220
242
|
// On startup, update any existing options with latest data from search
|
|
221
243
|
onInitialize: async function() {
|
|
@@ -244,9 +266,25 @@ class LucosSearchComponent extends HTMLSpanElement {
|
|
|
244
266
|
this.addOptionGroup(family.code, { label: family.label });
|
|
245
267
|
});
|
|
246
268
|
}
|
|
269
|
+
// Preload all matching options (after groups are registered so options slot correctly)
|
|
270
|
+
if (component.hasAttribute("data-preload")) {
|
|
271
|
+
const filterValue = component.getAttribute("data-types")
|
|
272
|
+
? `type:=[${component.getAttribute("data-types")}]`
|
|
273
|
+
: component.getAttribute("data-exclude_types")
|
|
274
|
+
? `type:!=[${component.getAttribute("data-exclude_types")}]`
|
|
275
|
+
: null;
|
|
276
|
+
// per_page: 250 acts as an upper bound — data-preload is intended for finite datasets
|
|
277
|
+
const preloadParams = new URLSearchParams({ q: '*', per_page: 250 });
|
|
278
|
+
if (filterValue) preloadParams.set("filter_by", filterValue);
|
|
279
|
+
const preloaded = await component.searchRequest(preloadParams);
|
|
280
|
+
component._preloadedOptions = preloaded;
|
|
281
|
+
const commonSet = new Set((component._commonOptions || []).map(o => o.id));
|
|
282
|
+
preloaded.filter(r => !commonSet.has(r.id)).forEach(r => this.addOption(r));
|
|
283
|
+
}
|
|
247
284
|
if (ids.length < 1) return;
|
|
248
|
-
// Fetch real options from Typesense, excluding
|
|
249
|
-
const
|
|
285
|
+
// Fetch real options from Typesense, excluding synthetic/preloaded items
|
|
286
|
+
const preloadedIds = component._preloadedOptions ? new Set(component._preloadedOptions.map(r => r.id)) : new Set();
|
|
287
|
+
const excludeIds = new Set([...(noLang ? [noLang.id] : []), ...commonIds, ...preloadedIds]);
|
|
250
288
|
const idsToFetch = ids.filter(id => !excludeIds.has(id));
|
|
251
289
|
if (idsToFetch.length > 0) {
|
|
252
290
|
const searchParams = new URLSearchParams({
|
|
@@ -269,6 +307,12 @@ class LucosSearchComponent extends HTMLSpanElement {
|
|
|
269
307
|
if (ids.includes(opt.id)) this.updateOption(opt.id, opt);
|
|
270
308
|
});
|
|
271
309
|
}
|
|
310
|
+
// Update any pre-selected preloaded items with fresh data
|
|
311
|
+
if (component._preloadedOptions) {
|
|
312
|
+
component._preloadedOptions.forEach(opt => {
|
|
313
|
+
if (ids.includes(opt.id)) this.updateOption(opt.id, opt);
|
|
314
|
+
});
|
|
315
|
+
}
|
|
272
316
|
},
|
|
273
317
|
onItemSelect: function (item) {
|
|
274
318
|
// Tom-select prevents clicking on link in an item to work as normal, so force it here
|