@cocreate/events 1.25.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.
- package/CHANGELOG.md +31 -0
- package/demo/set-value.html +21 -25
- package/package.json +1 -1
- package/src/index.js +347 -55
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,34 @@
|
|
|
1
|
+
# [1.27.0](https://github.com/CoCreate-app/CoCreate-events/compare/v1.26.0...v1.27.0) (2025-04-11)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* console.log() ([2174c1e](https://github.com/CoCreate-app/CoCreate-events/commit/2174c1e0a9fa0b777e073de30aed4f29ec59f8f6))
|
|
7
|
+
* formating ([58b8550](https://github.com/CoCreate-app/CoCreate-events/commit/58b8550c96c30153a94e24ce93b39914eed2fba3))
|
|
8
|
+
* removed console.log() ([f44cb8f](https://github.com/CoCreate-app/CoCreate-events/commit/f44cb8fdfec3b3b1787e830cd1b3bab3a1ef3fa5))
|
|
9
|
+
* renamed prefix-delay to prefix-setTimout ([84e511a](https://github.com/CoCreate-app/CoCreate-events/commit/84e511af8bcb521e5e8e7bc481a6f202fca04930))
|
|
10
|
+
* Selctor === "" returning null ([c49bc35](https://github.com/CoCreate-app/CoCreate-events/commit/c49bc35cd8a8ff9232229ee64d71bc4e32d3d6fc))
|
|
11
|
+
* selectors ([ccb2dee](https://github.com/CoCreate-app/CoCreate-events/commit/ccb2dee2a682bcdf601047f0783c5c44ebcfe5ed))
|
|
12
|
+
* update observer obseve param to type and and attributeName to attributeFilter ([44372d4](https://github.com/CoCreate-app/CoCreate-events/commit/44372d4ceba70360507cd0c94df43f4ee877be99))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* support "*-preventDefault", "*-stopPropagation", "*-stopImmediatePropagation" ([5b10663](https://github.com/CoCreate-app/CoCreate-events/commit/5b106633f425001ca6ec7d65dc0bd00ad6368b64))
|
|
18
|
+
|
|
19
|
+
# [1.26.0](https://github.com/CoCreate-app/CoCreate-events/compare/v1.25.0...v1.26.0) (2025-01-18)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Bug Fixes
|
|
23
|
+
|
|
24
|
+
* removed ovserver from local storage ([b07e5f7](https://github.com/CoCreate-app/CoCreate-events/commit/b07e5f7ef2d6f8a39dc77a56a63f078d0576f85a))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Features
|
|
28
|
+
|
|
29
|
+
* added focus ([0b81f3e](https://github.com/CoCreate-app/CoCreate-events/commit/0b81f3edff2c254281cb5a1028d2396b3b86e9e8))
|
|
30
|
+
* intersection handling ([dea8872](https://github.com/CoCreate-app/CoCreate-events/commit/dea887246eb0489022450fd135418dc42767fd59))
|
|
31
|
+
|
|
1
32
|
# [1.25.0](https://github.com/CoCreate-app/CoCreate-events/compare/v1.24.0...v1.25.0) (2024-12-14)
|
|
2
33
|
|
|
3
34
|
|
package/demo/set-value.html
CHANGED
|
@@ -1,31 +1,27 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
<head>
|
|
4
|
+
<title>Value | CoCreateJS</title>
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
6
|
+
<!-- CoCreate Favicon -->
|
|
7
|
+
<link
|
|
8
|
+
rel="icon"
|
|
9
|
+
type="image/png"
|
|
10
|
+
sizes="32x32"
|
|
11
|
+
href="../assets/favicon.ico" />
|
|
12
|
+
<link rel="manifest" href="/manifest.webmanifest" />
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<div click-selector="#testing" click-value="hello, bye" click-key="ty">
|
|
16
|
+
<span id="testing" class="{{ty}}">other content</span>
|
|
17
|
+
</div>
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
value-type="array" />
|
|
19
|
+
<form>
|
|
20
|
+
<input input-selector="#testing2" input-attribute="value" />
|
|
21
|
+
<input id="testing2" />
|
|
22
|
+
</form>
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
<!-- <script src="../../../CoCreateJS/dist/CoCreate.js"></script> -->
|
|
29
|
-
<script src="https://CoCreate.app/dist/CoCreate.js"></script>
|
|
30
|
-
</body>
|
|
24
|
+
<!-- <script src="../../../CoCreateJS/dist/CoCreate.js"></script> -->
|
|
25
|
+
<script src="https://CoCreate.app/dist/CoCreate.js"></script>
|
|
26
|
+
</body>
|
|
31
27
|
</html>
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -40,8 +40,10 @@ const CoCreateEvents = {
|
|
|
40
40
|
this.initPrefix("selected", ["click"]);
|
|
41
41
|
this.initPrefix("onload", ["onload"]);
|
|
42
42
|
this.initPrefix("observe", ["observer"]);
|
|
43
|
+
this.initPrefix("intersection", ["intersection"]);
|
|
43
44
|
this.initPrefix("resize", ["onload", "resize"]);
|
|
44
|
-
this.initPrefix("localstorage", ["onload"
|
|
45
|
+
this.initPrefix("localstorage", ["onload"]);
|
|
46
|
+
this.initPrefix("focus", ["focus"]);
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
let customEventEls = document.querySelectorAll("[event-name]");
|
|
@@ -61,7 +63,7 @@ const CoCreateEvents = {
|
|
|
61
63
|
const self = this;
|
|
62
64
|
observer.init({
|
|
63
65
|
name: "CoCreateEventName",
|
|
64
|
-
|
|
66
|
+
types: ["addedNodes"],
|
|
65
67
|
selector: `[event-name]`,
|
|
66
68
|
callback: function (mutation) {
|
|
67
69
|
let name = mutation.target.getAttribute("event-name");
|
|
@@ -87,38 +89,33 @@ const CoCreateEvents = {
|
|
|
87
89
|
}
|
|
88
90
|
});
|
|
89
91
|
|
|
90
|
-
let selector = `[${prefix}], [${prefix}-key], [${prefix}-attribute], [${prefix}-value], [${prefix}-action], [${prefix}-selector], [${prefix}-closest], [${prefix}-parent], [${prefix}-next], [${prefix}-previous]`;
|
|
92
|
+
let selector = `[${prefix}], [${prefix}-key], [${prefix}-attribute], [${prefix}-value], [${prefix}-action], [${prefix}-selector], [${prefix}-closest], [${prefix}-parent], [${prefix}-next], [${prefix}-previous], [${prefix}-preventDefault], [${prefix}-stopPropagation], [${prefix}-stopImmediatePropagation]`;
|
|
91
93
|
|
|
92
94
|
observer.init({
|
|
93
95
|
name: "CoCreateEventattributes",
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
types: ["attributes", "addedNodes"],
|
|
97
|
+
attributeFilter: [
|
|
98
|
+
`${prefix}-key`,
|
|
99
|
+
`${prefix}-value`,
|
|
100
|
+
`${prefix}-selector`,
|
|
101
|
+
`${prefix}-closest`,
|
|
102
|
+
`${prefix}-parent`,
|
|
103
|
+
`${prefix}-next`,
|
|
104
|
+
`${prefix}-previous`,
|
|
105
|
+
`${prefix}-events`,
|
|
106
|
+
`${prefix}-bubbles`,
|
|
107
|
+
`${prefix}-cancelable`,
|
|
108
|
+
`${prefix}-composed`,
|
|
109
|
+
`${prefix}-preventDefault`,
|
|
110
|
+
`${prefix}-stopPropagation`,
|
|
111
|
+
`${prefix}-stopImmediatePropagation`
|
|
112
|
+
],
|
|
113
|
+
selector,
|
|
97
114
|
callback: function (mutation) {
|
|
98
115
|
self.initElements([mutation.target], prefix, events);
|
|
99
116
|
}
|
|
100
117
|
});
|
|
101
118
|
|
|
102
|
-
if (events && events.includes("observer")) {
|
|
103
|
-
observer.init({
|
|
104
|
-
name: "observerAttributes",
|
|
105
|
-
observe: ["attributes"],
|
|
106
|
-
attributeName: [
|
|
107
|
-
`${prefix}-key`,
|
|
108
|
-
`${prefix}-value`,
|
|
109
|
-
`${prefix}-selector`,
|
|
110
|
-
`${prefix}-closest`,
|
|
111
|
-
`${prefix}-parent`,
|
|
112
|
-
`${prefix}-next`,
|
|
113
|
-
`${prefix}-previous`
|
|
114
|
-
],
|
|
115
|
-
callback: function (mutation) {
|
|
116
|
-
// remove previous observer
|
|
117
|
-
self.initElements([mutation.target], prefix, events);
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
|
|
122
119
|
let elements = document.querySelectorAll(selector);
|
|
123
120
|
this.initElements(elements, prefix, events);
|
|
124
121
|
},
|
|
@@ -134,7 +131,9 @@ const CoCreateEvents = {
|
|
|
134
131
|
this.elements.set(el, prefixes);
|
|
135
132
|
} else if (!prefixes[prefix]) {
|
|
136
133
|
prefixes[prefix] = { events };
|
|
137
|
-
} else
|
|
134
|
+
} else {
|
|
135
|
+
isEventable = false;
|
|
136
|
+
}
|
|
138
137
|
|
|
139
138
|
let customEvents = el.getAttribute(`${prefix}-events`);
|
|
140
139
|
if (customEvents) {
|
|
@@ -149,8 +148,25 @@ const CoCreateEvents = {
|
|
|
149
148
|
prefixes[prefix].events = events;
|
|
150
149
|
isEventable = true;
|
|
151
150
|
}
|
|
151
|
+
|
|
152
152
|
if (!events || !isEventable) continue;
|
|
153
|
-
|
|
153
|
+
|
|
154
|
+
// let originalSelector = ""; // i think we need to extract the selector and remove the operators
|
|
155
|
+
// if (originalSelector) {
|
|
156
|
+
// observer.init({
|
|
157
|
+
// types: ["addedNodes"],
|
|
158
|
+
// callback: function (mutation) {
|
|
159
|
+
// const els = el.queryElements();
|
|
160
|
+
// if (els && els.includes(mutation.target)) {
|
|
161
|
+
// self.__updateElements();
|
|
162
|
+
// }
|
|
163
|
+
// }
|
|
164
|
+
// });
|
|
165
|
+
// }
|
|
166
|
+
|
|
167
|
+
if (events.includes("onload")) {
|
|
168
|
+
this.__updateElements(el, prefix);
|
|
169
|
+
}
|
|
154
170
|
|
|
155
171
|
if (events.includes("observer")) {
|
|
156
172
|
let target;
|
|
@@ -172,7 +188,7 @@ const CoCreateEvents = {
|
|
|
172
188
|
}
|
|
173
189
|
}
|
|
174
190
|
|
|
175
|
-
let
|
|
191
|
+
let attributeFilter = (
|
|
176
192
|
el.getAttribute(`${prefix}-attributes`) || ""
|
|
177
193
|
)
|
|
178
194
|
.split(/\s*,\s*/)
|
|
@@ -185,7 +201,7 @@ const CoCreateEvents = {
|
|
|
185
201
|
.filter((item) => item);
|
|
186
202
|
|
|
187
203
|
let observerConfig = {
|
|
188
|
-
|
|
204
|
+
types: observeAttribute,
|
|
189
205
|
callback: function (mutation) {
|
|
190
206
|
self.__updateElements(el, prefix, mutation.target);
|
|
191
207
|
}
|
|
@@ -195,20 +211,19 @@ const CoCreateEvents = {
|
|
|
195
211
|
if (
|
|
196
212
|
target &&
|
|
197
213
|
!observeAttribute.length &&
|
|
198
|
-
!
|
|
214
|
+
!attributeFilter.length
|
|
199
215
|
) {
|
|
200
|
-
observerConfig.
|
|
216
|
+
observerConfig.types.push("addedNodes");
|
|
201
217
|
}
|
|
202
218
|
observerConfig.target = target;
|
|
203
219
|
}
|
|
204
220
|
|
|
205
|
-
if (
|
|
206
|
-
observerConfig.
|
|
207
|
-
observerConfig.
|
|
221
|
+
if (attributeFilter.length) {
|
|
222
|
+
observerConfig.types.push("attributes");
|
|
223
|
+
observerConfig.attributeFilter = attributeFilter;
|
|
208
224
|
}
|
|
209
225
|
|
|
210
|
-
if (observerConfig.
|
|
211
|
-
observer.init(observerConfig);
|
|
226
|
+
if (observerConfig.types.length) observer.init(observerConfig);
|
|
212
227
|
}
|
|
213
228
|
|
|
214
229
|
if (events.includes("resize")) {
|
|
@@ -221,19 +236,98 @@ const CoCreateEvents = {
|
|
|
221
236
|
resizeObserver.observe(el);
|
|
222
237
|
}
|
|
223
238
|
|
|
239
|
+
if (events.includes("intersection")) {
|
|
240
|
+
const rootSelector = el.getAttribute(`${prefix}-root`);
|
|
241
|
+
const rootMargin =
|
|
242
|
+
el.getAttribute(`${prefix}-root-margin`) || "0px";
|
|
243
|
+
const threshold = el.getAttribute(`${prefix}-threshold`)
|
|
244
|
+
? JSON.parse(el.getAttribute(`${prefix}-threshold`))
|
|
245
|
+
: [0];
|
|
246
|
+
const trigger = el.getAttribute(`${prefix}-trigger`) || "both"; // Default to "both"
|
|
247
|
+
|
|
248
|
+
// Resolve root from the selector or use null for viewport
|
|
249
|
+
const root = rootSelector
|
|
250
|
+
? document.querySelector(rootSelector)
|
|
251
|
+
: null;
|
|
252
|
+
|
|
253
|
+
// Validate and filter threshold values
|
|
254
|
+
const validThreshold = Array.isArray(threshold)
|
|
255
|
+
? threshold.filter((value) => value >= 0 && value <= 1)
|
|
256
|
+
: [0];
|
|
257
|
+
|
|
258
|
+
// Create IntersectionObserver
|
|
259
|
+
const intersectionObserver = new IntersectionObserver(
|
|
260
|
+
(entries) => {
|
|
261
|
+
entries.forEach((entry) => {
|
|
262
|
+
const isVisible = entry.isIntersecting;
|
|
263
|
+
|
|
264
|
+
// Determine if __updateElements should be called based on trigger
|
|
265
|
+
// if (
|
|
266
|
+
// (trigger === "visible" && isVisible) ||
|
|
267
|
+
// (trigger === "not-visible" && !isVisible) ||
|
|
268
|
+
// trigger === "both"
|
|
269
|
+
// ) {
|
|
270
|
+
if (isVisible) {
|
|
271
|
+
// Set an attribute to reflect visibility state
|
|
272
|
+
el.setAttribute(
|
|
273
|
+
`${prefix}-is-visible`,
|
|
274
|
+
isVisible ? "true" : "false"
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
// Call __updateElements
|
|
278
|
+
self.__updateElements(
|
|
279
|
+
el,
|
|
280
|
+
prefix
|
|
281
|
+
// {
|
|
282
|
+
// isVisible,
|
|
283
|
+
// intersectionRatio:
|
|
284
|
+
// entry.intersectionRatio
|
|
285
|
+
// }
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
},
|
|
290
|
+
{ root, rootMargin, threshold: validThreshold }
|
|
291
|
+
);
|
|
292
|
+
|
|
293
|
+
intersectionObserver.observe(el);
|
|
294
|
+
}
|
|
295
|
+
|
|
224
296
|
for (let i = 0; i < events.length; i++) {
|
|
297
|
+
// Skip specific lifecycle events
|
|
225
298
|
if (
|
|
226
|
-
events[i]
|
|
227
|
-
events[i]
|
|
228
|
-
events[i]
|
|
299
|
+
events[i] === "onload" ||
|
|
300
|
+
events[i] === "observer" ||
|
|
301
|
+
events[i] === "intersection" ||
|
|
302
|
+
events[i] === "resize"
|
|
229
303
|
) {
|
|
230
|
-
|
|
231
|
-
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Remove any existing event listener
|
|
308
|
+
el.removeEventListener(events[i], eventFunction);
|
|
309
|
+
|
|
310
|
+
// Initialize an empty options object
|
|
311
|
+
const options = {};
|
|
312
|
+
|
|
313
|
+
// Attributes to check dynamically
|
|
314
|
+
const attributes = ["bubbles", "cancelable", "composed"];
|
|
315
|
+
|
|
316
|
+
for (let j = 0; j < attributes.length; j++) {
|
|
317
|
+
const attrValue = el.getAttribute(
|
|
318
|
+
`${events[i]}-${attributes[j]}`
|
|
319
|
+
);
|
|
320
|
+
if (attrValue !== null) {
|
|
321
|
+
options[attributes[j]] = attrValue !== "false";
|
|
322
|
+
}
|
|
232
323
|
}
|
|
324
|
+
|
|
325
|
+
// Add the new event listener with the dynamically constructed options
|
|
326
|
+
el.addEventListener(events[i], eventFunction, options);
|
|
233
327
|
}
|
|
234
328
|
|
|
235
329
|
function eventFunction(event) {
|
|
236
|
-
// TODO: apply debounce
|
|
330
|
+
// TODO: apply debounce.
|
|
237
331
|
// let debounce;
|
|
238
332
|
// clearTimeout(debounce);
|
|
239
333
|
// debounce = setTimeout(function() {
|
|
@@ -251,6 +345,25 @@ const CoCreateEvents = {
|
|
|
251
345
|
if (attribute.includes(prefix)) return;
|
|
252
346
|
// if (target.closest(`[actions*="${prefix}"]`))
|
|
253
347
|
// return;
|
|
348
|
+
|
|
349
|
+
// Define the lifecycle attributes (matching JavaScript event methods)
|
|
350
|
+
const lifecycleAttributes = [
|
|
351
|
+
"preventDefault",
|
|
352
|
+
"stopPropagation",
|
|
353
|
+
"stopImmediatePropagation"
|
|
354
|
+
];
|
|
355
|
+
|
|
356
|
+
// Handle lifecycle attributes dynamically
|
|
357
|
+
for (let i = 0; i < lifecycleAttributes.length; i++) {
|
|
358
|
+
const attr = `${prefix}-${lifecycleAttributes[i]}`; // Add prefix dynamically
|
|
359
|
+
const attrValue = target.getAttribute(attr); // Directly get the attribute value
|
|
360
|
+
|
|
361
|
+
// If attribute exists and is not explicitly "false", apply the corresponding event method
|
|
362
|
+
if (attrValue !== null && attrValue !== "false") {
|
|
363
|
+
event[lifecycleAttributes[i]]();
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
254
367
|
self.__updateElements(
|
|
255
368
|
target,
|
|
256
369
|
prefix,
|
|
@@ -292,7 +405,26 @@ const CoCreateEvents = {
|
|
|
292
405
|
}
|
|
293
406
|
|
|
294
407
|
for (let element of elements) {
|
|
295
|
-
|
|
408
|
+
// const requestAnimationFrameAttr = element.getAttribute(
|
|
409
|
+
// `${prefix}-requestAnimationFrame`
|
|
410
|
+
// );
|
|
411
|
+
|
|
412
|
+
// if (
|
|
413
|
+
// requestAnimationFrameAttr !== null &&
|
|
414
|
+
// requestAnimationFrameAttr !== "false"
|
|
415
|
+
// ) {
|
|
416
|
+
// // Double requestAnimationFrame
|
|
417
|
+
// await new Promise((resolve) => {
|
|
418
|
+
// requestAnimationFrame(() => {
|
|
419
|
+
// requestAnimationFrame(() => {
|
|
420
|
+
// resolve();
|
|
421
|
+
// });
|
|
422
|
+
// });
|
|
423
|
+
// });
|
|
424
|
+
// }
|
|
425
|
+
|
|
426
|
+
// TODO: Handle setInterval logic
|
|
427
|
+
let delay = element.getAttribute(`${prefix}-setTimeout`);
|
|
296
428
|
|
|
297
429
|
if (delay) {
|
|
298
430
|
delay = parseInt(delay, 10) || 0;
|
|
@@ -382,13 +514,15 @@ const CoCreateEvents = {
|
|
|
382
514
|
let elseCondition = element.getAttribute(`${prefix}-else`);
|
|
383
515
|
|
|
384
516
|
let ifValue = element.getAttribute(`${prefix}-if-value`);
|
|
385
|
-
if (
|
|
386
|
-
ifValue
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
517
|
+
if (ifCondition) {
|
|
518
|
+
if (!ifValue && ifValue !== "")
|
|
519
|
+
ifValue = (await element.getValue()) || values;
|
|
520
|
+
//values // await element.getValue()
|
|
521
|
+
else if (ifValue || ifValue === "") ifValue = [ifValue];
|
|
522
|
+
else ifValue = values;
|
|
523
|
+
|
|
524
|
+
if (!Array.isArray(ifValue)) ifValue = [ifValue];
|
|
525
|
+
}
|
|
392
526
|
|
|
393
527
|
//TODO: improved resize toggling of values
|
|
394
528
|
// let hasCondition = this.elements2.get(element)
|
|
@@ -436,7 +570,11 @@ const CoCreateEvents = {
|
|
|
436
570
|
prefix,
|
|
437
571
|
selector: params
|
|
438
572
|
});
|
|
439
|
-
|
|
573
|
+
|
|
574
|
+
if (targetElements === false) {
|
|
575
|
+
targetElements = [element];
|
|
576
|
+
}
|
|
577
|
+
|
|
440
578
|
let action = element.getAttribute(`${prefix}-action`);
|
|
441
579
|
for (let i = 0; i < targetElements.length; i++) {
|
|
442
580
|
if (action) {
|
|
@@ -471,7 +609,7 @@ const CoCreateEvents = {
|
|
|
471
609
|
}
|
|
472
610
|
}
|
|
473
611
|
|
|
474
|
-
|
|
612
|
+
el.dispatchEvent(
|
|
475
613
|
new CustomEvent(`${prefix}End`, {
|
|
476
614
|
detail: {}
|
|
477
615
|
})
|
|
@@ -516,7 +654,7 @@ const CoCreateEvents = {
|
|
|
516
654
|
// let value = values[0]
|
|
517
655
|
replaceKey(prefix, element, key, values);
|
|
518
656
|
} else {
|
|
519
|
-
//
|
|
657
|
+
// TODO: if html in iframe
|
|
520
658
|
let domTextEditor;
|
|
521
659
|
if (element.parentElement) {
|
|
522
660
|
domTextEditor =
|
|
@@ -579,7 +717,7 @@ const CoCreateEvents = {
|
|
|
579
717
|
element.classList.add(newValue);
|
|
580
718
|
}
|
|
581
719
|
} else if (attrName === "value") {
|
|
582
|
-
element.setValue(newValue);
|
|
720
|
+
element.setValue(newValue, false);
|
|
583
721
|
} else if (
|
|
584
722
|
["$click", "$focus", "$blur", "$save", "$read"].includes(
|
|
585
723
|
attrName
|
|
@@ -822,6 +960,160 @@ function parseNumberCondition(condition) {
|
|
|
822
960
|
: condition;
|
|
823
961
|
}
|
|
824
962
|
|
|
963
|
+
// Helper function for delay using Promises
|
|
964
|
+
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
965
|
+
|
|
966
|
+
/**
|
|
967
|
+
* Waits for a specific element property to meet a readiness condition,
|
|
968
|
+
* based on retry attributes defined on the element.
|
|
969
|
+
* Incorporates optional exponential backoff for retry delays.
|
|
970
|
+
* Returns a Promise that resolves to true if the condition is met within
|
|
971
|
+
* the allowed attempts, and false otherwise.
|
|
972
|
+
*
|
|
973
|
+
* @param {HTMLElement} element The element with the onload-retry-* attributes.
|
|
974
|
+
* @returns {Promise<boolean>} A Promise resolving to true if ready, false if timed out.
|
|
975
|
+
*/
|
|
976
|
+
async function checkElementReadinessWithBackoff(element) {
|
|
977
|
+
const propertyName = element.getAttribute("onload-retry-property");
|
|
978
|
+
|
|
979
|
+
if (!propertyName) {
|
|
980
|
+
return true; // No retry needed
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
// --- Retry Parameters ---
|
|
984
|
+
const maxAttempts =
|
|
985
|
+
parseInt(element.getAttribute("onload-retry-attempts") || "3", 10) || 3;
|
|
986
|
+
// Initial delay (used for the first wait and as the base for backoff)
|
|
987
|
+
const initialDelayMs =
|
|
988
|
+
parseInt(element.getAttribute("onload-retry-delay") || "100", 10) ||
|
|
989
|
+
100;
|
|
990
|
+
// Exponential backoff factor (e.g., 2 for doubling). <= 1 means fixed delay.
|
|
991
|
+
// Default to 1 (no backoff) if missing or invalid.
|
|
992
|
+
const backoffFactor =
|
|
993
|
+
parseFloat(
|
|
994
|
+
element.getAttribute("onload-retry-backoff-factor") || "1"
|
|
995
|
+
) || 1;
|
|
996
|
+
// Optional maximum delay cap. Use Infinity if missing, invalid, or <= 0.
|
|
997
|
+
const maxDelayMs = parseInt(
|
|
998
|
+
element.getAttribute("onload-retry-max-delay") || "0",
|
|
999
|
+
10
|
|
1000
|
+
);
|
|
1001
|
+
const effectiveMaxDelay =
|
|
1002
|
+
maxDelayMs && maxDelayMs > 0 ? maxDelayMs : Infinity;
|
|
1003
|
+
|
|
1004
|
+
console.log(
|
|
1005
|
+
`Checking readiness for property "${propertyName}" on element ${
|
|
1006
|
+
element.id || ""
|
|
1007
|
+
}. Max attempts: ${maxAttempts}, Initial Delay: ${initialDelayMs}ms, Backoff Factor: ${backoffFactor}, Max Delay: ${
|
|
1008
|
+
effectiveMaxDelay === Infinity ? "None" : effectiveMaxDelay + "ms"
|
|
1009
|
+
}.`
|
|
1010
|
+
);
|
|
1011
|
+
|
|
1012
|
+
// Initialize the delay to be used for the *first* wait.
|
|
1013
|
+
let currentDelay = initialDelayMs;
|
|
1014
|
+
|
|
1015
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
1016
|
+
console.log(
|
|
1017
|
+
`Attempt ${attempt}/${maxAttempts}: Checking "${propertyName}"...`
|
|
1018
|
+
);
|
|
1019
|
+
try {
|
|
1020
|
+
const propertyValue = element[propertyName];
|
|
1021
|
+
// Example check: Adjust condition as needed
|
|
1022
|
+
if (propertyValue !== undefined && propertyValue > 0) {
|
|
1023
|
+
console.log(
|
|
1024
|
+
`Property "${propertyName}" ready on attempt ${attempt}. Value: ${propertyValue}`
|
|
1025
|
+
);
|
|
1026
|
+
return true; // Condition met
|
|
1027
|
+
}
|
|
1028
|
+
} catch (error) {
|
|
1029
|
+
console.error(
|
|
1030
|
+
`Error accessing property "${propertyName}" on attempt ${attempt}:`,
|
|
1031
|
+
error
|
|
1032
|
+
);
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
// If condition not met and more attempts remain:
|
|
1036
|
+
if (attempt < maxAttempts) {
|
|
1037
|
+
// Determine the actual delay for this wait, applying the cap
|
|
1038
|
+
const delayForThisWait = Math.min(currentDelay, effectiveMaxDelay);
|
|
1039
|
+
|
|
1040
|
+
console.log(
|
|
1041
|
+
`Waiting ${Math.round(
|
|
1042
|
+
delayForThisWait
|
|
1043
|
+
)}ms before next attempt...`
|
|
1044
|
+
);
|
|
1045
|
+
await delay(delayForThisWait);
|
|
1046
|
+
|
|
1047
|
+
// Calculate the delay for the *next* potential wait, only if backoff is active
|
|
1048
|
+
if (backoffFactor > 1) {
|
|
1049
|
+
currentDelay = currentDelay * backoffFactor;
|
|
1050
|
+
// Note: We apply the cap just before the actual delay,
|
|
1051
|
+
// but the base 'currentDelay' keeps growing exponentially.
|
|
1052
|
+
// Alternatively, you could cap 'currentDelay' itself here:
|
|
1053
|
+
// currentDelay = Math.min(currentDelay * backoffFactor, effectiveMaxDelay);
|
|
1054
|
+
// Let's stick to capping just before delay() for now.
|
|
1055
|
+
}
|
|
1056
|
+
// If backoffFactor <= 1, currentDelay remains initialDelayMs (implicitly handled by initialization)
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
// If loop finishes without condition being met
|
|
1061
|
+
console.warn(
|
|
1062
|
+
`Readiness check failed for property "${propertyName}" on element ${
|
|
1063
|
+
element.id || ""
|
|
1064
|
+
} after ${maxAttempts} attempts.`
|
|
1065
|
+
);
|
|
1066
|
+
return false; // Timed out
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
// --- Example Usage (calling code doesn't change) ---
|
|
1070
|
+
|
|
1071
|
+
async function handleElementProcessingWithBackoff(element) {
|
|
1072
|
+
// Call the function that now supports backoff
|
|
1073
|
+
const isReady = await checkElementReadinessWithBackoff(element);
|
|
1074
|
+
|
|
1075
|
+
if (isReady) {
|
|
1076
|
+
console.log(
|
|
1077
|
+
`Element ${element.id || ""} is ready. Proceeding with actions.`
|
|
1078
|
+
);
|
|
1079
|
+
// --- Execute subsequent actions ---
|
|
1080
|
+
if (element.hasAttribute("onload-attribute")) {
|
|
1081
|
+
/* ... */
|
|
1082
|
+
}
|
|
1083
|
+
if (element.hasAttribute("onload-next")) {
|
|
1084
|
+
/* ... */
|
|
1085
|
+
}
|
|
1086
|
+
} else {
|
|
1087
|
+
console.warn(
|
|
1088
|
+
`Skipping actions for element ${
|
|
1089
|
+
element.id || ""
|
|
1090
|
+
} because readiness check failed.`
|
|
1091
|
+
);
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
// --- Example Elements ---
|
|
1096
|
+
|
|
1097
|
+
// With Backoff (Delays: 100, 200, 400, 800 - capped)
|
|
1098
|
+
// <span id="elem1" onload-retry-property="scrollWidth"
|
|
1099
|
+
// onload-retry-attempts="5" onload-retry-delay="100"
|
|
1100
|
+
// onload-retry-backoff-factor="2" onload-retry-max-delay="500">
|
|
1101
|
+
// Content 1
|
|
1102
|
+
// </span>
|
|
1103
|
+
// Waits would be: 100ms, 200ms, 400ms, 500ms (capped)
|
|
1104
|
+
|
|
1105
|
+
// No Backoff (factor missing/invalid/<=1)
|
|
1106
|
+
// <span id="elem2" onload-retry-property="clientHeight"
|
|
1107
|
+
// onload-retry-attempts="4" onload-retry-delay="300">
|
|
1108
|
+
// Content 2
|
|
1109
|
+
// </span>
|
|
1110
|
+
// Waits would be: 300ms, 300ms, 300ms
|
|
1111
|
+
|
|
1112
|
+
// const element1 = document.getElementById('elem1');
|
|
1113
|
+
// if (element1) handleElementProcessingWithBackoff(element1);
|
|
1114
|
+
// const element2 = document.getElementById('elem2');
|
|
1115
|
+
// if (element2) handleElementProcessingWithBackoff(element2);
|
|
1116
|
+
|
|
825
1117
|
CoCreateEvents.init();
|
|
826
1118
|
|
|
827
1119
|
export default CoCreateEvents;
|