@schukai/monster 4.38.4 → 4.38.6

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.
@@ -14,18 +14,18 @@
14
14
 
15
15
  import { instanceSymbol } from "../../constants.mjs";
16
16
  import {
17
- findTargetElementFromEvent,
18
- fireCustomEvent,
17
+ findTargetElementFromEvent,
18
+ fireCustomEvent,
19
19
  } from "../../dom/events.mjs";
20
20
  import {
21
- findElementWithIdUpwards,
22
- findElementWithSelectorUpwards,
21
+ findElementWithIdUpwards,
22
+ findElementWithSelectorUpwards,
23
23
  } from "../../dom/util.mjs";
24
24
  import {
25
- assembleMethodSymbol,
26
- CustomElement,
27
- getSlottedElements,
28
- registerCustomElement,
25
+ assembleMethodSymbol,
26
+ CustomElement,
27
+ getSlottedElements,
28
+ registerCustomElement,
29
29
  } from "../../dom/customelement.mjs";
30
30
  import { ID } from "../../types/id.mjs";
31
31
  import { Settings } from "./filter/settings.mjs";
@@ -33,11 +33,11 @@ import { FilterStyleSheet } from "./stylesheet/filter.mjs";
33
33
  import { getDocument, getWindow } from "../../dom/util.mjs";
34
34
  import { getGlobal } from "../../types/global.mjs";
35
35
  import {
36
- isInstance,
37
- isFunction,
38
- isObject,
39
- isArray,
40
- isString,
36
+ isInstance,
37
+ isFunction,
38
+ isObject,
39
+ isArray,
40
+ isString,
41
41
  } from "../../types/is.mjs";
42
42
  import { Host } from "../host/host.mjs";
43
43
  import { addAttributeToken } from "../../dom/attributes.mjs";
@@ -47,17 +47,17 @@ import { Formatter } from "../../text/formatter.mjs";
47
47
  import { generateRangeComparisonExpression } from "../../text/util.mjs";
48
48
 
49
49
  import {
50
- parseBracketedKeyValueHash,
51
- createBracketedKeyValueHash,
50
+ parseBracketedKeyValueHash,
51
+ createBracketedKeyValueHash,
52
52
  } from "../../text/bracketed-key-value-hash.mjs";
53
53
  import { ThemeStyleSheet } from "../stylesheet/theme.mjs";
54
54
  import { SpaceStyleSheet } from "../stylesheet/space.mjs";
55
55
  import { FormStyleSheet } from "../stylesheet/form.mjs";
56
56
 
57
57
  import {
58
- getStoredFilterConfigKey,
59
- getFilterConfigKey,
60
- parseDateInput,
58
+ getStoredFilterConfigKey,
59
+ getFilterConfigKey,
60
+ parseDateInput,
61
61
  } from "./filter/util.mjs";
62
62
 
63
63
  import "./filter/select.mjs";
@@ -110,7 +110,7 @@ const filterControlElementSymbol = Symbol("filterControlElement");
110
110
  * @type {symbol}
111
111
  */
112
112
  const filterSaveActionButtonElementSymbol = Symbol(
113
- "filterSaveActionButtonElement",
113
+ "filterSaveActionButtonElement",
114
114
  );
115
115
 
116
116
  /**
@@ -170,241 +170,241 @@ const hashChangeSymbol = Symbol("hashChange");
170
170
  * @summary The Filter component is used to show and handle the filter values.
171
171
  */
172
172
  class Filter extends CustomElement {
173
- /**
174
- *
175
- */
176
- constructor() {
177
- super();
178
- this[settingsSymbol] = new Settings();
179
-
180
- // debounce the hash change event if doSearch is called by click the search button
181
- this[hashChangeSymbol] = 0;
182
- }
183
-
184
- /**
185
- * This method is called by the `instanceof` operator.
186
- * @return {symbol}
187
- */
188
- static get [instanceSymbol]() {
189
- return Symbol.for("@schukai/monster/components/filter@@instance");
190
- }
191
-
192
- /**
193
- *
194
- * @param {string} message
195
- * @return {Filter}
196
- */
197
- showFailureMessage(message) {
198
- this[searchButtonElementSymbol].setState(
199
- "failed",
200
- this.getOption("timeouts.message", 4000),
201
- );
202
- this[searchButtonElementSymbol]
203
- .setMessage(message.toString())
204
- .showMessage(this.getOption("timeouts.message", 4000));
205
- return this;
206
- }
207
-
208
- /**
209
- *
210
- * @return {Filter}
211
- */
212
- resetFailureMessage() {
213
- this[searchButtonElementSymbol].hideMessage();
214
- this[searchButtonElementSymbol].removeState();
215
- return this;
216
- }
217
-
218
- /**
219
- *
220
- * @return {Filter}
221
- */
222
- showSuccess() {
223
- this[searchButtonElementSymbol].setState(
224
- "successful",
225
- this.getOption("timeouts.message", 4000),
226
- );
227
- return this;
228
- }
229
-
230
- /**
231
- * To set the options via the HTML tag, the attribute `data-monster-options` must be used.
232
- * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
233
- *
234
- * The individual configuration values can be found in the table.
235
- *
236
- * @property {Object} templates Template definitions
237
- * @property {string} templates.main Main template
238
- * @property {Object} labels Label definitions
239
- * @property {string} labels.search Search button label
240
- * @property {string} labels.reset Reset button label
241
- * @property {string} labels.save Save button label
242
- * @property {string} labels.filter-name Filter name label
243
- * @property {string} labels.empty-query-and-no-default Empty query and no default query label
244
- * @property {string} labels.query-not-changed Query not changed label
245
- * @property {Object} formatter Formatter definitions
246
- * @property {Object} formatter.marker Marker definitions
247
- * @property {Object} formatter.marker.open Marker open
248
- * @property {Object} formatter.marker.close Marker close
249
- * @property {Object} features Feature definitions
250
- * @property {boolean} features.storedConfig Stored configuration, this replaces the setting `storedConfig.enabled` @since 3.97.0
251
- * @property {boolean} features.autoFilter Auto filter @since 3.100.0
252
- * @property {boolean} features.preventSameQuery Prevent same query @since 3.103.0
253
- * @property {Object} storedConfig Stored configuration
254
- * @property {boolean} storedConfig.enabled The store has been enabled, this option will no longer have any effect. @deprecated 20250101
255
- * @property {string} storedConfig.selector Selector
256
- * @property {Object} timeouts Timeout definitions
257
- * @property {number} timeouts.message Message timeout
258
- * @property {Object} queries Query definitions
259
- * @property {Function} queries.wrap Wrap callback
260
- * @property {Function} queries.join Join callback
261
- * @property {string} query Query
262
- * @property {string} defaultQuery Default query
263
- * @property {boolean} eventProcessing Event processing
264
- */
265
- get defaults() {
266
- return Object.assign({}, super.defaults, {
267
- templates: {
268
- main: getTemplate(),
269
- },
270
-
271
- formatter: {
272
- marker: {
273
- open: null,
274
- close: null,
275
- },
276
- },
277
-
278
- labels: getTranslations(),
279
-
280
- templateMapping: {
281
- "filter-save-label": null,
282
- "filter-name-label": name,
283
- },
284
-
285
- features: {
286
- storedConfig: false,
287
- autoFilter: true,
288
- preventSameQuery: false,
289
- },
290
-
291
- storedConfig: {
292
- enabled: true,
293
- selector: "",
294
- },
295
-
296
- timeouts: {
297
- message: 4000,
298
- },
299
-
300
- queries: {
301
- wrap: (value, definition) => {
302
- return value;
303
- },
304
- join: (queries) => {
305
- if (queries.length === 0) {
306
- return "";
307
- }
308
- return queries.join(" AND ");
309
- },
310
- },
311
-
312
- query: null,
313
- defaultQuery: null,
314
- eventProcessing: true,
315
-
316
- templateFormatter: {
317
- marker: {
318
- open: null,
319
- close: null,
320
- },
321
- i18n: true,
322
- },
323
- });
324
- }
325
-
326
- /**
327
- *
328
- * @return {string}
329
- */
330
- static getTag() {
331
- return "monster-datatable-filter";
332
- }
333
-
334
- /**
335
- * @return {FilterButton}
336
- * @fires monster-filter-initialized
337
- */
338
- [assembleMethodSymbol]() {
339
- const self = this;
340
-
341
- this.setOption(
342
- "templateMapping.filter-save-label",
343
- this.getOption("labels.save"),
344
- );
345
-
346
- this.setOption(
347
- "templateMapping.filter-name-label",
348
- this.getOption("labels.filter-name"),
349
- );
350
-
351
- super[assembleMethodSymbol]();
352
-
353
- initControlReferences.call(self);
354
- getWindow().requestAnimationFrame(() => {
355
- initEventHandler.call(self);
356
- });
357
-
358
- initFromConfig
359
- .call(self)
360
- .then(() => {})
361
- .catch((error) => {
362
- addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, error?.message);
363
- })
364
- .finally(() => {
365
- initFilter.call(self);
366
- updateFilterTabs.call(self);
367
-
368
- if (self.getOption("features.autoFilter") === true) {
369
- doSearch
370
- .call(self, { showEffect: false })
371
- .then(() => {
372
- fireCustomEvent(self, "monster-filter-initialized");
373
- })
374
- .catch(() => {});
375
- }
376
- });
377
- }
378
-
379
- /**
380
- *
381
- */
382
- connectedCallback() {
383
- super.connectedCallback();
384
- getWindow().addEventListener(
385
- "hashchange",
386
- this[locationChangeHandlerSymbol],
387
- );
388
- }
389
-
390
- /**
391
- *
392
- */
393
- disconnectedCallback() {
394
- super.disconnectedCallback();
395
-
396
- getWindow().removeEventListener(
397
- "hashchange",
398
- this[locationChangeHandlerSymbol],
399
- );
400
- }
401
-
402
- /**
403
- * @return {CSSStyleSheet[]}
404
- */
405
- static getCSSStyleSheet() {
406
- return [FilterStyleSheet, FormStyleSheet, ThemeStyleSheet, SpaceStyleSheet];
407
- }
173
+ /**
174
+ *
175
+ */
176
+ constructor() {
177
+ super();
178
+ this[settingsSymbol] = new Settings();
179
+
180
+ // debounce the hash change event if doSearch is called by click the search button
181
+ this[hashChangeSymbol] = 0;
182
+ }
183
+
184
+ /**
185
+ * This method is called by the `instanceof` operator.
186
+ * @return {symbol}
187
+ */
188
+ static get [instanceSymbol]() {
189
+ return Symbol.for("@schukai/monster/components/filter@@instance");
190
+ }
191
+
192
+ /**
193
+ *
194
+ * @param {string} message
195
+ * @return {Filter}
196
+ */
197
+ showFailureMessage(message) {
198
+ this[searchButtonElementSymbol].setState(
199
+ "failed",
200
+ this.getOption("timeouts.message", 4000),
201
+ );
202
+ this[searchButtonElementSymbol]
203
+ .setMessage(message.toString())
204
+ .showMessage(this.getOption("timeouts.message", 4000));
205
+ return this;
206
+ }
207
+
208
+ /**
209
+ *
210
+ * @return {Filter}
211
+ */
212
+ resetFailureMessage() {
213
+ this[searchButtonElementSymbol].hideMessage();
214
+ this[searchButtonElementSymbol].removeState();
215
+ return this;
216
+ }
217
+
218
+ /**
219
+ *
220
+ * @return {Filter}
221
+ */
222
+ showSuccess() {
223
+ this[searchButtonElementSymbol].setState(
224
+ "successful",
225
+ this.getOption("timeouts.message", 4000),
226
+ );
227
+ return this;
228
+ }
229
+
230
+ /**
231
+ * To set the options via the HTML tag, the attribute `data-monster-options` must be used.
232
+ * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
233
+ *
234
+ * The individual configuration values can be found in the table.
235
+ *
236
+ * @property {Object} templates Template definitions
237
+ * @property {string} templates.main Main template
238
+ * @property {Object} labels Label definitions
239
+ * @property {string} labels.search Search button label
240
+ * @property {string} labels.reset Reset button label
241
+ * @property {string} labels.save Save button label
242
+ * @property {string} labels.filter-name Filter name label
243
+ * @property {string} labels.empty-query-and-no-default Empty query and no default query label
244
+ * @property {string} labels.query-not-changed Query not changed label
245
+ * @property {Object} formatter Formatter definitions
246
+ * @property {Object} formatter.marker Marker definitions
247
+ * @property {Object} formatter.marker.open Marker open
248
+ * @property {Object} formatter.marker.close Marker close
249
+ * @property {Object} features Feature definitions
250
+ * @property {boolean} features.storedConfig Stored configuration, this replaces the setting `storedConfig.enabled` @since 3.97.0
251
+ * @property {boolean} features.autoFilter Auto filter @since 3.100.0
252
+ * @property {boolean} features.preventSameQuery Prevent same query @since 3.103.0
253
+ * @property {Object} storedConfig Stored configuration
254
+ * @property {boolean} storedConfig.enabled The store has been enabled, this option will no longer have any effect. @deprecated 20250101
255
+ * @property {string} storedConfig.selector Selector
256
+ * @property {Object} timeouts Timeout definitions
257
+ * @property {number} timeouts.message Message timeout
258
+ * @property {Object} queries Query definitions
259
+ * @property {Function} queries.wrap Wrap callback
260
+ * @property {Function} queries.join Join callback
261
+ * @property {string} query Query
262
+ * @property {string} defaultQuery Default query
263
+ * @property {boolean} eventProcessing Event processing
264
+ */
265
+ get defaults() {
266
+ return Object.assign({}, super.defaults, {
267
+ templates: {
268
+ main: getTemplate(),
269
+ },
270
+
271
+ formatter: {
272
+ marker: {
273
+ open: null,
274
+ close: null,
275
+ },
276
+ },
277
+
278
+ labels: getTranslations(),
279
+
280
+ templateMapping: {
281
+ "filter-save-label": null,
282
+ "filter-name-label": name,
283
+ },
284
+
285
+ features: {
286
+ storedConfig: false,
287
+ autoFilter: true,
288
+ preventSameQuery: false,
289
+ },
290
+
291
+ storedConfig: {
292
+ enabled: true,
293
+ selector: "",
294
+ },
295
+
296
+ timeouts: {
297
+ message: 4000,
298
+ },
299
+
300
+ queries: {
301
+ wrap: (value, definition) => {
302
+ return value;
303
+ },
304
+ join: (queries) => {
305
+ if (queries.length === 0) {
306
+ return "";
307
+ }
308
+ return queries.join(" AND ");
309
+ },
310
+ },
311
+
312
+ query: null,
313
+ defaultQuery: null,
314
+ eventProcessing: true,
315
+
316
+ templateFormatter: {
317
+ marker: {
318
+ open: null,
319
+ close: null,
320
+ },
321
+ i18n: true,
322
+ },
323
+ });
324
+ }
325
+
326
+ /**
327
+ *
328
+ * @return {string}
329
+ */
330
+ static getTag() {
331
+ return "monster-datatable-filter";
332
+ }
333
+
334
+ /**
335
+ * @return {FilterButton}
336
+ * @fires monster-filter-initialized
337
+ */
338
+ [assembleMethodSymbol]() {
339
+ const self = this;
340
+
341
+ this.setOption(
342
+ "templateMapping.filter-save-label",
343
+ this.getOption("labels.save"),
344
+ );
345
+
346
+ this.setOption(
347
+ "templateMapping.filter-name-label",
348
+ this.getOption("labels.filter-name"),
349
+ );
350
+
351
+ super[assembleMethodSymbol]();
352
+
353
+ initControlReferences.call(self);
354
+ getWindow().requestAnimationFrame(() => {
355
+ initEventHandler.call(self);
356
+ });
357
+
358
+ initFromConfig
359
+ .call(self)
360
+ .then(() => {})
361
+ .catch((error) => {
362
+ addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, error?.message);
363
+ })
364
+ .finally(() => {
365
+ initFilter.call(self);
366
+ updateFilterTabs.call(self);
367
+
368
+ if (self.getOption("features.autoFilter") === true) {
369
+ doSearch
370
+ .call(self, { showEffect: false })
371
+ .then(() => {
372
+ fireCustomEvent(self, "monster-filter-initialized");
373
+ })
374
+ .catch(() => {});
375
+ }
376
+ });
377
+ }
378
+
379
+ /**
380
+ *
381
+ */
382
+ connectedCallback() {
383
+ super.connectedCallback();
384
+ getWindow().addEventListener(
385
+ "hashchange",
386
+ this[locationChangeHandlerSymbol],
387
+ );
388
+ }
389
+
390
+ /**
391
+ *
392
+ */
393
+ disconnectedCallback() {
394
+ super.disconnectedCallback();
395
+
396
+ getWindow().removeEventListener(
397
+ "hashchange",
398
+ this[locationChangeHandlerSymbol],
399
+ );
400
+ }
401
+
402
+ /**
403
+ * @return {CSSStyleSheet[]}
404
+ */
405
+ static getCSSStyleSheet() {
406
+ return [FilterStyleSheet, FormStyleSheet, ThemeStyleSheet, SpaceStyleSheet];
407
+ }
408
408
  }
409
409
 
410
410
  /**
@@ -412,215 +412,212 @@ class Filter extends CustomElement {
412
412
  * @returns {object}
413
413
  */
414
414
  function getTranslations() {
415
- const locale = getLocaleOfDocument();
416
- switch (locale.language) {
417
- case "de":
418
- return {
419
- search: "Suchen",
420
- reset: "Zurücksetzen",
421
- save: "Speichern",
422
- "filter-name": "Filtername",
423
- "empty-query-and-no-default":
424
- "Die Abfrage ist leer und es gibt keine Standardabfrage.",
425
- "query-not-changed":
426
- "Die Suchanfrage hat sich nicht verändert, daher ist keine Suche erforderlich.",
427
- };
428
- case "fr":
429
- return {
430
- search: "Chercher",
431
- reset: "Réinitialiser",
432
- save: "Sauvegarder",
433
- "filter-name": "Nom du filtre",
434
- "empty-query-and-no-default":
435
- "La requête est vide et il n'y a pas de requête par défaut.",
436
- "query-not-changed":
437
- "La requête de recherche n'a pas changé, donc aucune recherche n'est nécessaire.",
438
- };
439
- case "es":
440
- return {
441
- search: "Buscar",
442
- reset: "Restablecer",
443
- save: "Guardar",
444
- "filter-name": "Nombre del filtro",
445
- "empty-query-and-no-default":
446
- "La consulta está vacía y no hay una consulta predeterminada.",
447
- "query-not-changed":
448
- "La solicitud de búsqueda no ha cambiado, por lo que no se requiere búsqueda.",
449
- };
450
- case "it":
451
- return {
452
- search: "Cerca",
453
- reset: "Reimposta",
454
- save: "Salva",
455
- "filter-name": "Nome del filtro",
456
- "empty-query-and-no-default":
457
- "La query è vuota e non c'è una query predefinita.",
458
- "query-not-changed":
459
- "La richiesta di ricerca non è cambiata, quindi non è necessaria una ricerca.",
460
- };
461
- case "pl":
462
- return {
463
- search: "Szukaj",
464
- reset: "Resetuj",
465
- save: "Zapisz",
466
- "filter-name": "Nazwa filtra",
467
- "empty-query-and-no-default":
468
- "Zapytanie jest puste i nie ma domyślnego zapytania.",
469
- "query-not-changed":
470
- "Żądanie wyszukiwania nie zmieniło się, więc wyszukiwanie nie jest wymagane.",
471
- };
472
- case "no":
473
- return {
474
- search: "Søk",
475
- reset: "Tilbakestill",
476
- save: "Lagre",
477
- "filter-name": "Filternavn",
478
- "empty-query-and-no-default":
479
- "Spørringen er tom og det er ingen standardspørring.",
480
- "query-not-changed":
481
- "Søkeforespørselen har ikke endret seg, så ingen søk er nødvendig.",
482
- };
483
- case "da":
484
- return {
485
- search: "Søg",
486
- reset: "Nulstil",
487
- save: "Gem",
488
- "filter-name": "Filternavn",
489
- "empty-query-and-no-default":
490
- "Forespørgslen er tom og der er ingen standardforespørgsel.",
491
- "query-not-changed":
492
- "Søgeanmodningen er ikke ændret, så ingen søgning er nødvendig.",
493
- };
494
- case "sv":
495
- return {
496
- search: "Sök",
497
- reset: "Återställ",
498
- save: "Spara",
499
- "filter-name": "Filternamn",
500
- "empty-query-and-no-default":
501
- "Förfrågan är tom och det finns ingen standardförfrågan.",
502
- "query-not-changed":
503
- "Sökförfrågan har inte ändrats, så ingen sökning krävs.",
504
- };
505
- case "nl":
506
- return {
507
- search: "Zoeken",
508
- reset: "Resetten",
509
- save: "Opslaan",
510
- "filter-name": "Filternaam",
511
- "empty-query-and-no-default":
512
- "De zoekopdracht is leeg en er is geen standaardzoekopdracht.",
513
- "query-not-changed":
514
- "De zoekopdracht is niet gewijzigd, dus zoeken is niet nodig.",
515
- };
516
- case "fi":
517
- return {
518
- search: "Haku",
519
- reset: "Palauta",
520
- save: "Tallenna",
521
- "filter-name": "Suodattimen nimi",
522
- "empty-query-and-no-default":
523
- "Hakukysely on tyhjä eikä oletushakua ole määritetty.",
524
- "query-not-changed":
525
- "Hakupyyntö ei ole muuttunut, joten hakua ei tarvita.",
526
- };
527
- case "cs":
528
- return {
529
- search: "Hledat",
530
- reset: "Resetovat",
531
- save: "Uložit",
532
- "filter-name": "Název filtru",
533
- "empty-query-and-no-default":
534
- "Dotaz je prázdný a není nastavena žádná výchozí hodnota.",
535
- "query-not-changed":
536
- "Dotaz na hledání se nezměnil, takže hledání není nutné.",
537
- };
538
- case "pt":
539
- return {
540
- search: "Buscar",
541
- reset: "Redefinir",
542
- save: "Salvar",
543
- "filter-name": "Nome do filtro",
544
- "empty-query-and-no-default":
545
- "A consulta está vazia e não há uma consulta padrão.",
546
- "query-not-changed":
547
- "A solicitação de pesquisa não foi alterada, portanto, nenhuma pesquisa é necessária.",
548
- };
549
- case "ru":
550
- return {
551
- search: "Поиск",
552
- reset: "Сброс",
553
- save: "Сохранить",
554
- "filter-name": "Имя фильтра",
555
- "empty-query-and-no-default": "Запрос пуст и нет запроса по умолчанию.",
556
- "query-not-changed":
557
- "Поисковый запрос не изменился, поэтому поиск не требуется.",
558
- };
559
- case "zh":
560
- return {
561
- search: "搜索",
562
- reset: "重置",
563
- save: "保存",
564
- "filter-name": "过滤器名称",
565
- "empty-query-and-no-default": "查询为空,且没有默认查询。",
566
- "query-not-changed": "搜索请求没有更改,因此不需要进行搜索。",
567
- };
568
- case "hi":
569
- return {
570
- search: "खोजें",
571
- reset: "रीसेट करें",
572
- save: "सहेजें",
573
- "filter-name": "फ़िल्टर नाम",
574
- "empty-query-and-no-default":
575
- "क्वेरी खाली है और कोई डिफ़ॉल्ट क्वेरी नहीं है।",
576
- "query-not-changed":
577
- "खोज अनुरोध में कोई बदलाव नहीं हुआ है, इसलिए खोज आवश्यक नहीं है।",
578
- };
579
- case "bn":
580
- return {
581
- search: "অনুসন্ধান",
582
- reset: "রিসেট",
583
- save: "সংরক্ষণ করুন",
584
- "filter-name": "ফিল্টারের নাম",
585
- "empty-query-and-no-default":
586
- "কোয়েরি খালি এবং কোনো ডিফল্ট কোয়েরি নেই।",
587
- "query-not-changed":
588
- "অনুসন্ধানের অনুরোধ পরিবর্তন হয়নি, তাই অনুসন্ধান প্রয়োজন নয়।",
589
- };
590
- case "ja":
591
- return {
592
- search: "検索",
593
- reset: "リセット",
594
- save: "保存",
595
- "filter-name": "フィルター名",
596
- "empty-query-and-no-default":
597
- "クエリが空で、デフォルトクエリがありません。",
598
- "query-not-changed": "検索リクエストに変更がないため、検索は不要です。",
599
- };
600
- case "pa":
601
- return {
602
- search: "ਖੋਜੋ",
603
- reset: "ਰੀਸੈੱਟ ਕਰੋ",
604
- save: "ਸੇਵ ਕਰੋ",
605
- "filter-name": "ਫਿਲਟਰ ਦਾ ਨਾਂ",
606
- "empty-query-and-no-default":
607
- "ਕੁਐਰੀ ਖਾਲੀ ਹੈ ਅਤੇ ਕੋਈ ਡਿਫੌਲਟ ਕੁਐਰੀ ਨਹੀਂ ਹੈ।",
608
- "query-not-changed":
609
- "ਖੋਜ ਦੀ ਬੇਨਤੀ ਵਿੱਚ ਕੋਈ ਤਬਦੀਲੀ ਨਹੀਂ ਆਈ ਹੈ, ਇਸ ਲਈ ਖੋਜ ਦੀ ਲੋੜ ਨਹੀਂ ਹੈ।",
610
- };
611
- default:
612
- case "en":
613
- return {
614
- search: "Search",
615
- reset: "Reset",
616
- save: "Save",
617
- "filter-name": "Filter name",
618
- "empty-query-and-no-default":
619
- "The query is empty and there is no default query.",
620
- "query-not-changed":
621
- "The search request has not changed, so no search is required.",
622
- };
623
- }
415
+ const locale = getLocaleOfDocument();
416
+ switch (locale.language) {
417
+ case "de":
418
+ return {
419
+ search: "Suchen",
420
+ reset: "Zurücksetzen",
421
+ save: "Speichern",
422
+ "filter-name": "Filtername",
423
+ "empty-query-and-no-default":
424
+ "Die Abfrage ist leer und es gibt keine Standardabfrage.",
425
+ "query-not-changed":
426
+ "Die Suchanfrage hat sich nicht verändert, daher ist keine Suche erforderlich.",
427
+ };
428
+ case "fr":
429
+ return {
430
+ search: "Chercher",
431
+ reset: "Réinitialiser",
432
+ save: "Sauvegarder",
433
+ "filter-name": "Nom du filtre",
434
+ "empty-query-and-no-default":
435
+ "La requête est vide et il n'y a pas de requête par défaut.",
436
+ "query-not-changed":
437
+ "La requête de recherche n'a pas changé, donc aucune recherche n'est nécessaire.",
438
+ };
439
+ case "es":
440
+ return {
441
+ search: "Buscar",
442
+ reset: "Restablecer",
443
+ save: "Guardar",
444
+ "filter-name": "Nombre del filtro",
445
+ "empty-query-and-no-default":
446
+ "La consulta está vacía y no hay una consulta predeterminada.",
447
+ "query-not-changed":
448
+ "La solicitud de búsqueda no ha cambiado, por lo que no se requiere búsqueda.",
449
+ };
450
+ case "it":
451
+ return {
452
+ search: "Cerca",
453
+ reset: "Reimposta",
454
+ save: "Salva",
455
+ "filter-name": "Nome del filtro",
456
+ "empty-query-and-no-default":
457
+ "La query è vuota e non c'è una query predefinita.",
458
+ "query-not-changed":
459
+ "La richiesta di ricerca non è cambiata, quindi non è necessaria una ricerca.",
460
+ };
461
+ case "pl":
462
+ return {
463
+ search: "Szukaj",
464
+ reset: "Resetuj",
465
+ save: "Zapisz",
466
+ "filter-name": "Nazwa filtra",
467
+ "empty-query-and-no-default":
468
+ "Zapytanie jest puste i nie ma domyślnego zapytania.",
469
+ "query-not-changed":
470
+ "Żądanie wyszukiwania nie zmieniło się, więc wyszukiwanie nie jest wymagane.",
471
+ };
472
+ case "no":
473
+ return {
474
+ search: "Søk",
475
+ reset: "Tilbakestill",
476
+ save: "Lagre",
477
+ "filter-name": "Filternavn",
478
+ "empty-query-and-no-default":
479
+ "Spørringen er tom og det er ingen standardspørring.",
480
+ "query-not-changed":
481
+ "Søkeforespørselen har ikke endret seg, så ingen søk er nødvendig.",
482
+ };
483
+ case "da":
484
+ return {
485
+ search: "Søg",
486
+ reset: "Nulstil",
487
+ save: "Gem",
488
+ "filter-name": "Filternavn",
489
+ "empty-query-and-no-default":
490
+ "Forespørgslen er tom og der er ingen standardforespørgsel.",
491
+ "query-not-changed":
492
+ "Søgeanmodningen er ikke ændret, så ingen søgning er nødvendig.",
493
+ };
494
+ case "sv":
495
+ return {
496
+ search: "Sök",
497
+ reset: "Återställ",
498
+ save: "Spara",
499
+ "filter-name": "Filternamn",
500
+ "empty-query-and-no-default":
501
+ "Förfrågan är tom och det finns ingen standardförfrågan.",
502
+ "query-not-changed":
503
+ "Sökförfrågan har inte ändrats, så ingen sökning krävs.",
504
+ };
505
+ case "nl":
506
+ return {
507
+ search: "Zoeken",
508
+ reset: "Resetten",
509
+ save: "Opslaan",
510
+ "filter-name": "Filternaam",
511
+ "empty-query-and-no-default":
512
+ "De zoekopdracht is leeg en er is geen standaardzoekopdracht.",
513
+ "query-not-changed":
514
+ "De zoekopdracht is niet gewijzigd, dus zoeken is niet nodig.",
515
+ };
516
+ case "fi":
517
+ return {
518
+ search: "Haku",
519
+ reset: "Palauta",
520
+ save: "Tallenna",
521
+ "filter-name": "Suodattimen nimi",
522
+ "empty-query-and-no-default":
523
+ "Hakukysely on tyhjä eikä oletushakua ole määritetty.",
524
+ "query-not-changed":
525
+ "Hakupyyntö ei ole muuttunut, joten hakua ei tarvita.",
526
+ };
527
+ case "cs":
528
+ return {
529
+ search: "Hledat",
530
+ reset: "Resetovat",
531
+ save: "Uložit",
532
+ "filter-name": "Název filtru",
533
+ "empty-query-and-no-default":
534
+ "Dotaz je prázdný a není nastavena žádná výchozí hodnota.",
535
+ "query-not-changed":
536
+ "Dotaz na hledání se nezměnil, takže hledání není nutné.",
537
+ };
538
+ case "pt":
539
+ return {
540
+ search: "Buscar",
541
+ reset: "Redefinir",
542
+ save: "Salvar",
543
+ "filter-name": "Nome do filtro",
544
+ "empty-query-and-no-default":
545
+ "A consulta está vazia e não há uma consulta padrão.",
546
+ "query-not-changed":
547
+ "A solicitação de pesquisa não foi alterada, portanto, nenhuma pesquisa é necessária.",
548
+ };
549
+ case "ru":
550
+ return {
551
+ search: "Поиск",
552
+ reset: "Сброс",
553
+ save: "Сохранить",
554
+ "filter-name": "Имя фильтра",
555
+ "empty-query-and-no-default": "Запрос пуст и нет запроса по умолчанию.",
556
+ "query-not-changed":
557
+ "Поисковый запрос не изменился, поэтому поиск не требуется.",
558
+ };
559
+ case "zh":
560
+ return {
561
+ search: "搜索",
562
+ reset: "重置",
563
+ save: "保存",
564
+ "filter-name": "过滤器名称",
565
+ "empty-query-and-no-default": "查询为空,且没有默认查询。",
566
+ "query-not-changed": "搜索请求没有更改,因此不需要进行搜索。",
567
+ };
568
+ case "hi":
569
+ return {
570
+ search: "खोजें",
571
+ reset: "रीसेट करें",
572
+ save: "सहेजें",
573
+ "filter-name": "फ़िल्टर नाम",
574
+ "empty-query-and-no-default": "क्वेरी खाली है और कोई डिफ़ॉल्ट क्वेरी नहीं है।",
575
+ "query-not-changed":
576
+ "खोज अनुरोध में कोई बदलाव नहीं हुआ है, इसलिए खोज आवश्यक नहीं है।",
577
+ };
578
+ case "bn":
579
+ return {
580
+ search: "অনুসন্ধান",
581
+ reset: "রিসেট",
582
+ save: "সংরক্ষণ করুন",
583
+ "filter-name": "ফিল্টারের নাম",
584
+ "empty-query-and-no-default": "কোয়েরি খালি এবং কোনো ডিফল্ট কোয়েরি নেই।",
585
+ "query-not-changed":
586
+ "অনুসন্ধানের অনুরোধ পরিবর্তন হয়নি, তাই অনুসন্ধান প্রয়োজন নয়।",
587
+ };
588
+ case "ja":
589
+ return {
590
+ search: "検索",
591
+ reset: "リセット",
592
+ save: "保存",
593
+ "filter-name": "フィルター名",
594
+ "empty-query-and-no-default":
595
+ "クエリが空で、デフォルトクエリがありません。",
596
+ "query-not-changed": "検索リクエストに変更がないため、検索は不要です。",
597
+ };
598
+ case "pa":
599
+ return {
600
+ search: "ਖੋਜੋ",
601
+ reset: "ਰੀਸੈੱਟ ਕਰੋ",
602
+ save: "ਸੇਵ ਕਰੋ",
603
+ "filter-name": "ਫਿਲਟਰ ਦਾ ਨਾਂ",
604
+ "empty-query-and-no-default": "ਕੁਐਰੀ ਖਾਲੀ ਹੈ ਅਤੇ ਕੋਈ ਡਿਫੌਲਟ ਕੁਐਰੀ ਨਹੀਂ ਹੈ।",
605
+ "query-not-changed":
606
+ "ਖੋਜ ਦੀ ਬੇਨਤੀ ਵਿੱਚ ਕੋਈ ਤਬਦੀਲੀ ਨਹੀਂ ਆਈ ਹੈ, ਇਸ ਲਈ ਖੋਜ ਦੀ ਲੋੜ ਨਹੀਂ ਹੈ।",
607
+ };
608
+ default:
609
+ case "en":
610
+ return {
611
+ search: "Search",
612
+ reset: "Reset",
613
+ save: "Save",
614
+ "filter-name": "Filter name",
615
+ "empty-query-and-no-default":
616
+ "The query is empty and there is no default query.",
617
+ "query-not-changed":
618
+ "The search request has not changed, so no search is required.",
619
+ };
620
+ }
624
621
  }
625
622
 
626
623
  /**
@@ -628,52 +625,52 @@ function getTranslations() {
628
625
  * @return {FilterButton}
629
626
  */
630
627
  function initControlReferences() {
631
- if (!this.shadowRoot) {
632
- throw new Error("no shadow-root is defined");
633
- }
634
-
635
- this[filterControlElementSymbol] = this.shadowRoot.querySelector(
636
- "[data-monster-role=control]",
637
- );
638
- this[filterSelectElementSymbol] = this.shadowRoot.querySelector(
639
- "[data-monster-role=filter-select]",
640
- );
641
- this[searchButtonElementSymbol] = this.shadowRoot.querySelector(
642
- "[data-monster-role=search-button]",
643
- );
644
- this[resetButtonElementSymbol] = this.shadowRoot.querySelector(
645
- "[data-monster-role=reset-button]",
646
- );
647
-
648
- this[saveButtonElementSymbol] = this.shadowRoot.querySelector(
649
- "[data-monster-role=save-button]",
650
- );
651
-
652
- this[filterSaveActionButtonElementSymbol] = this.shadowRoot.querySelector(
653
- "[data-monster-role=save-action-button]",
654
- );
655
-
656
- this[filterTabElementSymbol] = findElementWithSelectorUpwards(
657
- this,
658
- this.getOption("storedConfig.selector", ""),
659
- );
660
-
661
- return this;
628
+ if (!this.shadowRoot) {
629
+ throw new Error("no shadow-root is defined");
630
+ }
631
+
632
+ this[filterControlElementSymbol] = this.shadowRoot.querySelector(
633
+ "[data-monster-role=control]",
634
+ );
635
+ this[filterSelectElementSymbol] = this.shadowRoot.querySelector(
636
+ "[data-monster-role=filter-select]",
637
+ );
638
+ this[searchButtonElementSymbol] = this.shadowRoot.querySelector(
639
+ "[data-monster-role=search-button]",
640
+ );
641
+ this[resetButtonElementSymbol] = this.shadowRoot.querySelector(
642
+ "[data-monster-role=reset-button]",
643
+ );
644
+
645
+ this[saveButtonElementSymbol] = this.shadowRoot.querySelector(
646
+ "[data-monster-role=save-button]",
647
+ );
648
+
649
+ this[filterSaveActionButtonElementSymbol] = this.shadowRoot.querySelector(
650
+ "[data-monster-role=save-action-button]",
651
+ );
652
+
653
+ this[filterTabElementSymbol] = findElementWithSelectorUpwards(
654
+ this,
655
+ this.getOption("storedConfig.selector", ""),
656
+ );
657
+
658
+ return this;
662
659
  }
663
660
 
664
661
  /**
665
662
  * @private
666
663
  */
667
664
  function updateFilterSelections() {
668
- queueMicrotask(() => {
669
- const options = this[settingsSymbol].getOptions();
670
- this[filterSelectElementSymbol].setOption("options", options);
671
-
672
- setTimeout(() => {
673
- this[filterSelectElementSymbol].value =
674
- this[settingsSymbol].getSelected();
675
- }, 10);
676
- });
665
+ queueMicrotask(() => {
666
+ const options = this[settingsSymbol].getOptions();
667
+ this[filterSelectElementSymbol].setOption("options", options);
668
+
669
+ setTimeout(() => {
670
+ this[filterSelectElementSymbol].value =
671
+ this[settingsSymbol].getSelected();
672
+ }, 10);
673
+ });
677
674
  }
678
675
 
679
676
  /**
@@ -681,64 +678,64 @@ function updateFilterSelections() {
681
678
  * @throws {Error} no filter label is defined
682
679
  */
683
680
  function initFilter() {
684
- const storedSetting = this[settingsSymbol];
685
- this[settingsSymbol] = new Settings();
686
-
687
- const result = parseBracketedKeyValueHash(getGlobal().location.hash);
688
- let valuesFromHash = {};
689
- if (isObject(result) && result?.[this.id]) {
690
- valuesFromHash = result[this.id];
691
- }
692
-
693
- getSlottedElements
694
- .call(this, "label[data-monster-label]")
695
- .forEach((element) => {
696
- const label = element.getAttribute("data-monster-label");
697
- if (!label) {
698
- addAttributeToken(
699
- this,
700
- ATTRIBUTE_ERRORMESSAGE,
701
- "no filter label is defined",
702
- );
703
- return;
704
- }
705
-
706
- let value = element.id;
707
- if (!value) {
708
- const prefix = label.replace(/\W/g, "-");
709
- prefix.charAt(0).match(/[\d_]/g)?.length ? `f${prefix}` : prefix;
710
-
711
- value = new ID(prefix + "-").toString();
712
- element.id = value;
713
- }
714
-
715
- let setting = storedSetting.get(value);
716
-
717
- if (setting) {
718
- this[settingsSymbol].set(setting);
719
- }
720
-
721
- if (valuesFromHash?.[element.id]) {
722
- const v = escapeAttributeValue(valuesFromHash[element.id]);
723
- const searchInput = element.firstElementChild;
724
- try {
725
- searchInput.value = v;
726
- } catch (error) {}
727
- }
728
-
729
- setting = this[settingsSymbol].get(value);
730
- let visible = false;
731
- if (setting) {
732
- setSlotAttribute(element, setting.visible);
733
- visible = setting.visible;
734
- } else {
735
- visible = getVisibilityFromSlotAttribute(element);
736
- }
737
-
738
- this[settingsSymbol].set({ value, label, visible });
739
- });
740
-
741
- updateFilterSelections.call(this);
681
+ const storedSetting = this[settingsSymbol];
682
+ this[settingsSymbol] = new Settings();
683
+
684
+ const result = parseBracketedKeyValueHash(getGlobal().location.hash);
685
+ let valuesFromHash = {};
686
+ if (isObject(result) && result?.[this.id]) {
687
+ valuesFromHash = result[this.id];
688
+ }
689
+
690
+ getSlottedElements
691
+ .call(this, "label[data-monster-label]")
692
+ .forEach((element) => {
693
+ const label = element.getAttribute("data-monster-label");
694
+ if (!label) {
695
+ addAttributeToken(
696
+ this,
697
+ ATTRIBUTE_ERRORMESSAGE,
698
+ "no filter label is defined",
699
+ );
700
+ return;
701
+ }
702
+
703
+ let value = element.id;
704
+ if (!value) {
705
+ const prefix = label.replace(/\W/g, "-");
706
+ prefix.charAt(0).match(/[\d_]/g)?.length ? `f${prefix}` : prefix;
707
+
708
+ value = new ID(prefix + "-").toString();
709
+ element.id = value;
710
+ }
711
+
712
+ let setting = storedSetting.get(value);
713
+
714
+ if (setting) {
715
+ this[settingsSymbol].set(setting);
716
+ }
717
+
718
+ if (valuesFromHash?.[element.id]) {
719
+ const v = escapeAttributeValue(valuesFromHash[element.id]);
720
+ const searchInput = element.firstElementChild;
721
+ try {
722
+ searchInput.value = v;
723
+ } catch (error) {}
724
+ }
725
+
726
+ setting = this[settingsSymbol].get(value);
727
+ let visible = false;
728
+ if (setting) {
729
+ setSlotAttribute(element, setting.visible);
730
+ visible = setting.visible;
731
+ } else {
732
+ visible = getVisibilityFromSlotAttribute(element);
733
+ }
734
+
735
+ this[settingsSymbol].set({ value, label, visible });
736
+ });
737
+
738
+ updateFilterSelections.call(this);
742
739
  }
743
740
 
744
741
  /**
@@ -747,16 +744,16 @@ function initFilter() {
747
744
  * @return {*}
748
745
  */
749
746
  function escapeAttributeValue(input) {
750
- if (input === undefined || input === null) {
751
- return input;
752
- }
753
-
754
- return input
755
- .replace(/&/g, "&")
756
- .replace(/"/g, """)
757
- .replace(/'/g, "'")
758
- .replace(/</g, "&lt;")
759
- .replace(/>/g, "&gt;");
747
+ if (input === undefined || input === null) {
748
+ return input;
749
+ }
750
+
751
+ return input
752
+ .replace(/&/g, "&amp;")
753
+ .replace(/"/g, "&quot;")
754
+ .replace(/'/g, "&#x27;")
755
+ .replace(/</g, "&lt;")
756
+ .replace(/>/g, "&gt;");
760
757
  }
761
758
 
762
759
  /**
@@ -765,9 +762,9 @@ function escapeAttributeValue(input) {
765
762
  * @return {boolean}
766
763
  */
767
764
  function getVisibilityFromSlotAttribute(element) {
768
- return !(
769
- element.hasAttribute("slot") && element.getAttribute("slot") === "hidden"
770
- );
765
+ return !(
766
+ element.hasAttribute("slot") && element.getAttribute("slot") === "hidden"
767
+ );
771
768
  }
772
769
 
773
770
  /**
@@ -776,369 +773,369 @@ function getVisibilityFromSlotAttribute(element) {
776
773
  * @param {boolean} visible
777
774
  */
778
775
  function setSlotAttribute(element, visible) {
779
- if (visible) {
780
- element.removeAttribute("slot");
781
- return;
782
- }
776
+ if (visible) {
777
+ element.removeAttribute("slot");
778
+ return;
779
+ }
783
780
 
784
- element.setAttribute("slot", "hidden");
781
+ element.setAttribute("slot", "hidden");
785
782
  }
786
783
 
787
784
  /**
788
785
  * @private
789
786
  */
790
787
  function initEventHandler() {
791
- const self = this;
792
-
793
- let lastHash = getGlobal().location.hash;
794
- self[locationChangeHandlerSymbol] = () => {
795
- if (lastHash === getGlobal().location.hash) {
796
- return;
797
- }
798
-
799
- /**
800
- * debounce the hash change event if doSearch
801
- * is called by click the search button
802
- */
803
- if (self[hashChangeSymbol] > 0) {
804
- self[hashChangeSymbol]--;
805
- return;
806
- }
807
-
808
- initFilter.call(this);
809
-
810
- doSearch
811
- .call(self)
812
- .then(() => {})
813
- .catch((error) => {})
814
- .finally(() => {
815
- lastHash = getGlobal().location.hash;
816
- });
817
- };
818
-
819
- /**
820
- * Monster.Components.Form.event:monster-selection-cleared
821
- */
822
- if (self[filterSelectElementSymbol]) {
823
- self[filterSelectElementSymbol].addEventListener(
824
- "monster-selection-cleared",
825
- function () {
826
- const settings = self[settingsSymbol].getOptions();
827
-
828
- for (const setting of settings) {
829
- const filterElement = findElementWithIdUpwards(self, setting.value);
830
- if (filterElement) {
831
- setSlotAttribute(filterElement, false);
832
-
833
- self[settingsSymbol].set({ value: setting.value, visible: false });
834
- }
835
- }
836
-
837
- updateConfig.call(self);
838
- },
839
- );
840
-
841
- self[filterSelectElementSymbol].addEventListener(
842
- "monster-changed",
843
- function (event) {
844
- const filterElement = findElementWithIdUpwards(
845
- self,
846
- event.detail.value,
847
- );
848
- if (filterElement) {
849
- setSlotAttribute(filterElement, event.detail.checked);
850
- }
851
-
852
- self[settingsSymbol].set({
853
- value: event.detail.value,
854
- visible: event.detail.checked,
855
- });
856
-
857
- updateConfig.call(self);
858
- },
859
- );
860
- }
861
-
862
- /** save the current filter */
863
- if (self[filterSaveActionButtonElementSymbol]) {
864
- self[filterSaveActionButtonElementSymbol].setOption(
865
- "actions.click",
866
- function (event) {
867
- const button = findTargetElementFromEvent(
868
- event,
869
- "data-monster-role",
870
- "save-action-button",
871
- );
872
- const form = button.closest("[data-monster-role=form]");
873
-
874
- if (!form) {
875
- button.setState("failed", self.getOption("timeouts.message", 4000));
876
- return;
877
- }
878
-
879
- const input = form.querySelector("input[name=filter-name]");
880
- if (!input) {
881
- button.setState("failed", self.getOption("timeouts.message", 4000));
882
- return;
883
- }
884
-
885
- const name = input.value;
886
- if (!name) {
887
- button.setState("failed", self.getOption("timeouts.message", 4000));
888
- button.setMessage("Please enter a name").showMessage();
889
- return;
890
- }
891
-
892
- doSearch
893
- .call(self, { showEffect: false })
894
- .then(() => {
895
- const configKey = getStoredFilterConfigKey.call(self);
896
- const host = getDocument().querySelector("monster-host");
897
- if (!host) {
898
- return;
899
- }
900
-
901
- const query = self.getOption("query");
902
- if (!query) {
903
- button.setState(
904
- "failed",
905
- self.getOption(
906
- "timeouts.message",
907
- self.getOption("timeouts.message", 4000),
908
- ),
909
- );
910
- button
911
- .setMessage("No query found")
912
- .showMessage(self.getOption("timeouts.message", 4000));
913
- return;
914
- }
915
-
916
- host
917
- .hasConfig(configKey)
918
- .then((hasConfig) => {
919
- return new Promise((resolve, reject) => {
920
- if (hasConfig) {
921
- host.getConfig(configKey).then(resolve).catch(reject);
922
- return;
923
- }
924
- return resolve({});
925
- });
926
- })
927
- .then((config) => {
928
- config[name] = query;
929
- return host.setConfig(configKey, {
930
- ...config,
931
- });
932
- })
933
- .then(() => {
934
- button.setState(
935
- "successful",
936
- self.getOption("timeouts.message", 4000),
937
- );
938
- updateFilterTabs.call(self);
939
- })
940
- .catch((error) => {
941
- button.setState(
942
- "failed",
943
- self.getOption("timeouts.message", 4000),
944
- );
945
- button
946
- .setMessage(error.message)
947
- .showMessage(self.getOption("timeouts.message", 4000));
948
- });
949
- })
950
- .catch((error) => {
951
- button.setState("failed", self.getOption("timeouts.message", 4000));
952
- const msg = error.message || error;
953
- button
954
- .setMessage(msg)
955
- .showMessage(self.getOption("timeouts.message", 4000));
956
- });
957
- },
958
- );
959
- }
960
-
961
- self[searchButtonElementSymbol].setOption("actions.click", () => {
962
- self[hashChangeSymbol] = 1;
963
-
964
- doSearch
965
- .call(self)
966
- .then(() => {})
967
- .catch((error) => {});
968
- });
969
-
970
- // the reset button should reset the filter and the search query
971
- // all input elements should be reset to their default values
972
- // which is the empty string. we search for all input elements
973
- // in the filter and reset them to their default value
974
- self[resetButtonElementSymbol].setOption("actions.click", () => {
975
- getSlottedElements
976
- .call(self, "label[data-monster-label]")
977
- .forEach((element) => {
978
- const label = element.getAttribute("data-monster-label");
979
- if (!label) {
980
- return;
981
- }
982
-
983
- const input = element.firstElementChild;
984
-
985
- if (input) {
986
- input.value = "";
987
- }
988
- });
989
-
990
- doSearch
991
- .call(self, { showEffect: false })
992
- .then(() => {})
993
- .catch((e) => addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, e.message));
994
- });
995
-
996
- self.addEventListener("keyup", (event) => {
997
- const path = event.composedPath();
998
- if (path.length === 0) {
999
- return;
1000
- }
1001
-
1002
- if (!(path[0] instanceof HTMLInputElement)) {
1003
- return;
1004
- }
1005
-
1006
- if (event.keyCode === 13) {
1007
- doSearch
1008
- .call(self, { showEffect: false })
1009
- .then(() => {})
1010
- .catch((error) => {});
1011
- }
1012
- });
1013
-
1014
- // tabs
1015
- const element = this[filterTabElementSymbol];
1016
- if (element) {
1017
- initTabEvents.call(this);
1018
- }
788
+ const self = this;
789
+
790
+ let lastHash = getGlobal().location.hash;
791
+ self[locationChangeHandlerSymbol] = () => {
792
+ if (lastHash === getGlobal().location.hash) {
793
+ return;
794
+ }
795
+
796
+ /**
797
+ * debounce the hash change event if doSearch
798
+ * is called by click the search button
799
+ */
800
+ if (self[hashChangeSymbol] > 0) {
801
+ self[hashChangeSymbol]--;
802
+ return;
803
+ }
804
+
805
+ initFilter.call(this);
806
+
807
+ doSearch
808
+ .call(self)
809
+ .then(() => {})
810
+ .catch((error) => {})
811
+ .finally(() => {
812
+ lastHash = getGlobal().location.hash;
813
+ });
814
+ };
815
+
816
+ /**
817
+ * Monster.Components.Form.event:monster-selection-cleared
818
+ */
819
+ if (self[filterSelectElementSymbol]) {
820
+ self[filterSelectElementSymbol].addEventListener(
821
+ "monster-selection-cleared",
822
+ function () {
823
+ const settings = self[settingsSymbol].getOptions();
824
+
825
+ for (const setting of settings) {
826
+ const filterElement = findElementWithIdUpwards(self, setting.value);
827
+ if (filterElement) {
828
+ setSlotAttribute(filterElement, false);
829
+
830
+ self[settingsSymbol].set({ value: setting.value, visible: false });
831
+ }
832
+ }
833
+
834
+ updateConfig.call(self);
835
+ },
836
+ );
837
+
838
+ self[filterSelectElementSymbol].addEventListener(
839
+ "monster-changed",
840
+ function (event) {
841
+ const filterElement = findElementWithIdUpwards(
842
+ self,
843
+ event.detail.value,
844
+ );
845
+ if (filterElement) {
846
+ setSlotAttribute(filterElement, event.detail.checked);
847
+ }
848
+
849
+ self[settingsSymbol].set({
850
+ value: event.detail.value,
851
+ visible: event.detail.checked,
852
+ });
853
+
854
+ updateConfig.call(self);
855
+ },
856
+ );
857
+ }
858
+
859
+ /** save the current filter */
860
+ if (self[filterSaveActionButtonElementSymbol]) {
861
+ self[filterSaveActionButtonElementSymbol].setOption(
862
+ "actions.click",
863
+ function (event) {
864
+ const button = findTargetElementFromEvent(
865
+ event,
866
+ "data-monster-role",
867
+ "save-action-button",
868
+ );
869
+ const form = button.closest("[data-monster-role=form]");
870
+
871
+ if (!form) {
872
+ button.setState("failed", self.getOption("timeouts.message", 4000));
873
+ return;
874
+ }
875
+
876
+ const input = form.querySelector("input[name=filter-name]");
877
+ if (!input) {
878
+ button.setState("failed", self.getOption("timeouts.message", 4000));
879
+ return;
880
+ }
881
+
882
+ const name = input.value;
883
+ if (!name) {
884
+ button.setState("failed", self.getOption("timeouts.message", 4000));
885
+ button.setMessage("Please enter a name").showMessage();
886
+ return;
887
+ }
888
+
889
+ doSearch
890
+ .call(self, { showEffect: false })
891
+ .then(() => {
892
+ const configKey = getStoredFilterConfigKey.call(self);
893
+ const host = getDocument().querySelector("monster-host");
894
+ if (!host) {
895
+ return;
896
+ }
897
+
898
+ const query = self.getOption("query");
899
+ if (!query) {
900
+ button.setState(
901
+ "failed",
902
+ self.getOption(
903
+ "timeouts.message",
904
+ self.getOption("timeouts.message", 4000),
905
+ ),
906
+ );
907
+ button
908
+ .setMessage("No query found")
909
+ .showMessage(self.getOption("timeouts.message", 4000));
910
+ return;
911
+ }
912
+
913
+ host
914
+ .hasConfig(configKey)
915
+ .then((hasConfig) => {
916
+ return new Promise((resolve, reject) => {
917
+ if (hasConfig) {
918
+ host.getConfig(configKey).then(resolve).catch(reject);
919
+ return;
920
+ }
921
+ return resolve({});
922
+ });
923
+ })
924
+ .then((config) => {
925
+ config[name] = query;
926
+ return host.setConfig(configKey, {
927
+ ...config,
928
+ });
929
+ })
930
+ .then(() => {
931
+ button.setState(
932
+ "successful",
933
+ self.getOption("timeouts.message", 4000),
934
+ );
935
+ updateFilterTabs.call(self);
936
+ })
937
+ .catch((error) => {
938
+ button.setState(
939
+ "failed",
940
+ self.getOption("timeouts.message", 4000),
941
+ );
942
+ button
943
+ .setMessage(error.message)
944
+ .showMessage(self.getOption("timeouts.message", 4000));
945
+ });
946
+ })
947
+ .catch((error) => {
948
+ button.setState("failed", self.getOption("timeouts.message", 4000));
949
+ const msg = error.message || error;
950
+ button
951
+ .setMessage(msg)
952
+ .showMessage(self.getOption("timeouts.message", 4000));
953
+ });
954
+ },
955
+ );
956
+ }
957
+
958
+ self[searchButtonElementSymbol].setOption("actions.click", () => {
959
+ self[hashChangeSymbol] = 1;
960
+
961
+ doSearch
962
+ .call(self)
963
+ .then(() => {})
964
+ .catch((error) => {});
965
+ });
966
+
967
+ // the reset button should reset the filter and the search query
968
+ // all input elements should be reset to their default values
969
+ // which is the empty string. we search for all input elements
970
+ // in the filter and reset them to their default value
971
+ self[resetButtonElementSymbol].setOption("actions.click", () => {
972
+ getSlottedElements
973
+ .call(self, "label[data-monster-label]")
974
+ .forEach((element) => {
975
+ const label = element.getAttribute("data-monster-label");
976
+ if (!label) {
977
+ return;
978
+ }
979
+
980
+ const input = element.firstElementChild;
981
+
982
+ if (input) {
983
+ input.value = "";
984
+ }
985
+ });
986
+
987
+ doSearch
988
+ .call(self, { showEffect: false })
989
+ .then(() => {})
990
+ .catch((e) => addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, e.message));
991
+ });
992
+
993
+ self.addEventListener("keyup", (event) => {
994
+ const path = event.composedPath();
995
+ if (path.length === 0) {
996
+ return;
997
+ }
998
+
999
+ if (!(path[0] instanceof HTMLInputElement)) {
1000
+ return;
1001
+ }
1002
+
1003
+ if (event.keyCode === 13) {
1004
+ doSearch
1005
+ .call(self, { showEffect: false })
1006
+ .then(() => {})
1007
+ .catch((error) => {});
1008
+ }
1009
+ });
1010
+
1011
+ // tabs
1012
+ const element = this[filterTabElementSymbol];
1013
+ if (element) {
1014
+ initTabEvents.call(this);
1015
+ }
1019
1016
  }
1020
1017
 
1021
1018
  function initTabEvents() {
1022
- const self = this;
1023
- this[filterTabElementSymbol].addEventListener(
1024
- "monster-tab-changed",
1025
- (event) => {
1026
- const query = event?.detail?.data?.["data-monster-query"];
1027
- const q = this.getOption("query");
1028
- if (query !== q) {
1029
- this.setOption("query", query);
1030
- }
1031
- },
1032
- );
1033
-
1034
- this[filterTabElementSymbol].addEventListener(
1035
- "monster-tab-remove",
1036
- (event) => {
1037
- const labels = [];
1038
- const buttons = this[filterTabElementSymbol].getOption("buttons");
1039
-
1040
- const keys = ["popper", "standard"];
1041
- for (let i = 0; i < keys.length; i++) {
1042
- const key = keys[i];
1043
-
1044
- for (const button of buttons[key]) {
1045
- if (button.label !== event.detail.label) {
1046
- labels.push(button.label);
1047
- }
1048
- }
1049
- }
1050
-
1051
- const host = findElementWithSelectorUpwards(this, "monster-host");
1052
- if (!(host && this.id)) {
1053
- return;
1054
- }
1055
-
1056
- const configKey = getStoredFilterConfigKey.call(this);
1057
- host
1058
- .hasConfig(configKey)
1059
- .then((hasConfig) => {
1060
- if (!hasConfig) {
1061
- return;
1062
- }
1063
-
1064
- return host.getConfig(configKey);
1065
- })
1066
- .then((config) => {
1067
- for (const [name, query] of Object.entries(config)) {
1068
- if (labels.includes(name)) {
1069
- continue;
1070
- }
1071
-
1072
- delete config[name];
1073
- }
1074
-
1075
- return host.setConfig(configKey, {
1076
- ...config,
1077
- });
1078
- });
1079
- },
1080
- );
1019
+ const self = this;
1020
+ this[filterTabElementSymbol].addEventListener(
1021
+ "monster-tab-changed",
1022
+ (event) => {
1023
+ const query = event?.detail?.data?.["data-monster-query"];
1024
+ const q = this.getOption("query");
1025
+ if (query !== q) {
1026
+ this.setOption("query", query);
1027
+ }
1028
+ },
1029
+ );
1030
+
1031
+ this[filterTabElementSymbol].addEventListener(
1032
+ "monster-tab-remove",
1033
+ (event) => {
1034
+ const labels = [];
1035
+ const buttons = this[filterTabElementSymbol].getOption("buttons");
1036
+
1037
+ const keys = ["popper", "standard"];
1038
+ for (let i = 0; i < keys.length; i++) {
1039
+ const key = keys[i];
1040
+
1041
+ for (const button of buttons[key]) {
1042
+ if (button.label !== event.detail.label) {
1043
+ labels.push(button.label);
1044
+ }
1045
+ }
1046
+ }
1047
+
1048
+ const host = findElementWithSelectorUpwards(this, "monster-host");
1049
+ if (!(host && this.id)) {
1050
+ return;
1051
+ }
1052
+
1053
+ const configKey = getStoredFilterConfigKey.call(this);
1054
+ host
1055
+ .hasConfig(configKey)
1056
+ .then((hasConfig) => {
1057
+ if (!hasConfig) {
1058
+ return;
1059
+ }
1060
+
1061
+ return host.getConfig(configKey);
1062
+ })
1063
+ .then((config) => {
1064
+ for (const [name, query] of Object.entries(config)) {
1065
+ if (labels.includes(name)) {
1066
+ continue;
1067
+ }
1068
+
1069
+ delete config[name];
1070
+ }
1071
+
1072
+ return host.setConfig(configKey, {
1073
+ ...config,
1074
+ });
1075
+ });
1076
+ },
1077
+ );
1081
1078
  }
1082
1079
 
1083
1080
  /**
1084
1081
  * @private
1085
1082
  */
1086
1083
  function updateFilterTabs() {
1087
- const element = this[filterTabElementSymbol];
1088
- if (!element) {
1089
- return;
1090
- }
1091
-
1092
- const host = findElementWithSelectorUpwards(this, "monster-host");
1093
- if (!(host && this.id)) {
1094
- return;
1095
- }
1096
-
1097
- const configKey = getStoredFilterConfigKey.call(this);
1098
- host
1099
- .hasConfig(configKey)
1100
- .then((hasConfig) => {
1101
- if (!hasConfig) {
1102
- return;
1103
- }
1104
-
1105
- return host.getConfig(configKey);
1106
- })
1107
- .then((config) => {
1108
- for (const [name, query] of Object.entries(config)) {
1109
- const found = element.querySelector(
1110
- `[data-monster-button-label="${name}"]`,
1111
- );
1112
- if (found) {
1113
- continue;
1114
- }
1115
-
1116
- if (query === undefined || query === null) {
1117
- continue;
1118
- }
1119
-
1120
- const escapedQuery = escapeAttributeValue(query);
1121
-
1122
- element.insertAdjacentHTML(
1123
- "beforeend",
1124
- `<div data-monster-button-label="${name}"
1084
+ const element = this[filterTabElementSymbol];
1085
+ if (!element) {
1086
+ return;
1087
+ }
1088
+
1089
+ const host = findElementWithSelectorUpwards(this, "monster-host");
1090
+ if (!(host && this.id)) {
1091
+ return;
1092
+ }
1093
+
1094
+ const configKey = getStoredFilterConfigKey.call(this);
1095
+ host
1096
+ .hasConfig(configKey)
1097
+ .then((hasConfig) => {
1098
+ if (!hasConfig) {
1099
+ return;
1100
+ }
1101
+
1102
+ return host.getConfig(configKey);
1103
+ })
1104
+ .then((config) => {
1105
+ for (const [name, query] of Object.entries(config)) {
1106
+ const found = element.querySelector(
1107
+ `[data-monster-button-label="${name}"]`,
1108
+ );
1109
+ if (found) {
1110
+ continue;
1111
+ }
1112
+
1113
+ if (query === undefined || query === null) {
1114
+ continue;
1115
+ }
1116
+
1117
+ const escapedQuery = escapeAttributeValue(query);
1118
+
1119
+ element.insertAdjacentHTML(
1120
+ "beforeend",
1121
+ `<div data-monster-button-label="${name}"
1125
1122
  data-monster-removable="true"
1126
1123
  data-monster-query="${escapedQuery}" data-monster-role="filter-tab" >
1127
1124
  </div>`,
1128
- );
1129
- }
1130
- })
1131
- .catch((error) => {
1132
- if (error instanceof Error) {
1133
- addAttributeToken(
1134
- this,
1135
- ATTRIBUTE_ERRORMESSAGE,
1136
- error.message + " " + error.stack,
1137
- );
1138
- } else {
1139
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, error + "");
1140
- }
1141
- });
1125
+ );
1126
+ }
1127
+ })
1128
+ .catch((error) => {
1129
+ if (error instanceof Error) {
1130
+ addAttributeToken(
1131
+ this,
1132
+ ATTRIBUTE_ERRORMESSAGE,
1133
+ error.message + " " + error.stack,
1134
+ );
1135
+ } else {
1136
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, error + "");
1137
+ }
1138
+ });
1142
1139
  }
1143
1140
 
1144
1141
  /**
@@ -1147,92 +1144,92 @@ function updateFilterTabs() {
1147
1144
  * @return {Promise}
1148
1145
  */
1149
1146
  function doSearch({ showEffect } = { showEffect: true }) {
1150
- this.resetFailureMessage();
1151
-
1152
- if (showEffect) {
1153
- this[searchButtonElementSymbol].setState(
1154
- "activity",
1155
- this.getOption("timeouts.message", 4000),
1156
- );
1157
- }
1158
-
1159
- return collectSearchQueries
1160
- .call(this)
1161
- .then((query) => {
1162
- const buildQuery = buildSearchQuery.call(this, query);
1163
- if (buildQuery === null) {
1164
- const msg = this.getOption("labels.empty-query-and-no-default");
1165
- if (showEffect) {
1166
- this[searchButtonElementSymbol].removeState();
1167
- this[searchButtonElementSymbol]
1168
- .setMessage(msg)
1169
- .showMessage(this.getOption("timeouts.message", 4000));
1170
- }
1171
- return Promise.reject(new Error(msg));
1172
- }
1173
-
1174
- if (buildQuery === "" && this.getOption("defaultQuery") === null) {
1175
- const msg = this.getOption("labels.empty-query-and-no-default");
1176
-
1177
- if (showEffect) {
1178
- this[searchButtonElementSymbol].removeState();
1179
- this[searchButtonElementSymbol]
1180
- .setMessage(msg)
1181
- .showMessage(this.getOption("timeouts.message", 4000));
1182
- }
1183
-
1184
- return Promise.reject(new Error(msg));
1185
- }
1186
-
1187
- if (
1188
- this.getOption("features.preventSameQuery") &&
1189
- buildQuery === this.getOption("query")
1190
- ) {
1191
- const msg = this.getOption("labels.query-not-changed");
1192
-
1193
- if (showEffect) {
1194
- this[searchButtonElementSymbol].removeState();
1195
- this[searchButtonElementSymbol]
1196
- .setMessage(msg)
1197
- .showMessage(this.getOption("timeouts.message", 4000));
1198
- }
1199
-
1200
- return Promise.reject(new Error(msg));
1201
- }
1202
-
1203
- if (showEffect) {
1204
- this[searchButtonElementSymbol].removeState();
1205
- this[searchButtonElementSymbol].setState(
1206
- "activity",
1207
- this.getOption("timeouts.message", 4000),
1208
- );
1209
- }
1210
-
1211
- this.setOption("query", buildSearchQuery.call(this, query));
1212
-
1213
- return Promise.resolve();
1214
- })
1215
- .catch((error) => {
1216
- if (error instanceof Error) {
1217
- addAttributeToken(
1218
- this,
1219
- ATTRIBUTE_ERRORMESSAGE,
1220
- error.message + " " + error.stack,
1221
- );
1222
- } else {
1223
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, String(error));
1224
- }
1225
-
1226
- if (showEffect) {
1227
- this[searchButtonElementSymbol].setState(
1228
- "failed",
1229
- this.getOption("timeouts.message", 4000),
1230
- );
1231
- this[searchButtonElementSymbol].setMessage(error.message).showMessage();
1232
- }
1233
-
1234
- return Promise.reject(error);
1235
- });
1147
+ this.resetFailureMessage();
1148
+
1149
+ if (showEffect) {
1150
+ this[searchButtonElementSymbol].setState(
1151
+ "activity",
1152
+ this.getOption("timeouts.message", 4000),
1153
+ );
1154
+ }
1155
+
1156
+ return collectSearchQueries
1157
+ .call(this)
1158
+ .then((query) => {
1159
+ const buildQuery = buildSearchQuery.call(this, query);
1160
+ if (buildQuery === null) {
1161
+ const msg = this.getOption("labels.empty-query-and-no-default");
1162
+ if (showEffect) {
1163
+ this[searchButtonElementSymbol].removeState();
1164
+ this[searchButtonElementSymbol]
1165
+ .setMessage(msg)
1166
+ .showMessage(this.getOption("timeouts.message", 4000));
1167
+ }
1168
+ return Promise.reject(new Error(msg));
1169
+ }
1170
+
1171
+ if (buildQuery === "" && this.getOption("defaultQuery") === null) {
1172
+ const msg = this.getOption("labels.empty-query-and-no-default");
1173
+
1174
+ if (showEffect) {
1175
+ this[searchButtonElementSymbol].removeState();
1176
+ this[searchButtonElementSymbol]
1177
+ .setMessage(msg)
1178
+ .showMessage(this.getOption("timeouts.message", 4000));
1179
+ }
1180
+
1181
+ return Promise.reject(new Error(msg));
1182
+ }
1183
+
1184
+ if (
1185
+ this.getOption("features.preventSameQuery") &&
1186
+ buildQuery === this.getOption("query")
1187
+ ) {
1188
+ const msg = this.getOption("labels.query-not-changed");
1189
+
1190
+ if (showEffect) {
1191
+ this[searchButtonElementSymbol].removeState();
1192
+ this[searchButtonElementSymbol]
1193
+ .setMessage(msg)
1194
+ .showMessage(this.getOption("timeouts.message", 4000));
1195
+ }
1196
+
1197
+ return Promise.reject(new Error(msg));
1198
+ }
1199
+
1200
+ if (showEffect) {
1201
+ this[searchButtonElementSymbol].removeState();
1202
+ this[searchButtonElementSymbol].setState(
1203
+ "activity",
1204
+ this.getOption("timeouts.message", 4000),
1205
+ );
1206
+ }
1207
+
1208
+ this.setOption("query", buildSearchQuery.call(this, query));
1209
+
1210
+ return Promise.resolve();
1211
+ })
1212
+ .catch((error) => {
1213
+ if (error instanceof Error) {
1214
+ addAttributeToken(
1215
+ this,
1216
+ ATTRIBUTE_ERRORMESSAGE,
1217
+ error.message + " " + error.stack,
1218
+ );
1219
+ } else {
1220
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, String(error));
1221
+ }
1222
+
1223
+ if (showEffect) {
1224
+ this[searchButtonElementSymbol].setState(
1225
+ "failed",
1226
+ this.getOption("timeouts.message", 4000),
1227
+ );
1228
+ this[searchButtonElementSymbol].setMessage(error.message).showMessage();
1229
+ }
1230
+
1231
+ return Promise.reject(error);
1232
+ });
1236
1233
  }
1237
1234
 
1238
1235
  /**
@@ -1241,21 +1238,21 @@ function doSearch({ showEffect } = { showEffect: true }) {
1241
1238
  * @return {*|string}
1242
1239
  */
1243
1240
  function buildSearchQuery(queries) {
1244
- if (!isArray(queries) || queries.length === 0) {
1245
- return this.getOption("defaultQuery");
1246
- }
1241
+ if (!isArray(queries) || queries.length === 0) {
1242
+ return this.getOption("defaultQuery");
1243
+ }
1247
1244
 
1248
- const joinCallback = this.getOption("queries.join");
1249
- if (isFunction(joinCallback)) {
1250
- return joinCallback(queries);
1251
- }
1245
+ const joinCallback = this.getOption("queries.join");
1246
+ if (isFunction(joinCallback)) {
1247
+ return joinCallback(queries);
1248
+ }
1252
1249
 
1253
- const q = queries.join(" ").trim();
1254
- if (q.length === 0) {
1255
- return this.getOption("defaultQuery");
1256
- }
1250
+ const q = queries.join(" ").trim();
1251
+ if (q.length === 0) {
1252
+ return this.getOption("defaultQuery");
1253
+ }
1257
1254
 
1258
- return q;
1255
+ return q;
1259
1256
  }
1260
1257
 
1261
1258
  /**
@@ -1263,247 +1260,247 @@ function buildSearchQuery(queries) {
1263
1260
  * @return {Promise<unknown>}
1264
1261
  */
1265
1262
  function collectSearchQueries() {
1266
- const currentHash = parseBracketedKeyValueHash(getGlobal().location.hash);
1267
- const self = this;
1268
-
1269
- return new Promise((resolve, reject) => {
1270
- const query = [];
1271
- const wrapCallback = this.getOption("queries.wrap");
1272
-
1273
- let hasNoIdError = false;
1274
-
1275
- getSlottedElements
1276
- .call(this, "label[data-monster-label]")
1277
- .forEach((element) => {
1278
- const label = element.getAttribute("data-monster-label");
1279
- if (!label) {
1280
- throw new Error("no filter label is defined");
1281
- }
1282
-
1283
- const id = element.id;
1284
- if (!id) {
1285
- hasNoIdError = true;
1286
- return;
1287
- }
1288
-
1289
- const visible = getVisibilityFromSlotAttribute(element);
1290
- if (!visible) {
1291
- return;
1292
- }
1293
-
1294
- let template = element.getAttribute("data-monster-template");
1295
- if (!template) {
1296
- template = "${id}=${value}";
1297
- }
1298
-
1299
- const controlValue = getControlValuesFromLabel(element);
1300
- if (!controlValue) {
1301
- if (controlValue === "" && currentHash?.[this.id]?.[id]) {
1302
- delete currentHash[this.id][id];
1303
- }
1304
-
1305
- return;
1306
- }
1307
-
1308
- if (!isObject(currentHash[this.id])) {
1309
- currentHash[this.id] = {};
1310
- }
1311
- currentHash[this.id][id] = controlValue;
1312
-
1313
- const mapping = {
1314
- id,
1315
- value: controlValue,
1316
- label,
1317
- };
1318
-
1319
- const formatter = new Formatter(mapping, {
1320
- callbacks: {
1321
- range: (value, key) => {
1322
- return generateRangeComparisonExpression(value, key, {
1323
- urlEncode: true,
1324
- andOp: "AND",
1325
- orOp: "OR",
1326
- eqOp: "=",
1327
- gtOp: ">",
1328
- ltOp: "<",
1329
- });
1330
- },
1331
- "tag-list": (value, key) => {
1332
- if (isString(value)) {
1333
- value = value.split(",");
1334
- }
1335
-
1336
- if (!isArray(value)) {
1337
- return "";
1338
- }
1339
-
1340
- return (
1341
- key +
1342
- " IN " +
1343
- value
1344
- .map((v) => {
1345
- return `"${encodeURIComponent(v)}"`;
1346
- })
1347
- .join(",")
1348
- );
1349
- },
1350
- "list-tag": (value, key) => {
1351
- if (isString(value)) {
1352
- value = value.split(",");
1353
- }
1354
-
1355
- if (!isArray(value)) {
1356
- return "";
1357
- }
1358
-
1359
- return (
1360
- value
1361
- .map((v) => {
1362
- return `"${encodeURIComponent(v)}"`;
1363
- })
1364
- .join(",") +
1365
- " IN " +
1366
- encodeURIComponent(key)
1367
- );
1368
- },
1369
- "tags-in-list": (value, key, op) => {
1370
- if (isString(value)) {
1371
- value = value.split(",");
1372
- }
1373
-
1374
- if (!isArray(value)) {
1375
- return "";
1376
- }
1377
-
1378
- if (!op || !isString(op)) op = "OR";
1379
- op = " " + op.toUpperCase().trim() + " ";
1380
-
1381
- let query = "";
1382
- value.forEach((v) => {
1383
- if (query.length > 0) {
1384
- query += op;
1385
- }
1386
- query += `${encodeURIComponent(key)} IN "${encodeURIComponent(v)}"`;
1387
- });
1388
-
1389
- return query;
1390
- },
1391
- "list-not-in-tags": (value, key, op) => {
1392
- if (isString(value)) {
1393
- value = value.split(",");
1394
- }
1395
- if (!isArray(value)) {
1396
- return "";
1397
- }
1398
- if (!op || !isString(op)) op = "OR";
1399
- op = " " + op.toUpperCase().trim() + " ";
1400
- let query = "";
1401
- value.forEach((v) => {
1402
- if (query.length > 0) {
1403
- query += op;
1404
- }
1405
- query += `"${encodeURIComponent(v)}" NOT IN ${encodeURIComponent(key)}`;
1406
- });
1407
- return query;
1408
- },
1409
- "list-in-tags": (value, key, op) => {
1410
- if (isString(value)) {
1411
- value = value.split(",");
1412
- }
1413
-
1414
- if (!isArray(value)) {
1415
- return "";
1416
- }
1417
-
1418
- if (!op || !isString(op)) op = "OR";
1419
- op = " " + op.toUpperCase().trim() + " ";
1420
-
1421
- let query = "";
1422
- value.forEach((v) => {
1423
- if (query.length > 0) {
1424
- query += op;
1425
- }
1426
- query += `"${encodeURIComponent(v)}" IN ${encodeURIComponent(key)}`;
1427
- });
1428
-
1429
- return query;
1430
- },
1431
- "array-list": (value, key) => {
1432
- if (isString(value)) {
1433
- value = value.split(",");
1434
- }
1435
-
1436
- if (!isArray(value)) {
1437
- return "";
1438
- }
1439
-
1440
- return (
1441
- key +
1442
- "=" +
1443
- value
1444
- .map((v) => {
1445
- return `"${encodeURIComponent(v)}"`;
1446
- })
1447
- .join(",")
1448
- );
1449
- },
1450
- "date-range": (value, key) => {
1451
- const query = parseDateInput(value, key);
1452
- if (!query || query === "false") {
1453
- return "";
1454
- }
1455
-
1456
- // return query as url encoded
1457
- return encodeURIComponent(query);
1458
- },
1459
- "to-int-2": (value, key) => {
1460
- const query = normalizeNumber(value);
1461
- if (Number.isNaN(query)) {
1462
- return key + " IS NULL";
1463
- }
1464
- return key + "=" + encodeURIComponent(Math.round(query * 100));
1465
- },
1466
- "to-int-3": (value, key) => {
1467
- const query = normalizeNumber(value);
1468
- if (Number.isNaN(query)) {
1469
- return "";
1470
- }
1471
- return key + "=" + encodeURIComponent(Math.round(query * 1000));
1472
- },
1473
- "to-int-4": (value, key) => {
1474
- const query = normalizeNumber(value);
1475
- if (Number.isNaN(query)) {
1476
- return "";
1477
- }
1478
- return key + "=" + encodeURIComponent(Math.round(query * 10000));
1479
- },
1480
- },
1481
- });
1482
-
1483
- if (self.getOption("formatter.marker.open")) {
1484
- formatter.setMarker(
1485
- self.getOption("formatter.marker.open"),
1486
- self.getOption("formatter.marker.close"),
1487
- );
1488
- }
1489
-
1490
- let queryPart = formatter.format(template);
1491
- if (queryPart) {
1492
- if (isFunction(wrapCallback)) {
1493
- queryPart = wrapCallback(queryPart, mapping);
1494
- }
1495
- query.push(queryPart);
1496
- }
1497
- });
1498
-
1499
- if (hasNoIdError) {
1500
- reject(new Error("some or all filter elements have no id"));
1501
- return;
1502
- }
1503
-
1504
- getGlobal().location.hash = createBracketedKeyValueHash(currentHash);
1505
- resolve(query);
1506
- });
1263
+ const currentHash = parseBracketedKeyValueHash(getGlobal().location.hash);
1264
+ const self = this;
1265
+
1266
+ return new Promise((resolve, reject) => {
1267
+ const query = [];
1268
+ const wrapCallback = this.getOption("queries.wrap");
1269
+
1270
+ let hasNoIdError = false;
1271
+
1272
+ getSlottedElements
1273
+ .call(this, "label[data-monster-label]")
1274
+ .forEach((element) => {
1275
+ const label = element.getAttribute("data-monster-label");
1276
+ if (!label) {
1277
+ throw new Error("no filter label is defined");
1278
+ }
1279
+
1280
+ const id = element.id;
1281
+ if (!id) {
1282
+ hasNoIdError = true;
1283
+ return;
1284
+ }
1285
+
1286
+ const visible = getVisibilityFromSlotAttribute(element);
1287
+ if (!visible) {
1288
+ return;
1289
+ }
1290
+
1291
+ let template = element.getAttribute("data-monster-template");
1292
+ if (!template) {
1293
+ template = "${id}=${value}";
1294
+ }
1295
+
1296
+ const controlValue = getControlValuesFromLabel(element);
1297
+ if (!controlValue) {
1298
+ if (controlValue === "" && currentHash?.[this.id]?.[id]) {
1299
+ delete currentHash[this.id][id];
1300
+ }
1301
+
1302
+ return;
1303
+ }
1304
+
1305
+ if (!isObject(currentHash[this.id])) {
1306
+ currentHash[this.id] = {};
1307
+ }
1308
+ currentHash[this.id][id] = controlValue;
1309
+
1310
+ const mapping = {
1311
+ id,
1312
+ value: controlValue,
1313
+ label,
1314
+ };
1315
+
1316
+ const formatter = new Formatter(mapping, {
1317
+ callbacks: {
1318
+ range: (value, key) => {
1319
+ return generateRangeComparisonExpression(value, key, {
1320
+ urlEncode: true,
1321
+ andOp: "AND",
1322
+ orOp: "OR",
1323
+ eqOp: "=",
1324
+ gtOp: ">",
1325
+ ltOp: "<",
1326
+ });
1327
+ },
1328
+ "tag-list": (value, key) => {
1329
+ if (isString(value)) {
1330
+ value = value.split(",");
1331
+ }
1332
+
1333
+ if (!isArray(value)) {
1334
+ return "";
1335
+ }
1336
+
1337
+ return (
1338
+ key +
1339
+ " IN " +
1340
+ value
1341
+ .map((v) => {
1342
+ return `"${encodeURIComponent(v)}"`;
1343
+ })
1344
+ .join(",")
1345
+ );
1346
+ },
1347
+ "list-tag": (value, key) => {
1348
+ if (isString(value)) {
1349
+ value = value.split(",");
1350
+ }
1351
+
1352
+ if (!isArray(value)) {
1353
+ return "";
1354
+ }
1355
+
1356
+ return (
1357
+ value
1358
+ .map((v) => {
1359
+ return `"${encodeURIComponent(v)}"`;
1360
+ })
1361
+ .join(",") +
1362
+ " IN " +
1363
+ encodeURIComponent(key)
1364
+ );
1365
+ },
1366
+ "tags-in-list": (value, key, op) => {
1367
+ if (isString(value)) {
1368
+ value = value.split(",");
1369
+ }
1370
+
1371
+ if (!isArray(value)) {
1372
+ return "";
1373
+ }
1374
+
1375
+ if (!op || !isString(op)) op = "OR";
1376
+ op = " " + op.toUpperCase().trim() + " ";
1377
+
1378
+ let query = "";
1379
+ value.forEach((v) => {
1380
+ if (query.length > 0) {
1381
+ query += op;
1382
+ }
1383
+ query += `${encodeURIComponent(key)} IN "${encodeURIComponent(v)}"`;
1384
+ });
1385
+
1386
+ return query;
1387
+ },
1388
+ "list-not-in-tags": (value, key, op) => {
1389
+ if (isString(value)) {
1390
+ value = value.split(",");
1391
+ }
1392
+ if (!isArray(value)) {
1393
+ return "";
1394
+ }
1395
+ if (!op || !isString(op)) op = "OR";
1396
+ op = " " + op.toUpperCase().trim() + " ";
1397
+ let query = "";
1398
+ value.forEach((v) => {
1399
+ if (query.length > 0) {
1400
+ query += op;
1401
+ }
1402
+ query += `"${encodeURIComponent(v)}" NOT IN ${encodeURIComponent(key)}`;
1403
+ });
1404
+ return query;
1405
+ },
1406
+ "list-in-tags": (value, key, op) => {
1407
+ if (isString(value)) {
1408
+ value = value.split(",");
1409
+ }
1410
+
1411
+ if (!isArray(value)) {
1412
+ return "";
1413
+ }
1414
+
1415
+ if (!op || !isString(op)) op = "OR";
1416
+ op = " " + op.toUpperCase().trim() + " ";
1417
+
1418
+ let query = "";
1419
+ value.forEach((v) => {
1420
+ if (query.length > 0) {
1421
+ query += op;
1422
+ }
1423
+ query += `"${encodeURIComponent(v)}" IN ${encodeURIComponent(key)}`;
1424
+ });
1425
+
1426
+ return query;
1427
+ },
1428
+ "array-list": (value, key) => {
1429
+ if (isString(value)) {
1430
+ value = value.split(",");
1431
+ }
1432
+
1433
+ if (!isArray(value)) {
1434
+ return "";
1435
+ }
1436
+
1437
+ return (
1438
+ key +
1439
+ "=" +
1440
+ value
1441
+ .map((v) => {
1442
+ return `"${encodeURIComponent(v)}"`;
1443
+ })
1444
+ .join(",")
1445
+ );
1446
+ },
1447
+ "date-range": (value, key) => {
1448
+ const query = parseDateInput(value, key);
1449
+ if (!query || query === "false") {
1450
+ return "";
1451
+ }
1452
+
1453
+ // return query as url encoded
1454
+ return encodeURIComponent(query);
1455
+ },
1456
+ "to-int-2": (value, key) => {
1457
+ const query = normalizeNumber(value);
1458
+ if (Number.isNaN(query)) {
1459
+ return key + " IS NULL";
1460
+ }
1461
+ return key + "=" + encodeURIComponent(Math.round(query * 100));
1462
+ },
1463
+ "to-int-3": (value, key) => {
1464
+ const query = normalizeNumber(value);
1465
+ if (Number.isNaN(query)) {
1466
+ return "";
1467
+ }
1468
+ return key + "=" + encodeURIComponent(Math.round(query * 1000));
1469
+ },
1470
+ "to-int-4": (value, key) => {
1471
+ const query = normalizeNumber(value);
1472
+ if (Number.isNaN(query)) {
1473
+ return "";
1474
+ }
1475
+ return key + "=" + encodeURIComponent(Math.round(query * 10000));
1476
+ },
1477
+ },
1478
+ });
1479
+
1480
+ if (self.getOption("formatter.marker.open")) {
1481
+ formatter.setMarker(
1482
+ self.getOption("formatter.marker.open"),
1483
+ self.getOption("formatter.marker.close"),
1484
+ );
1485
+ }
1486
+
1487
+ let queryPart = formatter.format(template);
1488
+ if (queryPart) {
1489
+ if (isFunction(wrapCallback)) {
1490
+ queryPart = wrapCallback(queryPart, mapping);
1491
+ }
1492
+ query.push(queryPart);
1493
+ }
1494
+ });
1495
+
1496
+ if (hasNoIdError) {
1497
+ reject(new Error("some or all filter elements have no id"));
1498
+ return;
1499
+ }
1500
+
1501
+ getGlobal().location.hash = createBracketedKeyValueHash(currentHash);
1502
+ resolve(query);
1503
+ });
1507
1504
  }
1508
1505
 
1509
1506
  /**
@@ -1512,41 +1509,41 @@ function collectSearchQueries() {
1512
1509
  * @return {null|Array|undefined|string}
1513
1510
  */
1514
1511
  function getControlValuesFromLabel(label) {
1515
- // finde das erste Kind-Element vom type input
1516
- // wenn es ein input-Element ist, dann @todo
1517
-
1518
- const foundControl = label.firstElementChild;
1519
-
1520
- if (foundControl) {
1521
- if (foundControl.tagName === "INPUT") {
1522
- if (foundControl.type === "checkbox") {
1523
- const checkedControls = label.querySelectorAll(
1524
- `${foundControl}:checked`,
1525
- );
1526
- const values = [];
1527
-
1528
- checkedControls.forEach((checkedControl) => {
1529
- values.push(checkedControl.value);
1530
- });
1531
-
1532
- return values;
1533
- } else if (foundControl.type === "radio") {
1534
- const checkedControl = label.querySelector(`${foundControl}:checked`);
1535
-
1536
- if (checkedControl) {
1537
- return checkedControl.value;
1538
- } else {
1539
- return null;
1540
- }
1541
- } else {
1542
- return foundControl.value;
1543
- }
1544
- } else {
1545
- return foundControl.value;
1546
- }
1547
- }
1548
-
1549
- return null;
1512
+ // finde das erste Kind-Element vom type input
1513
+ // wenn es ein input-Element ist, dann @todo
1514
+
1515
+ const foundControl = label.firstElementChild;
1516
+
1517
+ if (foundControl) {
1518
+ if (foundControl.tagName === "INPUT") {
1519
+ if (foundControl.type === "checkbox") {
1520
+ const checkedControls = label.querySelectorAll(
1521
+ `${foundControl}:checked`,
1522
+ );
1523
+ const values = [];
1524
+
1525
+ checkedControls.forEach((checkedControl) => {
1526
+ values.push(checkedControl.value);
1527
+ });
1528
+
1529
+ return values;
1530
+ } else if (foundControl.type === "radio") {
1531
+ const checkedControl = label.querySelector(`${foundControl}:checked`);
1532
+
1533
+ if (checkedControl) {
1534
+ return checkedControl.value;
1535
+ } else {
1536
+ return null;
1537
+ }
1538
+ } else {
1539
+ return foundControl.value;
1540
+ }
1541
+ } else {
1542
+ return foundControl.value;
1543
+ }
1544
+ }
1545
+
1546
+ return null;
1550
1547
  }
1551
1548
 
1552
1549
  /**
@@ -1554,60 +1551,60 @@ function getControlValuesFromLabel(label) {
1554
1551
  * @return {Promise<unknown>}
1555
1552
  */
1556
1553
  function initFromConfig() {
1557
- const host = findElementWithSelectorUpwards(this, "monster-host");
1558
-
1559
- if (!(isInstance(host, Host) && this.id)) {
1560
- return Promise.resolve();
1561
- }
1562
-
1563
- const configKey = getFilterConfigKey.call(this);
1564
-
1565
- return new Promise((resolve, reject) => {
1566
- host
1567
- .getConfig(configKey)
1568
- .then((config) => {
1569
- if ((config && isObject(config)) || isArray(config)) {
1570
- this[settingsSymbol].setOptions(config);
1571
- }
1572
- resolve();
1573
- })
1574
- .catch((error) => {
1575
- if (error === undefined) {
1576
- resolve();
1577
- return;
1578
- }
1579
-
1580
- // config not written
1581
- if (error?.message?.match(/is not defined/)) {
1582
- resolve();
1583
- return;
1584
- }
1585
-
1586
- addAttributeToken(
1587
- this,
1588
- ATTRIBUTE_ERRORMESSAGE,
1589
- error?.message || error,
1590
- );
1591
- reject(error);
1592
- });
1593
- });
1554
+ const host = findElementWithSelectorUpwards(this, "monster-host");
1555
+
1556
+ if (!(isInstance(host, Host) && this.id)) {
1557
+ return Promise.resolve();
1558
+ }
1559
+
1560
+ const configKey = getFilterConfigKey.call(this);
1561
+
1562
+ return new Promise((resolve, reject) => {
1563
+ host
1564
+ .getConfig(configKey)
1565
+ .then((config) => {
1566
+ if ((config && isObject(config)) || isArray(config)) {
1567
+ this[settingsSymbol].setOptions(config);
1568
+ }
1569
+ resolve();
1570
+ })
1571
+ .catch((error) => {
1572
+ if (error === undefined) {
1573
+ resolve();
1574
+ return;
1575
+ }
1576
+
1577
+ // config not written
1578
+ if (error?.message?.match(/is not defined/)) {
1579
+ resolve();
1580
+ return;
1581
+ }
1582
+
1583
+ addAttributeToken(
1584
+ this,
1585
+ ATTRIBUTE_ERRORMESSAGE,
1586
+ error?.message || error,
1587
+ );
1588
+ reject(error);
1589
+ });
1590
+ });
1594
1591
  }
1595
1592
 
1596
1593
  /**
1597
1594
  * @private
1598
1595
  */
1599
1596
  function updateConfig() {
1600
- const host = findElementWithSelectorUpwards(this, "monster-host");
1601
- if (!(host && this.id)) {
1602
- return;
1603
- }
1604
- const configKey = getFilterConfigKey.call(this);
1605
-
1606
- try {
1607
- host.setConfig(configKey, this[settingsSymbol].getOptions());
1608
- } catch (error) {
1609
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, error?.message || error);
1610
- }
1597
+ const host = findElementWithSelectorUpwards(this, "monster-host");
1598
+ if (!(host && this.id)) {
1599
+ return;
1600
+ }
1601
+ const configKey = getFilterConfigKey.call(this);
1602
+
1603
+ try {
1604
+ host.setConfig(configKey, this[settingsSymbol].getOptions());
1605
+ } catch (error) {
1606
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, error?.message || error);
1607
+ }
1611
1608
  }
1612
1609
 
1613
1610
  /**
@@ -1615,8 +1612,8 @@ function updateConfig() {
1615
1612
  * @return {string}
1616
1613
  */
1617
1614
  function getTemplate() {
1618
- // language=HTML
1619
- return `
1615
+ // language=HTML
1616
+ return `
1620
1617
  <div data-monster-role="control" part="control">
1621
1618
  <div data-monster-role="container">
1622
1619
  <div data-monster-role="layout">