@schukai/monster 4.20.0 → 4.21.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 +20 -0
- package/package.json +1 -1
- package/source/components/content/viewer.mjs +88 -40
- package/source/components/datatable/columnbar.mjs +27 -16
- package/source/components/datatable/filter.mjs +4 -4
- package/source/components/form/select.mjs +2765 -2763
- package/source/components/layout/collapse.mjs +1 -4
- package/source/components/layout/style/collapse.pcss +0 -13
- package/source/components/layout/stylesheet/collapse.mjs +14 -7
- package/source/dom/customelement.mjs +3 -4
- package/source/text/markdown-parser.mjs +264 -0
- package/test/cases/text/markdown-parser.mjs +104 -0
package/CHANGELOG.md
CHANGED
@@ -2,6 +2,26 @@
|
|
2
2
|
|
3
3
|
|
4
4
|
|
5
|
+
## [4.21.0] - 2025-06-22
|
6
|
+
|
7
|
+
### Add Features
|
8
|
+
|
9
|
+
- Add Markdown parser and HTML converter [#324](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/324)
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
## [4.20.1] - 2025-06-12
|
14
|
+
|
15
|
+
### Bug Fixes
|
16
|
+
|
17
|
+
- update css styles
|
18
|
+
- update css collapse
|
19
|
+
### Changes
|
20
|
+
|
21
|
+
- move issues [#323](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/323)
|
22
|
+
|
23
|
+
|
24
|
+
|
5
25
|
## [4.20.0] - 2025-06-11
|
6
26
|
|
7
27
|
### Add Features
|
package/package.json
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"author":"schukai GmbH","dependencies":{"@floating-ui/dom":"^1.7.1","@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":"4.
|
1
|
+
{"author":"schukai GmbH","dependencies":{"@floating-ui/dom":"^1.7.1","@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":"4.21.0"}
|
@@ -23,6 +23,7 @@ import { instanceSymbol } from "../../constants.mjs";
|
|
23
23
|
import { isString } from "../../types/is.mjs";
|
24
24
|
import { getGlobal } from "../../types/global.mjs";
|
25
25
|
import { MediaType, parseMediaType } from "../../types/mediatype.mjs";
|
26
|
+
import { MarkdownToHTML } from "../../text/markdown-parser.mjs";
|
26
27
|
|
27
28
|
export { Viewer };
|
28
29
|
|
@@ -33,7 +34,7 @@ export { Viewer };
|
|
33
34
|
const viewerElementSymbol = Symbol("viewerElement");
|
34
35
|
|
35
36
|
/**
|
36
|
-
* The Viewer component is used to show a PDF, HTML or Image.
|
37
|
+
* The Viewer component is used to show a PDF, HTML, or Image.
|
37
38
|
*
|
38
39
|
* @fragments /fragments/components/content/viewer
|
39
40
|
*
|
@@ -42,7 +43,7 @@ const viewerElementSymbol = Symbol("viewerElement");
|
|
42
43
|
* @example /examples/components/content/html-viewer with HTML content
|
43
44
|
*
|
44
45
|
* @copyright schukai GmbH
|
45
|
-
* @summary A simple viewer component for PDF, HTML and images.
|
46
|
+
* @summary A simple viewer component for PDF, HTML, and images.
|
46
47
|
*/
|
47
48
|
class Viewer extends CustomElement {
|
48
49
|
/**
|
@@ -64,6 +65,12 @@ class Viewer extends CustomElement {
|
|
64
65
|
* @property {string} content Content to be displayed in the viewer
|
65
66
|
* @property {Object} classes Css classes
|
66
67
|
* @property {string} classes.viewer Css class for the viewer
|
68
|
+
* @property {Object} renderers Renderers for different media types
|
69
|
+
* @property {function} renderers.image Function to render image content
|
70
|
+
* @property {function} renderers.html Function to render HTML content
|
71
|
+
* @property {function} renderers.pdf Function to render PDF content
|
72
|
+
* @property {function} renderers.plaintext Function to render plain text content
|
73
|
+
* @property {function} renderers.markdown Function to render Markdown content
|
67
74
|
*/
|
68
75
|
get defaults() {
|
69
76
|
return Object.assign({}, super.defaults, {
|
@@ -74,63 +81,93 @@ class Viewer extends CustomElement {
|
|
74
81
|
classes: {
|
75
82
|
viewer: "",
|
76
83
|
},
|
84
|
+
renderers : {
|
85
|
+
image: this.setImage,
|
86
|
+
html: this.setHTML,
|
87
|
+
pdf: this.setPDF,
|
88
|
+
plaintext: this.setPlainText,
|
89
|
+
markdown: this.setMarkdown,
|
90
|
+
}
|
77
91
|
});
|
78
92
|
}
|
79
93
|
|
80
94
|
/**
|
81
|
-
* Sets the content of
|
95
|
+
* Sets the content of the viewer by processing `data` according to the specified `mediaType`.
|
96
|
+
* If no `mediaType` is provided, it defaults to "text/plain".
|
97
|
+
* The method uses an appropriate renderer based on the media type to process and display the content.
|
82
98
|
*
|
83
|
-
* @param {
|
84
|
-
* @param {string} [mediaType="text/plain"] - The media type of the content
|
85
|
-
* @return {void} This method does not return a value.
|
86
|
-
* @throws {Error} Throws an error if
|
99
|
+
* @param {any} data - The content to be displayed in the viewer.
|
100
|
+
* @param {string} [mediaType="text/plain"] - The media type of the content to determine the appropriate renderer.
|
101
|
+
* @return {void} This method does not return a value, but processes the content or throws an exception on failure.
|
102
|
+
* @throws {Error} Throws an error if there is no shadow root defined or if there is an issue with rendering `data`.
|
87
103
|
*/
|
88
|
-
setContent(
|
104
|
+
setContent(data, mediaType = "text/plain") {
|
89
105
|
if (!this.shadowRoot) {
|
90
106
|
throw new Error("no shadow-root is defined");
|
91
107
|
}
|
92
108
|
|
93
|
-
let type;
|
94
|
-
try {
|
95
|
-
const m = new parseMediaType(mediaType);
|
96
|
-
switch (m.type) {
|
97
|
-
case "image":
|
98
|
-
return this.setImage(content);
|
99
|
-
}
|
100
109
|
|
101
|
-
|
102
|
-
|
103
|
-
|
110
|
+
let mt;
|
111
|
+
try {
|
112
|
+
mt = new parseMediaType(mediaType).toString();
|
113
|
+
} catch {
|
114
|
+
mt = "text/plain";
|
104
115
|
}
|
116
|
+
if (!mt) mt = "text/plain";
|
117
|
+
|
118
|
+
const { renderers } = this.options;
|
119
|
+
const primaryType = mt.split("/")[0];
|
120
|
+
const renderer =
|
121
|
+
renderers[mt] ||
|
122
|
+
renderers[primaryType] ||
|
123
|
+
((d) => this.setPlainText(d));
|
105
124
|
|
106
|
-
|
107
|
-
|
125
|
+
try {
|
126
|
+
const result = renderer.call(this, data);
|
127
|
+
if (result && typeof result.then === "function") {
|
128
|
+
result.catch((err) => {
|
129
|
+
this.dispatchEvent(new CustomEvent("viewer-error", { detail: err }));
|
130
|
+
});
|
131
|
+
}
|
132
|
+
} catch (err) {
|
133
|
+
this.dispatchEvent(new CustomEvent("viewer-error", { detail: err }));
|
134
|
+
throw new Error(err);
|
108
135
|
}
|
136
|
+
}
|
137
|
+
|
138
|
+
/**
|
139
|
+
* Renders Markdown content using built-in or custom Markdown parser.
|
140
|
+
* Overrideable via `customRenderers['text/markdown']`.
|
141
|
+
*
|
142
|
+
* @param {string|Blob} data
|
143
|
+
*/
|
144
|
+
setMarkdown(data) {
|
145
|
+
const render = (markdownText) => {
|
146
|
+
try {
|
147
|
+
const html = MarkdownToHTML.convert(markdownText);
|
148
|
+
this.setHTML(html);
|
149
|
+
} catch (error) {
|
150
|
+
this.setPlainText(markdownText); // Fallback
|
151
|
+
}
|
152
|
+
};
|
109
153
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
case "image/png":
|
121
|
-
case "image/jpeg":
|
122
|
-
case "image/gif":
|
123
|
-
this.setImage(content);
|
124
|
-
break;
|
125
|
-
default:
|
126
|
-
this.setOption("content", content);
|
154
|
+
if (data instanceof Blob) {
|
155
|
+
blobToText(data)
|
156
|
+
.then(render)
|
157
|
+
.catch((err) => {
|
158
|
+
this.setPlainText("[Invalid Markdown]");
|
159
|
+
});
|
160
|
+
} else if (isString(data)) {
|
161
|
+
render(data);
|
162
|
+
} else {
|
163
|
+
this.setPlainText("[Unsupported Markdown input]");
|
127
164
|
}
|
128
165
|
}
|
129
166
|
|
130
167
|
/**
|
131
168
|
* Configures and embeds a PDF document into the application with customizable display settings.
|
132
169
|
*
|
133
|
-
* @param {Blob|URL|string} data The PDF data to be embedded. Can be provided as a Blob, URL or base64 string.
|
170
|
+
* @param {Blob|URL|string} data The PDF data to be embedded. Can be provided as a Blob, URL, or base64 string.
|
134
171
|
* @param {boolean} [navigation=true] Determines whether the navigation pane is displayed in the PDF viewer.
|
135
172
|
* @param {boolean} [toolbar=true] Controls the visibility of the toolbar in the PDF viewer.
|
136
173
|
* @param {boolean} [scrollbar=false] Configures the display of the scrollbar in the PDF viewer.
|
@@ -163,6 +200,7 @@ class Viewer extends CustomElement {
|
|
163
200
|
|
164
201
|
pdfURL = data;
|
165
202
|
} else {
|
203
|
+
this.dispatchEvent(new CustomEvent("viewer-error", { detail: "Blob or URL expected" }));
|
166
204
|
throw new Error("Blob or URL expected");
|
167
205
|
}
|
168
206
|
|
@@ -188,16 +226,20 @@ class Viewer extends CustomElement {
|
|
188
226
|
} else if (isString(data)) {
|
189
227
|
// nothing to do
|
190
228
|
} else {
|
229
|
+
this.dispatchEvent(new CustomEvent("viewer-error", { detail: "Blob or URL expected" }));
|
191
230
|
throw new Error("Blob or URL expected");
|
192
231
|
}
|
193
232
|
|
194
|
-
this.setOption(
|
233
|
+
this.setOption(
|
234
|
+
"content",
|
235
|
+
`<img style="max-width: 100%" src="${data}" alt="image" part="image">`
|
236
|
+
);
|
195
237
|
}
|
196
238
|
|
197
239
|
/**
|
198
240
|
*
|
199
241
|
* if the data is a string, it is interpreted as HTML.
|
200
|
-
* if the data is
|
242
|
+
* if the data is a URL, the HTML is loaded from the url and set as content.
|
201
243
|
* if the data is an HTMLElement, the outerHTML is used as content.
|
202
244
|
*
|
203
245
|
* @param {HTMLElement|URL|string|Blob} data
|
@@ -209,6 +251,7 @@ class Viewer extends CustomElement {
|
|
209
251
|
this.setOption("content", html);
|
210
252
|
})
|
211
253
|
.catch((error) => {
|
254
|
+
this.dispatchEvent(new CustomEvent("viewer-error", { detail: error }));
|
212
255
|
throw new Error(error);
|
213
256
|
});
|
214
257
|
|
@@ -228,9 +271,11 @@ class Viewer extends CustomElement {
|
|
228
271
|
this.setOption("content", html);
|
229
272
|
})
|
230
273
|
.catch((error) => {
|
274
|
+
this.dispatchEvent(new CustomEvent("viewer-error", { detail: error }));
|
231
275
|
throw new Error(error);
|
232
276
|
});
|
233
277
|
} else {
|
278
|
+
this.dispatchEvent(new CustomEvent("viewer-error", { detail: "HTMLElement or string expected" }));
|
234
279
|
throw new Error("HTMLElement or string expected");
|
235
280
|
}
|
236
281
|
|
@@ -265,6 +310,7 @@ class Viewer extends CustomElement {
|
|
265
310
|
this.setOption("content", mkPreSpan(text));
|
266
311
|
})
|
267
312
|
.catch((error) => {
|
313
|
+
this.dispatchEvent(new CustomEvent("viewer-error", { detail: error }));
|
268
314
|
throw new Error(error);
|
269
315
|
});
|
270
316
|
|
@@ -289,9 +335,11 @@ class Viewer extends CustomElement {
|
|
289
335
|
this.setOption("content", mkPreSpan(text));
|
290
336
|
})
|
291
337
|
.catch((error) => {
|
338
|
+
this.dispatchEvent(new CustomEvent("viewer-error", { detail: error }));
|
292
339
|
throw new Error(error);
|
293
340
|
});
|
294
341
|
} else {
|
342
|
+
this.dispatchEvent(new CustomEvent("viewer-error", { detail: "HTMLElement or string expected" }));
|
295
343
|
throw new Error("HTMLElement or string expected");
|
296
344
|
}
|
297
345
|
|
@@ -23,9 +23,9 @@ import { clone } from "../../util/clone.mjs";
|
|
23
23
|
import { ColumnBarStyleSheet } from "./stylesheet/column-bar.mjs";
|
24
24
|
import { createPopper } from "@popperjs/core";
|
25
25
|
import { getLocaleOfDocument } from "../../dom/locale.mjs";
|
26
|
-
import {hasObjectLink} from "../../dom/attributes.mjs";
|
27
|
-
import {customElementUpdaterLinkSymbol} from "../../dom/constants.mjs";
|
28
|
-
import {getGlobalObject} from "../../types/global.mjs";
|
26
|
+
import { hasObjectLink } from "../../dom/attributes.mjs";
|
27
|
+
import { customElementUpdaterLinkSymbol } from "../../dom/constants.mjs";
|
28
|
+
import { getGlobalObject } from "../../types/global.mjs";
|
29
29
|
|
30
30
|
export { ColumnBar };
|
31
31
|
|
@@ -89,10 +89,7 @@ class ColumnBar extends CustomElement {
|
|
89
89
|
* @returns {Map<unknown, unknown>}
|
90
90
|
*/
|
91
91
|
get customization() {
|
92
|
-
return new Map([
|
93
|
-
...super.customization,
|
94
|
-
["templateFormatter.i18n", true],
|
95
|
-
]);
|
92
|
+
return new Map([...super.customization, ["templateFormatter.i18n", true]]);
|
96
93
|
}
|
97
94
|
|
98
95
|
/**
|
@@ -130,14 +127,23 @@ class ColumnBar extends CustomElement {
|
|
130
127
|
const isOutsideElement = !path.includes(this);
|
131
128
|
const isOutsideShadow = !path.includes(this.shadowRoot);
|
132
129
|
|
133
|
-
if (
|
130
|
+
if (
|
131
|
+
isOutsideElement &&
|
132
|
+
isOutsideShadow &&
|
133
|
+
this[settingsLayerElementSymbol]
|
134
|
+
) {
|
134
135
|
this[settingsLayerElementSymbol].classList.remove("visible");
|
135
136
|
}
|
136
|
-
}
|
137
|
-
|
138
|
-
getGlobalObject("document").addEventListener("click" , this[closeEventHandlerSymbol]);
|
139
|
-
getGlobalObject("document").addEventListener("touch" , this[closeEventHandlerSymbol]);
|
137
|
+
};
|
140
138
|
|
139
|
+
getGlobalObject("document").addEventListener(
|
140
|
+
"click",
|
141
|
+
this[closeEventHandlerSymbol],
|
142
|
+
);
|
143
|
+
getGlobalObject("document").addEventListener(
|
144
|
+
"touch",
|
145
|
+
this[closeEventHandlerSymbol],
|
146
|
+
);
|
141
147
|
}
|
142
148
|
|
143
149
|
/**
|
@@ -149,12 +155,17 @@ class ColumnBar extends CustomElement {
|
|
149
155
|
disconnectedCallback() {
|
150
156
|
super.disconnectedCallback();
|
151
157
|
|
152
|
-
if(this[closeEventHandlerSymbol]) {
|
153
|
-
getGlobalObject("document").removeEventListener(
|
154
|
-
|
158
|
+
if (this[closeEventHandlerSymbol]) {
|
159
|
+
getGlobalObject("document").removeEventListener(
|
160
|
+
"click",
|
161
|
+
this[closeEventHandlerSymbol],
|
162
|
+
);
|
163
|
+
getGlobalObject("document").removeEventListener(
|
164
|
+
"touch",
|
165
|
+
this[closeEventHandlerSymbol],
|
166
|
+
);
|
155
167
|
this[closeEventHandlerSymbol] = null;
|
156
168
|
}
|
157
|
-
|
158
169
|
}
|
159
170
|
|
160
171
|
/**
|
@@ -1260,8 +1260,8 @@ function collectSearchQueries() {
|
|
1260
1260
|
return "";
|
1261
1261
|
}
|
1262
1262
|
|
1263
|
-
if(!op || !isString(op)) op = "OR";
|
1264
|
-
op = " "+op.toUpperCase().trim()+" ";
|
1263
|
+
if (!op || !isString(op)) op = "OR";
|
1264
|
+
op = " " + op.toUpperCase().trim() + " ";
|
1265
1265
|
|
1266
1266
|
let query = "";
|
1267
1267
|
value.forEach((v) => {
|
@@ -1282,8 +1282,8 @@ function collectSearchQueries() {
|
|
1282
1282
|
return "";
|
1283
1283
|
}
|
1284
1284
|
|
1285
|
-
if(!op || !isString(op)) op = "OR";
|
1286
|
-
op = " "+op.toUpperCase().trim()+" ";
|
1285
|
+
if (!op || !isString(op)) op = "OR";
|
1286
|
+
op = " " + op.toUpperCase().trim() + " ";
|
1287
1287
|
|
1288
1288
|
let query = "";
|
1289
1289
|
value.forEach((v) => {
|