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 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
- const commonIds = new Set(component._commonOptions.map(o => o.id));
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
- const noLangIsCommon = noLang && component._commonOptions && component._commonOptions.some(o => o.id === noLang.id);
5861
- if (noLang && !noLangIsCommon) this.addOption(noLang);
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 the synthetic no-lang option and common items
5892
- const excludeIds = new Set([...(noLang ? [noLang.id] : []), ...commonIds]);
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
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lucos_search_component",
3
- "version": "1.0.56",
3
+ "version": "1.0.57",
4
4
  "description": "Web Components for searching lucOS data",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -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
- const commonIds = new Set(component._commonOptions.map(o => o.id));
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
- const noLangIsCommon = noLang && component._commonOptions && component._commonOptions.some(o => o.id === noLang.id);
218
- if (noLang && !noLangIsCommon) this.addOption(noLang);
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 the synthetic no-lang option and common items
249
- const excludeIds = new Set([...(noLang ? [noLang.id] : []), ...commonIds]);
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