@schukai/monster 4.38.4 → 4.38.6
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 +23 -0
- package/package.json +1 -1
- package/source/components/datatable/datasource/dom.mjs +161 -161
- package/source/components/datatable/filter.mjs +1339 -1342
- package/source/components/datatable/pagination.mjs +491 -493
- package/source/components/datatable/save-button.mjs +331 -331
- package/source/components/form/select.mjs +2851 -2851
- package/source/components/form/toggle-switch.mjs +359 -359
- package/source/components/style/property.css +265 -261
- package/source/components/tree-menu/tree-menu.mjs +444 -446
- package/source/dom/updater.mjs +842 -838
- package/source/i18n/translations.mjs +206 -206
- package/source/types/observer.mjs +127 -132
- package/source/types/version.mjs +1 -1
- package/test/cases/dom/updater.mjs +639 -626
- package/test/cases/monster.mjs +1 -1
- package/test/web/test.html +2 -2
- package/test/web/tests.js +513 -452
@@ -15,149 +15,144 @@
|
|
15
15
|
import { Base } from "./base.mjs";
|
16
16
|
import { isObject } from "./is.mjs";
|
17
17
|
import { TokenList } from "./tokenlist.mjs";
|
18
|
-
import { UniqueQueue } from "./uniquequeue.mjs";
|
19
18
|
import { instanceSymbol } from "../constants.mjs";
|
20
19
|
export { Observer };
|
21
20
|
|
22
21
|
/**
|
23
|
-
*
|
22
|
+
* Manages a callback function that is executed asynchronously when updated.
|
24
23
|
*
|
25
|
-
* The update method is called with the subject object as this
|
26
|
-
* the callback should
|
24
|
+
* The `update` method is called with the subject object as its `this` context.
|
25
|
+
* For this reason, the callback should be a regular function, not an arrow function,
|
26
|
+
* if you need access to the subject via `this`.
|
27
27
|
*
|
28
|
-
*
|
28
|
+
* @example
|
29
|
+
* // Basic usage with a regular function to access the subject
|
30
|
+
* const observer = new Observer(function() {
|
31
|
+
* console.log("Subject updated:", this); // `this` refers to `mySubject`
|
32
|
+
* });
|
29
33
|
*
|
30
|
-
*
|
31
|
-
*
|
32
|
-
*
|
34
|
+
* // Usage with arguments
|
35
|
+
* const greeter = new Observer(function(greeting) {
|
36
|
+
* console.log(greeting, this.name); // "Hello", "World"
|
37
|
+
* }, "Hello");
|
33
38
|
*
|
34
|
-
*
|
35
|
-
*
|
36
|
-
*
|
37
|
-
* new Observer(()=>{
|
38
|
-
* // this is not subject
|
39
|
-
* })
|
40
|
-
*
|
41
|
-
* new Observer(function() {
|
42
|
-
* // this is subject
|
43
|
-
* })
|
44
|
-
* ```
|
45
|
-
*
|
46
|
-
* Additional arguments can be passed to the callback. To do this, simply specify them.
|
47
|
-
*
|
48
|
-
* ```js
|
49
|
-
* Observer(function(a, b, c) {
|
50
|
-
* console.log(a, b, c); // ↦ "a", 2, true
|
51
|
-
* }, "a", 2, true)
|
52
|
-
* ```
|
53
|
-
*
|
54
|
-
* The callback function must have as many parameters as arguments are given.
|
39
|
+
* const mySubject = { name: "World" };
|
40
|
+
* observer.update(mySubject);
|
41
|
+
* greeter.update(mySubject);
|
55
42
|
*
|
56
43
|
* @license AGPLv3
|
57
44
|
* @since 1.0.0
|
58
45
|
*/
|
59
46
|
class Observer extends Base {
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
47
|
+
/**
|
48
|
+
* Stores promises for updates that are scheduled but not yet executed.
|
49
|
+
* This prevents multiple executions for the same subject within one microtask cycle.
|
50
|
+
* @type {Map<object, Promise<*>>}
|
51
|
+
*/
|
52
|
+
#pendingUpdates = new Map();
|
53
|
+
#callback;
|
54
|
+
#arguments;
|
55
|
+
#tags = new TokenList();
|
56
|
+
|
57
|
+
/**
|
58
|
+
* @param {function} callback The function to execute on update.
|
59
|
+
* @param {...*} args Additional arguments to pass to the callback.
|
60
|
+
*/
|
61
|
+
constructor(callback, ...args) {
|
62
|
+
super();
|
63
|
+
|
64
|
+
if (typeof callback !== "function") {
|
65
|
+
throw new Error("Observer callback must be a function.");
|
66
|
+
}
|
67
|
+
|
68
|
+
this.#callback = callback;
|
69
|
+
this.#arguments = args;
|
70
|
+
}
|
71
|
+
|
72
|
+
/**
|
73
|
+
* This method is called by the `instanceof` operator.
|
74
|
+
* @returns {symbol}
|
75
|
+
* @since 2.1.0
|
76
|
+
*/
|
77
|
+
static get [instanceSymbol]() {
|
78
|
+
return Symbol.for("@schukai/monster/types/observer");
|
79
|
+
}
|
80
|
+
|
81
|
+
// Getter for properties for cleaner access if needed
|
82
|
+
get callback() {
|
83
|
+
return this.#callback;
|
84
|
+
}
|
85
|
+
|
86
|
+
get arguments() {
|
87
|
+
return this.#arguments;
|
88
|
+
}
|
89
|
+
|
90
|
+
/**
|
91
|
+
* Schedules the callback for execution with the given subject.
|
92
|
+
* If multiple updates for the same subject are requested in the same event loop tick,
|
93
|
+
* the callback is only executed once. All callers will receive the same promise.
|
94
|
+
*
|
95
|
+
* @param {object} subject The subject object that triggered the update.
|
96
|
+
* @returns {Promise<*>} A promise that resolves with the return value of the callback,
|
97
|
+
* or rejects if the callback throws an error.
|
98
|
+
*/
|
99
|
+
update(subject) {
|
100
|
+
if (!isObject(subject)) {
|
101
|
+
return Promise.reject(new Error("Subject must be an object."));
|
102
|
+
}
|
103
|
+
|
104
|
+
if (this.#pendingUpdates.has(subject)) {
|
105
|
+
return this.#pendingUpdates.get(subject);
|
106
|
+
}
|
107
|
+
|
108
|
+
const promise = new Promise((resolve, reject) => {
|
109
|
+
queueMicrotask(async () => {
|
110
|
+
try {
|
111
|
+
const result = await this.#callback.apply(subject, this.#arguments);
|
112
|
+
resolve(result);
|
113
|
+
} catch (e) {
|
114
|
+
reject(e);
|
115
|
+
} finally {
|
116
|
+
this.#pendingUpdates.delete(subject);
|
117
|
+
}
|
118
|
+
});
|
119
|
+
});
|
120
|
+
|
121
|
+
this.#pendingUpdates.set(subject, promise);
|
122
|
+
|
123
|
+
return promise;
|
124
|
+
}
|
125
|
+
|
126
|
+
/**
|
127
|
+
* @param {string} tag
|
128
|
+
* @returns {Observer}
|
129
|
+
*/
|
130
|
+
addTag(tag) {
|
131
|
+
this.#tags.add(tag);
|
132
|
+
return this;
|
133
|
+
}
|
134
|
+
|
135
|
+
/**
|
136
|
+
* @param {string} tag
|
137
|
+
* @returns {Observer}
|
138
|
+
*/
|
139
|
+
removeTag(tag) {
|
140
|
+
this.#tags.remove(tag);
|
141
|
+
return this;
|
142
|
+
}
|
143
|
+
|
144
|
+
/**
|
145
|
+
* @returns {string[]}
|
146
|
+
*/
|
147
|
+
getTags() {
|
148
|
+
return this.#tags.entries();
|
149
|
+
}
|
150
|
+
|
151
|
+
/**
|
152
|
+
* @param {string} tag
|
153
|
+
* @returns {boolean}
|
154
|
+
*/
|
155
|
+
hasTag(tag) {
|
156
|
+
return this.#tags.contains(tag);
|
157
|
+
}
|
163
158
|
}
|
package/source/types/version.mjs
CHANGED