@schukai/monster 1.24.0 → 1.27.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 (214) hide show
  1. package/CHANGELOG +47 -0
  2. package/README.md +4 -4
  3. package/dist/modules/constants.js +2 -2
  4. package/dist/modules/constraints/abstract.js +1 -1
  5. package/dist/modules/constraints/abstractoperator.js +1 -1
  6. package/dist/modules/constraints/andoperator.js +1 -1
  7. package/dist/modules/constraints/invalid.js +1 -1
  8. package/dist/modules/constraints/isarray.js +1 -1
  9. package/dist/modules/constraints/isobject.js +1 -1
  10. package/dist/modules/constraints/namespace.js +1 -1
  11. package/dist/modules/constraints/oroperator.js +1 -1
  12. package/dist/modules/constraints/valid.js +1 -1
  13. package/dist/modules/data/buildmap.js +2 -2
  14. package/dist/modules/data/buildtree.js +2 -0
  15. package/dist/modules/data/datasource/namespace.js +1 -1
  16. package/dist/modules/data/datasource/restapi/writeerror.js +1 -1
  17. package/dist/modules/data/datasource/restapi.js +1 -1
  18. package/dist/modules/data/datasource/storage/localstorage.js +1 -1
  19. package/dist/modules/data/datasource/storage/namespace.js +1 -1
  20. package/dist/modules/data/datasource/storage/sessionstorage.js +1 -1
  21. package/dist/modules/data/datasource/storage.js +1 -1
  22. package/dist/modules/data/datasource.js +1 -1
  23. package/dist/modules/data/diff.js +1 -1
  24. package/dist/modules/data/extend.js +1 -1
  25. package/dist/modules/data/namespace.js +1 -1
  26. package/dist/modules/data/pathfinder.js +1 -1
  27. package/dist/modules/data/pipe.js +1 -1
  28. package/dist/modules/data/transformer.js +2 -2
  29. package/dist/modules/dom/assembler.js +1 -1
  30. package/dist/modules/dom/attributes.js +2 -2
  31. package/dist/modules/dom/constants.js +2 -2
  32. package/dist/modules/dom/customcontrol.js +1 -1
  33. package/dist/modules/dom/customelement.js +1 -1
  34. package/dist/modules/dom/events.js +1 -1
  35. package/dist/modules/dom/focusmanager.js +2 -0
  36. package/dist/modules/dom/locale.js +1 -1
  37. package/dist/modules/dom/namespace.js +1 -1
  38. package/dist/modules/dom/resource/data.js +2 -0
  39. package/dist/modules/dom/resource/link/stylesheet.js +2 -0
  40. package/dist/modules/dom/resource/link.js +2 -0
  41. package/dist/modules/dom/resource/script.js +2 -0
  42. package/dist/modules/dom/resource.js +2 -0
  43. package/dist/modules/dom/resourcemanager.js +2 -0
  44. package/dist/modules/dom/template.js +2 -2
  45. package/dist/modules/dom/theme.js +1 -1
  46. package/dist/modules/dom/updater.js +2 -2
  47. package/dist/modules/dom/util.js +1 -1
  48. package/dist/modules/dom/worker/factory.js +2 -0
  49. package/dist/modules/i18n/formatter.js +2 -0
  50. package/dist/modules/i18n/locale.js +1 -1
  51. package/dist/modules/i18n/namespace.js +1 -1
  52. package/dist/modules/i18n/provider.js +1 -1
  53. package/dist/modules/i18n/providers/fetch.js +1 -1
  54. package/dist/modules/i18n/providers/namespace.js +1 -1
  55. package/dist/modules/i18n/translations.js +1 -1
  56. package/dist/modules/logging/handler/console.js +1 -1
  57. package/dist/modules/logging/handler/namespace.js +1 -1
  58. package/dist/modules/logging/handler.js +1 -1
  59. package/dist/modules/logging/logentry.js +1 -1
  60. package/dist/modules/logging/logger.js +1 -1
  61. package/dist/modules/logging/namespace.js +1 -1
  62. package/dist/modules/math/namespace.js +1 -1
  63. package/dist/modules/math/random.js +2 -2
  64. package/dist/modules/monster.js +1 -1
  65. package/dist/modules/namespace.js +1 -1
  66. package/dist/modules/text/formatter.js +2 -2
  67. package/dist/modules/text/namespace.js +1 -1
  68. package/dist/modules/types/base.js +1 -1
  69. package/dist/modules/types/basewithoptions.js +1 -1
  70. package/dist/modules/types/binary.js +1 -1
  71. package/dist/modules/types/dataurl.js +1 -1
  72. package/dist/modules/types/global.js +1 -1
  73. package/dist/modules/types/id.js +1 -1
  74. package/dist/modules/types/is.js +2 -2
  75. package/dist/modules/types/mediatype.js +1 -1
  76. package/dist/modules/types/namespace.js +1 -1
  77. package/dist/modules/types/node.js +2 -0
  78. package/dist/modules/types/nodelist.js +2 -0
  79. package/dist/modules/types/noderecursiveiterator.js +2 -0
  80. package/dist/modules/types/observer.js +1 -1
  81. package/dist/modules/types/observerlist.js +1 -1
  82. package/dist/modules/types/proxyobserver.js +1 -1
  83. package/dist/modules/types/queue.js +1 -1
  84. package/dist/modules/types/randomid.js +1 -1
  85. package/dist/modules/types/regex.js +2 -0
  86. package/dist/modules/types/stack.js +1 -1
  87. package/dist/modules/types/tokenlist.js +1 -1
  88. package/dist/modules/types/typeof.js +1 -1
  89. package/dist/modules/types/uniquequeue.js +1 -1
  90. package/dist/modules/types/uuid.js +2 -0
  91. package/dist/modules/types/validate.js +1 -1
  92. package/dist/modules/types/version.js +2 -2
  93. package/dist/modules/util/clone.js +1 -1
  94. package/dist/modules/util/comparator.js +1 -1
  95. package/dist/modules/util/freeze.js +1 -1
  96. package/dist/modules/util/namespace.js +1 -1
  97. package/dist/modules/util/processing.js +1 -1
  98. package/dist/modules/util/trimspaces.js +1 -1
  99. package/dist/monster.dev.js +1528 -770
  100. package/dist/monster.dev.js.map +1 -1
  101. package/dist/monster.js +2 -2
  102. package/package.json +13 -2
  103. package/source/constants.js +11 -2
  104. package/source/constraints/abstract.js +5 -0
  105. package/source/constraints/abstractoperator.js +5 -0
  106. package/source/constraints/andoperator.js +10 -5
  107. package/source/constraints/invalid.js +8 -3
  108. package/source/constraints/isarray.js +9 -4
  109. package/source/constraints/isobject.js +8 -3
  110. package/source/constraints/oroperator.js +10 -5
  111. package/source/constraints/valid.js +8 -3
  112. package/source/data/buildmap.js +25 -9
  113. package/source/data/buildtree.js +95 -0
  114. package/source/data/datasource/restapi.js +3 -3
  115. package/source/data/datasource/storage/localstorage.js +2 -2
  116. package/source/data/datasource/storage/sessionstorage.js +2 -2
  117. package/source/data/datasource/storage.js +3 -3
  118. package/source/data/datasource.js +3 -3
  119. package/source/data/diff.js +3 -3
  120. package/source/data/extend.js +2 -2
  121. package/source/data/pathfinder.js +4 -4
  122. package/source/data/pipe.js +3 -3
  123. package/source/data/transformer.js +7 -5
  124. package/source/dom/assembler.js +2 -2
  125. package/source/dom/attributes.js +111 -28
  126. package/source/dom/constants.js +287 -10
  127. package/source/dom/customcontrol.js +1 -1
  128. package/source/dom/customelement.js +1 -1
  129. package/source/dom/events.js +6 -7
  130. package/source/dom/focusmanager.js +250 -0
  131. package/source/dom/locale.js +10 -5
  132. package/source/dom/resource/data.js +170 -0
  133. package/source/dom/resource/link/stylesheet.js +54 -0
  134. package/source/dom/resource/link.js +125 -0
  135. package/source/dom/resource/script.js +112 -0
  136. package/source/dom/resource.js +268 -0
  137. package/source/dom/resourcemanager.js +214 -0
  138. package/source/dom/template.js +86 -16
  139. package/source/dom/theme.js +3 -3
  140. package/source/dom/updater.js +138 -90
  141. package/source/dom/util.js +6 -6
  142. package/source/dom/worker/factory.js +134 -0
  143. package/source/i18n/formatter.js +140 -0
  144. package/source/i18n/locale.js +6 -4
  145. package/source/i18n/provider.js +2 -2
  146. package/source/i18n/providers/fetch.js +18 -3
  147. package/source/i18n/translations.js +18 -9
  148. package/source/logging/handler/console.js +2 -2
  149. package/source/logging/handler.js +2 -2
  150. package/source/logging/logentry.js +2 -2
  151. package/source/logging/logger.js +2 -2
  152. package/source/math/random.js +9 -5
  153. package/source/namespace.js +1 -1
  154. package/source/text/formatter.js +190 -48
  155. package/source/types/base.js +4 -4
  156. package/source/types/basewithoptions.js +2 -2
  157. package/source/types/binary.js +4 -4
  158. package/source/types/dataurl.js +4 -4
  159. package/source/types/global.js +4 -4
  160. package/source/types/id.js +6 -3
  161. package/source/types/is.js +103 -85
  162. package/source/types/mediatype.js +4 -4
  163. package/source/types/node.js +179 -0
  164. package/source/types/nodelist.js +125 -0
  165. package/source/types/noderecursiveiterator.js +126 -0
  166. package/source/types/observer.js +3 -3
  167. package/source/types/observerlist.js +2 -2
  168. package/source/types/proxyobserver.js +5 -5
  169. package/source/types/queue.js +4 -4
  170. package/source/types/randomid.js +2 -2
  171. package/source/types/regex.js +49 -0
  172. package/source/types/stack.js +2 -2
  173. package/source/types/tokenlist.js +2 -2
  174. package/source/types/typeof.js +3 -3
  175. package/source/types/uniquequeue.js +2 -2
  176. package/source/types/uuid.js +102 -0
  177. package/source/types/validate.js +20 -20
  178. package/source/types/version.js +6 -6
  179. package/source/util/clone.js +2 -2
  180. package/source/util/comparator.js +4 -4
  181. package/source/util/freeze.js +5 -5
  182. package/source/util/processing.js +3 -3
  183. package/source/util/trimspaces.js +3 -3
  184. package/test/cases/data/buildtree.js +149 -0
  185. package/test/cases/data/datasource/restapi.js +1 -1
  186. package/test/cases/data/transformer.js +2 -0
  187. package/test/cases/dom/attributes.js +46 -19
  188. package/test/cases/dom/customelement.js +0 -3
  189. package/test/cases/dom/focusmanager.js +111 -0
  190. package/test/cases/dom/locale.js +1 -4
  191. package/test/cases/dom/resource/data.js +129 -0
  192. package/test/cases/dom/resource/link/stylesheet.js +101 -0
  193. package/test/cases/dom/resource/link.js +101 -0
  194. package/test/cases/dom/resource/script.js +115 -0
  195. package/test/cases/dom/resourcemanager.js +118 -0
  196. package/test/cases/dom/template.js +72 -14
  197. package/test/cases/dom/updater.js +102 -75
  198. package/test/cases/dom/worker/factory.js +63 -0
  199. package/test/cases/i18n/formatter.js +66 -0
  200. package/test/cases/monster.js +1 -1
  201. package/test/cases/text/formatter.js +36 -5
  202. package/test/cases/types/node.js +196 -0
  203. package/test/cases/types/nodelist.js +64 -0
  204. package/test/cases/types/noderecursiveiterator.js +54 -0
  205. package/test/cases/types/regex.js +32 -0
  206. package/test/cases/types/uuid.js +42 -0
  207. package/test/cases/util/freeze.js +30 -4
  208. package/test/util/cleanupdom.js +48 -0
  209. package/test/util/jsdom.js +22 -9
  210. package/test/web/import.js +14 -0
  211. package/test/web/monster-dev.html +3 -3
  212. package/test/web/monster.html +2 -2
  213. package/test/web/test.html +3 -3
  214. package/test/web/tests.js +7 -7
@@ -0,0 +1,268 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * @author schukai GmbH
5
+ */
6
+
7
+ import {internalStateSymbol, internalSymbol,} from "../constants.js";
8
+ import {extend} from "../data/extend.js";
9
+ import {assignToNamespace, Monster} from "../namespace.js";
10
+ import {BaseWithOptions} from "../types/basewithoptions.js";
11
+ import {getGlobalObject} from "../types/global.js";
12
+ import {ID} from "../types/id.js";
13
+ import {isString} from "../types/is.js";
14
+ import {Observer} from "../types/observer.js";
15
+ import {ProxyObserver} from "../types/proxyobserver.js";
16
+ import {ATTRIBUTE_CLASS, ATTRIBUTE_ID, ATTRIBUTE_TITLE} from "./constants.js";
17
+
18
+
19
+ /**
20
+ * @private
21
+ * @type {string}
22
+ */
23
+ export const KEY_DOCUMENT = 'document';
24
+
25
+ /**
26
+ * @private
27
+ * @type {string}
28
+ */
29
+ export const KEY_QUERY = 'query';
30
+
31
+ /**
32
+ * @private
33
+ * @type {string}
34
+ */
35
+ export const KEY_TIMEOUT = 'timeout';
36
+
37
+ /**
38
+ * @private
39
+ * @type {symbol}
40
+ */
41
+ export const referenceSymbol = Symbol('reference');
42
+
43
+ /**
44
+ * This class is the base class for all resources to be loaded.
45
+ *
46
+ * You can call the method via the monster namespace `new Monster.DOM.Resource()`.
47
+ *
48
+ * ```
49
+ * <script type="module">
50
+ * import {Monster} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.27.0/dist/monster.js';
51
+ * new Monster.DOM.Resource()
52
+ * </script>
53
+ * ```
54
+ *
55
+ * Alternatively, you can also integrate this function individually.
56
+ *
57
+ * ```
58
+ * <script type="module">
59
+ * import {Resource} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.27.0/dist/modules/dom/resource.js';
60
+ * new Resource()
61
+ * </script>
62
+ * ```
63
+ *
64
+ * @since 1.25.0
65
+ * @copyright schukai GmbH
66
+ * @memberOf Monster.DOM
67
+ * @summary A Resource class
68
+ */
69
+ class Resource extends BaseWithOptions {
70
+
71
+ /**
72
+ *
73
+ * @param {Object|undefined} options
74
+ */
75
+ constructor(options) {
76
+ super(options);
77
+
78
+ let uri = this.getOption(this.constructor.getURLAttribute());
79
+
80
+ if (uri === undefined) {
81
+ throw new Error('missing source')
82
+ } else if (uri instanceof URL) {
83
+ uri = uri.toString();
84
+ } else if (!isString(uri)) {
85
+ throw new Error('unsupported url type')
86
+ }
87
+
88
+ this[internalSymbol][this.constructor.getURLAttribute()] = uri;
89
+ this[internalStateSymbol] = new ProxyObserver({
90
+ loaded: false,
91
+ error: undefined,
92
+ })
93
+
94
+ this[referenceSymbol] = undefined;
95
+
96
+ }
97
+
98
+ /**
99
+ * @return {boolean}
100
+ */
101
+ isConnected() {
102
+
103
+ if (this[referenceSymbol] instanceof HTMLElement) {
104
+ return this[referenceSymbol].isConnected;
105
+ }
106
+
107
+ return false;
108
+ }
109
+
110
+ /**
111
+ * This method is overridden by the special classes and creates the DOM object.
112
+ * This method is also called implicitly, if not yet done explicitly, by calling `connect()`.
113
+ *
114
+ * @throws {Error} this method must be implemented by derived classes
115
+ * @return {Monster.DOM.Resource}
116
+ */
117
+ create() {
118
+ throw new Error("this method must be implemented by derived classes");
119
+ }
120
+
121
+ /**
122
+ * This method appends the HTMLElement to the specified document.
123
+ * If the element has not yet been created, `create()` is called implicitly.
124
+ *
125
+ * throws {Error} target not found
126
+ * @return {Monster.DOM.Resource}
127
+ */
128
+ connect() {
129
+
130
+ if (!(this[referenceSymbol] instanceof HTMLElement)) {
131
+ this.create();
132
+ }
133
+
134
+ appendToDocument.call(this);
135
+ return this;
136
+ }
137
+
138
+ /**
139
+ * @property {Document} document the document object into which the node is to be appended
140
+ * @property {string} src/href url to the corresponding resource
141
+ * @property {string} query defines the location where the resource is to be hooked into the dom.
142
+ * @property {string} id element attribute id
143
+ * @property {string} title element attribute title
144
+ * @property {string} class element attribute class
145
+ * @property {int} timeout timeout
146
+ */
147
+ get defaults() {
148
+ return extend({}, super.defaults, {
149
+ [this.constructor.getURLAttribute()]: undefined,
150
+ [KEY_DOCUMENT]: getGlobalObject('document'),
151
+ [KEY_QUERY]: 'head',
152
+ [KEY_TIMEOUT]: 10000,
153
+ [ATTRIBUTE_ID]: (new ID('resource')).toString(),
154
+ [ATTRIBUTE_CLASS]: undefined,
155
+ [ATTRIBUTE_TITLE]: undefined
156
+ })
157
+ }
158
+
159
+ /**
160
+ * With `available()` you can check if a resource is available.
161
+ * This is the case when the tag is included and the resource is loaded.
162
+ *
163
+ * @return {Promise}
164
+ */
165
+ available() {
166
+ const self = this;
167
+ if (!(self[referenceSymbol] instanceof HTMLElement)) {
168
+ return Promise.reject('no element')
169
+ }
170
+
171
+ if (!self.isConnected()) {
172
+ return Promise.reject('element not connected')
173
+ }
174
+
175
+ if (self[internalStateSymbol].getSubject()['loaded'] === true) {
176
+
177
+ if (self[internalStateSymbol].getSubject()['error'] !== undefined) {
178
+ return Promise.reject(self[internalStateSymbol].getSubject()['error']);
179
+ }
180
+
181
+ return Promise.resolve();
182
+
183
+ }
184
+
185
+ return new Promise(function (resolve, reject) {
186
+
187
+ const timeout = setTimeout(() => {
188
+ reject('timeout');
189
+ }, self.getOption('timeout'))
190
+
191
+ const observer = new Observer(() => {
192
+ clearTimeout(timeout);
193
+ self[internalStateSymbol].detachObserver(observer);
194
+ resolve();
195
+ })
196
+
197
+ self[internalStateSymbol].attachObserver(observer);
198
+
199
+ });
200
+
201
+ };
202
+
203
+ /**
204
+ * @return {string}
205
+ */
206
+ static getURLAttribute() {
207
+ throw new Error("this method must be implemented by derived classes");
208
+ }
209
+
210
+ }
211
+
212
+
213
+ /**
214
+ * @private
215
+ * @return {Promise}
216
+ * throws {Error} target not found
217
+ */
218
+ function appendToDocument() {
219
+ const self = this;
220
+
221
+ const targetNode = document.querySelector(self.getOption(KEY_QUERY, 'head'))
222
+ if (!(targetNode instanceof HTMLElement)) {
223
+ throw new Error('target not found')
224
+ }
225
+
226
+ addEvents.call(self);
227
+ targetNode.appendChild(self[referenceSymbol]);
228
+
229
+ return self;
230
+ }
231
+
232
+ /**
233
+ * @private
234
+ * @return {addEvents}
235
+ */
236
+ function addEvents() {
237
+ const self = this;
238
+
239
+ const onError = () => {
240
+
241
+ self[referenceSymbol].removeEventListener('error', onError);
242
+ self[referenceSymbol].removeEventListener('load', onLoad);
243
+
244
+ self[internalStateSymbol].setSubject({
245
+ loaded: true,
246
+ error: self[referenceSymbol][self.constructor.getURLAttribute()] + ' is not available',
247
+ })
248
+
249
+ return;
250
+ }
251
+
252
+ const onLoad = () => {
253
+ self[referenceSymbol].removeEventListener('error', onError);
254
+ self[referenceSymbol].removeEventListener('load', onLoad);
255
+ self[internalStateSymbol].getSubject()['loaded'] = true;
256
+ return;
257
+ }
258
+
259
+ self[referenceSymbol].addEventListener('load', onLoad, false);
260
+ self[referenceSymbol].addEventListener('error', onError, false);
261
+
262
+ return self;
263
+
264
+ }
265
+
266
+
267
+ assignToNamespace('Monster.DOM', Resource);
268
+ export {Monster, Resource}
@@ -0,0 +1,214 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * @author schukai GmbH
5
+ */
6
+
7
+ import {extend} from "../data/extend.js";
8
+ import {assignToNamespace, Monster} from "../namespace.js";
9
+ import {BaseWithOptions} from "../types/basewithoptions.js";
10
+ import {getGlobalObject} from "../types/global.js";
11
+ import {isArray} from "../types/is.js";
12
+ import {ATTRIBUTE_HREF, ATTRIBUTE_SRC} from "./constants.js";
13
+ import {Resource} from "./resource.js";
14
+ import {Data} from "./resource/data.js";
15
+ import {Stylesheet} from "./resource/link/stylesheet.js";
16
+ import {Script} from "./resource/script.js";
17
+
18
+
19
+ /**
20
+ * You can call the method via the monster namespace `new Monster.DOM.ResourceManager()`.
21
+ *
22
+ * ```
23
+ * <script type="module">
24
+ * import {Monster} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.27.0/dist/monster.js';
25
+ * new Monster.DOM.ResourceManager()
26
+ * </script>
27
+ * ```
28
+ *
29
+ * Alternatively, you can also integrate this function individually.
30
+ *
31
+ * ```
32
+ * <script type="module">
33
+ * import {Resource} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.27.0/dist/modules/dom/resourcemanager.js';
34
+ * new ResourceManager()
35
+ * </script>
36
+ * ```
37
+ *
38
+ * @since 1.25.0
39
+ * @copyright schukai GmbH
40
+ * @memberOf Monster.DOM
41
+ * @summary A Resource class
42
+ */
43
+ class ResourceManager extends BaseWithOptions {
44
+
45
+ /**
46
+ *
47
+ * @param {Object} options
48
+ * throw {Error} unsupported document type
49
+ */
50
+ constructor(options) {
51
+ super(options);
52
+
53
+ if (!(this.getOption('document') instanceof Document)) {
54
+ throw new Error('unsupported document type')
55
+ }
56
+
57
+
58
+ }
59
+
60
+ /**
61
+ * @property {string} baseurl
62
+ */
63
+ getBaseURL() {
64
+ this.getOption('document')?.baseURL;
65
+ }
66
+
67
+ /**
68
+ *
69
+ * @property {HTMLDocument} document=document Document
70
+ * @property {Object} resources
71
+ * @property {Array} resources.scripts=[] array with {@link Monster.DOM.Resource.Script} objects
72
+ * @property {Array} resources.stylesheets=[] array with {@link Monster.DOM.Resource.Link.Stylesheet} objects
73
+ * @property {Array} resources.data=[] array with {@link Monster.DOM.Resource.Data} objects
74
+ */
75
+ get defaults() {
76
+ return Object.assign({}, super.defaults, {
77
+ document: getGlobalObject('document'),
78
+ resources: {
79
+ scripts: [],
80
+ stylesheets: [],
81
+ data: []
82
+ }
83
+ })
84
+ }
85
+
86
+ /**
87
+ * Append Tags to DOM
88
+ *
89
+ * @return {Monster.DOM.ResourceManager}
90
+ * @throws {Error} unsupported resource definition
91
+ */
92
+ connect() {
93
+ runResourceMethod.call(this, 'connect');
94
+ return this;
95
+ }
96
+
97
+ /**
98
+ * Check if available
99
+ *
100
+ * @return {Promise}
101
+ * @throws {Error} unsupported resource definition
102
+ */
103
+ available() {
104
+ return Promise.all(runResourceMethod.call(this, 'available'));
105
+ }
106
+
107
+ /**
108
+ * Add a script
109
+ *
110
+ * @param {string|URL} url
111
+ * @param [Object|undefined} options
112
+ * @return {Monster.DOM.ResourceManager}
113
+ * @see Monster.DOM.Resource.Script
114
+ */
115
+ addScript(url, options) {
116
+ return addResource.call(this, 'scripts', url, options);
117
+ }
118
+
119
+
120
+ /**
121
+ * Add Stylesheet
122
+ *
123
+ * @param {string|URL} url
124
+ * @param [Object|undefined} options
125
+ * @return {Monster.DOM.ResourceManager}
126
+ * @see Monster.DOM.Resource.Link.Stylesheet
127
+ */
128
+ addStylesheet(url, options) {
129
+ return addResource.call(this, 'stylesheets', url, options);
130
+ }
131
+
132
+ /**
133
+ * Add Data Tag
134
+ *
135
+ * @param {string|URL} url
136
+ * @param [Object|undefined} options
137
+ * @return {Monster.DOM.ResourceManager}
138
+ * @see Monster.DOM.Resource.Data
139
+ */
140
+ addData(url, options) {
141
+ return addResource.call(this, 'data', url, options);
142
+ }
143
+
144
+
145
+ }
146
+
147
+ /**
148
+ * @private
149
+ * @param {string} method
150
+ * @return {Array}
151
+ */
152
+ function runResourceMethod(method) {
153
+ const self = this;
154
+
155
+ const result = [];
156
+
157
+ for (const type of ['scripts', 'stylesheets', 'data']) {
158
+ const resources = self.getOption('resources.' + type);
159
+ if (!isArray(resources)) {
160
+ continue;
161
+ }
162
+
163
+ for (const resource of resources) {
164
+ if (!(resource instanceof Resource)) {
165
+ throw new Error('unsupported resource definition')
166
+ }
167
+
168
+ result.push(resource[method]());
169
+ }
170
+
171
+ }
172
+
173
+ return result;
174
+ }
175
+
176
+ /**
177
+ *
178
+ * @param {string} type
179
+ * @param {string|URL} url
180
+ * @param [Object|undefined} options
181
+ * @return {Monster.DOM.ResourceManager}
182
+ * @private
183
+ */
184
+ function addResource(type, url, options) {
185
+ const self = this;
186
+
187
+ if (url instanceof URL) {
188
+ url = url.toString();
189
+ }
190
+
191
+ options = options || {}
192
+
193
+ let resource;
194
+ switch (type) {
195
+ case 'scripts':
196
+ resource = new Script(extend({}, options, {[ATTRIBUTE_SRC]: url}))
197
+ break;
198
+ case 'stylesheets':
199
+ resource = new Stylesheet(extend({}, options, {[ATTRIBUTE_HREF]: url}))
200
+ break;
201
+ case 'data':
202
+ resource = new Data(extend({}, options, {[ATTRIBUTE_SRC]: url}))
203
+ break;
204
+ default:
205
+ throw new Error('unsupported type ' + type)
206
+ }
207
+
208
+ (self.getOption('resources')?.[type]).push(resource);
209
+ return self;
210
+ }
211
+
212
+
213
+ assignToNamespace('Monster.DOM', ResourceManager);
214
+ export {Monster, ResourceManager}
@@ -7,6 +7,7 @@ import {assignToNamespace, Monster} from '../namespace.js';
7
7
  import {Base} from '../types/base.js';
8
8
  import {getGlobalFunction, getGlobalObject} from '../types/global.js';
9
9
  import {validateInstance, validateString} from "../types/validate.js";
10
+ import {ATTRIBUTE_TEMPLATE_PREFIX} from "./constants.js";
10
11
  import {getDocumentTheme} from "./theme.js";
11
12
 
12
13
  /**
@@ -14,8 +15,8 @@ import {getDocumentTheme} from "./theme.js";
14
15
  *
15
16
  * ```
16
17
  * <script type="module">
17
- * import {Monster} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.24.0/dist/modules/dom/template.js';
18
- * console.log(new Monster.DOM.Template())
18
+ * import {Monster} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.27.0/dist/monster.js';
19
+ * new Monster.DOM.Template()
19
20
  * </script>
20
21
  * ```
21
22
  *
@@ -23,8 +24,8 @@ import {getDocumentTheme} from "./theme.js";
23
24
  *
24
25
  * ```
25
26
  * <script type="module">
26
- * import {Template} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.24.0/dist/modules/dom/template.js';
27
- * console.log(new Template())
27
+ * import {Template} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.27.0/dist/modules/dom/template.js';
28
+ * new Template()
28
29
  * </script>
29
30
  * ```
30
31
  *
@@ -70,7 +71,7 @@ class Template extends Base {
70
71
  /**
71
72
  * This method loads a template with the given ID and returns it.
72
73
  *
73
- * To do this, it first fetches the theme of the document and looks for the `data-monster-theme-name` attribute in the HTML tag.
74
+ * To do this, it first reads the theme of the document and looks for the `data-monster-theme-name` attribute in the HTML tag.
74
75
  *
75
76
  * ```
76
77
  * <html data-monster-theme-name="my-theme">
@@ -78,15 +79,15 @@ class Template extends Base {
78
79
  *
79
80
  * If no theme was specified, the default theme is `monster`.
80
81
  *
81
- * Now it is looked if there is a template with the given ID and theme `id-theme` and if yes it is returned.
82
+ * Now it is looked if there is a template with the given ID and theme `id-theme` and if yes it is returned.
82
83
  * If there is no template a search for a template with the given ID `id` is done. If this is also not found, an error is thrown.
83
84
  *
84
85
  * You can call the method via the monster namespace `Monster.DOM.findDocumentTemplate()`.
85
86
  *
86
87
  * ```
87
88
  * <script type="module">
88
- * import {Monster} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.24.0/dist/modules/dom/template.js';
89
- * console.log(Monster.DOM.findDocumentTemplate())
89
+ * import {Monster} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.27.0/dist/monster.js';
90
+ * Monster.DOM.findDocumentTemplate()
90
91
  * </script>
91
92
  * ```
92
93
  *
@@ -94,11 +95,41 @@ class Template extends Base {
94
95
  *
95
96
  * ```
96
97
  * <script type="module">
97
- * import {findTemplate} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.24.0/dist/modules/dom/template.js';
98
- * console.log(findDocumentTemplate())
98
+ * import {findTemplate} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.27.0/dist/modules/dom/template.js';
99
+ * findDocumentTemplate()
99
100
  * </script>
100
101
  * ```
101
102
  *
103
+ * @example
104
+ *
105
+ * import { findDocumentTemplate } from "https://cdn.jsdelivr.net/npm/@schukai/monster@1.27.0/dist/modules/dom/template.js";
106
+ *
107
+ * const template = document.createElement("template");
108
+ * template.id = "myTemplate";
109
+ * template.innerHTML = "<p>my default template</p>";
110
+ * document.body.appendChild(template);
111
+ *
112
+ * const themedTemplate = document.createElement("template");
113
+ * themedTemplate.id = "myTemplate-myTheme";
114
+ * themedTemplate.innerHTML = "<p>my themed template</p>";
115
+ * document.body.appendChild(themedTemplate);
116
+ *
117
+ * // loads the temple and since no theme is set the default template
118
+ * const template1 = findDocumentTemplate("myTemplate");
119
+ * console.log(template1.createDocumentFragment());
120
+ * // ↦ '<p>my default template</p>'
121
+ *
122
+ * // now we set our own theme
123
+ * document
124
+ * .querySelector("html")
125
+ * .setAttribute("data-monster-theme-name", "myTheme");
126
+ *
127
+ * // now we don't get the default template,
128
+ * // but the template with the theme in the id
129
+ * const template2 = findDocumentTemplate("myTemplate");
130
+ * console.log(template2.createDocumentFragment());
131
+ * // ↦ '<p>my themed template</p>'
132
+ *
102
133
  * @param {string} id
103
134
  * @param {Node} currentNode
104
135
  * @return {Monster.DOM.Template}
@@ -111,9 +142,22 @@ class Template extends Base {
111
142
  function findDocumentTemplate(id, currentNode) {
112
143
  validateString(id);
113
144
 
145
+ const document = getGlobalObject('document');
146
+ const HTMLTemplateElement = getGlobalFunction('HTMLTemplateElement');
147
+ const DocumentFragment = getGlobalFunction('DocumentFragment');
148
+ const Document = getGlobalFunction('Document');
149
+
150
+
151
+ let prefixID;
152
+
114
153
  if (!(currentNode instanceof Document || currentNode instanceof DocumentFragment)) {
115
154
 
116
155
  if (currentNode instanceof Node) {
156
+
157
+ if (currentNode.hasAttribute(ATTRIBUTE_TEMPLATE_PREFIX)) {
158
+ prefixID = currentNode.getAttribute(ATTRIBUTE_TEMPLATE_PREFIX)
159
+ }
160
+
117
161
  currentNode = currentNode.getRootNode();
118
162
 
119
163
  if (!(currentNode instanceof Document || currentNode instanceof DocumentFragment)) {
@@ -123,27 +167,53 @@ function findDocumentTemplate(id, currentNode) {
123
167
  }
124
168
 
125
169
  if (!(currentNode instanceof Document || currentNode instanceof DocumentFragment)) {
126
- currentNode = getGlobalObject('document');
170
+ currentNode = document;
127
171
  }
128
172
  }
129
173
 
130
- const HTMLTemplateElement = getGlobalFunction('HTMLTemplateElement');
131
-
174
+ let template;
132
175
  let theme = getDocumentTheme()
176
+
177
+ if (prefixID) {
178
+ let themedPrefixID = prefixID + '-' + id + '-' + theme.getName();
179
+
180
+ // current + themedPrefixID
181
+ template = currentNode.getElementById(themedPrefixID);
182
+ if (template instanceof HTMLTemplateElement) {
183
+ return new Template(template);
184
+ }
185
+
186
+ // document + themedPrefixID
187
+ template = document.getElementById(themedPrefixID);
188
+ if (template instanceof HTMLTemplateElement) {
189
+ return new Template(template);
190
+ }
191
+ }
192
+
133
193
  let themedID = id + '-' + theme.getName();
134
194
 
135
- let template = currentNode.getElementById(themedID);
195
+ // current + themedID
196
+ template = currentNode.getElementById(themedID);
136
197
  if (template instanceof HTMLTemplateElement) {
137
198
  return new Template(template);
138
199
  }
139
200
 
201
+ // document + themedID
202
+ template = document.getElementById(themedID);
203
+ if (template instanceof HTMLTemplateElement) {
204
+ return new Template(template);
205
+ }
206
+
207
+ // current + ID
140
208
  template = currentNode.getElementById(id);
141
209
  if (template instanceof HTMLTemplateElement) {
142
210
  return new Template(template);
143
211
  }
144
212
 
145
- if (currentNode !== getGlobalObject('document')) {
146
- return findDocumentTemplate(id)
213
+ // document + ID
214
+ template = document.getElementById(id);
215
+ if (template instanceof HTMLTemplateElement) {
216
+ return new Template(template);
147
217
  }
148
218
 
149
219
  throw new Error("template " + id + " not found.")
@@ -15,7 +15,7 @@ import {ATTRIBUTE_THEME_NAME, DEFAULT_THEME} from "./constants.js";
15
15
  *
16
16
  * ```
17
17
  * <script type="module">
18
- * import {Monster} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.24.0/dist/modules/dom/theme.js';
18
+ * import {Monster} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.27.0/dist/monster.js';
19
19
  * console.log(new Monster.DOM.Theme())
20
20
  * </script>
21
21
  * ```
@@ -24,14 +24,14 @@ import {ATTRIBUTE_THEME_NAME, DEFAULT_THEME} from "./constants.js";
24
24
  *
25
25
  * ```
26
26
  * <script type="module">
27
- * import {Theme} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.24.0/dist/modules/dom/theme.js';
27
+ * import {Theme} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.27.0/dist/modules/dom/theme.js';
28
28
  * console.log(new Theme())
29
29
  * </script>
30
30
  * ```
31
31
  *
32
32
  * @example
33
33
  *
34
- * import {getDocumentTheme} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.24.0/dist/modules/dom/theme.js';
34
+ * import {getDocumentTheme} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.27.0/dist/modules/dom/theme.js';
35
35
  *
36
36
  * const theme = getDocumentTheme();
37
37
  * console.log(theme.getName());