@schukai/monster 3.95.2 → 3.96.0
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 +14 -0
- package/package.json +1 -1
- package/source/components/datatable/dataset.mjs +23 -19
- package/source/components/datatable/datasource/dom.mjs +4 -6
- package/source/components/datatable/datasource/rest.mjs +469 -471
- package/source/components/datatable/datasource.mjs +0 -8
- package/source/components/datatable/pagination.mjs +433 -439
- package/source/components/datatable/status.mjs +1 -3
- package/source/components/datatable/stylesheet/pagination.mjs +13 -6
- package/source/components/datatable/util.mjs +1 -1
- package/source/components/form/select.mjs +1 -1
- package/source/components/form/toggle-switch.mjs +2 -6
- package/source/components/layout/tabs.mjs +897 -895
- package/source/components/notify/message.mjs +10 -14
- package/source/components/notify/notify.mjs +9 -13
- package/source/components/notify/stylesheet/notify.mjs +13 -6
- package/source/components/state/log.mjs +184 -184
- package/source/components/state/stylesheet/log.mjs +13 -6
- package/source/data/datasource/server/restapi.mjs +2 -3
- package/source/data/transformer.mjs +803 -806
- package/source/dom/customelement.mjs +0 -34
- package/source/dom/updater.mjs +767 -767
- package/source/i18n/time-ago.mjs +1352 -636
- package/source/monster.mjs +2 -0
- package/source/types/has.mjs +3 -6
- package/source/types/version.mjs +1 -1
- package/test/cases/components/form/form.mjs +166 -125
- package/test/cases/monster.mjs +1 -1
- package/test/web/import.js +1 -0
- package/test/web/test.html +2 -2
- package/test/web/tests.js +2080 -1433
@@ -12,27 +12,27 @@
|
|
12
12
|
* SPDX-License-Identifier: AGPL-3.0
|
13
13
|
*/
|
14
14
|
|
15
|
-
import {diff} from "../../../data/diff.mjs";
|
16
|
-
import {addAttributeToken} from "../../../dom/attributes.mjs";
|
17
|
-
import {ATTRIBUTE_ERRORMESSAGE} from "../../../dom/constants.mjs";
|
18
|
-
import {isArray} from "../../../types/is.mjs";
|
19
|
-
import {Datasource, dataSourceSymbol} from "../datasource.mjs";
|
20
|
-
import {DatasourceStyleSheet} from "../stylesheet/datasource.mjs";
|
21
|
-
import {instanceSymbol} from "../../../constants.mjs";
|
15
|
+
import { diff } from "../../../data/diff.mjs";
|
16
|
+
import { addAttributeToken } from "../../../dom/attributes.mjs";
|
17
|
+
import { ATTRIBUTE_ERRORMESSAGE } from "../../../dom/constants.mjs";
|
18
|
+
import { isArray } from "../../../types/is.mjs";
|
19
|
+
import { Datasource, dataSourceSymbol } from "../datasource.mjs";
|
20
|
+
import { DatasourceStyleSheet } from "../stylesheet/datasource.mjs";
|
21
|
+
import { instanceSymbol } from "../../../constants.mjs";
|
22
22
|
import {
|
23
|
-
|
24
|
-
|
23
|
+
assembleMethodSymbol,
|
24
|
+
registerCustomElement,
|
25
25
|
} from "../../../dom/customelement.mjs";
|
26
|
-
import {RestAPI} from "../../../data/datasource/server/restapi.mjs";
|
27
|
-
import {Formatter} from "../../../text/formatter.mjs";
|
28
|
-
import {clone} from "../../../util/clone.mjs";
|
29
|
-
import {validateBoolean} from "../../../types/validate.mjs";
|
30
|
-
import {findElementWithIdUpwards} from "../../../dom/util.mjs";
|
31
|
-
import {Observer} from "../../../types/observer.mjs";
|
32
|
-
import {Pathfinder} from "../../../data/pathfinder.mjs";
|
33
|
-
import {fireCustomEvent} from "../../../dom/events.mjs";
|
26
|
+
import { RestAPI } from "../../../data/datasource/server/restapi.mjs";
|
27
|
+
import { Formatter } from "../../../text/formatter.mjs";
|
28
|
+
import { clone } from "../../../util/clone.mjs";
|
29
|
+
import { validateBoolean } from "../../../types/validate.mjs";
|
30
|
+
import { findElementWithIdUpwards } from "../../../dom/util.mjs";
|
31
|
+
import { Observer } from "../../../types/observer.mjs";
|
32
|
+
import { Pathfinder } from "../../../data/pathfinder.mjs";
|
33
|
+
import { fireCustomEvent } from "../../../dom/events.mjs";
|
34
34
|
|
35
|
-
export {Rest};
|
35
|
+
export { Rest };
|
36
36
|
|
37
37
|
/**
|
38
38
|
* @private
|
@@ -46,7 +46,7 @@ const intersectionObserverHandlerSymbol = Symbol("intersectionObserverHandler");
|
|
46
46
|
* @type {symbol}
|
47
47
|
*/
|
48
48
|
const rawDataSymbol = Symbol.for(
|
49
|
-
|
49
|
+
"@schukai/monster/data/datasource/server/restapi/rawdata",
|
50
50
|
);
|
51
51
|
|
52
52
|
/**
|
@@ -54,7 +54,7 @@ const rawDataSymbol = Symbol.for(
|
|
54
54
|
* @type {symbol}
|
55
55
|
*/
|
56
56
|
const intersectionObserverObserverSymbol = Symbol(
|
57
|
-
|
57
|
+
"intersectionObserverObserver",
|
58
58
|
);
|
59
59
|
|
60
60
|
/**
|
@@ -78,413 +78,412 @@ const filterObserverSymbol = Symbol("filterObserver");
|
|
78
78
|
* @summary A rest api datasource for the datatable or other components
|
79
79
|
*/
|
80
80
|
class Rest extends Datasource {
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
81
|
+
/**
|
82
|
+
* the constructor of the class
|
83
|
+
*/
|
84
|
+
constructor() {
|
85
|
+
super();
|
86
|
+
this[dataSourceSymbol] = new RestAPI();
|
87
|
+
}
|
88
|
+
|
89
|
+
/**
|
90
|
+
* This method is called by the `instanceof` operator.
|
91
|
+
* @return {symbol}
|
92
|
+
*/
|
93
|
+
static get [instanceSymbol]() {
|
94
|
+
return Symbol.for("@schukai/monster/components/datasource/rest@@instance");
|
95
|
+
}
|
96
|
+
|
97
|
+
/**
|
98
|
+
* To set the options via the HTML tag, the attribute `data-monster-options` must be used.
|
99
|
+
* @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
|
100
|
+
*
|
101
|
+
* The individual configuration values can be found in the table.
|
102
|
+
*
|
103
|
+
* @property {Object} templates Template definitions
|
104
|
+
* @property {string} templates.main Main template
|
105
|
+
* @property {Object} features Feature definitions
|
106
|
+
* @property {boolean} features.autoInit If true, the component is initialized automatically
|
107
|
+
* @property {boolean} features.filter If true, the component is initialized automatically
|
108
|
+
* @property {Object} autoInit Auto init definitions
|
109
|
+
* @property {boolean} autoInit.intersectionObserver If true, the intersection observer is initialized automatically
|
110
|
+
* @property {boolean} autoInit.oneTime If true, the intersection observer is initialized only once
|
111
|
+
* @property {Object} filter Filter definitions
|
112
|
+
* @property {string} filter.id The id of the filter control
|
113
|
+
* @property {Object} response Response definitions
|
114
|
+
* @property {Object} response.path Path definitions (changed in 3.56.0)
|
115
|
+
* @property {string} response.path.message Path to the message (changed in 3.56.0)
|
116
|
+
* @property {Object} read Read configuration
|
117
|
+
* @property {string} read.url The url of the rest api
|
118
|
+
* @property {string} read.method The method of the rest api
|
119
|
+
* @property {Object} read.parameters The parameters of the rest api
|
120
|
+
* @property {Object} read.parameters.filter The filter of the rest api
|
121
|
+
* @property {Object} read.parameters.orderBy The order by of the rest api
|
122
|
+
* @property {Object} read.parameters.page The page of the rest api
|
123
|
+
* @property {string} read.mapping.currentPage The current page
|
124
|
+
* @property {Object} write Write configuration
|
125
|
+
* @property {string} write.url The url of the rest api
|
126
|
+
* @property {string} write.method The method of the rest api
|
127
|
+
* @property {Object} write Write configuration
|
128
|
+
*/
|
129
|
+
get defaults() {
|
130
|
+
const restOptions = new RestAPI().defaults;
|
131
|
+
|
132
|
+
restOptions.read.parameters = {
|
133
|
+
filter: null,
|
134
|
+
oderBy: null,
|
135
|
+
page: "1",
|
136
|
+
};
|
137
|
+
|
138
|
+
restOptions.read.mapping.currentPage = "sys.pagination.currentPage";
|
139
|
+
|
140
|
+
return Object.assign({}, super.defaults, restOptions, {
|
141
|
+
templates: {
|
142
|
+
main: getTemplate(),
|
143
|
+
},
|
144
|
+
|
145
|
+
features: {
|
146
|
+
autoInit: false,
|
147
|
+
filter: false,
|
148
|
+
},
|
149
|
+
|
150
|
+
autoInit: {
|
151
|
+
intersectionObserver: false,
|
152
|
+
oneTime: true,
|
153
|
+
},
|
154
|
+
|
155
|
+
filter: {
|
156
|
+
id: null,
|
157
|
+
},
|
158
|
+
|
159
|
+
/*datatable: {
|
160
160
|
id: undefined, // not used?
|
161
161
|
}, */
|
162
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
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
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
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
163
|
+
response: {
|
164
|
+
path: {
|
165
|
+
message: "sys.message",
|
166
|
+
code: "sys.code",
|
167
|
+
},
|
168
|
+
},
|
169
|
+
});
|
170
|
+
}
|
171
|
+
|
172
|
+
/**
|
173
|
+
* With this method, you can set the parameters for the rest api. The parameters are
|
174
|
+
* used for building the url.
|
175
|
+
*
|
176
|
+
* @param {string} page
|
177
|
+
* @param {string} query
|
178
|
+
* @param {string} orderBy
|
179
|
+
* @return {Rest}
|
180
|
+
*/
|
181
|
+
setParameters({ page, query, orderBy }) {
|
182
|
+
const parameters = this.getOption("read.parameters");
|
183
|
+
if (query !== undefined) {
|
184
|
+
parameters.query = `${query}`;
|
185
|
+
parameters.page = "1";
|
186
|
+
}
|
187
|
+
|
188
|
+
// after a query the page is set to 1, so if the page is not set, it is set to 1
|
189
|
+
if (page !== undefined) parameters.page = `${page}`;
|
190
|
+
if (orderBy !== undefined) parameters.order = `${orderBy}`;
|
191
|
+
this.setOption("read.parameters", parameters);
|
192
|
+
return this;
|
193
|
+
}
|
194
|
+
|
195
|
+
/**
|
196
|
+
* @private
|
197
|
+
* @return {void}
|
198
|
+
*/
|
199
|
+
[assembleMethodSymbol]() {
|
200
|
+
super[assembleMethodSymbol]();
|
201
|
+
initEventHandler.call(this);
|
202
|
+
initAutoInit.call(this);
|
203
|
+
}
|
204
|
+
|
205
|
+
/**
|
206
|
+
* This method reloads the data from the rest api, this method is deprecated.
|
207
|
+
* You should use the method `read` instead.
|
208
|
+
*
|
209
|
+
* @deprecated 2023-06-25
|
210
|
+
* @return {Promise<never>|*}
|
211
|
+
*/
|
212
|
+
reload() {
|
213
|
+
return this.read();
|
214
|
+
}
|
215
|
+
|
216
|
+
/**
|
217
|
+
* Fetches the data from the rest api, this method is deprecated.
|
218
|
+
* You should use the method `read` instead.
|
219
|
+
*
|
220
|
+
* @deprecated 2024-12-24
|
221
|
+
* @return {Promise<never>|*}
|
222
|
+
*/
|
223
|
+
fetch() {
|
224
|
+
return this.read();
|
225
|
+
}
|
226
|
+
|
227
|
+
/**
|
228
|
+
*
|
229
|
+
* @return {CSSStyleSheet[]}
|
230
|
+
*/
|
231
|
+
static getCSSStyleSheet() {
|
232
|
+
return [DatasourceStyleSheet];
|
233
|
+
}
|
234
|
+
|
235
|
+
/**
|
236
|
+
* @private
|
237
|
+
* @return {string}
|
238
|
+
*/
|
239
|
+
static getTag() {
|
240
|
+
return "monster-datasource-rest";
|
241
|
+
}
|
242
|
+
|
243
|
+
/**
|
244
|
+
* This method activates the intersection observer manually.
|
245
|
+
* For this purpose, the option `autoInit.intersectionObserver` must be set to `false`.
|
246
|
+
*
|
247
|
+
* @return {Rest}
|
248
|
+
*/
|
249
|
+
initIntersectionObserver() {
|
250
|
+
initIntersectionObserver.call(this);
|
251
|
+
return this;
|
252
|
+
}
|
253
|
+
|
254
|
+
/**
|
255
|
+
* @private
|
256
|
+
*/
|
257
|
+
connectedCallback() {
|
258
|
+
super.connectedCallback();
|
259
|
+
|
260
|
+
queueMicrotask(() => {
|
261
|
+
if (this.getOption("features.filter", false) === true) {
|
262
|
+
initFilter.call(this);
|
263
|
+
}
|
264
|
+
});
|
265
|
+
}
|
266
|
+
|
267
|
+
/**
|
268
|
+
* @private
|
269
|
+
*/
|
270
|
+
disconnectedCallback() {
|
271
|
+
super.disconnectedCallback();
|
272
|
+
removeFilter.call(this);
|
273
|
+
}
|
274
|
+
|
275
|
+
/**
|
276
|
+
* This method reads the data from the rest api.
|
277
|
+
* The data is stored in the internal dataset object.
|
278
|
+
*
|
279
|
+
* @return {Promise}
|
280
|
+
* @fires monster-datasource-fetch
|
281
|
+
* @fires monster-datasource-fetched
|
282
|
+
* @fires monster-datasource-error
|
283
|
+
*/
|
284
|
+
read() {
|
285
|
+
const opt = clone(this.getOption("read"));
|
286
|
+
this[dataSourceSymbol].setOption("read", opt);
|
287
|
+
|
288
|
+
let url = this.getOption("read.url");
|
289
|
+
const formatter = new Formatter(this.getOption("read.parameters"));
|
290
|
+
|
291
|
+
if (!url) {
|
292
|
+
return Promise.reject(new Error("No url defined"));
|
293
|
+
}
|
294
|
+
|
295
|
+
url = formatter.format(url);
|
296
|
+
|
297
|
+
this[dataSourceSymbol].setOption("read.url", url);
|
298
|
+
|
299
|
+
return new Promise((resolve, reject) => {
|
300
|
+
fireCustomEvent(this, "monster-datasource-fetch", {
|
301
|
+
datasource: this,
|
302
|
+
});
|
303
|
+
|
304
|
+
queueMicrotask(() => {
|
305
|
+
this[dataSourceSymbol]
|
306
|
+
.read()
|
307
|
+
.then((response) => {
|
308
|
+
fireCustomEvent(this, "monster-datasource-fetched", {
|
309
|
+
datasource: this,
|
310
|
+
});
|
311
|
+
|
312
|
+
resolve(response);
|
313
|
+
})
|
314
|
+
.catch((error) => {
|
315
|
+
fireCustomEvent(this, "monster-datasource-error", {
|
316
|
+
error: error,
|
317
|
+
});
|
318
|
+
|
319
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, error.toString());
|
320
|
+
reject(error);
|
321
|
+
});
|
322
|
+
});
|
323
|
+
});
|
324
|
+
}
|
325
|
+
|
326
|
+
/**
|
327
|
+
* Fetches the data from the rest api.
|
328
|
+
* @return {Promise}
|
329
|
+
*/
|
330
|
+
write() {
|
331
|
+
const opt = clone(this.getOption("write"));
|
332
|
+
this[dataSourceSymbol].setOption("write", opt);
|
333
|
+
|
334
|
+
let url = this.getOption("write.url");
|
335
|
+
const formatter = new Formatter(this.getOption("write.parameters"));
|
336
|
+
|
337
|
+
if (!url) {
|
338
|
+
return Promise.reject(new Error("No url defined"));
|
339
|
+
}
|
340
|
+
|
341
|
+
url = formatter.format(url);
|
342
|
+
|
343
|
+
this[dataSourceSymbol].setOption("write.url", url);
|
344
|
+
|
345
|
+
return new Promise((resolve, reject) => {
|
346
|
+
fireCustomEvent(this, "monster-datasource-fetch", {
|
347
|
+
datasource: this,
|
348
|
+
});
|
349
|
+
|
350
|
+
queueMicrotask(() => {
|
351
|
+
this[dataSourceSymbol]
|
352
|
+
.write()
|
353
|
+
.then((response) => {
|
354
|
+
fireCustomEvent(this, "monster-datasource-fetched", {
|
355
|
+
datasource: this,
|
356
|
+
});
|
357
|
+
|
358
|
+
resolve(response);
|
359
|
+
})
|
360
|
+
.catch((error) => {
|
361
|
+
fireCustomEvent(this, "monster-datasource-error", {
|
362
|
+
error: error,
|
363
|
+
});
|
364
|
+
|
365
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, error.toString());
|
366
|
+
reject(error);
|
367
|
+
});
|
368
|
+
});
|
369
|
+
});
|
370
|
+
}
|
371
|
+
|
372
|
+
// /**
|
373
|
+
// * @return {int}
|
374
|
+
// */
|
375
|
+
// currentPage() {
|
376
|
+
//
|
377
|
+
// const key = this.getOption("read.mapping.currentPage")
|
378
|
+
// if (key === undefined) {
|
379
|
+
// return 1;
|
380
|
+
// }
|
381
|
+
//
|
382
|
+
// const pf = new Pathfinder(this.data);
|
383
|
+
// if (pf.exists(key)) {
|
384
|
+
// return parseInt(pf.getVia(key), 10);
|
385
|
+
// }
|
386
|
+
//
|
387
|
+
// return 1;
|
388
|
+
//
|
389
|
+
// }
|
391
390
|
}
|
392
391
|
|
393
392
|
/**
|
394
393
|
* @private
|
395
394
|
*/
|
396
395
|
function removeFilter() {
|
397
|
-
|
398
|
-
|
396
|
+
const filterID = this.getOption("filter.id", undefined);
|
397
|
+
if (!filterID) return;
|
399
398
|
|
400
|
-
|
399
|
+
const filterControl = findElementWithIdUpwards(this, filterID);
|
401
400
|
|
402
|
-
|
403
|
-
|
404
|
-
|
401
|
+
if (filterControl && this[filterObserverSymbol]) {
|
402
|
+
filterControl?.detachObserver(this[filterObserverSymbol]);
|
403
|
+
}
|
405
404
|
}
|
406
405
|
|
407
406
|
/**
|
408
407
|
* @private
|
409
408
|
*/
|
410
409
|
function initFilter() {
|
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
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
410
|
+
const filterID = this.getOption("filter.id", undefined);
|
411
|
+
|
412
|
+
if (!filterID)
|
413
|
+
throw new Error("filter feature is enabled but no filter id is defined");
|
414
|
+
|
415
|
+
const filterControl = findElementWithIdUpwards(this, filterID);
|
416
|
+
if (!filterControl)
|
417
|
+
throw new Error(
|
418
|
+
"filter feature is enabled but no filter control with id " +
|
419
|
+
filterID +
|
420
|
+
" is found",
|
421
|
+
);
|
422
|
+
|
423
|
+
this[filterObserverSymbol] = new Observer(() => {
|
424
|
+
const query = filterControl.getOption("query");
|
425
|
+
if (query === undefined) {
|
426
|
+
return;
|
427
|
+
}
|
428
|
+
this.setParameters({ query: query });
|
429
|
+
this.fetch()
|
430
|
+
.then((response) => {
|
431
|
+
if (!(response instanceof Response)) {
|
432
|
+
throw new Error("Response is not an instance of Response");
|
433
|
+
}
|
434
|
+
|
435
|
+
if (response?.ok === true) {
|
436
|
+
this.dispatchEvent(new CustomEvent("reload", { bubbles: true }));
|
437
|
+
filterControl?.showSuccess();
|
438
|
+
}
|
439
|
+
|
440
|
+
if (response.bodyUsed === true) {
|
441
|
+
return handleIntersectionObserver.call(
|
442
|
+
this,
|
443
|
+
response[rawDataSymbol],
|
444
|
+
response,
|
445
|
+
filterControl,
|
446
|
+
);
|
447
|
+
}
|
448
|
+
|
449
|
+
response
|
450
|
+
.text()
|
451
|
+
.then((jsonAsText) => {
|
452
|
+
let json;
|
453
|
+
try {
|
454
|
+
json = JSON.parse(jsonAsText);
|
455
|
+
} catch (e) {
|
456
|
+
const message = e instanceof Error ? e.message : `${e}`;
|
457
|
+
filterControl?.showFailureMessage(message);
|
458
|
+
return Promise.reject(e);
|
459
|
+
}
|
460
|
+
|
461
|
+
return handleIntersectionObserver.call(
|
462
|
+
this,
|
463
|
+
json,
|
464
|
+
response,
|
465
|
+
filterControl,
|
466
|
+
);
|
467
|
+
})
|
468
|
+
.catch((e) => {
|
469
|
+
filterControl?.showFailureMessage(e.message);
|
470
|
+
});
|
471
|
+
})
|
472
|
+
.catch((e) => {
|
473
|
+
this.dispatchEvent(
|
474
|
+
new CustomEvent("error", { bubbles: true, detail: e }),
|
475
|
+
);
|
476
|
+
|
477
|
+
if (!(e instanceof Error)) {
|
478
|
+
e = new Error(e);
|
479
|
+
}
|
480
|
+
|
481
|
+
filterControl?.showFailureMessage(e.message);
|
482
|
+
return Promise.reject(e);
|
483
|
+
});
|
484
|
+
});
|
485
|
+
|
486
|
+
filterControl.attachObserver(this[filterObserverSymbol]);
|
488
487
|
}
|
489
488
|
|
490
489
|
/**
|
@@ -495,89 +494,88 @@ function initFilter() {
|
|
495
494
|
* @returns {Promise<never>|Promise<Awaited<unknown>>}
|
496
495
|
*/
|
497
496
|
function handleIntersectionObserver(json, response, filterControl) {
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
497
|
+
const path = new Pathfinder(json);
|
498
|
+
|
499
|
+
const codePath = this.getOption("response.path.code");
|
500
|
+
|
501
|
+
if (path.exists(codePath)) {
|
502
|
+
const code = `${path.getVia(codePath)}`;
|
503
|
+
if (code && code === "200") {
|
504
|
+
filterControl?.showSuccess();
|
505
|
+
return Promise.resolve(response);
|
506
|
+
}
|
507
|
+
|
508
|
+
const messagePath = this.getOption("response.path.message");
|
509
|
+
if (path.exists(messagePath)) {
|
510
|
+
const message = path.getVia(messagePath);
|
511
|
+
filterControl?.showFailureMessage(message);
|
512
|
+
return Promise.reject(new Error(message));
|
513
|
+
}
|
514
|
+
|
515
|
+
return Promise.reject(new Error("Response code is not 200"));
|
516
|
+
}
|
518
517
|
}
|
519
518
|
|
520
519
|
/**
|
521
520
|
* @private
|
522
521
|
*/
|
523
522
|
function initAutoInit() {
|
524
|
-
|
525
|
-
|
523
|
+
const autoInit = this.getOption("features.autoInit");
|
524
|
+
validateBoolean(autoInit);
|
526
525
|
|
527
|
-
|
526
|
+
if (autoInit !== true) return;
|
528
527
|
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
528
|
+
if (this.getOption("autoInit.intersectionObserver") === true) {
|
529
|
+
initIntersectionObserver.call(this);
|
530
|
+
return;
|
531
|
+
}
|
533
532
|
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
});
|
533
|
+
queueMicrotask(() => {
|
534
|
+
this.fetch().catch(() => {});
|
535
|
+
});
|
538
536
|
}
|
539
537
|
|
540
538
|
/**
|
541
539
|
* @private
|
542
540
|
*/
|
543
541
|
function initEventHandler() {
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
542
|
+
this[intersectionObserverHandlerSymbol] = (entries) => {
|
543
|
+
entries.forEach((entry) => {
|
544
|
+
if (entry.isIntersecting) {
|
545
|
+
if (entry.intersectionRatio > 0) {
|
546
|
+
this.fetch();
|
547
|
+
}
|
548
|
+
|
549
|
+
// only load once
|
550
|
+
if (
|
551
|
+
this.getOption("autoInit.oneTime") === true &&
|
552
|
+
this[intersectionObserverObserverSymbol] !== undefined
|
553
|
+
) {
|
554
|
+
this[intersectionObserverObserverSymbol].unobserve(this);
|
555
|
+
}
|
556
|
+
}
|
557
|
+
});
|
558
|
+
};
|
561
559
|
}
|
562
560
|
|
563
561
|
/**
|
564
562
|
* @private
|
565
563
|
*/
|
566
564
|
function initIntersectionObserver() {
|
567
|
-
|
565
|
+
this.classList.add("intersection-observer");
|
568
566
|
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
567
|
+
const options = {
|
568
|
+
root: null,
|
569
|
+
rootMargin: "0px",
|
570
|
+
threshold: 0.1,
|
571
|
+
};
|
574
572
|
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
573
|
+
this[intersectionObserverObserverSymbol] = new IntersectionObserver(
|
574
|
+
this[intersectionObserverHandlerSymbol],
|
575
|
+
options,
|
576
|
+
);
|
579
577
|
|
580
|
-
|
578
|
+
this[intersectionObserverObserverSymbol].observe(this);
|
581
579
|
}
|
582
580
|
|
583
581
|
/**
|
@@ -585,8 +583,8 @@ function initIntersectionObserver() {
|
|
585
583
|
* @return {string}
|
586
584
|
*/
|
587
585
|
function getTemplate() {
|
588
|
-
|
589
|
-
|
586
|
+
// language=HTML
|
587
|
+
return `
|
590
588
|
<slot></slot>`;
|
591
589
|
}
|
592
590
|
|