@schukai/monster 2.2.1 → 3.1.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/README.md +1 -1
- package/package.json +1 -1
- package/source/data/datasource/restapi.mjs +21 -13
- package/source/data/datasource/websocket.mjs +337 -0
- package/source/data/datasource.mjs +12 -0
- package/source/dom/constants.mjs +9 -0
- package/source/dom/customelement.mjs +15 -49
- package/source/dom/updater.mjs +66 -8
- package/source/monster.mjs +0 -1
- package/source/types/queue.mjs +9 -2
- package/source/types/version.mjs +1 -1
- package/test/cases/data/datasource/websocket.mjs +96 -0
- package/test/cases/dom/customelement.mjs +161 -7
- package/test/cases/monster.mjs +1 -1
- package/test/cases/util/deadmansswitch.mjs +3 -3
- package/test/util/jsdom.mjs +2 -0
- package/test/util/websocket.mjs +22 -0
- package/test/web/import.js +3 -0
- package/test/web/test.html +3 -3
- package/test/web/tests.js +1428 -750
package/README.md
CHANGED
|
@@ -73,7 +73,7 @@ We do try to work around some browser bugs, but on the whole we don't use polyfi
|
|
|
73
73
|
However, many functions can be mapped via [polyfill.io](https://polyfill.io/) and thus the compatibility can be increased.
|
|
74
74
|
|
|
75
75
|
```html
|
|
76
|
-
<script id="polyfill" src="https://polyfill.io/v3/polyfill.min.js?features=Array.from,Array.isArray,Array.prototype.entries,Array.prototype.fill,Array.prototype.filter,Array.prototype.forEach,Array.prototype.indexOf,Array.prototype.keys,Array.prototype.lastIndexOf,Array.prototype.map,Array.prototype.reduce,Array.prototype.sort,ArrayBuffer,atob,CustomEvent,DataView,document,Document,DocumentFragment,Element,Event,fetch,globalThis,HTMLDocument,HTMLTemplateElement,Intl,JSON,Map,Math.log2,Number.isInteger,Object.assign,Object.defineProperty,Object.entries,Object.freeze,Object.getOwnPropertyDescriptor,Object.getOwnPropertyNames,Object.
|
|
76
|
+
<script id="polyfill" src="https://polyfill.io/v3/polyfill.min.js?features=Array.from,Array.isArray,Array.prototype.entries,Array.prototype.fill,Array.prototype.filter,Array.prototype.forEach,Array.prototype.indexOf,Array.prototype.keys,Array.prototype.lastIndexOf,Array.prototype.map,Array.prototype.reduce,Array.prototype.sort,ArrayBuffer,atob,CustomEvent,DataView,document,Document,DocumentFragment,Element,Event,fetch,globalThis,HTMLDocument,HTMLTemplateElement,Intl,JSON,Map,Math.log2,Number.isInteger,Object.assign,Object.defineProperty,Object.entries,Object.freeze,Object.getOwnPropertyDescriptor,Object.getOwnPropertyNames,Object.getPrototypeOf,Object.keys,Promise,Reflect,Reflect.defineProperty,Reflect.get,Reflect.getOwnPropertyDescriptor,Reflect.setPrototypeOf,Set,String.prototype.endsWith,String.prototype.matchAll,String.prototype.padStart,String.prototype.startsWith,String.prototype.trim,Symbol,Symbol.for,Symbol.hasInstance,Symbol.iterator,Uint16Array,Uint8Array,URL,WeakMap,WeakSet"
|
|
77
77
|
crossorigin="anonymous"
|
|
78
78
|
referrerpolicy="no-referrer"></script>
|
|
79
79
|
```
|
package/package.json
CHANGED
|
@@ -22,7 +22,7 @@ export {RestAPI}
|
|
|
22
22
|
* @since 1.22.0
|
|
23
23
|
* @copyright schukai GmbH
|
|
24
24
|
* @memberOf Monster.Data.Datasource
|
|
25
|
-
* @summary The
|
|
25
|
+
* @summary The RestAPI is a class that binds a REST API server.
|
|
26
26
|
*/
|
|
27
27
|
class RestAPI extends Datasource {
|
|
28
28
|
|
|
@@ -30,7 +30,6 @@ class RestAPI extends Datasource {
|
|
|
30
30
|
*
|
|
31
31
|
* @param {Object} [readDefinition] An options object containing any custom settings that you want to apply to the read request.
|
|
32
32
|
* @param {Object} [writeDefinition] An options object containing any custom settings that you want to apply to the write request.
|
|
33
|
-
* @throws {TypeError} value is not a string
|
|
34
33
|
*/
|
|
35
34
|
constructor(readDefinition, writeDefinition) {
|
|
36
35
|
super();
|
|
@@ -54,17 +53,21 @@ class RestAPI extends Datasource {
|
|
|
54
53
|
}
|
|
55
54
|
|
|
56
55
|
/**
|
|
57
|
-
* @property {string} url=undefined Defines the resource that you wish to fetch.
|
|
58
56
|
* @property {Object} write={} Options
|
|
59
57
|
* @property {Object} write.init={} An options object containing any custom settings that you want to apply to the request. The parameters are identical to those of the {@link https://developer.mozilla.org/en-US/docs/Web/API/Request/Request|Request constructor}
|
|
60
58
|
* @property {string} write.init.method=POST
|
|
59
|
+
* @property {Object} write.init.headers Object containing any custom headers that you want to apply to the request.
|
|
61
60
|
* @property {string} write.acceptedStatus=[200,201]
|
|
62
61
|
* @property {string} write.url URL
|
|
63
62
|
* @property {Object} write.mapping the mapping is applied before writing.
|
|
64
63
|
* @property {String} write.mapping.transformer Transformer to select the appropriate entries
|
|
64
|
+
* @property {Monster.Data.Datasource~exampleCallback[]} write.mapping.callback with the help of the callback, the structures can be adjusted before writing.
|
|
65
65
|
* @property {Object} write.report
|
|
66
66
|
* @property {String} write.report.path Path to validations
|
|
67
|
-
* @property {
|
|
67
|
+
* @property {Object} write.sheathing
|
|
68
|
+
* @property {Object} write.sheathing.object Object to be wrapped
|
|
69
|
+
* @property {string} write.sheathing.path Path to the data
|
|
70
|
+
* @property {Object} read={} Options
|
|
68
71
|
* @property {Object} read.init={} An options object containing any custom settings that you want to apply to the request. The parameters are identical to those of the {@link https://developer.mozilla.org/en-US/docs/Web/API/Request/Request|Request constructor}
|
|
69
72
|
* @property {string} read.init.method=GET
|
|
70
73
|
* @property {string} read.acceptedStatus=[200]
|
|
@@ -85,6 +88,10 @@ class RestAPI extends Datasource {
|
|
|
85
88
|
transformer: undefined,
|
|
86
89
|
callbacks: []
|
|
87
90
|
},
|
|
91
|
+
sheathing: {
|
|
92
|
+
object: undefined,
|
|
93
|
+
path: undefined,
|
|
94
|
+
},
|
|
88
95
|
report: {
|
|
89
96
|
path: undefined
|
|
90
97
|
}
|
|
@@ -146,6 +153,11 @@ class RestAPI extends Datasource {
|
|
|
146
153
|
let transformation = self.getOption('read.mapping.transformer');
|
|
147
154
|
if (transformation !== undefined) {
|
|
148
155
|
const pipe = new Pipe(transformation);
|
|
156
|
+
|
|
157
|
+
for (const callback of self.getOption('read.mapping.callbacks')) {
|
|
158
|
+
pipe.setCallback(callback.constructor.name, callback);
|
|
159
|
+
}
|
|
160
|
+
|
|
149
161
|
obj = pipe.run(obj);
|
|
150
162
|
}
|
|
151
163
|
|
|
@@ -174,6 +186,11 @@ class RestAPI extends Datasource {
|
|
|
174
186
|
let transformation = self.getOption('write.mapping.transformer');
|
|
175
187
|
if (transformation !== undefined) {
|
|
176
188
|
const pipe = new Pipe(transformation);
|
|
189
|
+
|
|
190
|
+
for (const callback of self.getOption('write.mapping.callbacks')) {
|
|
191
|
+
pipe.setCallback(callback.constructor.name, callback);
|
|
192
|
+
}
|
|
193
|
+
|
|
177
194
|
obj = pipe.run(obj);
|
|
178
195
|
}
|
|
179
196
|
|
|
@@ -234,12 +251,3 @@ class RestAPI extends Datasource {
|
|
|
234
251
|
}
|
|
235
252
|
|
|
236
253
|
|
|
237
|
-
/**
|
|
238
|
-
* This callback can be passed to a datasource and is used to adapt data structures.
|
|
239
|
-
*
|
|
240
|
-
* @callback Monster.Data.Datasource~exampleCallback
|
|
241
|
-
* @param {*} value Value
|
|
242
|
-
* @param {string} key Key
|
|
243
|
-
* @memberOf Monster.Data
|
|
244
|
-
* @see Monster.Data.Datasource
|
|
245
|
-
*/
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright schukai GmbH and contributors 2022. All Rights Reserved.
|
|
3
|
+
* Node module: @schukai/monster
|
|
4
|
+
* This file is licensed under the AGPLv3 License.
|
|
5
|
+
* License text available at https://www.gnu.org/licenses/agpl-3.0.en.html
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {internalSymbol, instanceSymbol} from "../../constants.mjs";
|
|
9
|
+
import {isInteger, isString, isObject} from "../../types/is.mjs";
|
|
10
|
+
import {Queue} from "../../types/queue.mjs";
|
|
11
|
+
import {Datasource} from "../datasource.mjs";
|
|
12
|
+
import {Pathfinder} from "../pathfinder.mjs";
|
|
13
|
+
import {Pipe} from "../pipe.mjs";
|
|
14
|
+
|
|
15
|
+
export {WebSocketDatasource}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @private
|
|
19
|
+
* @type {symbol}
|
|
20
|
+
*/
|
|
21
|
+
const receiveQueueSymbol = Symbol("queue");
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @private
|
|
26
|
+
* @type {symbol}
|
|
27
|
+
*
|
|
28
|
+
* hint: this name is used in the tests. if you want to change it, please change it in the tests as well.
|
|
29
|
+
*/
|
|
30
|
+
const connectionSymbol = Symbol("connection");
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @private
|
|
34
|
+
* @type {symbol}
|
|
35
|
+
*/
|
|
36
|
+
const manualCloseSymbol = Symbol("manualClose");
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @see https://www.rfc-editor.org/rfc/rfc6455.html#section-7.4.1
|
|
40
|
+
* @type {{"1000": string, "1011": string, "1010": string, "1008": string, "1007": string, "1006": string, "1005": string, "1004": string, "1015": string, "1003": string, "1002": string, "1001": string, "1009": string}}
|
|
41
|
+
*/
|
|
42
|
+
const connectionStatusCode = {
|
|
43
|
+
1000: "Normal closure",
|
|
44
|
+
1001: "Going away",
|
|
45
|
+
1002: "Protocol error",
|
|
46
|
+
1003: "Unsupported data",
|
|
47
|
+
1004: "Reserved",
|
|
48
|
+
1005: "No status code",
|
|
49
|
+
1006: "Connection closed abnormally",
|
|
50
|
+
1007: "Invalid frame payload data",
|
|
51
|
+
1008: "Policy violation",
|
|
52
|
+
1009: "Message too big",
|
|
53
|
+
1010: "Mandatory extension",
|
|
54
|
+
1011: "Internal server error",
|
|
55
|
+
1015: "TLS handshake"
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The RestAPI is a class that enables a REST API server.
|
|
60
|
+
*
|
|
61
|
+
* @externalExample ../../../example/data/storage/restapi.mjs
|
|
62
|
+
* @license AGPLv3
|
|
63
|
+
* @since 3.1.0
|
|
64
|
+
* @copyright schukai GmbH
|
|
65
|
+
* @memberOf Monster.Data.Datasource
|
|
66
|
+
* @summary The LocalStorage class encapsulates the access to data objects.
|
|
67
|
+
*/
|
|
68
|
+
class WebSocketDatasource extends Datasource {
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
*
|
|
72
|
+
* @param {Object} [options] options contains definitions for the datasource.
|
|
73
|
+
*/
|
|
74
|
+
constructor(options) {
|
|
75
|
+
super();
|
|
76
|
+
|
|
77
|
+
if (isString(options)) {
|
|
78
|
+
options = {url: options};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (!isObject(options)) options = {};
|
|
82
|
+
this.setOptions(options);
|
|
83
|
+
this[receiveQueueSymbol] = new Queue();
|
|
84
|
+
|
|
85
|
+
this[connectionSymbol] = {};
|
|
86
|
+
this[connectionSymbol].socket = null;
|
|
87
|
+
this[connectionSymbol].reconnectCounter = 0;
|
|
88
|
+
this[manualCloseSymbol]=false;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
*
|
|
93
|
+
* @returns {Websocketdatasource}
|
|
94
|
+
* @throws {Error} No url defined for websocket datasource.
|
|
95
|
+
*/
|
|
96
|
+
connect() {
|
|
97
|
+
const self = this;
|
|
98
|
+
|
|
99
|
+
let connected = false;
|
|
100
|
+
let reconnectTimeout = self.getOption('reconnect.timeout');
|
|
101
|
+
if (!isInteger(reconnectTimeout) || reconnectTimeout < 1000) reconnectTimeout = 1000;
|
|
102
|
+
let reconnectAttempts = self.getOption('reconnect.attempts');
|
|
103
|
+
if (!isInteger(reconnectAttempts) || reconnectAttempts < 1) reconnectAttempts = 1;
|
|
104
|
+
let reconnectEnabled = self.getOption('reconnect.enabled');
|
|
105
|
+
if (reconnectEnabled !== true) reconnectEnabled = false;
|
|
106
|
+
|
|
107
|
+
self[manualCloseSymbol] = false;
|
|
108
|
+
self[connectionSymbol].reconnectCounter++;
|
|
109
|
+
|
|
110
|
+
if (self[connectionSymbol].socket && self[connectionSymbol].socket.readyState < 2) {
|
|
111
|
+
self[connectionSymbol].socket.close();
|
|
112
|
+
}
|
|
113
|
+
self[connectionSymbol].socket = null;
|
|
114
|
+
|
|
115
|
+
const url = self.getOption('url');
|
|
116
|
+
if (!url) throw new Error('No url defined for websocket datasource.');
|
|
117
|
+
|
|
118
|
+
self[connectionSymbol].socket = new WebSocket(url);
|
|
119
|
+
|
|
120
|
+
self[connectionSymbol].socket.onmessage = function (event) {
|
|
121
|
+
self[receiveQueueSymbol].add(event);
|
|
122
|
+
setTimeout(function () {
|
|
123
|
+
self.read();
|
|
124
|
+
}, 0);
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
self[connectionSymbol].socket.onopen = function () {
|
|
128
|
+
connected = true;
|
|
129
|
+
self[connectionSymbol].reconnectCounter = 0;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
self[connectionSymbol].socket.close = function (event) {
|
|
133
|
+
|
|
134
|
+
if (self[manualCloseSymbol]) {
|
|
135
|
+
self[manualCloseSymbol] = false;
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (reconnectEnabled && this[connectionSymbol].reconnectCounter < reconnectAttempts) {
|
|
140
|
+
setTimeout(() => {
|
|
141
|
+
self.connect();
|
|
142
|
+
}, reconnectTimeout * this[connectionSymbol].reconnectCounter);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
self[connectionSymbol].socket.onerror = (error) => {
|
|
148
|
+
|
|
149
|
+
if (reconnectEnabled && self[connectionSymbol].reconnectCounter < reconnectAttempts) {
|
|
150
|
+
setTimeout(() => {
|
|
151
|
+
self.connect();
|
|
152
|
+
}, reconnectTimeout * this[connectionSymbol].reconnectCounter);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
isConnected() {
|
|
159
|
+
return this[connectionSymbol].socket && this[connectionSymbol].socket.readyState === 1;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* This method is called by the `instanceof` operator.
|
|
164
|
+
* @returns {symbol}
|
|
165
|
+
*/
|
|
166
|
+
static get [instanceSymbol]() {
|
|
167
|
+
return Symbol.for("@schukai/monster/data/datasource/websocket");
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* @property {string} url=undefined Defines the resource that you wish to fetch.
|
|
172
|
+
* @property {Number} reconnect.timeout The timeout in milliseconds for the reconnect.
|
|
173
|
+
* @property {Number} reconnect.attempts The maximum number of reconnects.
|
|
174
|
+
* @property {Bool} reconnect.enabled If the reconnect is enabled.
|
|
175
|
+
* @property {Object} write={} Options
|
|
176
|
+
* @property {Object} write.mapping the mapping is applied before writing.
|
|
177
|
+
* @property {String} write.mapping.transformer Transformer to select the appropriate entries
|
|
178
|
+
* @property {Monster.Data.Datasource~exampleCallback[]} write.mapping.callback with the help of the callback, the structures can be adjusted before writing.
|
|
179
|
+
* @property {Object} write.report
|
|
180
|
+
* @property {String} write.report.path Path to validations
|
|
181
|
+
* @property {Object} write.sheathing
|
|
182
|
+
* @property {Object} write.sheathing.object Object to be wrapped
|
|
183
|
+
* @property {string} write.sheathing.path Path to the data
|
|
184
|
+
* @property {Object} read={} Options
|
|
185
|
+
* @property {Object} read.mapping the mapping is applied after reading.
|
|
186
|
+
* @property {String} read.mapping.transformer Transformer to select the appropriate entries
|
|
187
|
+
* @property {Monster.Data.Datasource~exampleCallback[]} read.mapping.callback with the help of the callback, the structures can be adjusted after reading.
|
|
188
|
+
*/
|
|
189
|
+
get defaults() {
|
|
190
|
+
return Object.assign({}, super.defaults, {
|
|
191
|
+
url: undefined,
|
|
192
|
+
write: {
|
|
193
|
+
mapping: {
|
|
194
|
+
transformer: undefined,
|
|
195
|
+
callbacks: []
|
|
196
|
+
},
|
|
197
|
+
report: {
|
|
198
|
+
path: undefined
|
|
199
|
+
},
|
|
200
|
+
sheathing: {
|
|
201
|
+
object: undefined,
|
|
202
|
+
path: undefined,
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
read: {
|
|
206
|
+
mapping: {
|
|
207
|
+
transformer: undefined,
|
|
208
|
+
callbacks: []
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
reconnect: {
|
|
212
|
+
timeout: 1000,
|
|
213
|
+
attempts: 10,
|
|
214
|
+
enabled: true
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* This method closes the connection.
|
|
221
|
+
*
|
|
222
|
+
* @returns {Promise}
|
|
223
|
+
*/
|
|
224
|
+
close() {
|
|
225
|
+
this[manualCloseSymbol]=true;
|
|
226
|
+
if (this[connectionSymbol].socket) {
|
|
227
|
+
this[connectionSymbol].socket.close();
|
|
228
|
+
}
|
|
229
|
+
return this;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* @return {Promise}
|
|
234
|
+
* @throws {Error} the options does not contain a valid json definition
|
|
235
|
+
* @throws {Error} the data cannot be read
|
|
236
|
+
* @throws {TypeError} value is not an object
|
|
237
|
+
*/
|
|
238
|
+
read() {
|
|
239
|
+
const self = this;
|
|
240
|
+
let response;
|
|
241
|
+
|
|
242
|
+
return new Promise((resolve, reject) => {
|
|
243
|
+
if (self[receiveQueueSymbol].isEmpty()) {
|
|
244
|
+
resolve();
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
while (!self[receiveQueueSymbol].isEmpty()) {
|
|
248
|
+
|
|
249
|
+
const event = self[receiveQueueSymbol].poll();
|
|
250
|
+
const body = event?.data;
|
|
251
|
+
if (!body) continue;
|
|
252
|
+
|
|
253
|
+
let obj;
|
|
254
|
+
try {
|
|
255
|
+
obj = JSON.parse(body);
|
|
256
|
+
} catch (e) {
|
|
257
|
+
|
|
258
|
+
let msg = 'the response does not contain a valid json (actual: ';
|
|
259
|
+
|
|
260
|
+
if (body.length > 100) {
|
|
261
|
+
msg += body.substring(0, 97) + '...';
|
|
262
|
+
} else {
|
|
263
|
+
msg += body;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
msg += "; " + e.message + ')';
|
|
267
|
+
|
|
268
|
+
reject(msg);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
let transformation = self.getOption('read.mapping.transformer');
|
|
272
|
+
if (transformation !== undefined) {
|
|
273
|
+
const pipe = new Pipe(transformation);
|
|
274
|
+
|
|
275
|
+
for (const callback of self.getOption('read.mapping.callbacks')) {
|
|
276
|
+
pipe.setCallback(callback.constructor.name, callback);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
obj = pipe.run(obj);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
self.set(obj);
|
|
283
|
+
return response;
|
|
284
|
+
}
|
|
285
|
+
})
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* @return {Promise}
|
|
290
|
+
*/
|
|
291
|
+
write() {
|
|
292
|
+
const self = this;
|
|
293
|
+
|
|
294
|
+
let obj = self.get();
|
|
295
|
+
let transformation = self.getOption('write.mapping.transformer');
|
|
296
|
+
if (transformation !== undefined) {
|
|
297
|
+
const pipe = new Pipe(transformation);
|
|
298
|
+
|
|
299
|
+
for (const callback of self.getOption('write.mapping.callbacks')) {
|
|
300
|
+
pipe.setCallback(callback.constructor.name, callback);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
obj = pipe.run(obj);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
let sheathingObject = self.getOption('write.sheathing.object');
|
|
307
|
+
let sheathingPath = self.getOption('write.sheathing.path');
|
|
308
|
+
let reportPath = self.getOption('write.report.path');
|
|
309
|
+
|
|
310
|
+
if (sheathingObject && sheathingPath) {
|
|
311
|
+
const sub = obj;
|
|
312
|
+
obj = sheathingObject;
|
|
313
|
+
(new Pathfinder(obj)).setVia(sheathingPath, sub);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return new Promise((resolve, reject) => {
|
|
317
|
+
|
|
318
|
+
if (self[connectionSymbol].socket.readyState !== 1) {
|
|
319
|
+
reject('the socket is not ready');
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
self[connectionSymbol].socket.send(JSON.stringify(obj))
|
|
323
|
+
resolve();
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* @return {RestAPI}
|
|
330
|
+
*/
|
|
331
|
+
getClone() {
|
|
332
|
+
const self = this;
|
|
333
|
+
return new Websocketdatasource(self[internalSymbol].getRealSubject()['options']);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
}
|
|
337
|
+
|
|
@@ -17,6 +17,18 @@ import {Pathfinder} from "./pathfinder.mjs";
|
|
|
17
17
|
|
|
18
18
|
export {Datasource}
|
|
19
19
|
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* This callback can be passed to a datasource and is used to adapt data structures.
|
|
23
|
+
*
|
|
24
|
+
* @callback Monster.Data.Datasource~exampleCallback
|
|
25
|
+
* @param {*} value Value
|
|
26
|
+
* @param {string} key Key
|
|
27
|
+
* @memberOf Monster.Data
|
|
28
|
+
* @see Monster.Data.Datasource
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
|
|
20
32
|
/**
|
|
21
33
|
* @private
|
|
22
34
|
* @type {symbol}
|
package/source/dom/constants.mjs
CHANGED
|
@@ -59,6 +59,7 @@ export {
|
|
|
59
59
|
ATTRIBUTE_EXPORTPARTS,
|
|
60
60
|
ATTRIBUTE_HIDDEN,
|
|
61
61
|
objectUpdaterLinkSymbol,
|
|
62
|
+
customElementUpdaterLinkSymbol
|
|
62
63
|
|
|
63
64
|
}
|
|
64
65
|
|
|
@@ -223,6 +224,14 @@ const ATTRIBUTE_ERRORMESSAGE = ATTRIBUTE_PREFIX + 'error';
|
|
|
223
224
|
*/
|
|
224
225
|
const objectUpdaterLinkSymbol = Symbol.for('@schukai/monster/dom/@@object-updater-link');
|
|
225
226
|
|
|
227
|
+
/**
|
|
228
|
+
* @memberOf Monster.DOM
|
|
229
|
+
* @type {symbol}
|
|
230
|
+
* @license AGPLv3
|
|
231
|
+
* @since 1.24.0
|
|
232
|
+
*/
|
|
233
|
+
const customElementUpdaterLinkSymbol = Symbol.for('@schukai/monster/dom/custom-element@@options-updater-link');
|
|
234
|
+
|
|
226
235
|
/**
|
|
227
236
|
* @memberOf Monster.DOM
|
|
228
237
|
* @type {string}
|
|
@@ -16,19 +16,26 @@ import {Observer} from "../types/observer.mjs";
|
|
|
16
16
|
import {ProxyObserver} from "../types/proxyobserver.mjs";
|
|
17
17
|
import {validateFunction, validateInstance, validateObject, validateString} from "../types/validate.mjs";
|
|
18
18
|
import {clone} from "../util/clone.mjs";
|
|
19
|
-
import {addAttributeToken,
|
|
19
|
+
import {addAttributeToken, getLinkedObjects, hasObjectLink} from "./attributes.mjs";
|
|
20
20
|
import {
|
|
21
21
|
ATTRIBUTE_DISABLED,
|
|
22
22
|
ATTRIBUTE_ERRORMESSAGE,
|
|
23
23
|
ATTRIBUTE_OPTIONS,
|
|
24
24
|
ATTRIBUTE_OPTIONS_SELECTOR,
|
|
25
|
-
|
|
25
|
+
customElementUpdaterLinkSymbol
|
|
26
26
|
} from "./constants.mjs";
|
|
27
27
|
import {findDocumentTemplate, Template} from "./template.mjs";
|
|
28
|
-
import {
|
|
28
|
+
import {addObjectWithUpdaterToElement} from "./updater.mjs";
|
|
29
29
|
import {instanceSymbol} from '../constants.mjs';
|
|
30
30
|
|
|
31
|
-
export {
|
|
31
|
+
export {
|
|
32
|
+
CustomElement,
|
|
33
|
+
initMethodSymbol,
|
|
34
|
+
assembleMethodSymbol,
|
|
35
|
+
attributeObserverSymbol,
|
|
36
|
+
registerCustomElement,
|
|
37
|
+
getSlottedElements
|
|
38
|
+
}
|
|
32
39
|
|
|
33
40
|
/**
|
|
34
41
|
* @memberOf Monster.DOM
|
|
@@ -460,7 +467,7 @@ class CustomElement extends HTMLElement {
|
|
|
460
467
|
nodeList = elements
|
|
461
468
|
}
|
|
462
469
|
|
|
463
|
-
|
|
470
|
+
addObjectWithUpdaterToElement.call(self, nodeList, customElementUpdaterLinkSymbol, clone(self[internalSymbol].getRealSubject()['options']))
|
|
464
471
|
return self;
|
|
465
472
|
}
|
|
466
473
|
|
|
@@ -473,7 +480,7 @@ class CustomElement extends HTMLElement {
|
|
|
473
480
|
*/
|
|
474
481
|
connectedCallback() {
|
|
475
482
|
let self = this;
|
|
476
|
-
if (!hasObjectLink(self,
|
|
483
|
+
if (!hasObjectLink(self, customElementUpdaterLinkSymbol)) {
|
|
477
484
|
self[assembleMethodSymbol]()
|
|
478
485
|
}
|
|
479
486
|
}
|
|
@@ -673,11 +680,11 @@ function initOptionObserver() {
|
|
|
673
680
|
self.attachObserver(new Observer(function () {
|
|
674
681
|
|
|
675
682
|
// not initialised
|
|
676
|
-
if (!hasObjectLink(self,
|
|
683
|
+
if (!hasObjectLink(self, customElementUpdaterLinkSymbol)) {
|
|
677
684
|
return;
|
|
678
685
|
}
|
|
679
686
|
// inform every element
|
|
680
|
-
const updaters = getLinkedObjects(self,
|
|
687
|
+
const updaters = getLinkedObjects(self, customElementUpdaterLinkSymbol);
|
|
681
688
|
|
|
682
689
|
for (const list of updaters) {
|
|
683
690
|
for (const updater of list) {
|
|
@@ -935,44 +942,3 @@ function registerCustomElement(element) {
|
|
|
935
942
|
getGlobalObject('customElements').define(element.getTag(), element);
|
|
936
943
|
}
|
|
937
944
|
|
|
938
|
-
|
|
939
|
-
/**
|
|
940
|
-
*
|
|
941
|
-
* @param element
|
|
942
|
-
* @param object
|
|
943
|
-
* @return {Promise[]}
|
|
944
|
-
* @license AGPLv3
|
|
945
|
-
* @since 1.23.0
|
|
946
|
-
* @memberOf Monster.DOM
|
|
947
|
-
*/
|
|
948
|
-
function assignUpdaterToElement(elements, object) {
|
|
949
|
-
|
|
950
|
-
const updaters = new Set;
|
|
951
|
-
|
|
952
|
-
if (elements instanceof NodeList) {
|
|
953
|
-
elements = new Set([
|
|
954
|
-
...elements
|
|
955
|
-
])
|
|
956
|
-
}
|
|
957
|
-
|
|
958
|
-
let result = [];
|
|
959
|
-
|
|
960
|
-
elements.forEach((element) => {
|
|
961
|
-
if (!(element instanceof HTMLElement)) return;
|
|
962
|
-
if ((element instanceof HTMLTemplateElement)) return;
|
|
963
|
-
|
|
964
|
-
const u = new Updater(element, object)
|
|
965
|
-
updaters.add(u);
|
|
966
|
-
|
|
967
|
-
result.push(u.run().then(() => {
|
|
968
|
-
return u.enableEventProcessing();
|
|
969
|
-
}));
|
|
970
|
-
|
|
971
|
-
});
|
|
972
|
-
|
|
973
|
-
if (updaters.size > 0) {
|
|
974
|
-
addToObjectLink(this, objectUpdaterLinkSymbol, updaters);
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
return result;
|
|
978
|
-
}
|