@schukai/monster 3.54.0 → 3.55.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/package.json +1 -1
- package/source/components/datatable/datasource/rest.mjs +93 -57
- package/source/components/datatable/datatable/header.mjs +8 -0
- package/source/components/datatable/datatable.mjs +88 -44
- package/source/components/datatable/embedded-pagination.mjs +24 -43
- package/source/components/datatable/filter/util.mjs +138 -0
- package/source/components/datatable/filter.mjs +418 -174
- package/source/components/datatable/pagination.mjs +26 -2
- package/source/components/datatable/status.mjs +226 -0
- package/source/components/datatable/style/datatable.pcss +1 -0
- package/source/components/datatable/style/embedded-pagination.pcss +59 -2
- package/source/components/datatable/style/filter.pcss +4 -0
- package/source/components/datatable/style/pagination.pcss +28 -4
- package/source/components/datatable/style/status.pcss +42 -0
- package/source/components/datatable/stylesheet/column-bar.mjs +15 -9
- package/source/components/datatable/stylesheet/dataset.mjs +14 -8
- package/source/components/datatable/stylesheet/datasource.mjs +14 -8
- package/source/components/datatable/stylesheet/datatable.mjs +15 -9
- package/source/components/datatable/stylesheet/embedded-pagination.mjs +14 -8
- package/source/components/datatable/stylesheet/filter-button.mjs +15 -9
- package/source/components/datatable/stylesheet/filter-controls-defaults.mjs +14 -8
- package/source/components/datatable/stylesheet/filter-date-range.mjs +14 -8
- package/source/components/datatable/stylesheet/filter-range.mjs +14 -8
- package/source/components/datatable/stylesheet/filter.mjs +15 -9
- package/source/components/datatable/stylesheet/pagination.mjs +15 -9
- package/source/components/datatable/stylesheet/select-filter.mjs +14 -8
- package/source/components/datatable/stylesheet/status.mjs +33 -0
- package/source/components/form/action-button.mjs +3 -1
- package/source/components/form/api-button.mjs +1 -1
- package/source/components/form/button-bar.mjs +1 -1
- package/source/components/form/button.mjs +1 -1
- package/source/components/form/confirm-button.mjs +3 -1
- package/source/components/form/context-error.mjs +272 -0
- package/source/components/form/context-help.mjs +7 -5
- package/source/components/form/form.mjs +4 -2
- package/source/components/form/message-state-button.mjs +4 -2
- package/source/components/form/popper-button.mjs +9 -4
- package/source/components/form/popper.mjs +11 -3
- package/source/components/form/reload.mjs +1 -1
- package/source/components/form/select.mjs +3 -3
- package/source/components/form/shadow-reload.mjs +1 -1
- package/source/components/form/state-button.mjs +4 -1
- package/source/components/form/style/context-error.pcss +32 -0
- package/source/components/form/style/context-help.pcss +22 -5
- package/source/components/form/stylesheet/action-button.mjs +14 -8
- package/source/components/form/stylesheet/api-button.mjs +14 -8
- package/source/components/form/stylesheet/button-bar.mjs +14 -8
- package/source/components/form/stylesheet/button.mjs +14 -8
- package/source/components/form/stylesheet/confirm-button.mjs +14 -8
- package/source/components/form/stylesheet/context-error.mjs +33 -0
- package/source/components/form/stylesheet/context-help.mjs +15 -9
- package/source/components/form/stylesheet/form.mjs +14 -8
- package/source/components/form/stylesheet/message-state-button.mjs +14 -8
- package/source/components/form/stylesheet/popper-button.mjs +14 -8
- package/source/components/form/stylesheet/popper.mjs +14 -8
- package/source/components/form/stylesheet/select.mjs +15 -9
- package/source/components/form/stylesheet/state-button.mjs +14 -8
- package/source/components/form/stylesheet/tabs.mjs +15 -9
- package/source/components/form/stylesheet/tree-select.mjs +14 -8
- package/source/components/form/tabs.mjs +53 -7
- package/source/components/form/template.mjs +1 -1
- package/source/components/form/tree-select.mjs +1 -1
- package/source/components/host/collapse.mjs +20 -5
- package/source/components/host/config-manager.mjs +41 -2
- package/source/components/host/host.mjs +14 -0
- package/source/components/host/stylesheet/call-button.mjs +15 -9
- package/source/components/host/stylesheet/collapse.mjs +14 -8
- package/source/components/host/stylesheet/config-manager.mjs +14 -8
- package/source/components/host/stylesheet/details.mjs +14 -8
- package/source/components/host/stylesheet/host.mjs +14 -8
- package/source/components/host/stylesheet/overlay.mjs +15 -9
- package/source/components/host/stylesheet/toggle-button.mjs +15 -9
- package/source/components/host/stylesheet/viewer.mjs +14 -8
- package/source/components/host/util.mjs +6 -1
- package/source/components/notify/stylesheet/message.mjs +15 -9
- package/source/components/notify/stylesheet/notify.mjs +14 -8
- package/source/components/state/stylesheet/log.mjs +14 -8
- package/source/components/state/stylesheet/state.mjs +14 -8
- package/source/components/stylesheet/badge.mjs +14 -8
- package/source/components/stylesheet/border.mjs +14 -8
- package/source/components/stylesheet/button.mjs +14 -8
- package/source/components/stylesheet/card.mjs +14 -8
- package/source/components/stylesheet/color.mjs +14 -8
- package/source/components/stylesheet/common.mjs +14 -8
- package/source/components/stylesheet/control.mjs +14 -8
- package/source/components/stylesheet/data-grid.mjs +14 -8
- package/source/components/stylesheet/display.mjs +14 -8
- package/source/components/stylesheet/floating-ui.mjs +14 -8
- package/source/components/stylesheet/form.mjs +14 -8
- package/source/components/stylesheet/host.mjs +14 -8
- package/source/components/stylesheet/icons.mjs +15 -9
- package/source/components/stylesheet/link.mjs +14 -8
- package/source/components/stylesheet/normalize.mjs +14 -8
- package/source/components/stylesheet/popper.mjs +14 -8
- package/source/components/stylesheet/property.mjs +14 -8
- package/source/components/stylesheet/ripple.mjs +14 -8
- package/source/components/stylesheet/skeleton.mjs +14 -8
- package/source/components/stylesheet/space.mjs +14 -8
- package/source/components/stylesheet/spinner.mjs +14 -8
- package/source/components/stylesheet/table.mjs +14 -8
- package/source/components/stylesheet/theme.mjs +14 -8
- package/source/components/stylesheet/typography.mjs +14 -8
- package/source/components/tree-menu/stylesheet/tree-menu.mjs +14 -8
- package/source/data/transformer.mjs +38 -43
- package/source/dom/attributes.mjs +5 -5
- package/source/dom/customelement.mjs +1 -1
- package/source/dom/updater.mjs +14 -5
- package/source/dom/util.mjs +42 -0
- package/source/i18n/providers/embed.mjs +3 -3
- package/source/monster.mjs +5 -0
- package/source/text/formatter.mjs +2 -2
- package/source/types/noderecursiveiterator.mjs +9 -7
- package/source/types/observer.mjs +1 -1
- package/source/types/version.mjs +1 -1
- package/source/util/sleep.mjs +17 -0
- package/test/cases/components/form/button.mjs +2 -1
- package/test/cases/components/form/select.mjs +1 -1
- package/test/cases/components/form/tree-select.mjs +1 -1
- package/test/cases/data/transformer.mjs +2 -2
- package/test/cases/dom/updater.mjs +67 -46
- package/test/cases/monster.mjs +1 -1
- package/test/web/test.html +2 -2
- package/test/web/tests.js +18 -13
|
@@ -4,7 +4,11 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { instanceSymbol } from "../../constants.mjs";
|
|
7
|
-
import {
|
|
7
|
+
import { findTargetElementFromEvent } from "../../dom/events.mjs";
|
|
8
|
+
import {
|
|
9
|
+
findElementWithIdUpwards,
|
|
10
|
+
findElementWithSelectorUpwards,
|
|
11
|
+
} from "../../dom/util.mjs";
|
|
8
12
|
import {
|
|
9
13
|
assembleMethodSymbol,
|
|
10
14
|
CustomElement,
|
|
@@ -23,11 +27,20 @@ import { ATTRIBUTE_ERRORMESSAGE } from "../../dom/constants.mjs";
|
|
|
23
27
|
import "../form/message-state-button.mjs";
|
|
24
28
|
import { Formatter } from "../../text/formatter.mjs";
|
|
25
29
|
import { generateRangeComparisonExpression } from "../../text/util.mjs";
|
|
26
|
-
|
|
30
|
+
|
|
27
31
|
import {
|
|
28
32
|
parseBracketedKeyValueHash,
|
|
29
33
|
createBracketedKeyValueHash,
|
|
30
34
|
} from "../../text/bracketed-key-value-hash.mjs";
|
|
35
|
+
import { ThemeStyleSheet } from "../stylesheet/theme.mjs";
|
|
36
|
+
import { SpaceStyleSheet } from "../stylesheet/space.mjs";
|
|
37
|
+
import { FormStyleSheet } from "../stylesheet/form.mjs";
|
|
38
|
+
|
|
39
|
+
import {
|
|
40
|
+
getStoredFilterConfigKey,
|
|
41
|
+
getFilterConfigKey,
|
|
42
|
+
parseDateInput,
|
|
43
|
+
} from "./filter/util.mjs";
|
|
31
44
|
|
|
32
45
|
import "./filter/select.mjs";
|
|
33
46
|
|
|
@@ -51,12 +64,32 @@ const searchButtonElementSymbol = Symbol("searchButtonElement");
|
|
|
51
64
|
*/
|
|
52
65
|
const resetButtonElementSymbol = Symbol("resetButtonElement");
|
|
53
66
|
|
|
67
|
+
/**
|
|
68
|
+
* @private
|
|
69
|
+
* @type {symbol}
|
|
70
|
+
*/
|
|
71
|
+
const saveButtonElementSymbol = Symbol("saveButtonElement");
|
|
72
|
+
|
|
54
73
|
/**
|
|
55
74
|
* @private
|
|
56
75
|
* @type {symbol}
|
|
57
76
|
*/
|
|
58
77
|
const filterControlElementSymbol = Symbol("filterControlElement");
|
|
59
78
|
|
|
79
|
+
/**
|
|
80
|
+
* @private
|
|
81
|
+
* @type {symbol}
|
|
82
|
+
*/
|
|
83
|
+
const filterSaveActionButtonElementSymbol = Symbol(
|
|
84
|
+
"filterSaveActionButtonElement",
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @private
|
|
89
|
+
* @type {symbol}
|
|
90
|
+
*/
|
|
91
|
+
const filterTabElementSymbol = Symbol("filterTabElement");
|
|
92
|
+
|
|
60
93
|
/**
|
|
61
94
|
* @private
|
|
62
95
|
* @type {symbol}
|
|
@@ -132,10 +165,13 @@ class Filter extends CustomElement {
|
|
|
132
165
|
* @returns {Monster.Components.Datatable.Filter}
|
|
133
166
|
*/
|
|
134
167
|
showFailureMessage(message) {
|
|
135
|
-
this[searchButtonElementSymbol].setState(
|
|
168
|
+
this[searchButtonElementSymbol].setState(
|
|
169
|
+
"failed",
|
|
170
|
+
this.getOption("timeouts.message", 4000),
|
|
171
|
+
);
|
|
136
172
|
this[searchButtonElementSymbol]
|
|
137
|
-
.setMessage(
|
|
138
|
-
.showMessage(
|
|
173
|
+
.setMessage(message.toString())
|
|
174
|
+
.showMessage(this.getOption("timeouts.message", 4000));
|
|
139
175
|
return this;
|
|
140
176
|
}
|
|
141
177
|
|
|
@@ -154,7 +190,10 @@ class Filter extends CustomElement {
|
|
|
154
190
|
* @returns {Monster.Components.Datatable.Filter}
|
|
155
191
|
*/
|
|
156
192
|
showSuccess() {
|
|
157
|
-
this[searchButtonElementSymbol].setState(
|
|
193
|
+
this[searchButtonElementSymbol].setState(
|
|
194
|
+
"successful",
|
|
195
|
+
this.getOption("timeouts.message", 4000),
|
|
196
|
+
);
|
|
158
197
|
return this;
|
|
159
198
|
}
|
|
160
199
|
|
|
@@ -175,17 +214,34 @@ class Filter extends CustomElement {
|
|
|
175
214
|
* @property {string} defaultQuery Default query
|
|
176
215
|
*/
|
|
177
216
|
get defaults() {
|
|
178
|
-
|
|
217
|
+
return Object.assign({}, super.defaults, {
|
|
179
218
|
templates: {
|
|
180
219
|
main: getTemplate(),
|
|
181
220
|
},
|
|
221
|
+
|
|
182
222
|
labels: {
|
|
183
223
|
search: "Search",
|
|
184
224
|
reset: "Reset",
|
|
225
|
+
save: "Save",
|
|
226
|
+
"filter-name": "Filter name",
|
|
185
227
|
"empty-query-and-no-default": "Please select a filter",
|
|
186
228
|
"query-not-changed": "The query has not changed",
|
|
187
229
|
},
|
|
188
230
|
|
|
231
|
+
templateMapping: {
|
|
232
|
+
"filter-save-label": null,
|
|
233
|
+
"filter-name-label": name,
|
|
234
|
+
},
|
|
235
|
+
|
|
236
|
+
storedConfig: {
|
|
237
|
+
enabled: true,
|
|
238
|
+
selector: "",
|
|
239
|
+
},
|
|
240
|
+
|
|
241
|
+
timeouts: {
|
|
242
|
+
message: 4000,
|
|
243
|
+
},
|
|
244
|
+
|
|
189
245
|
queries: {
|
|
190
246
|
wrap: (value, definition) => {
|
|
191
247
|
return value;
|
|
@@ -201,8 +257,6 @@ class Filter extends CustomElement {
|
|
|
201
257
|
query: "",
|
|
202
258
|
defaultQuery: "",
|
|
203
259
|
});
|
|
204
|
-
|
|
205
|
-
return obj;
|
|
206
260
|
}
|
|
207
261
|
|
|
208
262
|
/**
|
|
@@ -217,6 +271,15 @@ class Filter extends CustomElement {
|
|
|
217
271
|
* @return {FilterButton}
|
|
218
272
|
*/
|
|
219
273
|
[assembleMethodSymbol]() {
|
|
274
|
+
this.setOption(
|
|
275
|
+
"templateMapping.filter-save-label",
|
|
276
|
+
this.getOption("labels.save"),
|
|
277
|
+
);
|
|
278
|
+
this.setOption(
|
|
279
|
+
"templateMapping.filter-name-label",
|
|
280
|
+
this.getOption("labels.filter-name"),
|
|
281
|
+
);
|
|
282
|
+
|
|
220
283
|
super[assembleMethodSymbol]();
|
|
221
284
|
|
|
222
285
|
initControlReferences.call(this);
|
|
@@ -226,9 +289,10 @@ class Filter extends CustomElement {
|
|
|
226
289
|
.call(this)
|
|
227
290
|
.then(() => {
|
|
228
291
|
initFilter.call(this);
|
|
292
|
+
updateFilterTabs.call(this);
|
|
229
293
|
})
|
|
230
294
|
.catch((error) => {
|
|
231
|
-
|
|
295
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, error?.message);
|
|
232
296
|
});
|
|
233
297
|
}
|
|
234
298
|
|
|
@@ -260,7 +324,7 @@ class Filter extends CustomElement {
|
|
|
260
324
|
* @return {Array<CSSStyleSheet>}
|
|
261
325
|
*/
|
|
262
326
|
static getCSSStyleSheet() {
|
|
263
|
-
return [FilterStyleSheet];
|
|
327
|
+
return [FilterStyleSheet, FormStyleSheet, ThemeStyleSheet, SpaceStyleSheet];
|
|
264
328
|
}
|
|
265
329
|
}
|
|
266
330
|
|
|
@@ -285,6 +349,20 @@ function initControlReferences() {
|
|
|
285
349
|
this[resetButtonElementSymbol] = this.shadowRoot.querySelector(
|
|
286
350
|
"[data-monster-role=reset-button]",
|
|
287
351
|
);
|
|
352
|
+
|
|
353
|
+
this[saveButtonElementSymbol] = this.shadowRoot.querySelector(
|
|
354
|
+
"[data-monster-role=save-button]",
|
|
355
|
+
);
|
|
356
|
+
|
|
357
|
+
this[filterSaveActionButtonElementSymbol] = this.shadowRoot.querySelector(
|
|
358
|
+
"[data-monster-role=save-action-button]",
|
|
359
|
+
);
|
|
360
|
+
|
|
361
|
+
this[filterTabElementSymbol] = findElementWithSelectorUpwards(
|
|
362
|
+
this,
|
|
363
|
+
this.getOption("storedConfig.selector", ""),
|
|
364
|
+
);
|
|
365
|
+
|
|
288
366
|
return this;
|
|
289
367
|
}
|
|
290
368
|
|
|
@@ -329,7 +407,8 @@ function initFilter() {
|
|
|
329
407
|
const v = escapeAttributeValue(valuesFromHash[element.id]);
|
|
330
408
|
const searchInput = element.firstElementChild;
|
|
331
409
|
try {
|
|
332
|
-
searchInput.value = valuesFromHash[element.id];
|
|
410
|
+
// searchInput.value = valuesFromHash[element.id];
|
|
411
|
+
searchInput.value = v; //valuesFromHash[element.id];
|
|
333
412
|
} catch (error) {}
|
|
334
413
|
}
|
|
335
414
|
|
|
@@ -349,6 +428,7 @@ function initFilter() {
|
|
|
349
428
|
"options",
|
|
350
429
|
this[settingsSymbol].getOptions(),
|
|
351
430
|
);
|
|
431
|
+
|
|
352
432
|
setTimeout(() => {
|
|
353
433
|
this[filterSelectElementSymbol].value = this[settingsSymbol].getSelected();
|
|
354
434
|
}, 10);
|
|
@@ -360,6 +440,11 @@ function initFilter() {
|
|
|
360
440
|
* @returns {*}
|
|
361
441
|
*/
|
|
362
442
|
function escapeAttributeValue(input) {
|
|
443
|
+
if (input === undefined || input === null) {
|
|
444
|
+
debugger;
|
|
445
|
+
return input;
|
|
446
|
+
}
|
|
447
|
+
|
|
363
448
|
return input
|
|
364
449
|
.replace(/&/g, "&")
|
|
365
450
|
.replace(/"/g, """)
|
|
@@ -374,10 +459,9 @@ function escapeAttributeValue(input) {
|
|
|
374
459
|
* @returns {boolean}
|
|
375
460
|
*/
|
|
376
461
|
function getVisibilityFromSlotAttribute(element) {
|
|
377
|
-
return
|
|
378
|
-
element.getAttribute("slot") === "hidden"
|
|
379
|
-
|
|
380
|
-
: true;
|
|
462
|
+
return !(
|
|
463
|
+
element.hasAttribute("slot") && element.getAttribute("slot") === "hidden"
|
|
464
|
+
);
|
|
381
465
|
}
|
|
382
466
|
|
|
383
467
|
/**
|
|
@@ -405,7 +489,7 @@ function initEventHandler() {
|
|
|
405
489
|
if (self[filterSelectElementSymbol]) {
|
|
406
490
|
self[filterSelectElementSymbol].addEventListener(
|
|
407
491
|
"monster-selection-cleared",
|
|
408
|
-
function (
|
|
492
|
+
function () {
|
|
409
493
|
const settings = self[settingsSymbol].getOptions();
|
|
410
494
|
|
|
411
495
|
for (const setting of settings) {
|
|
@@ -443,8 +527,109 @@ function initEventHandler() {
|
|
|
443
527
|
);
|
|
444
528
|
}
|
|
445
529
|
|
|
530
|
+
if (self[filterSaveActionButtonElementSymbol]) {
|
|
531
|
+
self[filterSaveActionButtonElementSymbol].setOption(
|
|
532
|
+
"actions.click",
|
|
533
|
+
function (event) {
|
|
534
|
+
const button = findTargetElementFromEvent(
|
|
535
|
+
event,
|
|
536
|
+
"data-monster-role",
|
|
537
|
+
"save-action-button",
|
|
538
|
+
);
|
|
539
|
+
const form = button.closest("[data-monster-role=form]");
|
|
540
|
+
|
|
541
|
+
if (!form) {
|
|
542
|
+
button.setState("failed", self.getOption("timeouts.message", 4000));
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
const input = form.querySelector("input[name=filter-name]");
|
|
547
|
+
if (!input) {
|
|
548
|
+
button.setState("failed", self.getOption("timeouts.message", 4000));
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
const name = input.value;
|
|
553
|
+
if (!name) {
|
|
554
|
+
button.setState("failed", self.getOption("timeouts.message", 4000));
|
|
555
|
+
button.setMessage("Please enter a name").showMessage();
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
doSearch
|
|
560
|
+
.call(self, { showEffect: false })
|
|
561
|
+
.then(() => {
|
|
562
|
+
const configKey = getStoredFilterConfigKey.call(self);
|
|
563
|
+
const host = getDocument().querySelector("monster-host");
|
|
564
|
+
if (!host) {
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
const query = self.getOption("query");
|
|
569
|
+
if (!query) {
|
|
570
|
+
button.setState(
|
|
571
|
+
"failed",
|
|
572
|
+
self.getOption(
|
|
573
|
+
"timeouts.message",
|
|
574
|
+
self.getOption("timeouts.message", 4000),
|
|
575
|
+
),
|
|
576
|
+
);
|
|
577
|
+
button
|
|
578
|
+
.setMessage("No query found")
|
|
579
|
+
.showMessage(self.getOption("timeouts.message", 4000));
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
host
|
|
584
|
+
.hasConfig(configKey)
|
|
585
|
+
.then((hasConfig) => {
|
|
586
|
+
return new Promise((resolve, reject) => {
|
|
587
|
+
if (hasConfig) {
|
|
588
|
+
host.getConfig(configKey).then(resolve).catch(reject);
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
return resolve({});
|
|
592
|
+
});
|
|
593
|
+
})
|
|
594
|
+
.then((config) => {
|
|
595
|
+
config[name] = query;
|
|
596
|
+
return host.setConfig(configKey, {
|
|
597
|
+
...config,
|
|
598
|
+
});
|
|
599
|
+
})
|
|
600
|
+
.then(() => {
|
|
601
|
+
button.setState(
|
|
602
|
+
"successful",
|
|
603
|
+
self.getOption("timeouts.message", 4000),
|
|
604
|
+
);
|
|
605
|
+
updateFilterTabs.call(self);
|
|
606
|
+
})
|
|
607
|
+
.catch((error) => {
|
|
608
|
+
button.setState(
|
|
609
|
+
"failed",
|
|
610
|
+
self.getOption("timeouts.message", 4000),
|
|
611
|
+
);
|
|
612
|
+
button
|
|
613
|
+
.setMessage(error.message)
|
|
614
|
+
.showMessage(self.getOption("timeouts.message", 4000));
|
|
615
|
+
});
|
|
616
|
+
})
|
|
617
|
+
.catch((error) => {
|
|
618
|
+
button.setState("failed", self.getOption("timeouts.message", 4000));
|
|
619
|
+
const msg = error.message || error;
|
|
620
|
+
button
|
|
621
|
+
.setMessage(msg)
|
|
622
|
+
.showMessage(self.getOption("timeouts.message", 4000));
|
|
623
|
+
});
|
|
624
|
+
},
|
|
625
|
+
);
|
|
626
|
+
}
|
|
627
|
+
|
|
446
628
|
self[searchButtonElementSymbol].setOption("actions.click", () => {
|
|
447
|
-
doSearch
|
|
629
|
+
doSearch
|
|
630
|
+
.call(self)
|
|
631
|
+
.then(() => {})
|
|
632
|
+
.catch((error) => {});
|
|
448
633
|
});
|
|
449
634
|
|
|
450
635
|
// the reset button should reset the filter and the search query
|
|
@@ -492,46 +677,192 @@ function initEventHandler() {
|
|
|
492
677
|
doSearch.call(self, { showEffect: false });
|
|
493
678
|
}
|
|
494
679
|
});
|
|
680
|
+
|
|
681
|
+
// tabs
|
|
682
|
+
const element = this[filterTabElementSymbol];
|
|
683
|
+
if (element) {
|
|
684
|
+
initTabEvents.call(this);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
function initTabEvents() {
|
|
689
|
+
this[filterTabElementSymbol].addEventListener(
|
|
690
|
+
"monster-tab-changed",
|
|
691
|
+
(event) => {
|
|
692
|
+
const query = event?.detail?.data?.["data-monster-query"];
|
|
693
|
+
this.setOption("query", query);
|
|
694
|
+
},
|
|
695
|
+
);
|
|
696
|
+
|
|
697
|
+
this[filterTabElementSymbol].addEventListener(
|
|
698
|
+
"monster-tab-remove",
|
|
699
|
+
(event) => {
|
|
700
|
+
const labels = [];
|
|
701
|
+
const buttons = this[filterTabElementSymbol].getOption("buttons");
|
|
702
|
+
|
|
703
|
+
const keys = ["popper", "standard"];
|
|
704
|
+
for (let i = 0; i < keys.length; i++) {
|
|
705
|
+
const key = keys[i];
|
|
706
|
+
|
|
707
|
+
for (const button of buttons[key]) {
|
|
708
|
+
if (button.label !== event.detail.label) {
|
|
709
|
+
labels.push(button.label);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
const document = getDocument();
|
|
715
|
+
const host = document.querySelector("monster-host");
|
|
716
|
+
if (!(host && this.id)) {
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
const configKey = getStoredFilterConfigKey.call(this);
|
|
721
|
+
host
|
|
722
|
+
.hasConfig(configKey)
|
|
723
|
+
.then((hasConfig) => {
|
|
724
|
+
if (!hasConfig) {
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
return host.getConfig(configKey);
|
|
729
|
+
})
|
|
730
|
+
.then((config) => {
|
|
731
|
+
for (const [name, query] of Object.entries(config)) {
|
|
732
|
+
if (labels.includes(name)) {
|
|
733
|
+
continue;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
delete config[name];
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
return host.setConfig(configKey, {
|
|
740
|
+
...config,
|
|
741
|
+
});
|
|
742
|
+
});
|
|
743
|
+
},
|
|
744
|
+
);
|
|
495
745
|
}
|
|
496
746
|
|
|
497
747
|
/**
|
|
498
748
|
* @private
|
|
499
749
|
*/
|
|
500
|
-
function
|
|
750
|
+
function updateFilterTabs() {
|
|
751
|
+
const element = this[filterTabElementSymbol];
|
|
752
|
+
if (!element) {
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
const document = getDocument();
|
|
757
|
+
const host = document.querySelector("monster-host");
|
|
758
|
+
if (!(host && this.id)) {
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
const configKey = getStoredFilterConfigKey.call(this);
|
|
763
|
+
host
|
|
764
|
+
.hasConfig(configKey)
|
|
765
|
+
.then((hasConfig) => {
|
|
766
|
+
if (!hasConfig) {
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
return host.getConfig(configKey);
|
|
771
|
+
})
|
|
772
|
+
.then((config) => {
|
|
773
|
+
for (const [name, query] of Object.entries(config)) {
|
|
774
|
+
const found = element.querySelector(
|
|
775
|
+
`[data-monster-button-label="${name}"]`,
|
|
776
|
+
);
|
|
777
|
+
if (found) {
|
|
778
|
+
continue;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
if (query === undefined || query === null) {
|
|
782
|
+
continue;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
const escapedQuery = escapeAttributeValue(query);
|
|
786
|
+
|
|
787
|
+
element.insertAdjacentHTML(
|
|
788
|
+
"beforeend",
|
|
789
|
+
`
|
|
790
|
+
<div data-monster-button-label="${name}"
|
|
791
|
+
data-monster-removable="true"
|
|
792
|
+
data-monster-query="${escapedQuery}" data-monster-role="filter-tab" >
|
|
793
|
+
</div>`,
|
|
794
|
+
);
|
|
795
|
+
}
|
|
796
|
+
})
|
|
797
|
+
.catch((error) => {
|
|
798
|
+
if (error instanceof Error) {
|
|
799
|
+
addAttributeToken(
|
|
800
|
+
this,
|
|
801
|
+
ATTRIBUTE_ERRORMESSAGE,
|
|
802
|
+
error.message + " " + error.stack,
|
|
803
|
+
);
|
|
804
|
+
} else {
|
|
805
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, error + "");
|
|
806
|
+
}
|
|
807
|
+
});
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
/**
|
|
811
|
+
* @private
|
|
812
|
+
* @param showEffect
|
|
813
|
+
* @returns {Promise<*>}
|
|
814
|
+
*/
|
|
815
|
+
function doSearch({ showEffect } = { showEffect: true }) {;
|
|
816
|
+
|
|
501
817
|
this.resetFailureMessage();
|
|
502
818
|
|
|
503
819
|
if (showEffect) {
|
|
504
|
-
this[searchButtonElementSymbol].setState(
|
|
820
|
+
this[searchButtonElementSymbol].setState(
|
|
821
|
+
"activity",
|
|
822
|
+
this.getOption("timeouts.message", 4000),
|
|
823
|
+
);
|
|
505
824
|
}
|
|
506
825
|
|
|
507
|
-
collectSearchQueries
|
|
826
|
+
return collectSearchQueries
|
|
508
827
|
.call(this)
|
|
509
828
|
.then((query) => {
|
|
510
829
|
const buildQuery = buildSearchQuery.call(this, query);
|
|
511
830
|
if (buildQuery === "" && !this.getOption("defaultQuery")) {
|
|
512
|
-
this
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
.
|
|
516
|
-
|
|
831
|
+
const msg = this.getOption("labels.empty-query-and-no-default");
|
|
832
|
+
|
|
833
|
+
if (showEffect) {
|
|
834
|
+
this[searchButtonElementSymbol].removeState();
|
|
835
|
+
this[searchButtonElementSymbol]
|
|
836
|
+
.setMessage(msg)
|
|
837
|
+
.showMessage(this.getOption("timeouts.message", 4000));
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
throw new Error(msg);
|
|
517
841
|
}
|
|
518
842
|
|
|
519
843
|
if (buildQuery === this.getOption("query")) {
|
|
520
|
-
this
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
.
|
|
524
|
-
|
|
844
|
+
const msg = this.getOption("labels.query-not-changed");
|
|
845
|
+
|
|
846
|
+
if (showEffect) {
|
|
847
|
+
this[searchButtonElementSymbol].removeState();
|
|
848
|
+
this[searchButtonElementSymbol]
|
|
849
|
+
.setMessage(msg)
|
|
850
|
+
.showMessage(this.getOption("timeouts.message", 4000));
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
throw new Error(msg);
|
|
525
854
|
}
|
|
526
855
|
|
|
527
856
|
if (showEffect) {
|
|
528
|
-
this[searchButtonElementSymbol].setState(
|
|
857
|
+
this[searchButtonElementSymbol].setState(
|
|
858
|
+
"activity",
|
|
859
|
+
this.getOption("timeouts.message", 4000),
|
|
860
|
+
);
|
|
529
861
|
}
|
|
530
862
|
|
|
531
863
|
this.setOption("query", buildSearchQuery.call(this, query));
|
|
532
864
|
})
|
|
533
865
|
.catch((error) => {
|
|
534
|
-
console.error(error);
|
|
535
866
|
if (error instanceof Error) {
|
|
536
867
|
addAttributeToken(
|
|
537
868
|
this,
|
|
@@ -542,15 +873,22 @@ function doSearch({ showEffect } = { showEffect: true }) {
|
|
|
542
873
|
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, String(error));
|
|
543
874
|
}
|
|
544
875
|
|
|
545
|
-
|
|
546
|
-
|
|
876
|
+
if (showEffect) {
|
|
877
|
+
this[searchButtonElementSymbol].setState(
|
|
878
|
+
"failed",
|
|
879
|
+
this.getOption("timeouts.message", 4000),
|
|
880
|
+
);
|
|
881
|
+
this[searchButtonElementSymbol].setMessage(error.message).showMessage();
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
return Promise.reject(error);
|
|
547
885
|
});
|
|
548
886
|
}
|
|
549
887
|
|
|
550
888
|
/**
|
|
551
889
|
* @private
|
|
552
890
|
* @param queries
|
|
553
|
-
* @returns {string
|
|
891
|
+
* @returns {*|string}
|
|
554
892
|
*/
|
|
555
893
|
function buildSearchQuery(queries) {
|
|
556
894
|
if (!isArray(queries) || queries.length === 0) {
|
|
@@ -581,6 +919,8 @@ function collectSearchQueries() {
|
|
|
581
919
|
const query = [];
|
|
582
920
|
const wrapCallback = this.getOption("queries.wrap");
|
|
583
921
|
|
|
922
|
+
let hasNoIdError = false;
|
|
923
|
+
|
|
584
924
|
getSlottedElements
|
|
585
925
|
.call(this, "label[data-monster-label]")
|
|
586
926
|
.forEach((element) => {
|
|
@@ -591,7 +931,7 @@ function collectSearchQueries() {
|
|
|
591
931
|
|
|
592
932
|
const id = element.id;
|
|
593
933
|
if (!id) {
|
|
594
|
-
|
|
934
|
+
hasNoIdError = true;
|
|
595
935
|
return;
|
|
596
936
|
}
|
|
597
937
|
|
|
@@ -659,132 +999,16 @@ function collectSearchQueries() {
|
|
|
659
999
|
}
|
|
660
1000
|
});
|
|
661
1001
|
|
|
1002
|
+
if (hasNoIdError) {
|
|
1003
|
+
reject(new Error("some or all filter elements have no id"));
|
|
1004
|
+
return;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
662
1007
|
getGlobal().location.hash = createBracketedKeyValueHash(currentHash);
|
|
663
1008
|
resolve(query);
|
|
664
1009
|
});
|
|
665
1010
|
}
|
|
666
1011
|
|
|
667
|
-
/**
|
|
668
|
-
* @private
|
|
669
|
-
* @param {String} str
|
|
670
|
-
* @param {String} field
|
|
671
|
-
* @returns {String}
|
|
672
|
-
* @throws {Error} if no field is defined
|
|
673
|
-
*/
|
|
674
|
-
function parseDateInput(str, field) {
|
|
675
|
-
if (!str) {
|
|
676
|
-
return "";
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
if (!field) {
|
|
680
|
-
throw new Error("no field is defined");
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
// Define the supported formats
|
|
684
|
-
//let formats = ['DD-MM-YYYY', 'MM-DD-YYYY', 'YYYY-MM-DD', 'YYYY/MM/DD', 'DD.MM.YYYY'];
|
|
685
|
-
const formats = ["YYYY-MM-DD"];
|
|
686
|
-
// Determine the current date format of the localization
|
|
687
|
-
const currentDateFormat = new Intl.DateTimeFormat()
|
|
688
|
-
.format(new Date())
|
|
689
|
-
.replace(/\d/g, "D");
|
|
690
|
-
// formats.push(currentDateFormat);
|
|
691
|
-
|
|
692
|
-
// Run through the supported formats and try to parse the date
|
|
693
|
-
for (let i = 0; i < formats.length; i++) {
|
|
694
|
-
const format = formats[i];
|
|
695
|
-
// Replace the corresponding placeholders in the format string with regular expressions
|
|
696
|
-
|
|
697
|
-
try {
|
|
698
|
-
const pattern = format
|
|
699
|
-
.replace("DD", "\\d{2}")
|
|
700
|
-
.replace("MM", "\\d{2}")
|
|
701
|
-
.replace("YYYY", "\\d{4}");
|
|
702
|
-
const rangePattern =
|
|
703
|
-
"(?<from>" + pattern + ")\\s*-\\s*(?<to>" + pattern + ")";
|
|
704
|
-
|
|
705
|
-
const rangeRegex = new RegExp("^" + rangePattern + "$", "g");
|
|
706
|
-
|
|
707
|
-
if (rangeRegex.test(str)) {
|
|
708
|
-
rangeRegex.lastIndex = 0;
|
|
709
|
-
|
|
710
|
-
const rangeResult = rangeRegex.exec(str);
|
|
711
|
-
|
|
712
|
-
if (!rangeResult) {
|
|
713
|
-
continue;
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
const from = rangeResult?.groups?.from;
|
|
717
|
-
const to = rangeResult?.groups?.to;
|
|
718
|
-
|
|
719
|
-
if (from && to) {
|
|
720
|
-
return (
|
|
721
|
-
"(" +
|
|
722
|
-
field +
|
|
723
|
-
">='" +
|
|
724
|
-
from +
|
|
725
|
-
" 00:00:00' AND " +
|
|
726
|
-
field +
|
|
727
|
-
"<='" +
|
|
728
|
-
to +
|
|
729
|
-
" 23:59:59')"
|
|
730
|
-
);
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
if (from) {
|
|
734
|
-
return "(" + field + ">='" + from + " 00:00:00')";
|
|
735
|
-
} else if (to) {
|
|
736
|
-
return "(" + field + "<='" + to + "' 23:59:59')";
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
return "false";
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
const prefix = str.substring(0, 1) === "-";
|
|
743
|
-
const suffix = str.substring(str.length - 1, str.length) === "-";
|
|
744
|
-
|
|
745
|
-
if (prefix) {
|
|
746
|
-
str = str.substring(1, str.length);
|
|
747
|
-
} else if (suffix) {
|
|
748
|
-
str = str.substring(0, str.length - 1);
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
const regex = new RegExp("^(?<date>" + pattern + ")$", "g");
|
|
752
|
-
if (regex.test(str)) {
|
|
753
|
-
regex.lastIndex = 0;
|
|
754
|
-
const result = regex.exec(str);
|
|
755
|
-
|
|
756
|
-
if (!result) {
|
|
757
|
-
continue;
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
const date = result?.groups?.date;
|
|
761
|
-
if (date) {
|
|
762
|
-
if (prefix) {
|
|
763
|
-
return "(" + field + "<='" + date + " 23:59:59')";
|
|
764
|
-
} else if (suffix) {
|
|
765
|
-
return "(" + field + ">='" + date + "' 00:00:00')";
|
|
766
|
-
}
|
|
767
|
-
return (
|
|
768
|
-
"(" +
|
|
769
|
-
field +
|
|
770
|
-
">='" +
|
|
771
|
-
date +
|
|
772
|
-
" 00:00:00' AND " +
|
|
773
|
-
field +
|
|
774
|
-
"<='" +
|
|
775
|
-
date +
|
|
776
|
-
" 23:59:59')"
|
|
777
|
-
);
|
|
778
|
-
} else {
|
|
779
|
-
return "false";
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
} catch (e) {}
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
return "false";
|
|
786
|
-
}
|
|
787
|
-
|
|
788
1012
|
/**
|
|
789
1013
|
* @private
|
|
790
1014
|
* @param label
|
|
@@ -796,7 +1020,9 @@ function getControlValuesFromLabel(label) {
|
|
|
796
1020
|
if (foundControl) {
|
|
797
1021
|
if (foundControl.tagName === "INPUT") {
|
|
798
1022
|
if (foundControl.type === "checkbox") {
|
|
799
|
-
const checkedControls = label.querySelectorAll(
|
|
1023
|
+
const checkedControls = label.querySelectorAll(
|
|
1024
|
+
`${foundControl}:checked`,
|
|
1025
|
+
);
|
|
800
1026
|
const values = [];
|
|
801
1027
|
|
|
802
1028
|
checkedControls.forEach((checkedControl) => {
|
|
@@ -805,7 +1031,7 @@ function getControlValuesFromLabel(label) {
|
|
|
805
1031
|
|
|
806
1032
|
return values;
|
|
807
1033
|
} else if (foundControl.type === "radio") {
|
|
808
|
-
const checkedControl = label.querySelector(`${
|
|
1034
|
+
const checkedControl = label.querySelector(`${foundControl}:checked`);
|
|
809
1035
|
|
|
810
1036
|
if (checkedControl) {
|
|
811
1037
|
return checkedControl.value;
|
|
@@ -823,14 +1049,6 @@ function getControlValuesFromLabel(label) {
|
|
|
823
1049
|
return null;
|
|
824
1050
|
}
|
|
825
1051
|
|
|
826
|
-
/**
|
|
827
|
-
* @private
|
|
828
|
-
* @returns {string}
|
|
829
|
-
*/
|
|
830
|
-
function getFilterConfigKey() {
|
|
831
|
-
return generateUniqueConfigKey("datatable", this?.id, "filter");
|
|
832
|
-
}
|
|
833
|
-
|
|
834
1052
|
/**
|
|
835
1053
|
* @private
|
|
836
1054
|
* @returns {Promise<unknown>}
|
|
@@ -849,7 +1067,7 @@ function initFromConfig() {
|
|
|
849
1067
|
host
|
|
850
1068
|
.getConfig(configKey)
|
|
851
1069
|
.then((config) => {
|
|
852
|
-
if (config) {
|
|
1070
|
+
if (config && isObject(config)) {
|
|
853
1071
|
this[settingsSymbol].setOptions(config);
|
|
854
1072
|
}
|
|
855
1073
|
resolve();
|
|
@@ -860,7 +1078,17 @@ function initFromConfig() {
|
|
|
860
1078
|
return;
|
|
861
1079
|
}
|
|
862
1080
|
|
|
863
|
-
|
|
1081
|
+
// config not written
|
|
1082
|
+
if (error?.message?.match(/is not defined/)) {
|
|
1083
|
+
resolve();
|
|
1084
|
+
return;
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
addAttributeToken(
|
|
1088
|
+
this,
|
|
1089
|
+
ATTRIBUTE_ERRORMESSAGE,
|
|
1090
|
+
error?.message || error,
|
|
1091
|
+
);
|
|
864
1092
|
reject(error);
|
|
865
1093
|
});
|
|
866
1094
|
});
|
|
@@ -880,7 +1108,7 @@ function updateConfig() {
|
|
|
880
1108
|
try {
|
|
881
1109
|
host.setConfig(configKey, this[settingsSymbol].getOptions());
|
|
882
1110
|
} catch (error) {
|
|
883
|
-
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE,
|
|
1111
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, error?.message || error);
|
|
884
1112
|
}
|
|
885
1113
|
}
|
|
886
1114
|
|
|
@@ -898,15 +1126,31 @@ function getTemplate() {
|
|
|
898
1126
|
<slot name="hidden"></slot>
|
|
899
1127
|
</div>
|
|
900
1128
|
<div data-monster-role="select-and-search">
|
|
1129
|
+
<monster-message-state-button data-monster-role="search-button" class="stretched-control"
|
|
1130
|
+
data-monster-replace="path:labels.search">
|
|
1131
|
+
</monster-message-state-button>
|
|
901
1132
|
<monster-select class="stretched-control"
|
|
902
1133
|
data-monster-selected-template="summary"
|
|
903
1134
|
data-monster-option-type="checkbox"
|
|
904
1135
|
data-monster-option-filter-mode="options"
|
|
905
1136
|
data-monster-option-filter-position="popper"
|
|
906
1137
|
data-monster-role="filter-select"></monster-select>
|
|
907
|
-
<monster-
|
|
908
|
-
|
|
909
|
-
|
|
1138
|
+
<monster-popper-button data-monster-role="save-button" class="stretched-control"
|
|
1139
|
+
data-monster-attributes="data-monster-visible path:storedConfig.enabled">
|
|
1140
|
+
<div slot="button">\${filter-save-label}</div>
|
|
1141
|
+
<div class="monster-form" data-monster-role="form">
|
|
1142
|
+
|
|
1143
|
+
<label for="filter-name">\${filter-name-label}
|
|
1144
|
+
<input name="filter-name"
|
|
1145
|
+
type="search"
|
|
1146
|
+
class="monster-margin-bottom-5"></label>
|
|
1147
|
+
<monster-message-state-button
|
|
1148
|
+
data-monster-role="save-action-button"
|
|
1149
|
+
data-monster-option-labels-button="\${filter-save-label}">
|
|
1150
|
+
</monster-message-state-button>
|
|
1151
|
+
|
|
1152
|
+
</div>
|
|
1153
|
+
</monster-popper-button>
|
|
910
1154
|
<monster-button data-monster-role="reset-button" class="stretched-control"
|
|
911
1155
|
data-monster-replace="path:labels.reset">
|
|
912
1156
|
</monster-button>
|