@schukai/monster 3.90.0 → 3.91.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 (52) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/package.json +1 -1
  3. package/source/components/datatable/datatable.mjs +2 -0
  4. package/source/components/datatable/filter.mjs +3 -0
  5. package/source/components/form/action-button.mjs +11 -40
  6. package/source/components/form/api-bar.mjs +551 -0
  7. package/source/components/form/button.mjs +1 -3
  8. package/source/components/form/field-set.mjs +1 -3
  9. package/source/components/form/message-state-button.mjs +10 -12
  10. package/source/components/form/password.mjs +1 -1
  11. package/source/components/form/style/action-button.pcss +11 -17
  12. package/source/components/form/style/api-bar.pcss +0 -0
  13. package/source/components/form/style/button-bar.pcss +5 -0
  14. package/source/components/form/style/button.pcss +1 -0
  15. package/source/components/form/style/message-state-button.pcss +1 -0
  16. package/source/components/form/style/state-button.pcss +1 -0
  17. package/source/components/form/stylesheet/action-button.mjs +1 -1
  18. package/source/components/form/stylesheet/api-bar.mjs +38 -0
  19. package/source/components/form/stylesheet/button-bar.mjs +1 -1
  20. package/source/components/form/stylesheet/button.mjs +1 -1
  21. package/source/components/form/stylesheet/message-state-button.mjs +1 -1
  22. package/source/components/form/stylesheet/state-button.mjs +1 -1
  23. package/source/components/layout/iframe.mjs +1 -3
  24. package/source/components/style/badge.css +147 -1
  25. package/source/components/style/border.css +65 -1
  26. package/source/components/style/button.css +205 -1
  27. package/source/components/style/card.css +149 -1
  28. package/source/components/style/color.css +166 -1
  29. package/source/components/style/common.css +159 -1
  30. package/source/components/style/control.css +14 -1
  31. package/source/components/style/data-grid.css +447 -1
  32. package/source/components/style/display.css +32 -1
  33. package/source/components/style/floating-ui.css +42 -1
  34. package/source/components/style/form.css +47 -1
  35. package/source/components/style/host.css +14 -1
  36. package/source/components/style/icons.css +1584 -1
  37. package/source/components/style/link.css +37 -1
  38. package/source/components/style/normalize.css +144 -1
  39. package/source/components/style/popper.css +101 -1
  40. package/source/components/style/property.css +327 -1
  41. package/source/components/style/ripple.css +13 -1
  42. package/source/components/style/skeleton.css +164 -1
  43. package/source/components/style/space.css +240 -1
  44. package/source/components/style/spinner.css +7 -1
  45. package/source/components/style/table.css +39 -1
  46. package/source/components/style/theme.css +356 -1
  47. package/source/components/style/typography.css +178 -1
  48. package/source/monster.mjs +1 -0
  49. package/source/types/version.mjs +1 -1
  50. package/test/cases/monster.mjs +1 -1
  51. package/test/web/test.html +2 -2
  52. package/test/web/tests.js +25 -47
package/CHANGELOG.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
 
4
4
 
5
+ ## [3.91.0] - 2024-12-15
6
+
7
+ ### Add Features
8
+
9
+ - new api button [#264](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/264)
10
+ ### Changes
11
+
12
+ - update project
13
+
14
+
15
+
5
16
  ## [3.90.0] - 2024-12-13
6
17
 
7
18
  ### Add Features
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.90.0"}
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.91.0"}
@@ -183,6 +183,8 @@ class DataTable extends CustomElement {
183
183
  * @property {boolean} features.footer Footer feature
184
184
  * @property {boolean} features.autoInit Auto init feature (init datasource automatically)
185
185
  * @property {boolean} features.doubleClickCopyToClipboard Double click copy to clipboard feature
186
+ * @property {boolean} features.copyAll Copy all feature
187
+ * @property {boolean} features.help Help feature
186
188
  * @property {Object} templateMapping Template mapping
187
189
  * @property {string} templateMapping.row-key Row key
188
190
  * @property {string} templateMapping.filter-id Filter id
@@ -1032,6 +1032,9 @@ function collectSearchQueries() {
1032
1032
  * @return {null|Array|undefined|string}
1033
1033
  */
1034
1034
  function getControlValuesFromLabel(label) {
1035
+ // finde das erste Kind-Element vom type input
1036
+ // wenn es ein input-Element ist, dann @todo
1037
+
1035
1038
  const foundControl = label.firstElementChild;
1036
1039
 
1037
1040
  if (foundControl) {
@@ -41,48 +41,15 @@ export { ActionButton };
41
41
  const containerElementSymbol = Symbol("containerElement");
42
42
 
43
43
  /**
44
- * The ActionButton is a button that opens a popper element with possible actions.
44
+ * A button that opens a popper element with possible actions.
45
45
  *
46
- * <img src="./images/action-button.png">
46
+ * @fragments /fragments/components/form/action-button
47
47
  *
48
- * You can create this control either by specifying the HTML tag <monster-action-button />` directly in the HTML or using
49
- * Javascript via the `document.createElement('monster-action-button');` method.
50
- *
51
- * ```html
52
- * <monster-action-button></monster-action-button>
53
- * ```
54
- *
55
- * Or you can create this CustomControl directly in Javascript:
56
- *
57
- * ```js
58
- * import {PopperButton} from '@schukai/component-form/source/action-button.js';
59
- * document.createElement('monster-action-button');
60
- * ```
61
- *
62
- * @startuml action-button.png
63
- * skinparam monochrome true
64
- * skinparam shadowing false
65
- * HTMLElement <|-- CustomElement
66
- * CustomElement <|-- CustomControl
67
- * CustomControl <|-- Button
68
- * Button <|-- PopperButton
69
- * PopperButton <|-- ActionButton
70
- * @enduml
71
- *
72
- * @copyright schukai GmbH
73
- * @summary A popper button
74
- */
75
-
76
- /**
77
- * A action button control.
78
- *
79
- * @fragments /fragments/components/form/select/
80
- *
81
- * @example /examples/components/form/select-simple
48
+ * @example /examples/components/form/action-button
82
49
  *
83
50
  * @since 3.32.0
84
51
  * @copyright schukai GmbH
85
- * @summary A ActionButton control
52
+ * @summary The ActionButton is a button that opens a popper element with possible actions
86
53
  */
87
54
  class ActionButton extends PopperButton {
88
55
  /**
@@ -128,7 +95,7 @@ class ActionButton extends PopperButton {
128
95
 
129
96
  /**
130
97
  *
131
- * @return {Monster.Components.Form.Popper}
98
+ * @return {ActionButton}
132
99
  * @fires monster-action-button-show-dialog
133
100
  */
134
101
  showDialog() {
@@ -141,7 +108,7 @@ class ActionButton extends PopperButton {
141
108
 
142
109
  /**
143
110
  *
144
- * @return {Monster.Components.Form.Popper}
111
+ * @return {ActionButton}
145
112
  */
146
113
  [assembleMethodSymbol]() {
147
114
  super[assembleMethodSymbol]();
@@ -159,7 +126,7 @@ class ActionButton extends PopperButton {
159
126
  }
160
127
 
161
128
  /**
162
- * @return {Array<CSSStyleSheet>}
129
+ * @return {CSSStyleSheet[]}
163
130
  */
164
131
  static getCSSStyleSheet() {
165
132
  const styles = super.getCSSStyleSheet();
@@ -205,6 +172,10 @@ function initEventHandler() {
205
172
  return this;
206
173
  }
207
174
 
175
+ /**
176
+ * @private
177
+ * @returns {updateButtonsI18n}
178
+ */
208
179
  function updateButtonsI18n() {
209
180
  const translations = getDocumentTranslations();
210
181
  if (!translations) {
@@ -0,0 +1,551 @@
1
+ /**
2
+ * Copyright © schukai GmbH and all contributing authors, {{copyRightYear}}. All rights reserved.
3
+ * Node module: @schukai/monster
4
+ *
5
+ * This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3).
6
+ * The full text of the license can be found at: https://www.gnu.org/licenses/agpl-3.0.en.html
7
+ *
8
+ * For those who do not wish to adhere to the AGPLv3, a commercial license is available.
9
+ * Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms.
10
+ * For more information about purchasing a commercial license, please contact schukai GmbH.
11
+ */
12
+
13
+ import { instanceSymbol } from "../../constants.mjs";
14
+ import { addAttributeToken } from "../../dom/attributes.mjs";
15
+ import {
16
+ ATTRIBUTE_ERRORMESSAGE,
17
+ ATTRIBUTE_ROLE,
18
+ } from "../../dom/constants.mjs";
19
+ import {
20
+ assembleMethodSymbol,
21
+ registerCustomElement,
22
+ } from "../../dom/customelement.mjs";
23
+
24
+ import {
25
+ isArray,
26
+ isFunction,
27
+ isString,
28
+ isIterable,
29
+ isObject,
30
+ isPrimitive,
31
+ } from "../../types/is.mjs";
32
+ import { fireCustomEvent } from "../../dom/events.mjs";
33
+ import { ButtonBar } from "./button-bar.mjs";
34
+ import { validateString } from "../../types/validate.mjs";
35
+ import { Pathfinder } from "../../data/pathfinder.mjs";
36
+ import { buildMap } from "../../data/buildmap.mjs";
37
+ import { ApiButtonStyleSheet } from "./stylesheet/api-button.mjs";
38
+ import { Formatter } from "../../text/formatter.mjs";
39
+ import { getGlobal } from "../../types/global.mjs";
40
+
41
+ import "./button.mjs";
42
+ import "./message-state-button.mjs";
43
+ import "./state-button.mjs";
44
+ import { MessageStateButton } from "./message-state-button.mjs";
45
+ import { StateButton } from "./state-button.mjs";
46
+
47
+ export { ApiBar };
48
+
49
+ /**
50
+ * A ApiBar
51
+ *
52
+ * @fragments /fragments/components/form/api-bar/
53
+ *
54
+ * @example /examples/components/form/api-bar-simple
55
+ *
56
+ * @since 3.90.0
57
+ * @copyright schukai GmbH
58
+ * @summary A beautiful ApiBar that can make your life easier and also looks good.
59
+ */
60
+ class ApiBar extends ButtonBar {
61
+ /**
62
+ * This method is called by the `instanceof` operator.
63
+ * @returns {symbol}
64
+ */
65
+ static get [instanceSymbol]() {
66
+ return Symbol.for("@schukai/monster/components/form/api-bar@@instance");
67
+ }
68
+
69
+ /**
70
+ * To set the options via the HTML tag, the attribute `data-monster-options` must be used.
71
+ * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
72
+ *
73
+ * The individual configuration values can be found in the table.
74
+ *
75
+ * @property {object} mapping - The mapping object.
76
+ * @property {string} mapping.selector - The selector to find the buttons in the response.
77
+ * @property {string} mapping.labelSelector - The selector to find the label for the button.
78
+ * @property {string} mapping.labelTemplate - The template to create the label for the button.
79
+ * @property {string} mapping.apiTemplate - The key to find the api value in the response.
80
+ * @property {string} mapping.urlTemplate - The key to find the url value in the response, if empty the api value is used.
81
+ * @property {function} mapping.filter - The filter function to filter the buttons.
82
+ * @property {string} url - The url to fetch the data.
83
+ * @property {string} buttonTag - The tag name of the button
84
+ * @property {object} api - The api options.
85
+ * @property {object} api.fetch - The fetch options.
86
+ * @property {string} api.body - The body template.
87
+ * @property {object} callbacks - The callbacks object.
88
+ * @property {function} callbacks.beforeApiCall - The beforeApiCall callback called before the api request is made.
89
+ * @property {function} callbacks.failedApiCall - The failedApiCall callback called when the api request failed.
90
+ * @property {function} callbacks.successfulApiCall - The successfulApiCall callback called when the api request was successful.
91
+ * @property {object} fetch - The fetch options.
92
+ * @property {string} fetch.redirect - The redirect option.
93
+ * @property {string} fetch.method - The method option.
94
+ * @property {string} fetch.mode - The mode option.
95
+ * @property {string} fetch.credentials - The credentials option.
96
+ * @property {object} fetch.headers - The headers option.
97
+ * @property {string} fetch.headers.accept - The acceptance option.
98
+ * @property {object} actions - The actions object.
99
+ * @property {function} actions.execute - The execute action.
100
+ * @property {object} data - The data object, this can be used to store some data and send it with the request.
101
+ * @extends {ActionButton.defaults}
102
+ */
103
+ get defaults() {
104
+ const opts = Object.assign({}, super.defaults, {
105
+ mapping: {
106
+ selector: "*",
107
+ labelSelector: "",
108
+ labelTemplate: "",
109
+ apiTemplate: "",
110
+ urlTemplate: "",
111
+ filter: "",
112
+ },
113
+ api: {
114
+ fetch: {
115
+ method: "POST",
116
+ redirect: "error",
117
+ mode: "same-origin",
118
+ credentials: "same-origin",
119
+ headers: {
120
+ accept: "application/json",
121
+ },
122
+ },
123
+ body: null,
124
+ },
125
+ url: "",
126
+ buttonTag: "monster-message-state-button",
127
+ callbacks: {
128
+ beforeApiCal: null,
129
+ failedApiCall: null,
130
+ successfulApiCall: null,
131
+ },
132
+ fetch: {
133
+ redirect: "error",
134
+ method: "GET",
135
+ mode: "same-origin",
136
+ credentials: "same-origin",
137
+ headers: {
138
+ accept: "application/json",
139
+ },
140
+ },
141
+ actions: {
142
+ execute: executeAPIButton,
143
+ },
144
+ data: null,
145
+ });
146
+
147
+ return opts;
148
+ }
149
+
150
+ /**
151
+ *
152
+ * @return {Promise}
153
+ */
154
+ fetch(url) {
155
+ if (url instanceof URL) {
156
+ url = url.toString();
157
+ }
158
+
159
+ if (url !== undefined) {
160
+ url = validateString(url);
161
+ }
162
+
163
+ return fetchData.call(this, url).then((map) => {
164
+ if (
165
+ isObject(map) ||
166
+ isArray(map) | (map instanceof Set) ||
167
+ map instanceof Map
168
+ ) {
169
+ this.importButtons(map);
170
+ }
171
+ });
172
+ }
173
+
174
+ /**
175
+ * Import buttons from a map.
176
+ *
177
+ * @param {array|object|Map|Set} data
178
+ * @return {ApiButton}
179
+ * @throws {Error} map is not iterable
180
+ * @throws {Error} missing label configuration
181
+ */
182
+ importButtons(data) {
183
+ const self = this;
184
+
185
+ const currentButtons = self.querySelectorAll(
186
+ `[${ATTRIBUTE_ROLE}="api-button"]`,
187
+ );
188
+ for (const btnElement of currentButtons) {
189
+ btnElement.remove();
190
+ }
191
+
192
+ const mappingOptions = this.getOption("mapping", {});
193
+ const selector = mappingOptions?.["selector"];
194
+ const labelSelector = mappingOptions?.["labelSelector"];
195
+ const labelTemplate = mappingOptions?.["labelTemplate"];
196
+ const apiTemplate = mappingOptions?.["apiTemplate"];
197
+ let urlTemplate = mappingOptions?.["urlTemplate"];
198
+
199
+ const filter = mappingOptions?.["filter"];
200
+
201
+ let flag = false;
202
+ let apiEqualUrl = false;
203
+ if (labelTemplate === "") {
204
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, "empty label template");
205
+ flag = true;
206
+ }
207
+
208
+ if (apiTemplate === "") {
209
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, "empty api template");
210
+ flag = true;
211
+ }
212
+
213
+ if (urlTemplate === "") {
214
+ urlTemplate = apiTemplate;
215
+ apiEqualUrl = true;
216
+ }
217
+
218
+ if (flag === true) {
219
+ throw new Error(
220
+ "missing label or api configuration, check the error attribute",
221
+ );
222
+ }
223
+
224
+ if (isPrimitive(labelSelector) && labelSelector !== "") {
225
+ const finder = new Pathfinder(data);
226
+ const label = finder.getVia(labelSelector);
227
+ this.setOption("labels.button", label);
228
+ this.value = label;
229
+ }
230
+
231
+ let labelMap;
232
+ const urlMap = buildMap(data, selector, urlTemplate, apiTemplate, filter);
233
+ if (apiEqualUrl === true) {
234
+ labelMap = urlMap;
235
+ } else {
236
+ labelMap = buildMap(data, selector, labelTemplate, apiTemplate, filter);
237
+ }
238
+
239
+ const buttons = [];
240
+ if (!isIterable(urlMap)) {
241
+ throw new Error("map is not iterable");
242
+ }
243
+
244
+ const buttonTag = this.getOption("buttonTag");
245
+ const executerCallback = this.getOption("actions.execute");
246
+
247
+ for (const [iterKey] of urlMap) {
248
+ const vmUrl = urlMap.get(iterKey);
249
+ const vmLabel = labelMap.get(iterKey);
250
+
251
+ const button = getGlobal().document.createElement(buttonTag);
252
+ button.setAttribute(ATTRIBUTE_ROLE, `api-button`);
253
+ button.setOption("labels.button", vmLabel);
254
+ button.setOption("actions.click", (event) => {
255
+ if (isFunction(executerCallback)) {
256
+ executerCallback.call(this, event, {
257
+ key: iterKey,
258
+ url: vmUrl,
259
+ label: vmLabel,
260
+ button: button,
261
+ });
262
+ }
263
+ });
264
+
265
+ this.appendChild(button);
266
+ }
267
+
268
+ try {
269
+ this.updateI18n();
270
+ } catch (e) {
271
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
272
+ }
273
+
274
+ this.setOption("buttons", buttons);
275
+
276
+ fireCustomEvent(this, "monster-button-set", {
277
+ buttons: buttons,
278
+ });
279
+
280
+ return this;
281
+ }
282
+
283
+ /**
284
+ *
285
+ * @return {void}
286
+ */
287
+ [assembleMethodSymbol]() {
288
+ super[assembleMethodSymbol]();
289
+ }
290
+
291
+ /**
292
+ * @return {string}
293
+ */
294
+ static getTag() {
295
+ return "monster-api-bar";
296
+ }
297
+
298
+ /**
299
+ * @return {Array<CSSStyleSheet>}
300
+ */
301
+ static getCSSStyleSheet() {
302
+ const styles = super.getCSSStyleSheet();
303
+ styles.push(ApiButtonStyleSheet);
304
+ return styles;
305
+ }
306
+ }
307
+
308
+ /**
309
+ *
310
+ * @param {Event} event
311
+ * @param {object} opts
312
+ */
313
+ function executeAPIButton(event, opts) {
314
+ const self = this;
315
+
316
+ if (!isObject(opts)) {
317
+ opts = {};
318
+ }
319
+
320
+ const button = opts?.["button"];
321
+ const fetchOptions = self.getOption("api.fetch", {});
322
+
323
+ const callback = self.getOption("callbacks.beforeApiCall");
324
+ if (isFunction(callback)) {
325
+ callback.call(self, fetchOptions);
326
+ }
327
+
328
+ const successfulApiCall = self.getOption("callbacks.successfulApiCall");
329
+ const failedApiCall = self.getOption("callbacks.failedApiCall");
330
+
331
+ let url = opts?.["url"];
332
+ let label = opts?.["label"];
333
+ let key = opts?.["key"];
334
+
335
+ let body = self.getOption("api.body");
336
+
337
+ if (isString(body)) {
338
+ try {
339
+ body = JSON.parse(body);
340
+ } catch (e) {
341
+ body = {};
342
+ }
343
+ }
344
+
345
+ if (isObject(body)) {
346
+ const bodyString = JSON.stringify(body);
347
+
348
+ const obj = {
349
+ url: url,
350
+ label: label,
351
+ key: key,
352
+ data: self.getOption("data"),
353
+ };
354
+
355
+ fetchOptions.body = new Formatter(obj, {}).format(bodyString);
356
+ }
357
+
358
+ if (button instanceof HTMLElement) {
359
+ button?.setState("activity");
360
+ }
361
+
362
+ fireCustomEvent(self, "monster-api-bar-click", {
363
+ button,
364
+ });
365
+
366
+ const global = getGlobal();
367
+ global
368
+ .fetch(url, fetchOptions)
369
+ .then((response) => {
370
+ if (!response.ok) {
371
+ if (
372
+ button instanceof MessageStateButton ||
373
+ button instanceof StateButton
374
+ ) {
375
+ button.setState("failed", 4000);
376
+ }
377
+ return Promise.reject(response);
378
+ }
379
+
380
+ const contentType = response?.headers?.get("content-type");
381
+ if (contentType && contentType.indexOf("application/json") !== -1) {
382
+ return response
383
+ .text()
384
+ .then((text) => {
385
+ try {
386
+ const data = JSON.parse(text); // Try to parse the response as JSON
387
+
388
+ if (
389
+ button instanceof MessageStateButton ||
390
+ button instanceof StateButton
391
+ ) {
392
+ button.setState("successful", 4000);
393
+ }
394
+
395
+ fireCustomEvent(self, "monster-api-bar-successful", {
396
+ button,
397
+ data,
398
+ response,
399
+ contentType: response.headers.get("Content-Type"),
400
+ });
401
+
402
+ if (isFunction(successfulApiCall)) {
403
+ successfulApiCall.call(self, data, response);
404
+ }
405
+ } catch (error) {
406
+ if (button instanceof HTMLElement) {
407
+ button.setState("failed", 4000);
408
+ button.setMessage(error.message).showMessage(2000);
409
+ }
410
+
411
+ fireCustomEvent(self, "monster-api-bar-failed", {
412
+ button,
413
+ error,
414
+ response,
415
+ contentType: response.headers.get("Content-Type"),
416
+ });
417
+ }
418
+ })
419
+ .catch((error) => {
420
+ button.setState("failed", 4000);
421
+
422
+ if (isFunction(failedApiCall)) {
423
+ failedApiCall.call(self, error, response);
424
+ } else if (
425
+ button instanceof MessageStateButton ||
426
+ button instanceof StateButton
427
+ ) {
428
+ button.setMessage("request failed").showMessage(2000);
429
+ }
430
+
431
+ fireCustomEvent(self, "monster-api-bar-failed", {
432
+ button,
433
+ error,
434
+ response,
435
+ contentType: response.headers.get("Content-Type"),
436
+ });
437
+ });
438
+ } else {
439
+ return response
440
+ .blob()
441
+ .then((data) => {
442
+ if (
443
+ button instanceof MessageStateButton ||
444
+ button instanceof StateButton
445
+ ) {
446
+ button.setState("successful", 4000);
447
+ }
448
+
449
+ fireCustomEvent(self, "monster-api-bar-successful", {
450
+ button,
451
+ data,
452
+ response,
453
+ contentType: response.headers.get("Content-Type"),
454
+ });
455
+
456
+ if (isFunction(successfulApiCall)) {
457
+ successfulApiCall.call(self, data, response);
458
+ }
459
+ })
460
+ .catch((error) => {
461
+ if (
462
+ button instanceof MessageStateButton ||
463
+ button instanceof StateButton
464
+ ) {
465
+ button.setState("failed", 4000);
466
+ }
467
+
468
+ if (isFunction(failedApiCall)) {
469
+ failedApiCall.call(self, error, response);
470
+ } else if (
471
+ button instanceof MessageStateButton ||
472
+ button instanceof StateButton
473
+ ) {
474
+ if (error instanceof Response) {
475
+ error = new Error(error.statusText);
476
+ }
477
+
478
+ button.setMessage("request failed").showMessage(2000);
479
+ }
480
+
481
+ fireCustomEvent(self, "monster-api-bar-failed", {
482
+ button,
483
+ error,
484
+ response,
485
+ contentType: response.headers.get("Content-Type"),
486
+ });
487
+ });
488
+ }
489
+ })
490
+ .catch((error) => {
491
+ if (
492
+ button instanceof MessageStateButton ||
493
+ button instanceof StateButton
494
+ ) {
495
+ button.setState("failed", 4000);
496
+ }
497
+
498
+ if (isFunction(failedApiCall)) {
499
+ failedApiCall.call(self, button, error, response);
500
+ } else if (
501
+ button instanceof MessageStateButton ||
502
+ button instanceof StateButton
503
+ ) {
504
+ if (error instanceof Response) {
505
+ error = new Error(error.statusText);
506
+ }
507
+
508
+ button?.setMessage(error.message).showMessage(3000);
509
+ }
510
+
511
+ fireCustomEvent(self, "monster-api-bar-failed", {
512
+ button,
513
+ error,
514
+ });
515
+ });
516
+ }
517
+
518
+ /**
519
+ * @private
520
+ * @param {string} url
521
+ * @return {Promise}
522
+ * @throws {TypeError} the result cannot be parsed
523
+ * @throws {TypeError} unsupported response
524
+ */
525
+ function fetchData(url) {
526
+ if (!url) url = this.getOption("url");
527
+ if (!url) return Promise.resolve();
528
+
529
+ const fetchOptions = this.getOption("fetch", {});
530
+
531
+ const global = getGlobal();
532
+ return global
533
+ .fetch(url, fetchOptions)
534
+ .then((response) => {
535
+ const contentType = response.headers.get("content-type");
536
+ if (contentType && contentType.indexOf("application/json") !== -1) {
537
+ return response.text();
538
+ }
539
+
540
+ throw new TypeError(`unsupported response ${contentType}`);
541
+ })
542
+ .then((text) => {
543
+ try {
544
+ return Promise.resolve(JSON.parse(text));
545
+ } catch (e) {
546
+ throw new TypeError("the result cannot be parsed");
547
+ }
548
+ });
549
+ }
550
+
551
+ registerCustomElement(ApiBar);
@@ -209,9 +209,7 @@ class Button extends CustomControl {
209
209
  },
210
210
  disabled: false,
211
211
  actions: {
212
- click: () => {
213
- throw new Error("the click action is not defined");
214
- },
212
+ click: () => {},
215
213
  },
216
214
  effects: {
217
215
  ripple: true,
@@ -132,9 +132,7 @@ class FieldSet extends CustomControl {
132
132
  multipleColumns: true,
133
133
  },
134
134
  actions: {
135
- click: () => {
136
- throw new Error("the click action is not defined");
137
- },
135
+ click: () => {},
138
136
  },
139
137
  value: null,
140
138
  });