lucos_search_component 0.1.1 → 0.1.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/README.md CHANGED
@@ -6,22 +6,56 @@ Web Component for searching lucOS data
6
6
  * Web Components
7
7
 
8
8
  ## Usage
9
+
9
10
  Include the following in your javascript:
10
11
  ```
11
12
  import 'lucos_search_component';
12
13
  ```
13
14
 
15
+ Then pick the relevant component
16
+ ### Search
17
+
18
+ Searches all items available in [lucos_arachne](https://github.com/lucas42/lucos_arachne)
19
+
14
20
  Include the following in your html:
15
21
  ```
16
22
  <span is="lucos-search">
17
- <select>
18
- <option>A</option>
19
- <option>B</option>
20
- <option>C</option>
23
+ <select multiple>
24
+ <option selected>https://contacts.l42.eu/people/2</option>
25
+ <option selected>https://eolas.l42.eu/metadata/place/2/</option>
26
+ <option selected>https://media-metadata.l42.eu/tracks/13713</option>
21
27
  </select>
22
28
  </span>
23
29
  ```
30
+ Selected options use the item's URI as their value.
31
+
32
+ The following attributes can be added to the lucos-search span:
33
+ * **data-api-key** \[required\] — a valid API key for the production instance of [lucos_arachne](https://github.com/lucas42/lucos_arachne), as generated by [lucos_creds](https://github.com/lucas42/lucos_creds).
34
+ * **data-types** — A comma separated list of item types to search for (defaults to all types).
35
+ * **data-exclude-types** — A comma separated list of item types to exclude from the search (ignored if `data-types` is set).
36
+
37
+ ### Languages
38
+
39
+ Language selector, grouped by language families.
40
+
41
+ Include the following in your html:
42
+ ```
43
+ <span is="lucos-lang">
44
+ <select multiple>
45
+ <option selected>en</option>
46
+ <option selected>ga</option>
47
+ <option selected>ain</option>
48
+ </select>
49
+ </span>
50
+ ```
51
+ Selected options use a language's ISO 639 code.
52
+ Note: [lucos_arachne](https://github.com/lucas42/lucos_arachne) has a mixture of ISO 639-1, ISO 639-2, ISO 639-3 and ISO 639-6 codes as well as some custom codes for artificial languages. The code used must match what's in lucos_arachne.
53
+
24
54
 
55
+ The following attributes can be added to the lucos-lang span:
56
+ * **data-api-key** \[required\] — a valid API key for the production instance of [lucos_arachne](https://github.com/lucas42/lucos_arachne), as generated by [lucos_creds](https://github.com/lucas42/lucos_creds).
57
+ * **data-no-lang** — The name to give for a "no language" option. Defaults to not having a no language option. If selected, the code returned will be `zxx` (The ISO 639 code which denotes absence of linguistic content)
58
+ * **data-common** — A comma separated list of language codes to put in a separate "Common Languages" group at the top of the selections. This removes the provided languages from their normal family; they'll only be listed under Common Languages. Unrecognised language codes in this list are ignored.
25
59
 
26
60
  ## Manual Testing
27
61
 
package/dist/index.js CHANGED
@@ -5823,7 +5823,7 @@ customElements.define('lucos-search', LucosSearchComponent, { extends: "span" })
5823
5823
 
5824
5824
  class LucosLangComponent extends HTMLSpanElement {
5825
5825
  static get observedAttributes() {
5826
- return ['data-api-key'];
5826
+ return ['data-api-key','data-no-lang', 'data-common'];
5827
5827
  }
5828
5828
  constructor() {
5829
5829
  super();
@@ -5869,6 +5869,9 @@ class LucosLangComponent extends HTMLSpanElement {
5869
5869
  color: inherit;
5870
5870
  text-decoration: none;
5871
5871
  }
5872
+ .optgroup-header {
5873
+ text-transform: capitalize;
5874
+ }
5872
5875
  `;
5873
5876
  shadow.appendChild(mainStyle);
5874
5877
 
@@ -5880,6 +5883,8 @@ class LucosLangComponent extends HTMLSpanElement {
5880
5883
  valueField: 'code',
5881
5884
  labelField: 'label',
5882
5885
  searchField: ['code','label'],
5886
+ optgroupField: 'family',
5887
+ lockOptgroupOrder: true,
5883
5888
  closeAfterSelect: true,
5884
5889
  plugins: {
5885
5890
  remove_button:{
@@ -5893,10 +5898,35 @@ class LucosLangComponent extends HTMLSpanElement {
5893
5898
  },
5894
5899
  // On startup, update any existing options with latest data from search
5895
5900
  onInitialize: async function() {
5896
- const results = await component.searchRequest();
5897
- results.forEach(result => {
5898
- this.updateOption(result.code, result); // Updates any existing options which are selected with the correct label
5899
- this.addOption(result); // Makes the option available for new selections
5901
+ const families = await component.getLanguageFamilies();
5902
+ const languages = await component.getLanguages();
5903
+
5904
+ // If there's an attribute for a no language option, put that top of the list
5905
+ if (component.hasAttribute("data-no-lang")) {
5906
+ languages.unshift({
5907
+ code: 'zxx', // ISO 639 code to denote absence of linguistic content
5908
+ label: component.getAttribute("data-no-lang"),
5909
+ });
5910
+ }
5911
+ if (component.hasAttribute("data-common")) {
5912
+ const commonLangs = component.getAttribute("data-common").split(",");
5913
+ console.log(commonLangs);
5914
+ families.unshift({ // Put common languages as top option
5915
+ code: 'x-common',
5916
+ label: 'common languages',
5917
+ });
5918
+ languages.forEach(language => {
5919
+ if (commonLangs.includes(language.code)) {
5920
+ language.family = 'x-common';
5921
+ }
5922
+ });
5923
+ }
5924
+ families.forEach(family => {
5925
+ this.addOptionGroup(family.code, family);
5926
+ });
5927
+ languages.forEach(language => {
5928
+ this.updateOption(language.code, language); // Updates any existing options which are selected with the correct label
5929
+ this.addOption(language); // Makes the option available for new selections
5900
5930
  });
5901
5931
  },
5902
5932
  onItemSelect: function (item) {
@@ -5905,7 +5935,11 @@ class LucosLangComponent extends HTMLSpanElement {
5905
5935
  },
5906
5936
  render:{
5907
5937
  item: function(data, escape) {
5908
- return `<div class="lozenge" data-url="${escape(data.url)}"><a href="${escape(data.url)}" target="_blank">${escape(data.label)}</a></div>`;
5938
+ if (data.url) {
5939
+ return `<div class="lozenge" data-url="${escape(data.url)}"><a href="${escape(data.url)}" target="_blank">${escape(data.label)}</a></div>`;
5940
+ } else {
5941
+ return `<div class="lozenge">${escape(data.label)}</div>`;
5942
+ }
5909
5943
  },
5910
5944
  },
5911
5945
  });
@@ -5913,17 +5947,9 @@ class LucosLangComponent extends HTMLSpanElement {
5913
5947
  shadow.append(selector.nextElementSibling);
5914
5948
  }
5915
5949
  }
5916
- async searchRequest() {
5950
+ async searchRequest(searchParams) {
5917
5951
  const key = this.getAttribute("data-api-key");
5918
5952
  if (!key) throw new Error("No `data-api-key` attribute set on `lucos-search` component");
5919
- const searchParams = new URLSearchParams({
5920
- filter_by: 'type:=Language',
5921
- query_by: "pref_label",
5922
- include_fields: "id,pref_label",
5923
- sort_by: "pref_label:asc",
5924
- enable_highlight_v1: false,
5925
- per_page: 200,
5926
- });
5927
5953
  const response = await fetch("https://arachne.l42.eu/search?"+searchParams.toString(), {
5928
5954
  headers: { 'X-TYPESENSE-API-KEY': key },
5929
5955
  signal: AbortSignal.timeout(900),
@@ -5932,14 +5958,44 @@ class LucosLangComponent extends HTMLSpanElement {
5932
5958
  if (!response.ok) {
5933
5959
  throw new Error(`Recieved ${response.status} error from search endpoint: ${data["message"]}`);
5934
5960
  }
5935
- const results = data.hits.map(result => {
5961
+ return data;
5962
+ }
5963
+ async getLanguages() {
5964
+ const searchParams = new URLSearchParams({
5965
+ filter_by: 'type:=Language',
5966
+ query_by: "pref_label",
5967
+ include_fields: "id,pref_label,lang_family",
5968
+ sort_by: "pref_label:asc",
5969
+ enable_highlight_v1: false,
5970
+ per_page: 200,
5971
+ });
5972
+ const data = await this.searchRequest(searchParams);
5973
+ return data.hits.map(result => {
5936
5974
  return {
5937
5975
  code: result.document.id.split("/").reverse()[1],
5938
5976
  label: result.document.pref_label,
5939
5977
  url: result.document.id,
5978
+ family: result.document.lang_family || 'qli', // If no language family is given, using `qli` code as language isolate
5979
+ }
5980
+ });
5981
+ }
5982
+ async getLanguageFamilies() {
5983
+ const searchParams = new URLSearchParams({
5984
+ filter_by: 'type:=Language Family',
5985
+ query_by: "pref_label",
5986
+ include_fields: "id,pref_label",
5987
+ sort_by: "pref_label:asc",
5988
+ enable_highlight_v1: false,
5989
+ per_page: 200,
5990
+ });
5991
+ const data = await this.searchRequest(searchParams);
5992
+ return data.hits.map(result => {
5993
+ return {
5994
+ code: result.document.id.split("/").pop() || 'qli',
5995
+ label: result.document.pref_label,
5996
+ url: result.document.id,
5940
5997
  }
5941
5998
  });
5942
- return results;
5943
5999
  }
5944
6000
  }
5945
6001
  customElements.define('lucos-lang', LucosLangComponent, { extends: "span" });
@@ -8,33 +8,39 @@
8
8
  <label for="search2">No Tracks:</label><span is="lucos-search" data-api-key="${KEY_LUCOS_ARACHNE}" data-exclude_types="Track"><select id="search2"></select></span>
9
9
  <label for="search3">Only Cites and Rivers:</label><span is="lucos-search" data-api-key="${KEY_LUCOS_ARACHNE}" data-types="City,River"><select id="search3"></select></span>
10
10
  <label for="search4">Load with existing items:</label><span is="lucos-search" data-api-key="${KEY_LUCOS_ARACHNE}"><select id="search4" multiple>
11
- <option id="https://contacts.l42.eu/people/2" selected>https://contacts.l42.eu/people/2</option>
12
- <option id="https://eolas.l42.eu/metadata/place/2/" selected>https://eolas.l42.eu/metadata/place/2/</option>
13
- <option id="https://media-metadata.l42.eu/tracks/13713" selected>https://media-metadata.l42.eu/tracks/13713</option>
11
+ <option selected>https://contacts.l42.eu/people/2</option>
12
+ <option selected>https://eolas.l42.eu/metadata/place/2/</option>
13
+ <option selected>https://media-metadata.l42.eu/tracks/13713</option>
14
14
  </select></span>
15
15
  <label for="search5">More than 10:</label>
16
16
  <span is="lucos-search" data-api-key="${KEY_LUCOS_ARACHNE}" data-exclude_types="Track"><select id="search5" multiple>
17
- <option value="https://eolas.l42.eu/metadata/place/125/" selected>https://eolas.l42.eu/metadata/place/125/</option>
18
- <option value="https://eolas.l42.eu/metadata/place/126/" selected>https://eolas.l42.eu/metadata/place/126/</option>
19
- <option value="https://eolas.l42.eu/metadata/place/28/" selected>https://eolas.l42.eu/metadata/place/28/</option>
20
- <option value="https://eolas.l42.eu/metadata/place/307/" selected>https://eolas.l42.eu/metadata/place/307/</option>
21
- <option value="https://eolas.l42.eu/metadata/place/308/" selected>https://eolas.l42.eu/metadata/place/308/</option>
22
- <option value="https://eolas.l42.eu/metadata/place/310/" selected>https://eolas.l42.eu/metadata/place/310/</option>
23
- <option value="https://eolas.l42.eu/metadata/place/311/" selected>https://eolas.l42.eu/metadata/place/311/</option>
24
- <option value="https://eolas.l42.eu/metadata/place/312/" selected>https://eolas.l42.eu/metadata/place/312/</option>
25
- <option value="https://eolas.l42.eu/metadata/place/313/" selected>https://eolas.l42.eu/metadata/place/313/</option>
26
- <option value="https://eolas.l42.eu/metadata/place/314/" selected>https://eolas.l42.eu/metadata/place/314/</option>
27
- <option value="https://eolas.l42.eu/metadata/place/315/" selected>https://eolas.l42.eu/metadata/place/315/</option>
28
- <option value="https://eolas.l42.eu/metadata/place/316/" selected>https://eolas.l42.eu/metadata/place/316/</option>
29
- <option value="https://eolas.l42.eu/metadata/place/317/" selected>https://eolas.l42.eu/metadata/place/317/</option>
17
+ <option selected>https://eolas.l42.eu/metadata/place/125/</option>
18
+ <option selected>https://eolas.l42.eu/metadata/place/126/</option>
19
+ <option selected>https://eolas.l42.eu/metadata/place/28/</option>
20
+ <option selected>https://eolas.l42.eu/metadata/place/307/</option>
21
+ <option selected>https://eolas.l42.eu/metadata/place/308/</option>
22
+ <option selected>https://eolas.l42.eu/metadata/place/310/</option>
23
+ <option selected>https://eolas.l42.eu/metadata/place/311/</option>
24
+ <option selected>https://eolas.l42.eu/metadata/place/312/</option>
25
+ <option selected>https://eolas.l42.eu/metadata/place/313/</option>
26
+ <option selected>https://eolas.l42.eu/metadata/place/314/</option>
27
+ <option selected>https://eolas.l42.eu/metadata/place/315/</option>
28
+ <option selected>https://eolas.l42.eu/metadata/place/316/</option>
29
+ <option selected>https://eolas.l42.eu/metadata/place/317/</option>
30
30
  </select></span>
31
31
  <h1>lucos-lang</h1>
32
32
  <label for="lang1">Blank:</label><span is="lucos-lang" data-api-key="${KEY_LUCOS_ARACHNE}"><select id="lang1"></select></span>
33
33
  <label for="lang2">Load with existing:</label><span is="lucos-lang" data-api-key="${KEY_LUCOS_ARACHNE}"><select id="lang2" multiple>
34
- <option id="ga" selected>ga</option>
35
- <option id="emen" selected>emen</option>
36
- <option id="art-x-simlish" selected>art-x-simlish</option>
34
+ <option selected>ga</option>
35
+ <option selected>emen</option>
36
+ <option selected>art-x-simlish</option>
37
37
  </select></span>
38
+ <label for="lang3">No lang option</label><span is="lucos-lang" data-api-key="${KEY_LUCOS_ARACHNE}" data-no-lang="No Language">
39
+ <select id="lang3" multiple><option selected>zxx</option></select>
40
+ </span>
41
+ <label for="lang3">Common languages option</label><span is="lucos-lang" data-api-key="${KEY_LUCOS_ARACHNE}" data-no-lang="No Language" data-common="en,ga,zxx">
42
+ <select id="lang3"></select>
43
+ </span>
38
44
  <script src="./built.js"></script>
39
45
  </body>
40
46
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lucos_search_component",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
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 LucosLangComponent extends HTMLSpanElement {
5
5
  static get observedAttributes() {
6
- return ['data-api-key'];
6
+ return ['data-api-key','data-no-lang', 'data-common'];
7
7
  }
8
8
  constructor() {
9
9
  super();
@@ -49,6 +49,9 @@ class LucosLangComponent extends HTMLSpanElement {
49
49
  color: inherit;
50
50
  text-decoration: none;
51
51
  }
52
+ .optgroup-header {
53
+ text-transform: capitalize;
54
+ }
52
55
  `;
53
56
  shadow.appendChild(mainStyle);
54
57
 
@@ -60,6 +63,8 @@ class LucosLangComponent extends HTMLSpanElement {
60
63
  valueField: 'code',
61
64
  labelField: 'label',
62
65
  searchField: ['code','label'],
66
+ optgroupField: 'family',
67
+ lockOptgroupOrder: true,
63
68
  closeAfterSelect: true,
64
69
  plugins: {
65
70
  remove_button:{
@@ -73,10 +78,35 @@ class LucosLangComponent extends HTMLSpanElement {
73
78
  },
74
79
  // On startup, update any existing options with latest data from search
75
80
  onInitialize: async function() {
76
- const results = await component.searchRequest();
77
- results.forEach(result => {
78
- this.updateOption(result.code, result); // Updates any existing options which are selected with the correct label
79
- this.addOption(result); // Makes the option available for new selections
81
+ const families = await component.getLanguageFamilies();
82
+ const languages = await component.getLanguages();
83
+
84
+ // If there's an attribute for a no language option, put that top of the list
85
+ if (component.hasAttribute("data-no-lang")) {
86
+ languages.unshift({
87
+ code: 'zxx', // ISO 639 code to denote absence of linguistic content
88
+ label: component.getAttribute("data-no-lang"),
89
+ });
90
+ }
91
+ if (component.hasAttribute("data-common")) {
92
+ const commonLangs = component.getAttribute("data-common").split(",");
93
+ console.log(commonLangs);
94
+ families.unshift({ // Put common languages as top option
95
+ code: 'x-common',
96
+ label: 'common languages',
97
+ });
98
+ languages.forEach(language => {
99
+ if (commonLangs.includes(language.code)) {
100
+ language.family = 'x-common';
101
+ }
102
+ })
103
+ }
104
+ families.forEach(family => {
105
+ this.addOptionGroup(family.code, family);
106
+ });
107
+ languages.forEach(language => {
108
+ this.updateOption(language.code, language); // Updates any existing options which are selected with the correct label
109
+ this.addOption(language); // Makes the option available for new selections
80
110
  });
81
111
  },
82
112
  onItemSelect: function (item) {
@@ -85,7 +115,11 @@ class LucosLangComponent extends HTMLSpanElement {
85
115
  },
86
116
  render:{
87
117
  item: function(data, escape) {
88
- return `<div class="lozenge" data-url="${escape(data.url)}"><a href="${escape(data.url)}" target="_blank">${escape(data.label)}</a></div>`;
118
+ if (data.url) {
119
+ return `<div class="lozenge" data-url="${escape(data.url)}"><a href="${escape(data.url)}" target="_blank">${escape(data.label)}</a></div>`;
120
+ } else {
121
+ return `<div class="lozenge">${escape(data.label)}</div>`;
122
+ }
89
123
  },
90
124
  },
91
125
  });
@@ -93,17 +127,9 @@ class LucosLangComponent extends HTMLSpanElement {
93
127
  shadow.append(selector.nextElementSibling);
94
128
  }
95
129
  }
96
- async searchRequest() {
130
+ async searchRequest(searchParams) {
97
131
  const key = this.getAttribute("data-api-key");
98
132
  if (!key) throw new Error("No `data-api-key` attribute set on `lucos-search` component");
99
- const searchParams = new URLSearchParams({
100
- filter_by: 'type:=Language',
101
- query_by: "pref_label",
102
- include_fields: "id,pref_label",
103
- sort_by: "pref_label:asc",
104
- enable_highlight_v1: false,
105
- per_page: 200,
106
- });
107
133
  const response = await fetch("https://arachne.l42.eu/search?"+searchParams.toString(), {
108
134
  headers: { 'X-TYPESENSE-API-KEY': key },
109
135
  signal: AbortSignal.timeout(900),
@@ -112,14 +138,44 @@ class LucosLangComponent extends HTMLSpanElement {
112
138
  if (!response.ok) {
113
139
  throw new Error(`Recieved ${response.status} error from search endpoint: ${data["message"]}`);
114
140
  }
115
- const results = data.hits.map(result => {
141
+ return data;
142
+ }
143
+ async getLanguages() {
144
+ const searchParams = new URLSearchParams({
145
+ filter_by: 'type:=Language',
146
+ query_by: "pref_label",
147
+ include_fields: "id,pref_label,lang_family",
148
+ sort_by: "pref_label:asc",
149
+ enable_highlight_v1: false,
150
+ per_page: 200,
151
+ });
152
+ const data = await this.searchRequest(searchParams);
153
+ return data.hits.map(result => {
116
154
  return {
117
155
  code: result.document.id.split("/").reverse()[1],
118
156
  label: result.document.pref_label,
119
157
  url: result.document.id,
158
+ family: result.document.lang_family || 'qli', // If no language family is given, using `qli` code as language isolate
159
+ }
160
+ });
161
+ }
162
+ async getLanguageFamilies() {
163
+ const searchParams = new URLSearchParams({
164
+ filter_by: 'type:=Language Family',
165
+ query_by: "pref_label",
166
+ include_fields: "id,pref_label",
167
+ sort_by: "pref_label:asc",
168
+ enable_highlight_v1: false,
169
+ per_page: 200,
170
+ });
171
+ const data = await this.searchRequest(searchParams);
172
+ return data.hits.map(result => {
173
+ return {
174
+ code: result.document.id.split("/").pop() || 'qli',
175
+ label: result.document.pref_label,
176
+ url: result.document.id,
120
177
  }
121
178
  });
122
- return results;
123
179
  }
124
180
  }
125
181
  customElements.define('lucos-lang', LucosLangComponent, { extends: "span" });