@schukai/monster 3.96.2 → 3.96.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/package.json +1 -1
- package/source/components/datatable/datasource/rest.mjs +33 -10
- package/source/components/datatable/filter.mjs +164 -63
- package/source/components/form/form.mjs +4 -2
- package/source/constants.mjs +14 -1
- package/source/data/extend.mjs +2 -1
- package/source/data/transformer.mjs +2 -0
- package/source/dom/customelement.mjs +7 -3
- package/source/dom/updater.mjs +5 -1
- package/source/monster.mjs +1 -1
- package/source/text/formatter.mjs +5 -3
- package/source/types/is.mjs +13 -0
- package/source/types/proxyobserver.mjs +7 -2
- package/source/types/version.mjs +1 -1
- package/source/util/clone.mjs +9 -14
- package/test/cases/data/pathfinder.mjs +18 -0
- package/test/cases/monster.mjs +1 -1
- package/test/cases/text/formatter.mjs +21 -1
- package/test/web/test.html +2 -2
- package/test/web/tests.js +115 -75
package/CHANGELOG.md
CHANGED
@@ -2,6 +2,16 @@
|
|
2
2
|
|
3
3
|
|
4
4
|
|
5
|
+
## [3.96.3] - 2025-01-03
|
6
|
+
|
7
|
+
### Bug Fixes
|
8
|
+
|
9
|
+
- optimize the filter rest api pipeline [#274](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/274) [#241](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/241)
|
10
|
+
- update undefined handling [#275](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/275)
|
11
|
+
- repair some small issues [#274](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/274)
|
12
|
+
|
13
|
+
|
14
|
+
|
5
15
|
## [3.96.2] - 2024-12-31
|
6
16
|
|
7
17
|
### Bug Fixes
|
package/package.json
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"author":"schukai GmbH","dependencies":{"@floating-ui/dom":"^1.6.12","@popperjs/core":"^2.11.8"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"3.96.
|
1
|
+
{"author":"schukai GmbH","dependencies":{"@floating-ui/dom":"^1.6.12","@popperjs/core":"^2.11.8"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"3.96.3"}
|
@@ -104,7 +104,7 @@ class Rest extends Datasource {
|
|
104
104
|
* @property {string} templates.main Main template
|
105
105
|
* @property {Object} features Feature definitions
|
106
106
|
* @property {boolean} features.autoInit If true, the component is initialized automatically
|
107
|
-
* @property {boolean} features.filter If true, the
|
107
|
+
* @property {boolean} features.filter If true, the filter.id is used to attach a filter control
|
108
108
|
* @property {Object} autoInit Auto init definitions
|
109
109
|
* @property {boolean} autoInit.intersectionObserver If true, the intersection observer is initialized automatically
|
110
110
|
* @property {boolean} autoInit.oneTime If true, the intersection observer is initialized only once
|
@@ -131,7 +131,7 @@ class Rest extends Datasource {
|
|
131
131
|
|
132
132
|
restOptions.read.parameters = {
|
133
133
|
filter: null,
|
134
|
-
|
134
|
+
orderBy: null,
|
135
135
|
page: "1",
|
136
136
|
};
|
137
137
|
|
@@ -199,7 +199,6 @@ class Rest extends Datasource {
|
|
199
199
|
[assembleMethodSymbol]() {
|
200
200
|
super[assembleMethodSymbol]();
|
201
201
|
initEventHandler.call(this);
|
202
|
-
initAutoInit.call(this);
|
203
202
|
}
|
204
203
|
|
205
204
|
/**
|
@@ -260,6 +259,12 @@ class Rest extends Datasource {
|
|
260
259
|
queueMicrotask(() => {
|
261
260
|
if (this.getOption("features.filter", false) === true) {
|
262
261
|
initFilter.call(this);
|
262
|
+
|
263
|
+
if (!this[filterObserverSymbol]) {
|
264
|
+
initAutoInit.call(this);
|
265
|
+
}
|
266
|
+
} else {
|
267
|
+
initAutoInit.call(this);
|
263
268
|
}
|
264
269
|
});
|
265
270
|
}
|
@@ -286,12 +291,26 @@ class Rest extends Datasource {
|
|
286
291
|
this[dataSourceSymbol].setOption("read", opt);
|
287
292
|
|
288
293
|
let url = this.getOption("read.url");
|
289
|
-
const formatter = new Formatter(this.getOption("read.parameters"));
|
290
|
-
|
291
294
|
if (!url) {
|
292
295
|
return Promise.reject(new Error("No url defined"));
|
293
296
|
}
|
294
297
|
|
298
|
+
const param = this.getOption("read.parameters", {});
|
299
|
+
|
300
|
+
if (param.query === null || param.query === undefined) {
|
301
|
+
param.query = "";
|
302
|
+
}
|
303
|
+
|
304
|
+
if (param.page === null || param.page === undefined) {
|
305
|
+
param.page = "1";
|
306
|
+
}
|
307
|
+
|
308
|
+
if (param.orderBy === null || param.orderBy === undefined) {
|
309
|
+
param.orderBy = "";
|
310
|
+
}
|
311
|
+
|
312
|
+
const formatter = new Formatter(param);
|
313
|
+
|
295
314
|
url = formatter.format(url);
|
296
315
|
|
297
316
|
this[dataSourceSymbol].setOption("read.url", url);
|
@@ -394,23 +413,28 @@ function initFilter() {
|
|
394
413
|
throw new Error("filter feature is enabled but no filter id is defined");
|
395
414
|
|
396
415
|
const filterControl = findElementWithIdUpwards(this, filterID);
|
397
|
-
if (!filterControl)
|
398
|
-
|
416
|
+
if (!filterControl) {
|
417
|
+
addAttributeToken(
|
418
|
+
this,
|
419
|
+
ATTRIBUTE_ERRORMESSAGE,
|
399
420
|
"filter feature is enabled but no filter control with id " +
|
400
421
|
filterID +
|
401
422
|
" is found",
|
402
423
|
);
|
424
|
+
return;
|
425
|
+
}
|
403
426
|
|
404
427
|
this[filterObserverSymbol] = new Observer(() => {
|
405
428
|
const query = filterControl.getOption("query");
|
406
429
|
if (query === undefined) {
|
407
430
|
return;
|
408
431
|
}
|
432
|
+
|
409
433
|
this.setParameters({ query: query });
|
410
434
|
this.fetch()
|
411
435
|
.then((response) => {
|
412
436
|
if (!(response instanceof Response)) {
|
413
|
-
|
437
|
+
return Promise.reject(new Error("response is not a Response object"));
|
414
438
|
}
|
415
439
|
|
416
440
|
if (response?.ok === true) {
|
@@ -565,8 +589,7 @@ function initIntersectionObserver() {
|
|
565
589
|
*/
|
566
590
|
function getTemplate() {
|
567
591
|
// language=HTML
|
568
|
-
return
|
569
|
-
<slot></slot>`;
|
592
|
+
return `<slot></slot>`;
|
570
593
|
}
|
571
594
|
|
572
595
|
registerCustomElement(Rest);
|
@@ -13,7 +13,10 @@
|
|
13
13
|
*/
|
14
14
|
|
15
15
|
import { instanceSymbol } from "../../constants.mjs";
|
16
|
-
import {
|
16
|
+
import {
|
17
|
+
findTargetElementFromEvent,
|
18
|
+
fireCustomEvent,
|
19
|
+
} from "../../dom/events.mjs";
|
17
20
|
import {
|
18
21
|
findElementWithIdUpwards,
|
19
22
|
findElementWithSelectorUpwards,
|
@@ -25,7 +28,6 @@ import {
|
|
25
28
|
registerCustomElement,
|
26
29
|
} from "../../dom/customelement.mjs";
|
27
30
|
import { ID } from "../../types/id.mjs";
|
28
|
-
import { DeadMansSwitch } from "../../util/deadmansswitch.mjs";
|
29
31
|
import { Settings } from "./filter/settings.mjs";
|
30
32
|
import { FilterStyleSheet } from "./stylesheet/filter.mjs";
|
31
33
|
import { getDocument, getWindow } from "../../dom/util.mjs";
|
@@ -54,6 +56,14 @@ import {
|
|
54
56
|
|
55
57
|
import "./filter/select.mjs";
|
56
58
|
|
59
|
+
import "../form/button.mjs";
|
60
|
+
import "../form/select.mjs";
|
61
|
+
import "../form/popper-button.mjs";
|
62
|
+
import "../form/toggle-switch.mjs";
|
63
|
+
import "../form/context-help.mjs";
|
64
|
+
import "../form/context-error.mjs";
|
65
|
+
import "../form/message-state-button.mjs";
|
66
|
+
|
57
67
|
export { Filter };
|
58
68
|
|
59
69
|
/**
|
@@ -130,9 +140,23 @@ const sizeDataSymbol = Symbol("sizeData");
|
|
130
140
|
*/
|
131
141
|
const debounceSizeSymbol = Symbol("debounceSize");
|
132
142
|
|
143
|
+
/**
|
144
|
+
* @private
|
145
|
+
* @type {symbol}
|
146
|
+
*/
|
147
|
+
const hashChangeSymbol = Symbol("hashChange");
|
148
|
+
|
133
149
|
/**
|
134
150
|
* The Filter component is used to show and handle the filter values.
|
135
151
|
*
|
152
|
+
* @fragments /fragments/components/datatable/filter
|
153
|
+
*
|
154
|
+
* @example /examples/components/datatable/filter-simple First filter
|
155
|
+
* @example /examples/components/datatable/filter-advanced Advanced filter
|
156
|
+
* @example /examples/components/datatable/filter-store Store filter
|
157
|
+
*
|
158
|
+
* @issue https://localhost.alvine.dev:8443/development/issues/closed/272.html
|
159
|
+
*
|
136
160
|
* @copyright schukai GmbH
|
137
161
|
* @summary The Filter component is used to show and handle the filter values.
|
138
162
|
*/
|
@@ -143,6 +167,9 @@ class Filter extends CustomElement {
|
|
143
167
|
constructor() {
|
144
168
|
super();
|
145
169
|
this[settingsSymbol] = new Settings();
|
170
|
+
|
171
|
+
// debounce the hash change event if doSearch is called by click the search button
|
172
|
+
this[hashChangeSymbol] = 0;
|
146
173
|
}
|
147
174
|
|
148
175
|
/**
|
@@ -171,7 +198,7 @@ class Filter extends CustomElement {
|
|
171
198
|
|
172
199
|
/**
|
173
200
|
*
|
174
|
-
* @return {
|
201
|
+
* @return {Filter}
|
175
202
|
*/
|
176
203
|
resetFailureMessage() {
|
177
204
|
this[searchButtonElementSymbol].hideMessage();
|
@@ -181,7 +208,7 @@ class Filter extends CustomElement {
|
|
181
208
|
|
182
209
|
/**
|
183
210
|
*
|
184
|
-
* @return {
|
211
|
+
* @return {Filter}
|
185
212
|
*/
|
186
213
|
showSuccess() {
|
187
214
|
this[searchButtonElementSymbol].setState(
|
@@ -210,8 +237,10 @@ class Filter extends CustomElement {
|
|
210
237
|
* @property {Object} formatter.marker Marker definitions
|
211
238
|
* @property {Object} formatter.marker.open Marker open
|
212
239
|
* @property {Object} formatter.marker.close Marker close
|
240
|
+
* @property {Object} features Feature definitions
|
241
|
+
* @property {boolean} features.storedConfig Stored configuration, this replaces the setting `storedConfig.enabled` @since 3.97.0
|
213
242
|
* @property {Object} storedConfig Stored configuration
|
214
|
-
* @property {boolean} storedConfig.enabled
|
243
|
+
* @property {boolean} storedConfig.enabled The store has been enabled, this option will no longer have any effect. @deprecated 20250101
|
215
244
|
* @property {string} storedConfig.selector Selector
|
216
245
|
* @property {Object} timeouts Timeout definitions
|
217
246
|
* @property {number} timeouts.message Message timeout
|
@@ -227,19 +256,23 @@ class Filter extends CustomElement {
|
|
227
256
|
templates: {
|
228
257
|
main: getTemplate(),
|
229
258
|
},
|
259
|
+
|
230
260
|
formatter: {
|
231
261
|
marker: {
|
232
262
|
open: null,
|
233
263
|
close: null,
|
234
264
|
},
|
235
265
|
},
|
266
|
+
|
236
267
|
labels: {
|
237
268
|
search: "Search",
|
238
269
|
reset: "Reset",
|
239
270
|
save: "Save",
|
240
271
|
"filter-name": "Filter name",
|
241
|
-
"empty-query-and-no-default":
|
242
|
-
|
272
|
+
"empty-query-and-no-default":
|
273
|
+
"The query is empty and there is no default query.",
|
274
|
+
"query-not-changed":
|
275
|
+
"The search request has not changed, so no search is required.",
|
243
276
|
},
|
244
277
|
|
245
278
|
templateMapping: {
|
@@ -247,6 +280,10 @@ class Filter extends CustomElement {
|
|
247
280
|
"filter-name-label": name,
|
248
281
|
},
|
249
282
|
|
283
|
+
features: {
|
284
|
+
storedConfig: false,
|
285
|
+
},
|
286
|
+
|
250
287
|
storedConfig: {
|
251
288
|
enabled: true,
|
252
289
|
selector: "",
|
@@ -268,8 +305,8 @@ class Filter extends CustomElement {
|
|
268
305
|
},
|
269
306
|
},
|
270
307
|
|
271
|
-
query:
|
272
|
-
defaultQuery:
|
308
|
+
query: null,
|
309
|
+
defaultQuery: null,
|
273
310
|
eventProcessing: true,
|
274
311
|
});
|
275
312
|
}
|
@@ -284,12 +321,14 @@ class Filter extends CustomElement {
|
|
284
321
|
|
285
322
|
/**
|
286
323
|
* @return {FilterButton}
|
324
|
+
* @fires monster-filter-initialized
|
287
325
|
*/
|
288
326
|
[assembleMethodSymbol]() {
|
289
327
|
this.setOption(
|
290
328
|
"templateMapping.filter-save-label",
|
291
329
|
this.getOption("labels.save"),
|
292
330
|
);
|
331
|
+
|
293
332
|
this.setOption(
|
294
333
|
"templateMapping.filter-name-label",
|
295
334
|
this.getOption("labels.filter-name"),
|
@@ -302,12 +341,19 @@ class Filter extends CustomElement {
|
|
302
341
|
|
303
342
|
initFromConfig
|
304
343
|
.call(this)
|
305
|
-
.then(() => {
|
306
|
-
initFilter.call(this);
|
307
|
-
updateFilterTabs.call(this);
|
308
|
-
})
|
344
|
+
.then(() => {})
|
309
345
|
.catch((error) => {
|
310
346
|
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, error?.message);
|
347
|
+
})
|
348
|
+
.finally(() => {
|
349
|
+
initFilter.call(this);
|
350
|
+
updateFilterTabs.call(this);
|
351
|
+
doSearch
|
352
|
+
.call(this, { showEffect: false })
|
353
|
+
.then(() => {
|
354
|
+
fireCustomEvent(this, "monster-filter-initialized");
|
355
|
+
})
|
356
|
+
.catch(() => {});
|
311
357
|
});
|
312
358
|
}
|
313
359
|
|
@@ -316,7 +362,6 @@ class Filter extends CustomElement {
|
|
316
362
|
*/
|
317
363
|
connectedCallback() {
|
318
364
|
super.connectedCallback();
|
319
|
-
|
320
365
|
getWindow().addEventListener(
|
321
366
|
"hashchange",
|
322
367
|
this[locationChangeHandlerSymbol],
|
@@ -385,10 +430,13 @@ function updateFilterSelections() {
|
|
385
430
|
queueMicrotask(() => {
|
386
431
|
const options = this[settingsSymbol].getOptions();
|
387
432
|
this[filterSelectElementSymbol].setOption("options", options);
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
433
|
+
|
434
|
+
setTimeout(() => {
|
435
|
+
window.requestAnimationFrame(() => {
|
436
|
+
this[filterSelectElementSymbol].value =
|
437
|
+
this[settingsSymbol].getSelected();
|
438
|
+
});
|
439
|
+
}, 0);
|
392
440
|
});
|
393
441
|
}
|
394
442
|
|
@@ -411,7 +459,12 @@ function initFilter() {
|
|
411
459
|
.forEach((element) => {
|
412
460
|
const label = element.getAttribute("data-monster-label");
|
413
461
|
if (!label) {
|
414
|
-
|
462
|
+
addAttributeToken(
|
463
|
+
this,
|
464
|
+
ATTRIBUTE_ERRORMESSAGE,
|
465
|
+
"no filter label is defined",
|
466
|
+
);
|
467
|
+
return;
|
415
468
|
}
|
416
469
|
|
417
470
|
let value = element.id;
|
@@ -448,6 +501,7 @@ function initFilter() {
|
|
448
501
|
|
449
502
|
this[settingsSymbol].set({ value, label, visible });
|
450
503
|
});
|
504
|
+
|
451
505
|
updateFilterSelections.call(this);
|
452
506
|
}
|
453
507
|
|
@@ -499,6 +553,33 @@ function setSlotAttribute(element, visible) {
|
|
499
553
|
*/
|
500
554
|
function initEventHandler() {
|
501
555
|
const self = this;
|
556
|
+
|
557
|
+
let lastHash = getGlobal().location.hash;
|
558
|
+
self[locationChangeHandlerSymbol] = () => {
|
559
|
+
if (lastHash === getGlobal().location.hash) {
|
560
|
+
return;
|
561
|
+
}
|
562
|
+
|
563
|
+
/**
|
564
|
+
* debounce the hash change event if doSearch
|
565
|
+
* is called by click the search button
|
566
|
+
*/
|
567
|
+
if (self[hashChangeSymbol] > 0) {
|
568
|
+
self[hashChangeSymbol]--;
|
569
|
+
return;
|
570
|
+
}
|
571
|
+
|
572
|
+
initFilter.call(this);
|
573
|
+
|
574
|
+
doSearch
|
575
|
+
.call(self)
|
576
|
+
.then(() => {})
|
577
|
+
.catch((error) => {})
|
578
|
+
.finally(() => {
|
579
|
+
lastHash = getGlobal().location.hash;
|
580
|
+
});
|
581
|
+
};
|
582
|
+
|
502
583
|
/**
|
503
584
|
* Monster.Components.Form.event:monster-selection-cleared
|
504
585
|
*/
|
@@ -542,6 +623,7 @@ function initEventHandler() {
|
|
542
623
|
);
|
543
624
|
}
|
544
625
|
|
626
|
+
/** save the current filter */
|
545
627
|
if (self[filterSaveActionButtonElementSymbol]) {
|
546
628
|
self[filterSaveActionButtonElementSymbol].setOption(
|
547
629
|
"actions.click",
|
@@ -641,6 +723,8 @@ function initEventHandler() {
|
|
641
723
|
}
|
642
724
|
|
643
725
|
self[searchButtonElementSymbol].setOption("actions.click", () => {
|
726
|
+
self[hashChangeSymbol] = 1;
|
727
|
+
|
644
728
|
doSearch
|
645
729
|
.call(self)
|
646
730
|
.then(() => {})
|
@@ -684,7 +768,10 @@ function initEventHandler() {
|
|
684
768
|
}
|
685
769
|
|
686
770
|
if (event.keyCode === 13) {
|
687
|
-
doSearch
|
771
|
+
doSearch
|
772
|
+
.call(self, { showEffect: false })
|
773
|
+
.then(() => {})
|
774
|
+
.catch((error) => {});
|
688
775
|
}
|
689
776
|
});
|
690
777
|
|
@@ -696,6 +783,7 @@ function initEventHandler() {
|
|
696
783
|
}
|
697
784
|
|
698
785
|
function initTabEvents() {
|
786
|
+
const self = this;
|
699
787
|
this[filterTabElementSymbol].addEventListener(
|
700
788
|
"monster-tab-changed",
|
701
789
|
(event) => {
|
@@ -836,7 +924,18 @@ function doSearch({ showEffect } = { showEffect: true }) {
|
|
836
924
|
.call(this)
|
837
925
|
.then((query) => {
|
838
926
|
const buildQuery = buildSearchQuery.call(this, query);
|
839
|
-
if (buildQuery ===
|
927
|
+
if (buildQuery === null) {
|
928
|
+
const msg = this.getOption("labels.empty-query-and-no-default");
|
929
|
+
if (showEffect) {
|
930
|
+
this[searchButtonElementSymbol].removeState();
|
931
|
+
this[searchButtonElementSymbol]
|
932
|
+
.setMessage(msg)
|
933
|
+
.showMessage(this.getOption("timeouts.message", 4000));
|
934
|
+
}
|
935
|
+
return Promise.reject(new Error(msg));
|
936
|
+
}
|
937
|
+
|
938
|
+
if (buildQuery === "" && this.getOption("defaultQuery") === null) {
|
840
939
|
const msg = this.getOption("labels.empty-query-and-no-default");
|
841
940
|
|
842
941
|
if (showEffect) {
|
@@ -846,7 +945,7 @@ function doSearch({ showEffect } = { showEffect: true }) {
|
|
846
945
|
.showMessage(this.getOption("timeouts.message", 4000));
|
847
946
|
}
|
848
947
|
|
849
|
-
|
948
|
+
return Promise.reject(new Error(msg));
|
850
949
|
}
|
851
950
|
|
852
951
|
if (buildQuery === this.getOption("query")) {
|
@@ -859,7 +958,7 @@ function doSearch({ showEffect } = { showEffect: true }) {
|
|
859
958
|
.showMessage(this.getOption("timeouts.message", 4000));
|
860
959
|
}
|
861
960
|
|
862
|
-
|
961
|
+
return Promise.reject(new Error(msg));
|
863
962
|
}
|
864
963
|
|
865
964
|
if (showEffect) {
|
@@ -870,6 +969,8 @@ function doSearch({ showEffect } = { showEffect: true }) {
|
|
870
969
|
}
|
871
970
|
|
872
971
|
this.setOption("query", buildSearchQuery.call(this, query));
|
972
|
+
|
973
|
+
return Promise.resolve();
|
873
974
|
})
|
874
975
|
.catch((error) => {
|
875
976
|
if (error instanceof Error) {
|
@@ -945,7 +1046,6 @@ function collectSearchQueries() {
|
|
945
1046
|
return;
|
946
1047
|
}
|
947
1048
|
|
948
|
-
//const visible = window.getComputedStyle(element).display !== "none";
|
949
1049
|
const visible = getVisibilityFromSlotAttribute(element);
|
950
1050
|
if (!visible) {
|
951
1051
|
return;
|
@@ -1136,49 +1236,50 @@ function updateConfig() {
|
|
1136
1236
|
*/
|
1137
1237
|
function getTemplate() {
|
1138
1238
|
// language=HTML
|
1139
|
-
return
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1150
|
-
<monster-select class="stretched-control"
|
1151
|
-
data-monster-selected-template="summary"
|
1152
|
-
data-monster-option-type="checkbox"
|
1153
|
-
data-monster-option-filter-mode="options"
|
1154
|
-
data-monster-option-filter-position="popper"
|
1155
|
-
data-monster-role="filter-select"></monster-select>
|
1156
|
-
<monster-popper-button data-monster-role="save-button" class="stretched-control"
|
1157
|
-
data-monster-attributes="data-monster-visible path:storedConfig.enabled">
|
1158
|
-
<div slot="button">\${filter-save-label}</div>
|
1159
|
-
<div class="monster-form" data-monster-role="form">
|
1160
|
-
|
1161
|
-
<label for="filter-name">\${filter-name-label}
|
1162
|
-
<input name="filter-name"
|
1163
|
-
type="search"
|
1164
|
-
class="monster-margin-bottom-5"></label>
|
1165
|
-
<monster-message-state-button
|
1166
|
-
data-monster-role="save-action-button"
|
1167
|
-
data-monster-option-labels-button="\${filter-save-label}">
|
1239
|
+
return `
|
1240
|
+
<div data-monster-role="control" part="control">
|
1241
|
+
<div data-monster-role="container">
|
1242
|
+
<div data-monster-role="layout">
|
1243
|
+
<div data-monster-role="filter">
|
1244
|
+
<slot></slot>
|
1245
|
+
<slot name="hidden"></slot>
|
1246
|
+
</div>
|
1247
|
+
<div data-monster-role="select-and-search">
|
1248
|
+
<monster-message-state-button data-monster-role="search-button" class="stretched-control"
|
1249
|
+
data-monster-replace="path:labels.search">
|
1168
1250
|
</monster-message-state-button>
|
1169
|
-
|
1251
|
+
<monster-select class="stretched-control"
|
1252
|
+
data-monster-selected-template="summary"
|
1253
|
+
data-monster-option-type="checkbox"
|
1254
|
+
data-monster-option-filter-mode="options"
|
1255
|
+
data-monster-option-filter-position="popper"
|
1256
|
+
data-monster-role="filter-select"></monster-select>
|
1257
|
+
<monster-popper-button data-monster-role="save-button" class="stretched-control"
|
1258
|
+
data-monster-attributes="data-monster-visible path:features.storedConfig">
|
1259
|
+
<div slot="button">\${filter-save-label}</div>
|
1260
|
+
<div class="monster-form" data-monster-role="form">
|
1261
|
+
|
1262
|
+
<label for="filter-name">\${filter-name-label}
|
1263
|
+
<input name="filter-name"
|
1264
|
+
type="search"
|
1265
|
+
class="monster-margin-bottom-5"></label>
|
1266
|
+
<monster-message-state-button
|
1267
|
+
data-monster-role="save-action-button"
|
1268
|
+
data-monster-option-labels-button="\${filter-save-label}">
|
1269
|
+
</monster-message-state-button>
|
1270
|
+
|
1271
|
+
</div>
|
1272
|
+
</monster-popper-button>
|
1273
|
+
<monster-button data-monster-role="reset-button" class="stretched-control"
|
1274
|
+
data-monster-replace="path:labels.reset">
|
1275
|
+
</monster-button>
|
1170
1276
|
</div>
|
1171
|
-
</monster-popper-button>
|
1172
|
-
<monster-button data-monster-role="reset-button" class="stretched-control"
|
1173
|
-
data-monster-replace="path:labels.reset">
|
1174
|
-
</monster-button>
|
1175
|
-
</div>
|
1176
1277
|
|
1278
|
+
</div>
|
1279
|
+
<input class="hidden" name="query" data-monster-role="query"
|
1280
|
+
data-monster-attributes="value path:query">
|
1281
|
+
</div>
|
1177
1282
|
</div>
|
1178
|
-
<input class="hidden" name="query" data-monster-role="query"
|
1179
|
-
data-monster-attributes="value path:query">
|
1180
|
-
</div>
|
1181
|
-
</div>
|
1182
1283
|
`;
|
1183
1284
|
}
|
1184
1285
|
|
@@ -22,6 +22,7 @@ import {
|
|
22
22
|
} from "../../dom/customelement.mjs";
|
23
23
|
import { datasourceLinkedElementSymbol } from "../datatable/util.mjs";
|
24
24
|
import { FormStyleSheet } from "./stylesheet/form.mjs";
|
25
|
+
import { addAttributeToken } from "../../dom/attributes.mjs";
|
25
26
|
|
26
27
|
export { Form };
|
27
28
|
|
@@ -54,7 +55,6 @@ const debounceBindSymbol = Symbol("debounceBind");
|
|
54
55
|
*/
|
55
56
|
class Form extends DataSet {
|
56
57
|
/**
|
57
|
-
*
|
58
58
|
* @property {Object} templates Template definitions
|
59
59
|
* @property {string} templates.main Main template
|
60
60
|
* @property {Object} classes Class definitions
|
@@ -199,7 +199,9 @@ function initEventHandler() {
|
|
199
199
|
|
200
200
|
this[debounceWriteBackSymbol] = new DeadMansSwitch(200, () => {
|
201
201
|
setTimeout(() => {
|
202
|
-
this.write()
|
202
|
+
this.write().catch((e) => {
|
203
|
+
addAttributeToken(this, "error", e.message || `${e}`);
|
204
|
+
});
|
203
205
|
}, 0);
|
204
206
|
});
|
205
207
|
});
|
package/source/constants.mjs
CHANGED
@@ -12,7 +12,12 @@
|
|
12
12
|
* SPDX-License-Identifier: AGPL-3.0
|
13
13
|
*/
|
14
14
|
|
15
|
-
export {
|
15
|
+
export {
|
16
|
+
internalSymbol,
|
17
|
+
internalStateSymbol,
|
18
|
+
instanceSymbol,
|
19
|
+
proxyInstanceMarker,
|
20
|
+
};
|
16
21
|
|
17
22
|
/**
|
18
23
|
* @private
|
@@ -35,3 +40,11 @@ const internalStateSymbol = Symbol.for("@schukai/monster/state");
|
|
35
40
|
* @type {symbol}
|
36
41
|
*/
|
37
42
|
const instanceSymbol = Symbol.for("@schukai/monster/instance");
|
43
|
+
|
44
|
+
/**
|
45
|
+
* @private
|
46
|
+
* @type {symbol}
|
47
|
+
*/
|
48
|
+
const proxyInstanceMarker = Symbol.for(
|
49
|
+
"@schukai/monster/proxy-instance-marker",
|
50
|
+
);
|
package/source/data/extend.mjs
CHANGED
@@ -265,9 +265,11 @@ function transform(value) {
|
|
265
265
|
validateString(value);
|
266
266
|
return value.toUpperCase();
|
267
267
|
|
268
|
+
case "to-string":
|
268
269
|
case "tostring":
|
269
270
|
return `${value}`;
|
270
271
|
|
272
|
+
case "to-integer":
|
271
273
|
case "tointeger":
|
272
274
|
const n = parseInt(value);
|
273
275
|
validateInteger(n);
|
@@ -610,9 +610,13 @@ class CustomElement extends HTMLElement {
|
|
610
610
|
nodeList = elements;
|
611
611
|
}
|
612
612
|
|
613
|
-
|
614
|
-
this[
|
615
|
-
|
613
|
+
try {
|
614
|
+
this[updateCloneDataSymbol] = clone(
|
615
|
+
this[internalSymbol].getRealSubject()["options"],
|
616
|
+
);
|
617
|
+
} catch (e) {
|
618
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e?.messages || `${e}`);
|
619
|
+
}
|
616
620
|
|
617
621
|
const cfg = {};
|
618
622
|
if (this.getOption("eventProcessing") === true) {
|
package/source/dom/updater.mjs
CHANGED
@@ -307,7 +307,11 @@ function getControlEventHandler() {
|
|
307
307
|
}
|
308
308
|
|
309
309
|
queueMicrotask(() => {
|
310
|
-
|
310
|
+
try {
|
311
|
+
retrieveAndSetValue.call(this, element);
|
312
|
+
} catch (e) {
|
313
|
+
addAttributeToken(element, ATTRIBUTE_ERRORMESSAGE, e.message || `${e}`);
|
314
|
+
}
|
311
315
|
});
|
312
316
|
};
|
313
317
|
|