@schukai/monster 3.95.1 → 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.
Files changed (34) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/package.json +1 -1
  3. package/source/components/datatable/dataset.mjs +331 -305
  4. package/source/components/datatable/datasource/dom.mjs +35 -1
  5. package/source/components/datatable/datasource/rest.mjs +99 -69
  6. package/source/components/datatable/datasource.mjs +15 -15
  7. package/source/components/datatable/embedded-pagination.mjs +11 -0
  8. package/source/components/datatable/pagination.mjs +41 -25
  9. package/source/components/datatable/status.mjs +1 -3
  10. package/source/components/datatable/style/pagination.pcss +2 -2
  11. package/source/components/datatable/stylesheet/pagination.mjs +1 -1
  12. package/source/components/datatable/util.mjs +2 -1
  13. package/source/components/form/select.mjs +1 -1
  14. package/source/components/form/toggle-switch.mjs +2 -6
  15. package/source/components/host/config-manager.mjs +1 -3
  16. package/source/components/layout/tabs.mjs +897 -895
  17. package/source/components/notify/message.mjs +10 -14
  18. package/source/components/notify/notify.mjs +9 -13
  19. package/source/components/notify/stylesheet/notify.mjs +13 -6
  20. package/source/components/state/log.mjs +184 -184
  21. package/source/components/state/stylesheet/log.mjs +13 -6
  22. package/source/data/datasource/server/restapi.mjs +22 -16
  23. package/source/data/datasource/server.mjs +1 -0
  24. package/source/data/transformer.mjs +803 -806
  25. package/source/dom/updater.mjs +767 -767
  26. package/source/i18n/time-ago.mjs +1352 -636
  27. package/source/monster.mjs +2 -0
  28. package/source/types/has.mjs +26 -0
  29. package/source/types/version.mjs +1 -1
  30. package/test/cases/components/form/form.mjs +166 -125
  31. package/test/cases/monster.mjs +1 -1
  32. package/test/web/import.js +1 -0
  33. package/test/web/test.html +2 -2
  34. package/test/web/tests.js +2080 -1433
@@ -53,6 +53,8 @@ class Dom extends Datasource {
53
53
  *
54
54
  * @property {Object} templates Template definitions
55
55
  * @property {string} templates.main Main template
56
+ * @property {Object} features Feature definitions
57
+ * @property {boolean} features.autoInit Automatically initializes the component
56
58
  */
57
59
  get defaults() {
58
60
  return Object.assign({}, super.defaults, {
@@ -63,11 +65,19 @@ class Dom extends Datasource {
63
65
  features: {
64
66
  autoInit: true,
65
67
  },
68
+
69
+ /** @private */
70
+ sys: {
71
+ pagination: {
72
+ pages: 1,
73
+ objectsPerPage: 10,
74
+ currentPage: 1,
75
+ },
76
+ },
66
77
  });
67
78
  }
68
79
 
69
80
  /**
70
- *
71
81
  * @return {void}
72
82
  */
73
83
  [assembleMethodSymbol]() {
@@ -76,6 +86,17 @@ class Dom extends Datasource {
76
86
  updateDataSource.call(this);
77
87
  }
78
88
 
89
+ /**
90
+ * This method set the current page of the pagination
91
+ *
92
+ * @param {string} page
93
+ * @return {Dom}
94
+ */
95
+ setParameters({ page }) {
96
+ this.setOption("sys.pagination.currentPage", page);
97
+ return this;
98
+ }
99
+
79
100
  /**
80
101
  *
81
102
  * @return {CSSStyleSheet[]}
@@ -108,6 +129,13 @@ class Dom extends Datasource {
108
129
  updateDataSource.call(this);
109
130
  }
110
131
  }
132
+
133
+ /**
134
+ * @return {int}
135
+ */
136
+ currentPage() {
137
+ return this.getOption("sys.pagination.currentPage");
138
+ }
111
139
  }
112
140
 
113
141
  /**
@@ -170,6 +198,12 @@ function updateDataSource() {
170
198
  data = [];
171
199
  }
172
200
 
201
+ // set pagination
202
+ this.setOption("sys.pagination.objectsPerPage", 1);
203
+ this.setOption("sys.pagination.pages", data.length);
204
+ this.setOption("sys.pagination.currentPage", 1);
205
+
206
+ /** call setter */
173
207
  this.data = data;
174
208
  }
175
209
 
@@ -64,26 +64,19 @@ const intersectionObserverObserverSymbol = Symbol(
64
64
  const filterObserverSymbol = Symbol("filterObserver");
65
65
 
66
66
  /**
67
- * The Datasource component is a basic class for the datatable component.
67
+ * A rest api datasource
68
68
  *
69
- * <img src="./images/rest.png">
69
+ * @fragments /fragments/components/datatable/datasource/rest
70
70
  *
71
- * Dependencies: the system uses functions of the [monsterjs](https://monsterjs.org/) library
71
+ * @example /examples/components/datatable/datasource-rest-simple
72
+ * @example /examples/components/datatable/datasource-rest-auto-init
73
+ * @example /examples/components/datatable/datasource-rest-do-fetch
72
74
  *
73
- * @startuml rest.png
74
- * skinparam monochrome true
75
- * skinparam shadowing false
76
- * HTMLElement <|-- CustomElement
77
- * CustomElement <|-- Datasource
78
- * Datasource <|-- Rest
79
- * @enduml
75
+ * @issue https://localhost.alvine.dev:8443/development/issues/closed/272.html
80
76
  *
81
77
  * @copyright schukai GmbH
82
- * @summary A rest api datasource
78
+ * @summary A rest api datasource for the datatable or other components
83
79
  */
84
-
85
-
86
-
87
80
  class Rest extends Datasource {
88
81
  /**
89
82
  * the constructor of the class
@@ -117,8 +110,6 @@ class Rest extends Datasource {
117
110
  * @property {boolean} autoInit.oneTime If true, the intersection observer is initialized only once
118
111
  * @property {Object} filter Filter definitions
119
112
  * @property {string} filter.id The id of the filter control
120
- * @property {Object} datatable Datatable definitions
121
- * @property {string} datatable.id The id of the datatable control
122
113
  * @property {Object} response Response definitions
123
114
  * @property {Object} response.path Path definitions (changed in 3.56.0)
124
115
  * @property {string} response.path.message Path to the message (changed in 3.56.0)
@@ -129,17 +120,23 @@ class Rest extends Datasource {
129
120
  * @property {Object} read.parameters.filter The filter of the rest api
130
121
  * @property {Object} read.parameters.orderBy The order by of the rest api
131
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
132
127
  * @property {Object} write Write configuration
133
128
  */
134
129
  get defaults() {
135
130
  const restOptions = new RestAPI().defaults;
136
131
 
137
132
  restOptions.read.parameters = {
138
- filter: undefined,
139
- oderBy: undefined,
133
+ filter: null,
134
+ oderBy: null,
140
135
  page: "1",
141
136
  };
142
137
 
138
+ restOptions.read.mapping.currentPage = "sys.pagination.currentPage";
139
+
143
140
  return Object.assign({}, super.defaults, restOptions, {
144
141
  templates: {
145
142
  main: getTemplate(),
@@ -156,12 +153,12 @@ class Rest extends Datasource {
156
153
  },
157
154
 
158
155
  filter: {
159
- id: undefined,
156
+ id: null,
160
157
  },
161
158
 
162
- datatable: {
163
- id: undefined,
164
- },
159
+ /*datatable: {
160
+ id: undefined, // not used?
161
+ }, */
165
162
 
166
163
  response: {
167
164
  path: {
@@ -173,6 +170,8 @@ class Rest extends Datasource {
173
170
  }
174
171
 
175
172
  /**
173
+ * With this method, you can set the parameters for the rest api. The parameters are
174
+ * used for building the url.
176
175
  *
177
176
  * @param {string} page
178
177
  * @param {string} query
@@ -194,67 +193,35 @@ class Rest extends Datasource {
194
193
  }
195
194
 
196
195
  /**
196
+ * @private
197
197
  * @return {void}
198
198
  */
199
199
  [assembleMethodSymbol]() {
200
200
  super[assembleMethodSymbol]();
201
-
202
201
  initEventHandler.call(this);
203
202
  initAutoInit.call(this);
204
203
  }
205
204
 
206
205
  /**
206
+ * This method reloads the data from the rest api, this method is deprecated.
207
+ * You should use the method `read` instead.
208
+ *
207
209
  * @deprecated 2023-06-25
208
210
  * @return {Promise<never>|*}
209
211
  */
210
212
  reload() {
211
- return this.fetch();
213
+ return this.read();
212
214
  }
213
215
 
214
216
  /**
215
- * Fetches the data from the rest api
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
216
221
  * @return {Promise<never>|*}
217
222
  */
218
223
  fetch() {
219
- const opt = clone(this.getOption("read"));
220
- this[dataSourceSymbol].setOption("read", opt);
221
-
222
- let url = this.getOption("read.url");
223
- const formatter = new Formatter(this.getOption("read.parameters"));
224
-
225
- if (!url) {
226
- return Promise.reject(new Error("No url defined"));
227
- }
228
-
229
- url = formatter.format(url);
230
-
231
- this[dataSourceSymbol].setOption("read.url", url);
232
-
233
- return new Promise((resolve, reject) => {
234
- fireCustomEvent(this, "monster-datasource-fetch", {
235
- datasource: this,
236
- });
237
-
238
- queueMicrotask(() => {
239
- this[dataSourceSymbol]
240
- .read()
241
- .then((response) => {
242
- fireCustomEvent(this, "monster-datasource-fetched", {
243
- datasource: this,
244
- });
245
-
246
- resolve(response);
247
- })
248
- .catch((error) => {
249
- fireCustomEvent(this, "monster-datasource-error", {
250
- error: error,
251
- });
252
-
253
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, error.toString());
254
- reject(error);
255
- });
256
- });
257
- });
224
+ return this.read();
258
225
  }
259
226
 
260
227
  /**
@@ -277,7 +244,7 @@ class Rest extends Datasource {
277
244
  * This method activates the intersection observer manually.
278
245
  * For this purpose, the option `autoInit.intersectionObserver` must be set to `false`.
279
246
  *
280
- * @return {Monster.Components.Datatable.Datasource.Rest}
247
+ * @return {Rest}
281
248
  */
282
249
  initIntersectionObserver() {
283
250
  initIntersectionObserver.call(this);
@@ -306,15 +273,59 @@ class Rest extends Datasource {
306
273
  }
307
274
 
308
275
  /**
309
- * @return {Promise<never>|*}
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
310
283
  */
311
284
  read() {
312
- return this.fetch();
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
+ });
313
324
  }
314
325
 
315
326
  /**
316
- * Fetches the data from the rest api
317
- * @return {Promise<never>|*}
327
+ * Fetches the data from the rest api.
328
+ * @return {Promise}
318
329
  */
319
330
  write() {
320
331
  const opt = clone(this.getOption("write"));
@@ -357,6 +368,25 @@ class Rest extends Datasource {
357
368
  });
358
369
  });
359
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
+ // }
360
390
  }
361
391
 
362
392
  /**
@@ -30,21 +30,16 @@ const dataSourceSymbol = Symbol.for(
30
30
  );
31
31
 
32
32
  /**
33
- * The Datasource component is a basic class for the datatable component.
33
+ * A datasource
34
34
  *
35
- * <img src="./images/datasource.png">
35
+ * @fragments /fragments/components/datatable/datasource
36
36
  *
37
- * Dependencies: the system uses functions of the [monsterjs](https://monsterjs.org/) library
37
+ * @example /examples/components/datatable/datasource
38
38
  *
39
- * @startuml datasource.png
40
- * skinparam monochrome true
41
- * skinparam shadowing false
42
- * HTMLElement <|-- CustomElement
43
- * CustomElement <|-- Datasource
44
- * @enduml
39
+ * @issue https://localhost.alvine.dev:8443/development/issues/closed/272.html
45
40
  *
46
41
  * @copyright schukai GmbH
47
- * @summary A abstract datasource
42
+ * @summary A generic datasource
48
43
  */
49
44
  class Datasource extends CustomElement {
50
45
  /**
@@ -77,8 +72,7 @@ class Datasource extends CustomElement {
77
72
  }
78
73
 
79
74
  /**
80
- *
81
- * @return {Monster.Components.Form.Form}
75
+ * @return {void}
82
76
  */
83
77
  [assembleMethodSymbol]() {
84
78
  super[assembleMethodSymbol]();
@@ -93,7 +87,7 @@ class Datasource extends CustomElement {
93
87
  }
94
88
 
95
89
  /**
96
- * set the data
90
+ * set the data with proxy
97
91
  * @param {Object} data
98
92
  */
99
93
  set data(data) {
@@ -101,17 +95,23 @@ class Datasource extends CustomElement {
101
95
  }
102
96
 
103
97
  /**
104
- * Get the datasource
105
- * @return {Monster.Data.Datasource}
98
+ * Get the base datasource
99
+ * @return {Datasource}
106
100
  */
107
101
  get datasource() {
108
102
  return this[dataSourceSymbol];
109
103
  }
110
104
 
105
+ /**
106
+ * Wrapper for the write method of the datasource
107
+ */
111
108
  write() {
112
109
  this[dataSourceSymbol].write();
113
110
  }
114
111
 
112
+ /**
113
+ * Wrapper for the read method of the datasource
114
+ */
115
115
  read() {
116
116
  this[dataSourceSymbol].read();
117
117
  }
@@ -42,10 +42,21 @@ class EmbeddedPagination extends Pagination {
42
42
  return Symbol.for("@schukai/monster/components/embedded-pagination");
43
43
  }
44
44
 
45
+ /**
46
+ * @private
47
+ */
45
48
  [assembleMethodSymbol]() {
46
49
  super[assembleMethodSymbol]();
47
50
  }
48
51
 
52
+ /**
53
+ *
54
+ * @property {Object} classes Class definitions
55
+ * @property {string} classes.spinner Spinner class
56
+ * @property {string} classes.spinnerContainer Spinner container class
57
+ * @property {string} classes.error Error class
58
+ * @property {string} classes.errorContainer Error container class
59
+ */
49
60
  get defaults() {
50
61
  return Object.assign({}, super.defaults, {
51
62
  classes: {
@@ -71,7 +71,11 @@ const sizeDataSymbol = Symbol("sizeData");
71
71
  const debounceSizeSymbol = Symbol("debounceSize");
72
72
 
73
73
  /**
74
- * The Pagination component
74
+ * A Pagination component
75
+ *
76
+ * @fragments /fragments/components/datatable/pagination
77
+ *
78
+ * @example /examples/components/datatable/pagination-simple
75
79
  *
76
80
  * @copyright schukai GmbH
77
81
  * @summary The Pagination component is used to show the current page and the total number of pages.
@@ -116,7 +120,6 @@ class Pagination extends CustomElement {
116
120
  * @property {string} mapping.pages Pages mapping
117
121
  * @property {string} mapping.objectsPerPage Objects per page mapping
118
122
  * @property {string} mapping.currentPage Current page mapping
119
- * @property {Object} pagination Pagination
120
123
  */
121
124
  get defaults() {
122
125
  return Object.assign(
@@ -141,9 +144,9 @@ class Pagination extends CustomElement {
141
144
 
142
145
  href: "page-${page}",
143
146
 
144
- currentPage: undefined,
145
- pages: undefined,
147
+ pages: null,
146
148
  objectsPerPage: 20,
149
+ currentPage: null,
147
150
 
148
151
  mapping: {
149
152
  pages: "sys.pagination.pages",
@@ -151,6 +154,7 @@ class Pagination extends CustomElement {
151
154
  currentPage: "sys.pagination.currentPage",
152
155
  },
153
156
 
157
+ /* @private */
154
158
  pagination: {
155
159
  items: [],
156
160
  },
@@ -188,21 +192,25 @@ class Pagination extends CustomElement {
188
192
  return;
189
193
  }
190
194
 
191
- const parentParentNode = parentNode?.parentNode || parentNode;
195
+ try {
196
+ handleDataSourceChanges.call(this);
197
+ } catch (e) {
198
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e?.message || `${e}`);
199
+ }
192
200
 
193
- const parentWidth = parentParentNode.offsetWidth;
194
- const ownWidth = this.offsetWidth;
201
+ requestAnimationFrame(() => {
202
+ const parentParentNode = parentNode?.parentNode || parentNode;
195
203
 
196
- this[sizeDataSymbol] = {
197
- last: {
198
- parentWidth: parentParentNode.offsetWidth || 0,
199
- },
200
- showNumbers: ownWidth < parentWidth,
201
- };
204
+ const parentWidth = parentParentNode.offsetWidth;
205
+ const ownWidth = this.offsetWidth;
202
206
 
203
- handleDataSourceChanges.call(this);
207
+ this[sizeDataSymbol] = {
208
+ last: {
209
+ parentWidth: 0,
210
+ },
211
+ showNumbers: ownWidth < parentWidth,
212
+ };
204
213
 
205
- setTimeout(() => {
206
214
  this[resizeObserverSymbol] = new ResizeObserver((entries) => {
207
215
  if (this[debounceSizeSymbol] instanceof DeadMansSwitch) {
208
216
  try {
@@ -226,14 +234,14 @@ class Pagination extends CustomElement {
226
234
  parentWidth: parentWidth,
227
235
  };
228
236
 
229
- this[sizeDataSymbol].showNumbers = ownWidth < parentWidth;
237
+ this[sizeDataSymbol].showNumbers = ownWidth <= parentWidth;
230
238
  handleDataSourceChanges.call(this);
231
239
  });
232
240
  });
233
241
  });
234
242
 
235
243
  this[resizeObserverSymbol].observe(this?.parentNode?.parentNode);
236
- }, 500);
244
+ });
237
245
  }
238
246
 
239
247
  /**
@@ -262,6 +270,8 @@ class Pagination extends CustomElement {
262
270
  new Observer(handleDataSourceChanges.bind(this)),
263
271
  );
264
272
 
273
+ element.attachObserver(new Observer(handleDataSourceChanges.bind(this)));
274
+
265
275
  handleDataSourceChanges.call(this);
266
276
  }
267
277
  }
@@ -315,6 +325,7 @@ function initEventHandler() {
315
325
  ATTRIBUTE_ROLE,
316
326
  "pagination-item",
317
327
  );
328
+
318
329
  if (!element) {
319
330
  element = findTargetElementFromEvent(
320
331
  event,
@@ -344,7 +355,6 @@ function initEventHandler() {
344
355
  }
345
356
 
346
357
  page = element.getAttribute("data-page-no");
347
- event.preventDefault();
348
358
 
349
359
  if (
350
360
  !page ||
@@ -361,6 +371,7 @@ function initEventHandler() {
361
371
  return;
362
372
  }
363
373
 
374
+ event.preventDefault();
364
375
  datasource.setParameters({ page });
365
376
 
366
377
  if (typeof datasource.reload !== "function") {
@@ -404,17 +415,19 @@ function handleDataSourceChanges() {
404
415
  }
405
416
 
406
417
  const mapping = this.getOption("mapping");
418
+ const pf = new Pathfinder(this[datasourceLinkedElementSymbol].data);
419
+
407
420
  for (const key in mapping) {
408
421
  const path = mapping[key];
409
422
 
410
- let value;
411
- try {
412
- value = new Pathfinder(this[datasourceLinkedElementSymbol].data).getVia(
413
- path,
414
- );
423
+ if (pf.exists(path)) {
424
+ const value = pf.getVia(path);
415
425
  this.setOption(key, value);
416
- } catch (e) {
417
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
426
+ }
427
+
428
+ const o = this[datasourceLinkedElementSymbol].getOption(path);
429
+ if (o !== undefined && o !== null) {
430
+ this.setOption(key, o);
418
431
  }
419
432
  }
420
433
 
@@ -440,6 +453,9 @@ function handleDataSourceChanges() {
440
453
  * @return {object}
441
454
  */
442
455
  function buildPagination(current, max) {
456
+ current = parseInt(current, 10);
457
+ max = parseInt(max, 10);
458
+
443
459
  let prev = current === 1 ? null : current - 1;
444
460
  let next = current === max ? null : current + 1;
445
461
  const itemList = [1];
@@ -88,9 +88,7 @@ class DatasourceStatus extends CustomElement {
88
88
  * @return {symbol}
89
89
  */
90
90
  static get [instanceSymbol]() {
91
- return Symbol.for(
92
- "@schukai/monster/components/datatables/status@@instance",
93
- );
91
+ return Symbol.for("@schukai/monster/components/datatable/status@@instance");
94
92
  }
95
93
 
96
94
  /**
@@ -33,9 +33,9 @@
33
33
 
34
34
  & ul li a {
35
35
  @mixin button;
36
- background-color: var(--monster-theme-control-bg-color);
36
+ background-color: var(--monster-bg-color-primary-1);
37
37
  color: var(--monster-theme-control-color);
38
- border-color: var(--monster-theme-control-bg-color);
38
+ border-color: var(--monster-bg-color-primary-1);
39
39
  width: max-content;
40
40
 
41
41
  &.current {