@schukai/monster 3.90.0 → 3.92.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 +22 -0
- package/package.json +1 -1
- package/source/components/datatable/datatable.mjs +2 -0
- package/source/components/datatable/filter.mjs +3 -0
- package/source/components/datatable/save-button.mjs +3 -0
- package/source/components/form/action-button.mjs +11 -40
- package/source/components/form/api-bar.mjs +551 -0
- package/source/components/form/button.mjs +1 -3
- package/source/components/form/context-error.mjs +2 -13
- package/source/components/form/context-help.mjs +1 -1
- package/source/components/form/field-set.mjs +1 -3
- package/source/components/form/message-state-button.mjs +10 -12
- package/source/components/form/password.mjs +3 -3
- package/source/components/form/reload.mjs +1 -1
- package/source/components/form/shadow-reload.mjs +1 -1
- package/source/components/form/style/action-button.pcss +11 -17
- package/source/components/form/style/api-bar.pcss +0 -0
- package/source/components/form/style/button-bar.pcss +5 -0
- package/source/components/form/style/button.pcss +1 -0
- package/source/components/form/style/message-state-button.pcss +1 -0
- package/source/components/form/style/state-button.pcss +1 -0
- package/source/components/form/stylesheet/action-button.mjs +1 -1
- package/source/components/form/stylesheet/api-bar.mjs +38 -0
- package/source/components/form/stylesheet/button-bar.mjs +1 -1
- package/source/components/form/stylesheet/button.mjs +1 -1
- package/source/components/form/stylesheet/message-state-button.mjs +1 -1
- package/source/components/form/stylesheet/state-button.mjs +1 -1
- package/source/components/form/template.mjs +49 -18
- package/source/components/form/tree-select.mjs +60 -42
- package/source/components/layout/iframe.mjs +1 -3
- package/source/components/layout/tabs.mjs +38 -3
- package/source/components/style/badge.css +147 -1
- package/source/components/style/border.css +65 -1
- package/source/components/style/button.css +205 -1
- package/source/components/style/card.css +149 -1
- package/source/components/style/color.css +166 -1
- package/source/components/style/common.css +159 -1
- package/source/components/style/control.css +14 -1
- package/source/components/style/data-grid.css +447 -1
- package/source/components/style/display.css +32 -1
- package/source/components/style/floating-ui.css +42 -1
- package/source/components/style/form.css +47 -1
- package/source/components/style/host.css +14 -1
- package/source/components/style/icons.css +1584 -1
- package/source/components/style/link.css +37 -1
- package/source/components/style/normalize.css +144 -1
- package/source/components/style/popper.css +101 -1
- package/source/components/style/property.css +327 -1
- package/source/components/style/ripple.css +13 -1
- package/source/components/style/skeleton.css +164 -1
- package/source/components/style/space.css +240 -1
- package/source/components/style/spinner.css +7 -1
- package/source/components/style/table.css +39 -1
- package/source/components/style/theme.css +356 -1
- package/source/components/style/typography.css +178 -1
- package/source/monster.mjs +1 -0
- package/source/types/version.mjs +1 -1
- package/test/cases/monster.mjs +1 -1
- package/test/web/test.html +2 -2
- package/test/web/tests.js +119 -64
package/CHANGELOG.md
CHANGED
@@ -2,6 +2,28 @@
|
|
2
2
|
|
3
3
|
|
4
4
|
|
5
|
+
## [3.92.0] - 2024-12-18
|
6
|
+
|
7
|
+
### Add Features
|
8
|
+
|
9
|
+
- **tabs:** new feature flag removeBehavior [#268](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/268) , update form/template and tree-select
|
10
|
+
### Changes
|
11
|
+
|
12
|
+
- update project
|
13
|
+
|
14
|
+
|
15
|
+
|
16
|
+
## [3.91.0] - 2024-12-15
|
17
|
+
|
18
|
+
### Add Features
|
19
|
+
|
20
|
+
- new api button [#264](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/264)
|
21
|
+
### Changes
|
22
|
+
|
23
|
+
- update project
|
24
|
+
|
25
|
+
|
26
|
+
|
5
27
|
## [3.90.0] - 2024-12-13
|
6
28
|
|
7
29
|
### 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.
|
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.92.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
|
-
*
|
44
|
+
* A button that opens a popper element with possible actions.
|
45
45
|
*
|
46
|
-
*
|
46
|
+
* @fragments /fragments/components/form/action-button
|
47
47
|
*
|
48
|
-
*
|
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
|
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 {
|
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 {
|
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 {
|
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);
|