@schukai/monster 3.88.0 → 3.88.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 +65 -46
- package/package.json +1 -1
- package/source/components/content/stylesheet/copy.mjs +1 -1
- package/source/components/datatable/datatable.mjs +922 -914
- package/source/components/datatable/filter.mjs +914 -920
- package/source/components/datatable/pagination.mjs +1 -3
- package/source/components/datatable/stylesheet/change-button.mjs +1 -1
- package/source/components/datatable/stylesheet/column-bar.mjs +13 -6
- package/source/components/datatable/stylesheet/dataset.mjs +1 -1
- package/source/components/datatable/stylesheet/datatable.mjs +13 -6
- package/source/components/datatable/stylesheet/embedded-pagination.mjs +13 -6
- package/source/components/datatable/stylesheet/filter-select.mjs +1 -1
- package/source/components/datatable/stylesheet/filter.mjs +13 -6
- package/source/components/datatable/stylesheet/save-button.mjs +1 -1
- package/source/components/datatable/stylesheet/status.mjs +1 -1
- package/source/components/form/api-button.mjs +420 -415
- package/source/components/form/button-bar.mjs +24 -6
- package/source/components/form/popper.mjs +1 -1
- package/source/components/form/stylesheet/action-button.mjs +13 -6
- package/source/components/form/stylesheet/button.mjs +13 -6
- package/source/components/form/stylesheet/confirm-button.mjs +13 -6
- package/source/components/form/stylesheet/form.mjs +1 -1
- package/source/components/form/stylesheet/popper-button.mjs +13 -6
- package/source/components/form/stylesheet/select.mjs +13 -6
- package/source/components/form/stylesheet/state-button.mjs +13 -6
- package/source/components/form/tree-select.mjs +1 -1
- package/source/components/host/stylesheet/call-button.mjs +1 -1
- package/source/components/host/stylesheet/host.mjs +1 -1
- package/source/components/host/stylesheet/overlay.mjs +1 -1
- package/source/components/host/stylesheet/toggle-button.mjs +1 -1
- package/source/components/host/stylesheet/viewer.mjs +1 -1
- package/source/components/layout/stylesheet/collapse.mjs +1 -1
- package/source/components/layout/stylesheet/details.mjs +1 -1
- package/source/components/layout/stylesheet/slider.mjs +1 -1
- package/source/components/layout/stylesheet/tabs.mjs +1 -1
- package/source/components/navigation/stylesheet/table-of-content.mjs +1 -1
- package/source/components/navigation/table-of-content.mjs +20 -4
- package/source/components/style/common.css +1 -1
- package/source/components/style/common.pcss +7 -1
- package/source/components/style/mixin/property.pcss +1 -0
- package/source/components/style/normalize.css +1 -1
- package/source/components/style/normalize.pcss +8 -0
- package/source/components/style/property.css +1 -1
- package/source/components/stylesheet/common.mjs +7 -14
- package/source/components/stylesheet/mixin/property.mjs +6 -13
- package/source/components/stylesheet/normalize.mjs +7 -14
- package/source/components/stylesheet/property.mjs +1 -1
- package/source/components/tree-menu/style/tree-menu.pcss +0 -2
- package/source/components/tree-menu/stylesheet/tree-menu.mjs +7 -14
- package/source/types/is.mjs +9 -1
- package/source/types/version.mjs +1 -1
- package/test/cases/monster.mjs +1 -1
- package/test/cases/types/is.mjs +59 -1
- package/test/util/jsdom.mjs +2 -0
- package/test/web/test.html +2 -2
- package/test/web/tests.js +83 -21
@@ -12,49 +12,49 @@
|
|
12
12
|
* SPDX-License-Identifier: AGPL-3.0
|
13
13
|
*/
|
14
14
|
|
15
|
-
import {instanceSymbol} from "../../constants.mjs";
|
16
|
-
import {findTargetElementFromEvent} from "../../dom/events.mjs";
|
15
|
+
import { instanceSymbol } from "../../constants.mjs";
|
16
|
+
import { findTargetElementFromEvent } from "../../dom/events.mjs";
|
17
17
|
import {
|
18
|
-
|
19
|
-
|
18
|
+
findElementWithIdUpwards,
|
19
|
+
findElementWithSelectorUpwards,
|
20
20
|
} from "../../dom/util.mjs";
|
21
21
|
import {
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
assembleMethodSymbol,
|
23
|
+
CustomElement,
|
24
|
+
getSlottedElements,
|
25
|
+
registerCustomElement,
|
26
26
|
} from "../../dom/customelement.mjs";
|
27
|
-
import {ID} from "../../types/id.mjs";
|
28
|
-
import {DeadMansSwitch} from "../../util/deadmansswitch.mjs";
|
29
|
-
import {Settings} from "./filter/settings.mjs";
|
30
|
-
import {FilterStyleSheet} from "./stylesheet/filter.mjs";
|
31
|
-
import {getDocument, getWindow} from "../../dom/util.mjs";
|
32
|
-
import {getGlobal} from "../../types/global.mjs";
|
33
|
-
import {isInstance, isFunction, isObject, isArray} from "../../types/is.mjs";
|
34
|
-
import {Host} from "../host/host.mjs";
|
35
|
-
import {addAttributeToken} from "../../dom/attributes.mjs";
|
36
|
-
import {ATTRIBUTE_ERRORMESSAGE} from "../../dom/constants.mjs";
|
27
|
+
import { ID } from "../../types/id.mjs";
|
28
|
+
import { DeadMansSwitch } from "../../util/deadmansswitch.mjs";
|
29
|
+
import { Settings } from "./filter/settings.mjs";
|
30
|
+
import { FilterStyleSheet } from "./stylesheet/filter.mjs";
|
31
|
+
import { getDocument, getWindow } from "../../dom/util.mjs";
|
32
|
+
import { getGlobal } from "../../types/global.mjs";
|
33
|
+
import { isInstance, isFunction, isObject, isArray } from "../../types/is.mjs";
|
34
|
+
import { Host } from "../host/host.mjs";
|
35
|
+
import { addAttributeToken } from "../../dom/attributes.mjs";
|
36
|
+
import { ATTRIBUTE_ERRORMESSAGE } from "../../dom/constants.mjs";
|
37
37
|
import "../form/message-state-button.mjs";
|
38
|
-
import {Formatter} from "../../text/formatter.mjs";
|
39
|
-
import {generateRangeComparisonExpression} from "../../text/util.mjs";
|
38
|
+
import { Formatter } from "../../text/formatter.mjs";
|
39
|
+
import { generateRangeComparisonExpression } from "../../text/util.mjs";
|
40
40
|
|
41
41
|
import {
|
42
|
-
|
43
|
-
|
42
|
+
parseBracketedKeyValueHash,
|
43
|
+
createBracketedKeyValueHash,
|
44
44
|
} from "../../text/bracketed-key-value-hash.mjs";
|
45
|
-
import {ThemeStyleSheet} from "../stylesheet/theme.mjs";
|
46
|
-
import {SpaceStyleSheet} from "../stylesheet/space.mjs";
|
47
|
-
import {FormStyleSheet} from "../stylesheet/form.mjs";
|
45
|
+
import { ThemeStyleSheet } from "../stylesheet/theme.mjs";
|
46
|
+
import { SpaceStyleSheet } from "../stylesheet/space.mjs";
|
47
|
+
import { FormStyleSheet } from "../stylesheet/form.mjs";
|
48
48
|
|
49
49
|
import {
|
50
|
-
|
51
|
-
|
52
|
-
|
50
|
+
getStoredFilterConfigKey,
|
51
|
+
getFilterConfigKey,
|
52
|
+
parseDateInput,
|
53
53
|
} from "./filter/util.mjs";
|
54
54
|
|
55
55
|
import "./filter/select.mjs";
|
56
56
|
|
57
|
-
export {Filter};
|
57
|
+
export { Filter };
|
58
58
|
|
59
59
|
/**
|
60
60
|
* @private
|
@@ -91,7 +91,7 @@ const filterControlElementSymbol = Symbol("filterControlElement");
|
|
91
91
|
* @type {symbol}
|
92
92
|
*/
|
93
93
|
const filterSaveActionButtonElementSymbol = Symbol(
|
94
|
-
|
94
|
+
"filterSaveActionButtonElement",
|
95
95
|
);
|
96
96
|
|
97
97
|
/**
|
@@ -112,7 +112,6 @@ const locationChangeHandlerSymbol = Symbol("locationChangeHandler");
|
|
112
112
|
*/
|
113
113
|
const settingsSymbol = Symbol("settings");
|
114
114
|
|
115
|
-
|
116
115
|
/**
|
117
116
|
* @private
|
118
117
|
* @type {symbol}
|
@@ -138,211 +137,210 @@ const debounceSizeSymbol = Symbol("debounceSize");
|
|
138
137
|
* @summary The Filter component is used to show and handle the filter values.
|
139
138
|
*/
|
140
139
|
class Filter extends CustomElement {
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
}
|
140
|
+
/**
|
141
|
+
*
|
142
|
+
*/
|
143
|
+
constructor() {
|
144
|
+
super();
|
145
|
+
this[settingsSymbol] = new Settings();
|
146
|
+
}
|
147
|
+
|
148
|
+
/**
|
149
|
+
* This method is called by the `instanceof` operator.
|
150
|
+
* @return {symbol}
|
151
|
+
*/
|
152
|
+
static get [instanceSymbol]() {
|
153
|
+
return Symbol.for("@schukai/monster/components/filter@@instance");
|
154
|
+
}
|
155
|
+
|
156
|
+
/**
|
157
|
+
*
|
158
|
+
* @param {string} message
|
159
|
+
* @return {Filter}
|
160
|
+
*/
|
161
|
+
showFailureMessage(message) {
|
162
|
+
this[searchButtonElementSymbol].setState(
|
163
|
+
"failed",
|
164
|
+
this.getOption("timeouts.message", 4000),
|
165
|
+
);
|
166
|
+
this[searchButtonElementSymbol]
|
167
|
+
.setMessage(message.toString())
|
168
|
+
.showMessage(this.getOption("timeouts.message", 4000));
|
169
|
+
return this;
|
170
|
+
}
|
171
|
+
|
172
|
+
/**
|
173
|
+
*
|
174
|
+
* @return {{Filter}}
|
175
|
+
*/
|
176
|
+
resetFailureMessage() {
|
177
|
+
this[searchButtonElementSymbol].hideMessage();
|
178
|
+
this[searchButtonElementSymbol].removeState();
|
179
|
+
return this;
|
180
|
+
}
|
181
|
+
|
182
|
+
/**
|
183
|
+
*
|
184
|
+
* @return {{Filter}}
|
185
|
+
*/
|
186
|
+
showSuccess() {
|
187
|
+
this[searchButtonElementSymbol].setState(
|
188
|
+
"successful",
|
189
|
+
this.getOption("timeouts.message", 4000),
|
190
|
+
);
|
191
|
+
return this;
|
192
|
+
}
|
193
|
+
|
194
|
+
/**
|
195
|
+
* To set the options via the HTML tag, the attribute `data-monster-options` must be used.
|
196
|
+
* @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
|
197
|
+
*
|
198
|
+
* The individual configuration values can be found in the table.
|
199
|
+
*
|
200
|
+
* @property {Object} templates Template definitions
|
201
|
+
* @property {string} templates.main Main template
|
202
|
+
* @property {Object} labels Label definitions
|
203
|
+
* @property {string} labels.search Search button label
|
204
|
+
* @property {string} labels.reset Reset button label
|
205
|
+
* @property {string} labels.save Save button label
|
206
|
+
* @property {string} labels.filter-name Filter name label
|
207
|
+
* @property {string} labels.empty-query-and-no-default Empty query and no default query label
|
208
|
+
* @property {string} labels.query-not-changed Query not changed label
|
209
|
+
* @property {Object} formatter Formatter definitions
|
210
|
+
* @property {Object} formatter.marker Marker definitions
|
211
|
+
* @property {Object} formatter.marker.open Marker open
|
212
|
+
* @property {Object} formatter.marker.close Marker close
|
213
|
+
* @property {Object} storedConfig Stored configuration
|
214
|
+
* @property {boolean} storedConfig.enabled Enabled
|
215
|
+
* @property {string} storedConfig.selector Selector
|
216
|
+
* @property {Object} timeouts Timeout definitions
|
217
|
+
* @property {number} timeouts.message Message timeout
|
218
|
+
* @property {Object} queries Query definitions
|
219
|
+
* @property {Function} queries.wrap Wrap callback
|
220
|
+
* @property {Function} queries.join Join callback
|
221
|
+
* @property {string} query Query
|
222
|
+
* @property {string} defaultQuery Default query
|
223
|
+
* @property {boolean} eventProcessing Event processing
|
224
|
+
*/
|
225
|
+
get defaults() {
|
226
|
+
return Object.assign({}, super.defaults, {
|
227
|
+
templates: {
|
228
|
+
main: getTemplate(),
|
229
|
+
},
|
230
|
+
formatter: {
|
231
|
+
marker: {
|
232
|
+
open: null,
|
233
|
+
close: null,
|
234
|
+
},
|
235
|
+
},
|
236
|
+
labels: {
|
237
|
+
search: "Search",
|
238
|
+
reset: "Reset",
|
239
|
+
save: "Save",
|
240
|
+
"filter-name": "Filter name",
|
241
|
+
"empty-query-and-no-default": "Please select a filter",
|
242
|
+
"query-not-changed": "The query has not changed",
|
243
|
+
},
|
244
|
+
|
245
|
+
templateMapping: {
|
246
|
+
"filter-save-label": null,
|
247
|
+
"filter-name-label": name,
|
248
|
+
},
|
249
|
+
|
250
|
+
storedConfig: {
|
251
|
+
enabled: true,
|
252
|
+
selector: "",
|
253
|
+
},
|
254
|
+
|
255
|
+
timeouts: {
|
256
|
+
message: 4000,
|
257
|
+
},
|
258
|
+
|
259
|
+
queries: {
|
260
|
+
wrap: (value, definition) => {
|
261
|
+
return value;
|
262
|
+
},
|
263
|
+
join: (queries) => {
|
264
|
+
if (queries.length === 0) {
|
265
|
+
return "";
|
266
|
+
}
|
267
|
+
return queries.join(" AND ");
|
268
|
+
},
|
269
|
+
},
|
270
|
+
|
271
|
+
query: undefined,
|
272
|
+
defaultQuery: "",
|
273
|
+
eventProcessing: true,
|
274
|
+
});
|
275
|
+
}
|
276
|
+
|
277
|
+
/**
|
278
|
+
*
|
279
|
+
* @return {string}
|
280
|
+
*/
|
281
|
+
static getTag() {
|
282
|
+
return "monster-datatable-filter";
|
283
|
+
}
|
284
|
+
|
285
|
+
/**
|
286
|
+
* @return {FilterButton}
|
287
|
+
*/
|
288
|
+
[assembleMethodSymbol]() {
|
289
|
+
this.setOption(
|
290
|
+
"templateMapping.filter-save-label",
|
291
|
+
this.getOption("labels.save"),
|
292
|
+
);
|
293
|
+
this.setOption(
|
294
|
+
"templateMapping.filter-name-label",
|
295
|
+
this.getOption("labels.filter-name"),
|
296
|
+
);
|
297
|
+
|
298
|
+
super[assembleMethodSymbol]();
|
299
|
+
|
300
|
+
initControlReferences.call(this);
|
301
|
+
initEventHandler.call(this);
|
302
|
+
|
303
|
+
initFromConfig
|
304
|
+
.call(this)
|
305
|
+
.then(() => {
|
306
|
+
initFilter.call(this);
|
307
|
+
updateFilterTabs.call(this);
|
308
|
+
})
|
309
|
+
.catch((error) => {
|
310
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, error?.message);
|
311
|
+
});
|
312
|
+
}
|
313
|
+
|
314
|
+
/**
|
315
|
+
*
|
316
|
+
*/
|
317
|
+
connectedCallback() {
|
318
|
+
super.connectedCallback();
|
319
|
+
|
320
|
+
getWindow().addEventListener(
|
321
|
+
"hashchange",
|
322
|
+
this[locationChangeHandlerSymbol],
|
323
|
+
);
|
324
|
+
}
|
325
|
+
|
326
|
+
/**
|
327
|
+
*
|
328
|
+
*/
|
329
|
+
disconnectedCallback() {
|
330
|
+
super.disconnectedCallback();
|
331
|
+
|
332
|
+
getWindow().removeEventListener(
|
333
|
+
"hashchange",
|
334
|
+
this[locationChangeHandlerSymbol],
|
335
|
+
);
|
336
|
+
}
|
337
|
+
|
338
|
+
/**
|
339
|
+
* @return {Array<CSSStyleSheet>}
|
340
|
+
*/
|
341
|
+
static getCSSStyleSheet() {
|
342
|
+
return [FilterStyleSheet, FormStyleSheet, ThemeStyleSheet, SpaceStyleSheet];
|
343
|
+
}
|
346
344
|
}
|
347
345
|
|
348
346
|
/**
|
@@ -350,48 +348,48 @@ class Filter extends CustomElement {
|
|
350
348
|
* @return {FilterButton}
|
351
349
|
*/
|
352
350
|
function initControlReferences() {
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
351
|
+
if (!this.shadowRoot) {
|
352
|
+
throw new Error("no shadow-root is defined");
|
353
|
+
}
|
354
|
+
|
355
|
+
this[filterControlElementSymbol] = this.shadowRoot.querySelector(
|
356
|
+
"[data-monster-role=control]",
|
357
|
+
);
|
358
|
+
this[filterSelectElementSymbol] = this.shadowRoot.querySelector(
|
359
|
+
"[data-monster-role=filter-select]",
|
360
|
+
);
|
361
|
+
this[searchButtonElementSymbol] = this.shadowRoot.querySelector(
|
362
|
+
"[data-monster-role=search-button]",
|
363
|
+
);
|
364
|
+
this[resetButtonElementSymbol] = this.shadowRoot.querySelector(
|
365
|
+
"[data-monster-role=reset-button]",
|
366
|
+
);
|
367
|
+
|
368
|
+
this[saveButtonElementSymbol] = this.shadowRoot.querySelector(
|
369
|
+
"[data-monster-role=save-button]",
|
370
|
+
);
|
371
|
+
|
372
|
+
this[filterSaveActionButtonElementSymbol] = this.shadowRoot.querySelector(
|
373
|
+
"[data-monster-role=save-action-button]",
|
374
|
+
);
|
375
|
+
|
376
|
+
this[filterTabElementSymbol] = findElementWithSelectorUpwards(
|
377
|
+
this,
|
378
|
+
this.getOption("storedConfig.selector", ""),
|
379
|
+
);
|
380
|
+
|
381
|
+
return this;
|
384
382
|
}
|
385
383
|
|
386
384
|
function updateFilterSelections() {
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
385
|
+
queueMicrotask(() => {
|
386
|
+
const options = this[settingsSymbol].getOptions();
|
387
|
+
this[filterSelectElementSymbol].setOption("options", options);
|
388
|
+
queueMicrotask(() => {
|
389
|
+
this[filterSelectElementSymbol].value =
|
390
|
+
this[settingsSymbol].getSelected();
|
391
|
+
});
|
392
|
+
});
|
395
393
|
}
|
396
394
|
|
397
395
|
/**
|
@@ -399,59 +397,58 @@ function updateFilterSelections() {
|
|
399
397
|
* @throws {Error} no filter label is defined
|
400
398
|
*/
|
401
399
|
function initFilter() {
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
updateFilterSelections.call(this);
|
400
|
+
const storedSetting = this[settingsSymbol];
|
401
|
+
this[settingsSymbol] = new Settings();
|
402
|
+
|
403
|
+
const result = parseBracketedKeyValueHash(getGlobal().location.hash);
|
404
|
+
let valuesFromHash = {};
|
405
|
+
if (isObject(result) && result?.[this.id]) {
|
406
|
+
valuesFromHash = result[this.id];
|
407
|
+
}
|
408
|
+
|
409
|
+
getSlottedElements
|
410
|
+
.call(this, "label[data-monster-label]")
|
411
|
+
.forEach((element) => {
|
412
|
+
const label = element.getAttribute("data-monster-label");
|
413
|
+
if (!label) {
|
414
|
+
throw new Error("no filter label is defined");
|
415
|
+
}
|
416
|
+
|
417
|
+
let value = element.id;
|
418
|
+
if (!value) {
|
419
|
+
const prefix = label.replace(/\W/g, "-");
|
420
|
+
prefix.charAt(0).match(/[\d_]/g)?.length ? `f${prefix}` : prefix;
|
421
|
+
|
422
|
+
value = new ID(prefix + "-").toString();
|
423
|
+
element.id = value;
|
424
|
+
}
|
425
|
+
|
426
|
+
let setting = storedSetting.get(value);
|
427
|
+
|
428
|
+
if (setting) {
|
429
|
+
this[settingsSymbol].set(setting);
|
430
|
+
}
|
431
|
+
|
432
|
+
if (valuesFromHash?.[element.id]) {
|
433
|
+
const v = escapeAttributeValue(valuesFromHash[element.id]);
|
434
|
+
const searchInput = element.firstElementChild;
|
435
|
+
try {
|
436
|
+
searchInput.value = v;
|
437
|
+
} catch (error) {}
|
438
|
+
}
|
439
|
+
|
440
|
+
setting = this[settingsSymbol].get(value);
|
441
|
+
let visible = false;
|
442
|
+
if (setting) {
|
443
|
+
setSlotAttribute(element, setting.visible);
|
444
|
+
visible = setting.visible;
|
445
|
+
} else {
|
446
|
+
visible = getVisibilityFromSlotAttribute(element);
|
447
|
+
}
|
448
|
+
|
449
|
+
this[settingsSymbol].set({ value, label, visible });
|
450
|
+
});
|
451
|
+
updateFilterSelections.call(this);
|
455
452
|
}
|
456
453
|
|
457
454
|
/**
|
@@ -460,16 +457,16 @@ function initFilter() {
|
|
460
457
|
* @return {*}
|
461
458
|
*/
|
462
459
|
function escapeAttributeValue(input) {
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
460
|
+
if (input === undefined || input === null) {
|
461
|
+
return input;
|
462
|
+
}
|
463
|
+
|
464
|
+
return input
|
465
|
+
.replace(/&/g, "&")
|
466
|
+
.replace(/"/g, """)
|
467
|
+
.replace(/'/g, "'")
|
468
|
+
.replace(/</g, "<")
|
469
|
+
.replace(/>/g, ">");
|
473
470
|
}
|
474
471
|
|
475
472
|
/**
|
@@ -478,9 +475,9 @@ function escapeAttributeValue(input) {
|
|
478
475
|
* @return {boolean}
|
479
476
|
*/
|
480
477
|
function getVisibilityFromSlotAttribute(element) {
|
481
|
-
|
482
|
-
|
483
|
-
|
478
|
+
return !(
|
479
|
+
element.hasAttribute("slot") && element.getAttribute("slot") === "hidden"
|
480
|
+
);
|
484
481
|
}
|
485
482
|
|
486
483
|
/**
|
@@ -489,338 +486,335 @@ function getVisibilityFromSlotAttribute(element) {
|
|
489
486
|
* @param {boolean} visible
|
490
487
|
*/
|
491
488
|
function setSlotAttribute(element, visible) {
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
489
|
+
if (visible) {
|
490
|
+
element.removeAttribute("slot");
|
491
|
+
return;
|
492
|
+
}
|
496
493
|
|
497
|
-
|
494
|
+
element.setAttribute("slot", "hidden");
|
498
495
|
}
|
499
496
|
|
500
497
|
/**
|
501
498
|
* @private
|
502
499
|
*/
|
503
500
|
function initEventHandler() {
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
if (element) {
|
700
|
-
initTabEvents.call(this);
|
701
|
-
}
|
501
|
+
const self = this;
|
502
|
+
/**
|
503
|
+
* Monster.Components.Form.event:monster-selection-cleared
|
504
|
+
*/
|
505
|
+
if (self[filterSelectElementSymbol]) {
|
506
|
+
self[filterSelectElementSymbol].addEventListener(
|
507
|
+
"monster-selection-cleared",
|
508
|
+
function () {
|
509
|
+
const settings = self[settingsSymbol].getOptions();
|
510
|
+
|
511
|
+
for (const setting of settings) {
|
512
|
+
const filterElement = findElementWithIdUpwards(self, setting.value);
|
513
|
+
if (filterElement) {
|
514
|
+
setSlotAttribute(filterElement, false);
|
515
|
+
|
516
|
+
self[settingsSymbol].set({ value: setting.value, visible: false });
|
517
|
+
}
|
518
|
+
}
|
519
|
+
|
520
|
+
updateConfig.call(self);
|
521
|
+
},
|
522
|
+
);
|
523
|
+
|
524
|
+
self[filterSelectElementSymbol].addEventListener(
|
525
|
+
"monster-changed",
|
526
|
+
function (event) {
|
527
|
+
const filterElement = findElementWithIdUpwards(
|
528
|
+
self,
|
529
|
+
event.detail.value,
|
530
|
+
);
|
531
|
+
if (filterElement) {
|
532
|
+
setSlotAttribute(filterElement, event.detail.checked);
|
533
|
+
}
|
534
|
+
|
535
|
+
self[settingsSymbol].set({
|
536
|
+
value: event.detail.value,
|
537
|
+
visible: event.detail.checked,
|
538
|
+
});
|
539
|
+
|
540
|
+
updateConfig.call(self);
|
541
|
+
},
|
542
|
+
);
|
543
|
+
}
|
544
|
+
|
545
|
+
if (self[filterSaveActionButtonElementSymbol]) {
|
546
|
+
self[filterSaveActionButtonElementSymbol].setOption(
|
547
|
+
"actions.click",
|
548
|
+
function (event) {
|
549
|
+
const button = findTargetElementFromEvent(
|
550
|
+
event,
|
551
|
+
"data-monster-role",
|
552
|
+
"save-action-button",
|
553
|
+
);
|
554
|
+
const form = button.closest("[data-monster-role=form]");
|
555
|
+
|
556
|
+
if (!form) {
|
557
|
+
button.setState("failed", self.getOption("timeouts.message", 4000));
|
558
|
+
return;
|
559
|
+
}
|
560
|
+
|
561
|
+
const input = form.querySelector("input[name=filter-name]");
|
562
|
+
if (!input) {
|
563
|
+
button.setState("failed", self.getOption("timeouts.message", 4000));
|
564
|
+
return;
|
565
|
+
}
|
566
|
+
|
567
|
+
const name = input.value;
|
568
|
+
if (!name) {
|
569
|
+
button.setState("failed", self.getOption("timeouts.message", 4000));
|
570
|
+
button.setMessage("Please enter a name").showMessage();
|
571
|
+
return;
|
572
|
+
}
|
573
|
+
|
574
|
+
doSearch
|
575
|
+
.call(self, { showEffect: false })
|
576
|
+
.then(() => {
|
577
|
+
const configKey = getStoredFilterConfigKey.call(self);
|
578
|
+
const host = getDocument().querySelector("monster-host");
|
579
|
+
if (!host) {
|
580
|
+
return;
|
581
|
+
}
|
582
|
+
|
583
|
+
const query = self.getOption("query");
|
584
|
+
if (!query) {
|
585
|
+
button.setState(
|
586
|
+
"failed",
|
587
|
+
self.getOption(
|
588
|
+
"timeouts.message",
|
589
|
+
self.getOption("timeouts.message", 4000),
|
590
|
+
),
|
591
|
+
);
|
592
|
+
button
|
593
|
+
.setMessage("No query found")
|
594
|
+
.showMessage(self.getOption("timeouts.message", 4000));
|
595
|
+
return;
|
596
|
+
}
|
597
|
+
|
598
|
+
host
|
599
|
+
.hasConfig(configKey)
|
600
|
+
.then((hasConfig) => {
|
601
|
+
return new Promise((resolve, reject) => {
|
602
|
+
if (hasConfig) {
|
603
|
+
host.getConfig(configKey).then(resolve).catch(reject);
|
604
|
+
return;
|
605
|
+
}
|
606
|
+
return resolve({});
|
607
|
+
});
|
608
|
+
})
|
609
|
+
.then((config) => {
|
610
|
+
config[name] = query;
|
611
|
+
return host.setConfig(configKey, {
|
612
|
+
...config,
|
613
|
+
});
|
614
|
+
})
|
615
|
+
.then(() => {
|
616
|
+
button.setState(
|
617
|
+
"successful",
|
618
|
+
self.getOption("timeouts.message", 4000),
|
619
|
+
);
|
620
|
+
updateFilterTabs.call(self);
|
621
|
+
})
|
622
|
+
.catch((error) => {
|
623
|
+
button.setState(
|
624
|
+
"failed",
|
625
|
+
self.getOption("timeouts.message", 4000),
|
626
|
+
);
|
627
|
+
button
|
628
|
+
.setMessage(error.message)
|
629
|
+
.showMessage(self.getOption("timeouts.message", 4000));
|
630
|
+
});
|
631
|
+
})
|
632
|
+
.catch((error) => {
|
633
|
+
button.setState("failed", self.getOption("timeouts.message", 4000));
|
634
|
+
const msg = error.message || error;
|
635
|
+
button
|
636
|
+
.setMessage(msg)
|
637
|
+
.showMessage(self.getOption("timeouts.message", 4000));
|
638
|
+
});
|
639
|
+
},
|
640
|
+
);
|
641
|
+
}
|
642
|
+
|
643
|
+
self[searchButtonElementSymbol].setOption("actions.click", () => {
|
644
|
+
doSearch
|
645
|
+
.call(self)
|
646
|
+
.then(() => {})
|
647
|
+
.catch((error) => {});
|
648
|
+
});
|
649
|
+
|
650
|
+
// the reset button should reset the filter and the search query
|
651
|
+
// all input elements should be reset to their default values
|
652
|
+
// which is the empty string. we search for all input elements
|
653
|
+
// in the filter and reset them to their default value
|
654
|
+
self[resetButtonElementSymbol].setOption("actions.click", () => {
|
655
|
+
getSlottedElements
|
656
|
+
.call(self, "label[data-monster-label]")
|
657
|
+
.forEach((element) => {
|
658
|
+
const label = element.getAttribute("data-monster-label");
|
659
|
+
if (!label) {
|
660
|
+
return;
|
661
|
+
}
|
662
|
+
|
663
|
+
const input = element.firstElementChild;
|
664
|
+
|
665
|
+
if (input) {
|
666
|
+
input.value = "";
|
667
|
+
}
|
668
|
+
});
|
669
|
+
|
670
|
+
doSearch
|
671
|
+
.call(self, { showEffect: false })
|
672
|
+
.then(() => {})
|
673
|
+
.catch((e) => addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, e.message));
|
674
|
+
});
|
675
|
+
|
676
|
+
self.addEventListener("keyup", (event) => {
|
677
|
+
const path = event.composedPath();
|
678
|
+
if (path.length === 0) {
|
679
|
+
return;
|
680
|
+
}
|
681
|
+
|
682
|
+
if (!(path[0] instanceof HTMLInputElement)) {
|
683
|
+
return;
|
684
|
+
}
|
685
|
+
|
686
|
+
if (event.keyCode === 13) {
|
687
|
+
doSearch.call(self, { showEffect: false });
|
688
|
+
}
|
689
|
+
});
|
690
|
+
|
691
|
+
// tabs
|
692
|
+
const element = this[filterTabElementSymbol];
|
693
|
+
if (element) {
|
694
|
+
initTabEvents.call(this);
|
695
|
+
}
|
702
696
|
}
|
703
697
|
|
704
698
|
function initTabEvents() {
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
699
|
+
this[filterTabElementSymbol].addEventListener(
|
700
|
+
"monster-tab-changed",
|
701
|
+
(event) => {
|
702
|
+
const query = event?.detail?.data?.["data-monster-query"];
|
703
|
+
const q = this.getOption("query");
|
704
|
+
if (query !== q) {
|
705
|
+
this.setOption("query", query);
|
706
|
+
}
|
707
|
+
},
|
708
|
+
);
|
709
|
+
|
710
|
+
this[filterTabElementSymbol].addEventListener(
|
711
|
+
"monster-tab-remove",
|
712
|
+
(event) => {
|
713
|
+
const labels = [];
|
714
|
+
const buttons = this[filterTabElementSymbol].getOption("buttons");
|
715
|
+
|
716
|
+
const keys = ["popper", "standard"];
|
717
|
+
for (let i = 0; i < keys.length; i++) {
|
718
|
+
const key = keys[i];
|
719
|
+
|
720
|
+
for (const button of buttons[key]) {
|
721
|
+
if (button.label !== event.detail.label) {
|
722
|
+
labels.push(button.label);
|
723
|
+
}
|
724
|
+
}
|
725
|
+
}
|
726
|
+
|
727
|
+
const host = findElementWithSelectorUpwards(this, "monster-host");
|
728
|
+
if (!(host && this.id)) {
|
729
|
+
return;
|
730
|
+
}
|
731
|
+
|
732
|
+
const configKey = getStoredFilterConfigKey.call(this);
|
733
|
+
host
|
734
|
+
.hasConfig(configKey)
|
735
|
+
.then((hasConfig) => {
|
736
|
+
if (!hasConfig) {
|
737
|
+
return;
|
738
|
+
}
|
739
|
+
|
740
|
+
return host.getConfig(configKey);
|
741
|
+
})
|
742
|
+
.then((config) => {
|
743
|
+
for (const [name, query] of Object.entries(config)) {
|
744
|
+
if (labels.includes(name)) {
|
745
|
+
continue;
|
746
|
+
}
|
747
|
+
|
748
|
+
delete config[name];
|
749
|
+
}
|
750
|
+
|
751
|
+
return host.setConfig(configKey, {
|
752
|
+
...config,
|
753
|
+
});
|
754
|
+
});
|
755
|
+
},
|
756
|
+
);
|
763
757
|
}
|
764
758
|
|
765
759
|
/**
|
766
760
|
* @private
|
767
761
|
*/
|
768
762
|
function updateFilterTabs() {
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
763
|
+
const element = this[filterTabElementSymbol];
|
764
|
+
if (!element) {
|
765
|
+
return;
|
766
|
+
}
|
767
|
+
|
768
|
+
const host = findElementWithSelectorUpwards(this, "monster-host");
|
769
|
+
if (!(host && this.id)) {
|
770
|
+
return;
|
771
|
+
}
|
772
|
+
|
773
|
+
const configKey = getStoredFilterConfigKey.call(this);
|
774
|
+
host
|
775
|
+
.hasConfig(configKey)
|
776
|
+
.then((hasConfig) => {
|
777
|
+
if (!hasConfig) {
|
778
|
+
return;
|
779
|
+
}
|
780
|
+
|
781
|
+
return host.getConfig(configKey);
|
782
|
+
})
|
783
|
+
.then((config) => {
|
784
|
+
for (const [name, query] of Object.entries(config)) {
|
785
|
+
const found = element.querySelector(
|
786
|
+
`[data-monster-button-label="${name}"]`,
|
787
|
+
);
|
788
|
+
if (found) {
|
789
|
+
continue;
|
790
|
+
}
|
791
|
+
|
792
|
+
if (query === undefined || query === null) {
|
793
|
+
continue;
|
794
|
+
}
|
795
|
+
|
796
|
+
const escapedQuery = escapeAttributeValue(query);
|
797
|
+
|
798
|
+
element.insertAdjacentHTML(
|
799
|
+
"beforeend",
|
800
|
+
`<div data-monster-button-label="${name}"
|
807
801
|
data-monster-removable="true"
|
808
802
|
data-monster-query="${escapedQuery}" data-monster-role="filter-tab" >
|
809
803
|
</div>`,
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
804
|
+
);
|
805
|
+
}
|
806
|
+
})
|
807
|
+
.catch((error) => {
|
808
|
+
if (error instanceof Error) {
|
809
|
+
addAttributeToken(
|
810
|
+
this,
|
811
|
+
ATTRIBUTE_ERRORMESSAGE,
|
812
|
+
error.message + " " + error.stack,
|
813
|
+
);
|
814
|
+
} else {
|
815
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, error + "");
|
816
|
+
}
|
817
|
+
});
|
824
818
|
}
|
825
819
|
|
826
820
|
/**
|
@@ -828,76 +822,76 @@ function updateFilterTabs() {
|
|
828
822
|
* @param showEffect
|
829
823
|
* @return {Promise<*>}
|
830
824
|
*/
|
831
|
-
function doSearch({showEffect} = {showEffect: true}) {
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
825
|
+
function doSearch({ showEffect } = { showEffect: true }) {
|
826
|
+
this.resetFailureMessage();
|
827
|
+
|
828
|
+
if (showEffect) {
|
829
|
+
this[searchButtonElementSymbol].setState(
|
830
|
+
"activity",
|
831
|
+
this.getOption("timeouts.message", 4000),
|
832
|
+
);
|
833
|
+
}
|
834
|
+
|
835
|
+
return collectSearchQueries
|
836
|
+
.call(this)
|
837
|
+
.then((query) => {
|
838
|
+
const buildQuery = buildSearchQuery.call(this, query);
|
839
|
+
if (buildQuery === "" && !this.getOption("defaultQuery")) {
|
840
|
+
const msg = this.getOption("labels.empty-query-and-no-default");
|
841
|
+
|
842
|
+
if (showEffect) {
|
843
|
+
this[searchButtonElementSymbol].removeState();
|
844
|
+
this[searchButtonElementSymbol]
|
845
|
+
.setMessage(msg)
|
846
|
+
.showMessage(this.getOption("timeouts.message", 4000));
|
847
|
+
}
|
848
|
+
|
849
|
+
throw new Error(msg);
|
850
|
+
}
|
851
|
+
|
852
|
+
if (buildQuery === this.getOption("query")) {
|
853
|
+
const msg = this.getOption("labels.query-not-changed");
|
854
|
+
|
855
|
+
if (showEffect) {
|
856
|
+
this[searchButtonElementSymbol].removeState();
|
857
|
+
this[searchButtonElementSymbol]
|
858
|
+
.setMessage(msg)
|
859
|
+
.showMessage(this.getOption("timeouts.message", 4000));
|
860
|
+
}
|
861
|
+
|
862
|
+
throw new Error(msg);
|
863
|
+
}
|
864
|
+
|
865
|
+
if (showEffect) {
|
866
|
+
this[searchButtonElementSymbol].setState(
|
867
|
+
"activity",
|
868
|
+
this.getOption("timeouts.message", 4000),
|
869
|
+
);
|
870
|
+
}
|
871
|
+
|
872
|
+
this.setOption("query", buildSearchQuery.call(this, query));
|
873
|
+
})
|
874
|
+
.catch((error) => {
|
875
|
+
if (error instanceof Error) {
|
876
|
+
addAttributeToken(
|
877
|
+
this,
|
878
|
+
ATTRIBUTE_ERRORMESSAGE,
|
879
|
+
error.message + " " + error.stack,
|
880
|
+
);
|
881
|
+
} else {
|
882
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, String(error));
|
883
|
+
}
|
884
|
+
|
885
|
+
if (showEffect) {
|
886
|
+
this[searchButtonElementSymbol].setState(
|
887
|
+
"failed",
|
888
|
+
this.getOption("timeouts.message", 4000),
|
889
|
+
);
|
890
|
+
this[searchButtonElementSymbol].setMessage(error.message).showMessage();
|
891
|
+
}
|
892
|
+
|
893
|
+
return Promise.reject(error);
|
894
|
+
});
|
901
895
|
}
|
902
896
|
|
903
897
|
/**
|
@@ -906,21 +900,21 @@ function doSearch({showEffect} = {showEffect: true}) {
|
|
906
900
|
* @return {*|string}
|
907
901
|
*/
|
908
902
|
function buildSearchQuery(queries) {
|
909
|
-
|
910
|
-
|
911
|
-
|
903
|
+
if (!isArray(queries) || queries.length === 0) {
|
904
|
+
return this.getOption("defaultQuery");
|
905
|
+
}
|
912
906
|
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
907
|
+
const joinCallback = this.getOption("queries.join");
|
908
|
+
if (isFunction(joinCallback)) {
|
909
|
+
return joinCallback(queries);
|
910
|
+
}
|
917
911
|
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
912
|
+
const q = queries.join(" ").trim();
|
913
|
+
if (q.length === 0) {
|
914
|
+
return this.getOption("defaultQuery");
|
915
|
+
}
|
922
916
|
|
923
|
-
|
917
|
+
return q;
|
924
918
|
}
|
925
919
|
|
926
920
|
/**
|
@@ -928,108 +922,108 @@ function buildSearchQuery(queries) {
|
|
928
922
|
* @return {Promise<unknown>}
|
929
923
|
*/
|
930
924
|
function collectSearchQueries() {
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
925
|
+
const currentHash = parseBracketedKeyValueHash(getGlobal().location.hash);
|
926
|
+
const self = this;
|
927
|
+
|
928
|
+
return new Promise((resolve, reject) => {
|
929
|
+
const query = [];
|
930
|
+
const wrapCallback = this.getOption("queries.wrap");
|
931
|
+
|
932
|
+
let hasNoIdError = false;
|
933
|
+
|
934
|
+
getSlottedElements
|
935
|
+
.call(this, "label[data-monster-label]")
|
936
|
+
.forEach((element) => {
|
937
|
+
const label = element.getAttribute("data-monster-label");
|
938
|
+
if (!label) {
|
939
|
+
throw new Error("no filter label is defined");
|
940
|
+
}
|
941
|
+
|
942
|
+
const id = element.id;
|
943
|
+
if (!id) {
|
944
|
+
hasNoIdError = true;
|
945
|
+
return;
|
946
|
+
}
|
947
|
+
|
948
|
+
//const visible = window.getComputedStyle(element).display !== "none";
|
949
|
+
const visible = getVisibilityFromSlotAttribute(element);
|
950
|
+
if (!visible) {
|
951
|
+
return;
|
952
|
+
}
|
953
|
+
|
954
|
+
let template = element.getAttribute("data-monster-template");
|
955
|
+
if (!template) {
|
956
|
+
template = "${id}=${value}";
|
957
|
+
}
|
958
|
+
|
959
|
+
const controlValue = getControlValuesFromLabel(element);
|
960
|
+
if (!controlValue) {
|
961
|
+
if (controlValue === "" && currentHash?.[this.id]?.[id]) {
|
962
|
+
delete currentHash[this.id][id];
|
963
|
+
}
|
964
|
+
|
965
|
+
return;
|
966
|
+
}
|
967
|
+
|
968
|
+
if (!isObject(currentHash[this.id])) {
|
969
|
+
currentHash[this.id] = {};
|
970
|
+
}
|
971
|
+
currentHash[this.id][id] = controlValue;
|
972
|
+
|
973
|
+
const mapping = {
|
974
|
+
id,
|
975
|
+
value: controlValue,
|
976
|
+
label,
|
977
|
+
};
|
978
|
+
|
979
|
+
const formatter = new Formatter(mapping, {
|
980
|
+
callbacks: {
|
981
|
+
range: (value, key) => {
|
982
|
+
return generateRangeComparisonExpression(value, key, {
|
983
|
+
urlEncode: true,
|
984
|
+
andOp: "AND",
|
985
|
+
orOp: "OR",
|
986
|
+
eqOp: "=",
|
987
|
+
gtOp: ">",
|
988
|
+
ltOp: "<",
|
989
|
+
});
|
990
|
+
},
|
991
|
+
"date-range": (value, key) => {
|
992
|
+
const query = parseDateInput(value, key);
|
993
|
+
if (!query || query === "false") {
|
994
|
+
return "";
|
995
|
+
}
|
996
|
+
|
997
|
+
// return query as url encoded
|
998
|
+
return encodeURIComponent(query);
|
999
|
+
},
|
1000
|
+
},
|
1001
|
+
});
|
1002
|
+
|
1003
|
+
if (self.getOption("formatter.marker.open")) {
|
1004
|
+
formatter.setMarker(
|
1005
|
+
self.getOption("formatter.marker.open"),
|
1006
|
+
self.getOption("formatter.marker.close"),
|
1007
|
+
);
|
1008
|
+
}
|
1009
|
+
|
1010
|
+
let queryPart = formatter.format(template);
|
1011
|
+
if (queryPart) {
|
1012
|
+
if (isFunction(wrapCallback)) {
|
1013
|
+
queryPart = wrapCallback(queryPart, mapping);
|
1014
|
+
}
|
1015
|
+
query.push(queryPart);
|
1016
|
+
}
|
1017
|
+
});
|
1018
|
+
|
1019
|
+
if (hasNoIdError) {
|
1020
|
+
reject(new Error("some or all filter elements have no id"));
|
1021
|
+
return;
|
1022
|
+
}
|
1023
|
+
|
1024
|
+
getGlobal().location.hash = createBracketedKeyValueHash(currentHash);
|
1025
|
+
resolve(query);
|
1026
|
+
});
|
1033
1027
|
}
|
1034
1028
|
|
1035
1029
|
/**
|
@@ -1038,38 +1032,38 @@ function collectSearchQueries() {
|
|
1038
1032
|
* @return {null|Array|undefined|string}
|
1039
1033
|
*/
|
1040
1034
|
function getControlValuesFromLabel(label) {
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1035
|
+
const foundControl = label.firstElementChild;
|
1036
|
+
|
1037
|
+
if (foundControl) {
|
1038
|
+
if (foundControl.tagName === "INPUT") {
|
1039
|
+
if (foundControl.type === "checkbox") {
|
1040
|
+
const checkedControls = label.querySelectorAll(
|
1041
|
+
`${foundControl}:checked`,
|
1042
|
+
);
|
1043
|
+
const values = [];
|
1044
|
+
|
1045
|
+
checkedControls.forEach((checkedControl) => {
|
1046
|
+
values.push(checkedControl.value);
|
1047
|
+
});
|
1048
|
+
|
1049
|
+
return values;
|
1050
|
+
} else if (foundControl.type === "radio") {
|
1051
|
+
const checkedControl = label.querySelector(`${foundControl}:checked`);
|
1052
|
+
|
1053
|
+
if (checkedControl) {
|
1054
|
+
return checkedControl.value;
|
1055
|
+
} else {
|
1056
|
+
return null;
|
1057
|
+
}
|
1058
|
+
} else {
|
1059
|
+
return foundControl.value;
|
1060
|
+
}
|
1061
|
+
} else {
|
1062
|
+
return foundControl.value;
|
1063
|
+
}
|
1064
|
+
}
|
1065
|
+
|
1066
|
+
return null;
|
1073
1067
|
}
|
1074
1068
|
|
1075
1069
|
/**
|
@@ -1077,60 +1071,60 @@ function getControlValuesFromLabel(label) {
|
|
1077
1071
|
* @return {Promise<unknown>}
|
1078
1072
|
*/
|
1079
1073
|
function initFromConfig() {
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1116
|
-
|
1074
|
+
const host = findElementWithSelectorUpwards(this, "monster-host");
|
1075
|
+
|
1076
|
+
if (!(isInstance(host, Host) && this.id)) {
|
1077
|
+
return Promise.resolve();
|
1078
|
+
}
|
1079
|
+
|
1080
|
+
const configKey = getFilterConfigKey.call(this);
|
1081
|
+
|
1082
|
+
return new Promise((resolve, reject) => {
|
1083
|
+
host
|
1084
|
+
.getConfig(configKey)
|
1085
|
+
.then((config) => {
|
1086
|
+
if ((config && isObject(config)) || isArray(config)) {
|
1087
|
+
this[settingsSymbol].setOptions(config);
|
1088
|
+
}
|
1089
|
+
resolve();
|
1090
|
+
})
|
1091
|
+
.catch((error) => {
|
1092
|
+
if (error === undefined) {
|
1093
|
+
resolve();
|
1094
|
+
return;
|
1095
|
+
}
|
1096
|
+
|
1097
|
+
// config not written
|
1098
|
+
if (error?.message?.match(/is not defined/)) {
|
1099
|
+
resolve();
|
1100
|
+
return;
|
1101
|
+
}
|
1102
|
+
|
1103
|
+
addAttributeToken(
|
1104
|
+
this,
|
1105
|
+
ATTRIBUTE_ERRORMESSAGE,
|
1106
|
+
error?.message || error,
|
1107
|
+
);
|
1108
|
+
reject(error);
|
1109
|
+
});
|
1110
|
+
});
|
1117
1111
|
}
|
1118
1112
|
|
1119
1113
|
/**
|
1120
1114
|
* @private
|
1121
1115
|
*/
|
1122
1116
|
function updateConfig() {
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1117
|
+
const host = findElementWithSelectorUpwards(this, "monster-host");
|
1118
|
+
if (!(host && this.id)) {
|
1119
|
+
return;
|
1120
|
+
}
|
1121
|
+
const configKey = getFilterConfigKey.call(this);
|
1122
|
+
|
1123
|
+
try {
|
1124
|
+
host.setConfig(configKey, this[settingsSymbol].getOptions());
|
1125
|
+
} catch (error) {
|
1126
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, error?.message || error);
|
1127
|
+
}
|
1134
1128
|
}
|
1135
1129
|
|
1136
1130
|
/**
|
@@ -1138,8 +1132,8 @@ function updateConfig() {
|
|
1138
1132
|
* @return {string}
|
1139
1133
|
*/
|
1140
1134
|
function getTemplate() {
|
1141
|
-
|
1142
|
-
|
1135
|
+
// language=HTML
|
1136
|
+
return `<div data-monster-role="control" part="control">
|
1143
1137
|
<div data-monster-role="container">
|
1144
1138
|
<div data-monster-role="layout">
|
1145
1139
|
<div data-monster-role="filter">
|