@cocreate/events 1.26.0 → 1.27.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocreate/events",
3
- "version": "1.26.0",
3
+ "version": "1.27.1",
4
4
  "description": "A simple events component in vanilla javascript. Easily configured using HTML5 attributes and/or JavaScript API.",
5
5
  "keywords": [
6
6
  "events",
@@ -45,22 +45,18 @@
45
45
  },
46
46
  "main": "./src/index.js",
47
47
  "devDependencies": {
48
- "@babel/core": "^7.9.6",
49
- "@babel/preset-env": "^7.9.6",
50
- "babel-loader": "^8.1.0",
51
- "clean-webpack-plugin": "^3.0.0",
52
- "file-loader": "^6.2.0",
48
+ "css-loader": "^5.1.3",
49
+ "esbuild": "^0.25.2",
50
+ "esbuild-loader": "^4.3.0",
53
51
  "mini-css-extract-plugin": "^1.5.0",
54
- "style-loader": "^3.3.1",
55
- "terser-webpack-plugin": "^5.1.1",
56
52
  "webpack": "^5.24.4",
57
53
  "webpack-cli": "^4.5.0",
58
54
  "webpack-log": "^3.0.1"
59
55
  },
60
56
  "dependencies": {
61
- "@cocreate/actions": "^1.18.2",
62
- "@cocreate/element-prototype": "^1.23.0",
63
- "@cocreate/observer": "^1.16.1",
64
- "@cocreate/utils": "^1.33.7"
57
+ "@cocreate/actions": "^1.21.0",
58
+ "@cocreate/element-prototype": "^1.29.0",
59
+ "@cocreate/observer": "^1.18.0",
60
+ "@cocreate/utils": "^1.38.0"
65
61
  }
66
62
  }
package/src/index.js CHANGED
@@ -63,7 +63,7 @@ const CoCreateEvents = {
63
63
  const self = this;
64
64
  observer.init({
65
65
  name: "CoCreateEventName",
66
- observe: ["addedNodes"],
66
+ types: ["addedNodes"],
67
67
  selector: `[event-name]`,
68
68
  callback: function (mutation) {
69
69
  let name = mutation.target.getAttribute("event-name");
@@ -89,20 +89,22 @@ const CoCreateEvents = {
89
89
  }
90
90
  });
91
91
 
92
- 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}-query], [${prefix}-preventDefault], [${prefix}-stopPropagation], [${prefix}-stopImmediatePropagation]`;
93
93
 
94
94
  observer.init({
95
95
  name: "CoCreateEventattributes",
96
- observe: ["attributes", "addedNodes"],
97
- attributeName: [
96
+ types: ["attributes", "addedNodes"],
97
+ attributeFilter: [
98
98
  `${prefix}-key`,
99
99
  `${prefix}-value`,
100
- `${prefix}-selector`,
101
- `${prefix}-closest`,
102
- `${prefix}-parent`,
103
- `${prefix}-next`,
104
- `${prefix}-previous`,
105
- `${prefix}-events`
100
+ `${prefix}-query`,
101
+ `${prefix}-events`,
102
+ `${prefix}-bubbles`,
103
+ `${prefix}-cancelable`,
104
+ `${prefix}-composed`,
105
+ `${prefix}-preventDefault`,
106
+ `${prefix}-stopPropagation`,
107
+ `${prefix}-stopImmediatePropagation`
106
108
  ],
107
109
  selector,
108
110
  callback: function (mutation) {
@@ -125,7 +127,9 @@ const CoCreateEvents = {
125
127
  this.elements.set(el, prefixes);
126
128
  } else if (!prefixes[prefix]) {
127
129
  prefixes[prefix] = { events };
128
- } else isEventable = false;
130
+ } else {
131
+ isEventable = false;
132
+ }
129
133
 
130
134
  let customEvents = el.getAttribute(`${prefix}-events`);
131
135
  if (customEvents) {
@@ -140,8 +144,25 @@ const CoCreateEvents = {
140
144
  prefixes[prefix].events = events;
141
145
  isEventable = true;
142
146
  }
147
+
143
148
  if (!events || !isEventable) continue;
144
- if (events.includes("onload")) this.__updateElements(el, prefix);
149
+
150
+ // let originalSelector = ""; // i think we need to extract the selector and remove the operators
151
+ // if (originalSelector) {
152
+ // observer.init({
153
+ // types: ["addedNodes"],
154
+ // callback: function (mutation) {
155
+ // const els = el.queryElements();
156
+ // if (els && els.includes(mutation.target)) {
157
+ // self.__updateElements();
158
+ // }
159
+ // }
160
+ // });
161
+ // }
162
+
163
+ if (events.includes("onload")) {
164
+ this.__updateElements(el, prefix);
165
+ }
145
166
 
146
167
  if (events.includes("observer")) {
147
168
  let target;
@@ -149,21 +170,13 @@ const CoCreateEvents = {
149
170
  if (attribute.name === "observe-target") {
150
171
  target = attribute.value;
151
172
  break;
152
- } else if (
153
- [
154
- `${prefix}-selector`,
155
- `${prefix}-closest`,
156
- `${prefix}-parent`,
157
- `${prefix}-next`,
158
- `${prefix}-previous`
159
- ].includes(attribute.name)
160
- ) {
173
+ } else if ([`${prefix}-query`].includes(attribute.name)) {
161
174
  target = attribute.value;
162
175
  break;
163
176
  }
164
177
  }
165
178
 
166
- let attributeName = (
179
+ let attributeFilter = (
167
180
  el.getAttribute(`${prefix}-attributes`) || ""
168
181
  )
169
182
  .split(/\s*,\s*/)
@@ -176,7 +189,7 @@ const CoCreateEvents = {
176
189
  .filter((item) => item);
177
190
 
178
191
  let observerConfig = {
179
- observe: observeAttribute,
192
+ types: observeAttribute,
180
193
  callback: function (mutation) {
181
194
  self.__updateElements(el, prefix, mutation.target);
182
195
  }
@@ -186,20 +199,19 @@ const CoCreateEvents = {
186
199
  if (
187
200
  target &&
188
201
  !observeAttribute.length &&
189
- !attributeName.length
202
+ !attributeFilter.length
190
203
  ) {
191
- observerConfig.observe.push("addedNodes");
204
+ observerConfig.types.push("addedNodes");
192
205
  }
193
206
  observerConfig.target = target;
194
207
  }
195
208
 
196
- if (attributeName.length) {
197
- observerConfig.observe.push("attributes");
198
- observerConfig.attributeName = attributeName;
209
+ if (attributeFilter.length) {
210
+ observerConfig.types.push("attributes");
211
+ observerConfig.attributeFilter = attributeFilter;
199
212
  }
200
213
 
201
- if (observerConfig.observe.length)
202
- observer.init(observerConfig);
214
+ if (observerConfig.types.length) observer.init(observerConfig);
203
215
  }
204
216
 
205
217
  if (events.includes("resize")) {
@@ -270,19 +282,40 @@ const CoCreateEvents = {
270
282
  }
271
283
 
272
284
  for (let i = 0; i < events.length; i++) {
285
+ // Skip specific lifecycle events
273
286
  if (
274
- events[i] !== "onload" &&
275
- events[i] !== "observer" &&
276
- events[i] !== "intersection" &&
277
- events[i] !== "resize"
287
+ events[i] === "onload" ||
288
+ events[i] === "observer" ||
289
+ events[i] === "intersection" ||
290
+ events[i] === "resize"
278
291
  ) {
279
- el.removeEventListener(events[i], eventFunction);
280
- el.addEventListener(events[i], eventFunction);
292
+ continue;
293
+ }
294
+
295
+ // Remove any existing event listener
296
+ el.removeEventListener(events[i], eventFunction);
297
+
298
+ // Initialize an empty options object
299
+ const options = {};
300
+
301
+ // Attributes to check dynamically
302
+ const attributes = ["bubbles", "cancelable", "composed"];
303
+
304
+ for (let j = 0; j < attributes.length; j++) {
305
+ const attrValue = el.getAttribute(
306
+ `${events[i]}-${attributes[j]}`
307
+ );
308
+ if (attrValue !== null) {
309
+ options[attributes[j]] = attrValue !== "false";
310
+ }
281
311
  }
312
+
313
+ // Add the new event listener with the dynamically constructed options
314
+ el.addEventListener(events[i], eventFunction, options);
282
315
  }
283
316
 
284
317
  function eventFunction(event) {
285
- // TODO: apply debounce
318
+ // TODO: apply debounce.
286
319
  // let debounce;
287
320
  // clearTimeout(debounce);
288
321
  // debounce = setTimeout(function() {
@@ -300,6 +333,25 @@ const CoCreateEvents = {
300
333
  if (attribute.includes(prefix)) return;
301
334
  // if (target.closest(`[actions*="${prefix}"]`))
302
335
  // return;
336
+
337
+ // Define the lifecycle attributes (matching JavaScript event methods)
338
+ const lifecycleAttributes = [
339
+ "preventDefault",
340
+ "stopPropagation",
341
+ "stopImmediatePropagation"
342
+ ];
343
+
344
+ // Handle lifecycle attributes dynamically
345
+ for (let i = 0; i < lifecycleAttributes.length; i++) {
346
+ const attr = `${prefix}-${lifecycleAttributes[i]}`; // Add prefix dynamically
347
+ const attrValue = target.getAttribute(attr); // Directly get the attribute value
348
+
349
+ // If attribute exists and is not explicitly "false", apply the corresponding event method
350
+ if (attrValue !== null && attrValue !== "false") {
351
+ event[lifecycleAttributes[i]]();
352
+ }
353
+ }
354
+
303
355
  self.__updateElements(
304
356
  target,
305
357
  prefix,
@@ -307,7 +359,7 @@ const CoCreateEvents = {
307
359
  prefixes[prefix].events
308
360
  );
309
361
 
310
- // let selector = `[${prefix}], [${prefix}-key], [${prefix}-value], [${prefix}-selector], [${prefix}-closest], [${prefix}-parent], [${prefix}-next], [${prefix}-previous]`
362
+ // let selector = `[${prefix}], [${prefix}-key], [${prefix}-value], [${prefix}-query]`
311
363
 
312
364
  // let parentElement = target.parentElement;
313
365
  // if (parentElement) {
@@ -341,7 +393,26 @@ const CoCreateEvents = {
341
393
  }
342
394
 
343
395
  for (let element of elements) {
344
- let delay = element.getAttribute(`${prefix}-delay`);
396
+ // const requestAnimationFrameAttr = element.getAttribute(
397
+ // `${prefix}-requestAnimationFrame`
398
+ // );
399
+
400
+ // if (
401
+ // requestAnimationFrameAttr !== null &&
402
+ // requestAnimationFrameAttr !== "false"
403
+ // ) {
404
+ // // Double requestAnimationFrame
405
+ // await new Promise((resolve) => {
406
+ // requestAnimationFrame(() => {
407
+ // requestAnimationFrame(() => {
408
+ // resolve();
409
+ // });
410
+ // });
411
+ // });
412
+ // }
413
+
414
+ // TODO: Handle setInterval logic
415
+ let delay = element.getAttribute(`${prefix}-setTimeout`);
345
416
 
346
417
  if (delay) {
347
418
  delay = parseInt(delay, 10) || 0;
@@ -390,7 +461,9 @@ const CoCreateEvents = {
390
461
  values = localStorage.getItem(key);
391
462
  } else if ((key = element.getAttribute("localstorage-set"))) {
392
463
  values = await element.getValue();
393
- if (values) localStorage.setItem(key, values);
464
+ if (values) {
465
+ localStorage.setItem(key, values);
466
+ }
394
467
  }
395
468
 
396
469
  // if (!key || !values)
@@ -403,59 +476,95 @@ const CoCreateEvents = {
403
476
  element,
404
477
  prefix: `${prefix}-value`
405
478
  });
406
- if (valueElements) {
479
+ if (valueElements.length) {
407
480
  let elementValues = [];
408
- for (let i = 0; i < valueElements.length; i++)
481
+ for (let i = 0; i < valueElements.length; i++) {
409
482
  elementValues.push(valueElements[i].getValue());
410
-
411
- if (elementValues.length) values = elementValues;
483
+ }
484
+ if (elementValues.length) {
485
+ values = elementValues;
486
+ }
412
487
  }
413
488
  }
414
489
 
415
- if (values === null)
490
+ if (values === null) {
416
491
  values = element.getAttribute(`${prefix}-if-value`);
417
- if (values === null) values = element.getAttribute(prefix);
492
+ }
493
+ if (values === null) {
494
+ values = element.getAttribute(prefix);
495
+ }
418
496
  }
419
497
 
420
498
  if (values || values === "") {
421
- if (typeof values === "string") values = values.split(",");
422
- else if (!Array.isArray(values)) values = [values];
499
+ if (typeof values === "string") {
500
+ values = values.split(",");
501
+ } else if (!Array.isArray(values)) {
502
+ values = [values];
503
+ }
423
504
  } else {
424
505
  values = await element.getValue();
425
- if (!Array.isArray(values)) values = [values];
506
+ if (!Array.isArray(values)) {
507
+ values = [values];
508
+ }
426
509
  }
427
510
 
428
- if ((targetAttribute && !values) || values.length === 0) return;
511
+ if ((targetAttribute && !values) || values.length === 0) {
512
+ return;
513
+ }
429
514
 
430
515
  let ifCondition = element.getAttribute(`${prefix}-if`);
431
516
  let elseCondition = element.getAttribute(`${prefix}-else`);
432
517
 
433
518
  let ifValue = element.getAttribute(`${prefix}-if-value`);
434
- if (!ifValue && ifValue !== "")
435
- ifValue = (await element.getValue()) || values;
436
- //values // await element.getValue()
437
- else if (ifValue || ifValue === "") ifValue = [ifValue];
438
- else ifValue = values;
519
+ if (ifCondition) {
520
+ if (!ifValue && ifValue !== "")
521
+ ifValue = (await element.getValue()) || values;
522
+ //values // await element.getValue()
523
+ else if (ifValue || ifValue === "") {
524
+ ifValue = [ifValue];
525
+ } else {
526
+ ifValue = values;
527
+ }
439
528
 
440
- if (!Array.isArray(ifValue)) ifValue = [ifValue];
529
+ if (!Array.isArray(ifValue)) {
530
+ ifValue = [ifValue];
531
+ }
532
+ }
441
533
 
442
534
  //TODO: improved resize toggling of values
443
535
  // let hasCondition = this.elements2.get(element)
444
- if (ifCondition && evaluateCondition(ifCondition, ifValue)) {
445
- // if (hasCondition && hasCondition.condition === ifCondition) {
446
- // return
447
- // } else
448
- // this.elements2.set(element, { condition: ifCondition })
449
- } else if (
450
- elseCondition &&
451
- evaluateCondition(elseCondition, ifValue)
452
- ) {
453
- // if (hasCondition && hasCondition.condition === elseCondition) {
454
- // return
455
- // } else
456
- // this.elements2.set(element, { condition: elseCondition })
457
- } else if (ifCondition || elseCondition) {
458
- return;
536
+ if (ifCondition) {
537
+ if (evaluateCondition(ifCondition, ifValue)) {
538
+ // Action 1: Condition exists and evaluates true
539
+ // console.log("Executing Action 1 for ifCondition:", ifCondition); // Optional debug log
540
+ // Replace this comment with your actual code for Path 1
541
+ // e.g., this.elements2.set(element, { condition: ifCondition });
542
+
543
+ // Assuming we stop processing for this element once a condition is met and actioned
544
+ return;
545
+ } else {
546
+ // Condition existed but evaluated false. Stop processing.
547
+ // Corresponds to the original `else if (ifCondition || elseCondition) { return; }` for the ifCondition case
548
+ return;
549
+ }
550
+ }
551
+
552
+ // If we reach here, ifCondition was falsy (didn't exist)
553
+ // Now check the 'else' condition
554
+ if (elseCondition) {
555
+ if (evaluateCondition(elseCondition, ifValue)) {
556
+ // Action 2: Condition exists and evaluates true
557
+ // console.log("Executing Action 2 for elseCondition:", elseCondition); // Optional debug log
558
+ // Replace this comment with your actual code for Path 2
559
+ // e.g., this.elements2.set(element, { condition: elseCondition });
560
+
561
+ // Assuming we stop processing for this element once a condition is met and actioned
562
+ return;
563
+ } else {
564
+ // Condition existed but evaluated false. Stop processing.
565
+ // Corresponds to the original `else if (ifCondition || elseCondition) { return; }` for the elseCondition case
566
+ return;
567
+ }
459
568
  }
460
569
 
461
570
  let targetText = element.getAttribute(`${prefix}-text`);
@@ -463,12 +572,17 @@ const CoCreateEvents = {
463
572
  let targetKey = element.getAttribute(`${prefix}-key`);
464
573
 
465
574
  if (prefix === "selected") {
466
- if (el !== element) element.removeAttribute("selected");
467
- else element.setAttribute("selected", "");
575
+ if (el !== element) {
576
+ element.removeAttribute("selected");
577
+ } else {
578
+ element.setAttribute("selected", "");
579
+ }
468
580
  }
469
581
 
470
582
  let deactivate = false;
471
- if (el !== element) deactivate = true;
583
+ if (el !== element) {
584
+ deactivate = true;
585
+ }
472
586
  // values = values.map(x => x.trim());
473
587
 
474
588
  values = values.map((x) => {
@@ -479,13 +593,17 @@ const CoCreateEvents = {
479
593
  }
480
594
  return x; // Return the updated x
481
595
  });
596
+ let targetElements;
597
+ if (element.hasAttribute(`${prefix}-query`)) {
598
+ targetElements = queryElements({
599
+ element,
600
+ prefix,
601
+ selector: params
602
+ });
603
+ } else {
604
+ targetElements = [element];
605
+ }
482
606
 
483
- let targetElements = queryElements({
484
- element,
485
- prefix,
486
- selector: params
487
- });
488
- if (targetElements === false) targetElements = [element];
489
607
  let action = element.getAttribute(`${prefix}-action`);
490
608
  for (let i = 0; i < targetElements.length; i++) {
491
609
  if (action) {
@@ -520,7 +638,7 @@ const CoCreateEvents = {
520
638
  }
521
639
  }
522
640
 
523
- document.dispatchEvent(
641
+ el.dispatchEvent(
524
642
  new CustomEvent(`${prefix}End`, {
525
643
  detail: {}
526
644
  })
@@ -565,7 +683,7 @@ const CoCreateEvents = {
565
683
  // let value = values[0]
566
684
  replaceKey(prefix, element, key, values);
567
685
  } else {
568
- // TODo: if html in iframe
686
+ // TODO: if html in iframe
569
687
  let domTextEditor;
570
688
  if (element.parentElement) {
571
689
  domTextEditor =
@@ -628,7 +746,7 @@ const CoCreateEvents = {
628
746
  element.classList.add(newValue);
629
747
  }
630
748
  } else if (attrName === "value") {
631
- element.setValue(newValue);
749
+ element.setValue(newValue, false);
632
750
  } else if (
633
751
  ["$click", "$focus", "$blur", "$save", "$read"].includes(
634
752
  attrName
@@ -871,6 +989,160 @@ function parseNumberCondition(condition) {
871
989
  : condition;
872
990
  }
873
991
 
992
+ // Helper function for delay using Promises
993
+ const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
994
+
995
+ /**
996
+ * Waits for a specific element property to meet a readiness condition,
997
+ * based on retry attributes defined on the element.
998
+ * Incorporates optional exponential backoff for retry delays.
999
+ * Returns a Promise that resolves to true if the condition is met within
1000
+ * the allowed attempts, and false otherwise.
1001
+ *
1002
+ * @param {HTMLElement} element The element with the onload-retry-* attributes.
1003
+ * @returns {Promise<boolean>} A Promise resolving to true if ready, false if timed out.
1004
+ */
1005
+ async function checkElementReadinessWithBackoff(element) {
1006
+ const propertyName = element.getAttribute("onload-retry-property");
1007
+
1008
+ if (!propertyName) {
1009
+ return true; // No retry needed
1010
+ }
1011
+
1012
+ // --- Retry Parameters ---
1013
+ const maxAttempts =
1014
+ parseInt(element.getAttribute("onload-retry-attempts") || "3", 10) || 3;
1015
+ // Initial delay (used for the first wait and as the base for backoff)
1016
+ const initialDelayMs =
1017
+ parseInt(element.getAttribute("onload-retry-delay") || "100", 10) ||
1018
+ 100;
1019
+ // Exponential backoff factor (e.g., 2 for doubling). <= 1 means fixed delay.
1020
+ // Default to 1 (no backoff) if missing or invalid.
1021
+ const backoffFactor =
1022
+ parseFloat(
1023
+ element.getAttribute("onload-retry-backoff-factor") || "1"
1024
+ ) || 1;
1025
+ // Optional maximum delay cap. Use Infinity if missing, invalid, or <= 0.
1026
+ const maxDelayMs = parseInt(
1027
+ element.getAttribute("onload-retry-max-delay") || "0",
1028
+ 10
1029
+ );
1030
+ const effectiveMaxDelay =
1031
+ maxDelayMs && maxDelayMs > 0 ? maxDelayMs : Infinity;
1032
+
1033
+ console.log(
1034
+ `Checking readiness for property "${propertyName}" on element ${
1035
+ element.id || ""
1036
+ }. Max attempts: ${maxAttempts}, Initial Delay: ${initialDelayMs}ms, Backoff Factor: ${backoffFactor}, Max Delay: ${
1037
+ effectiveMaxDelay === Infinity ? "None" : effectiveMaxDelay + "ms"
1038
+ }.`
1039
+ );
1040
+
1041
+ // Initialize the delay to be used for the *first* wait.
1042
+ let currentDelay = initialDelayMs;
1043
+
1044
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1045
+ console.log(
1046
+ `Attempt ${attempt}/${maxAttempts}: Checking "${propertyName}"...`
1047
+ );
1048
+ try {
1049
+ const propertyValue = element[propertyName];
1050
+ // Example check: Adjust condition as needed
1051
+ if (propertyValue !== undefined && propertyValue > 0) {
1052
+ console.log(
1053
+ `Property "${propertyName}" ready on attempt ${attempt}. Value: ${propertyValue}`
1054
+ );
1055
+ return true; // Condition met
1056
+ }
1057
+ } catch (error) {
1058
+ console.error(
1059
+ `Error accessing property "${propertyName}" on attempt ${attempt}:`,
1060
+ error
1061
+ );
1062
+ }
1063
+
1064
+ // If condition not met and more attempts remain:
1065
+ if (attempt < maxAttempts) {
1066
+ // Determine the actual delay for this wait, applying the cap
1067
+ const delayForThisWait = Math.min(currentDelay, effectiveMaxDelay);
1068
+
1069
+ console.log(
1070
+ `Waiting ${Math.round(
1071
+ delayForThisWait
1072
+ )}ms before next attempt...`
1073
+ );
1074
+ await delay(delayForThisWait);
1075
+
1076
+ // Calculate the delay for the *next* potential wait, only if backoff is active
1077
+ if (backoffFactor > 1) {
1078
+ currentDelay = currentDelay * backoffFactor;
1079
+ // Note: We apply the cap just before the actual delay,
1080
+ // but the base 'currentDelay' keeps growing exponentially.
1081
+ // Alternatively, you could cap 'currentDelay' itself here:
1082
+ // currentDelay = Math.min(currentDelay * backoffFactor, effectiveMaxDelay);
1083
+ // Let's stick to capping just before delay() for now.
1084
+ }
1085
+ // If backoffFactor <= 1, currentDelay remains initialDelayMs (implicitly handled by initialization)
1086
+ }
1087
+ }
1088
+
1089
+ // If loop finishes without condition being met
1090
+ console.warn(
1091
+ `Readiness check failed for property "${propertyName}" on element ${
1092
+ element.id || ""
1093
+ } after ${maxAttempts} attempts.`
1094
+ );
1095
+ return false; // Timed out
1096
+ }
1097
+
1098
+ // --- Example Usage (calling code doesn't change) ---
1099
+
1100
+ async function handleElementProcessingWithBackoff(element) {
1101
+ // Call the function that now supports backoff
1102
+ const isReady = await checkElementReadinessWithBackoff(element);
1103
+
1104
+ if (isReady) {
1105
+ console.log(
1106
+ `Element ${element.id || ""} is ready. Proceeding with actions.`
1107
+ );
1108
+ // --- Execute subsequent actions ---
1109
+ if (element.hasAttribute("onload-attribute")) {
1110
+ /* ... */
1111
+ }
1112
+ if (element.hasAttribute("onload-query")) {
1113
+ /* ... */
1114
+ }
1115
+ } else {
1116
+ console.warn(
1117
+ `Skipping actions for element ${
1118
+ element.id || ""
1119
+ } because readiness check failed.`
1120
+ );
1121
+ }
1122
+ }
1123
+
1124
+ // --- Example Elements ---
1125
+
1126
+ // With Backoff (Delays: 100, 200, 400, 800 - capped)
1127
+ // <span id="elem1" onload-retry-property="scrollWidth"
1128
+ // onload-retry-attempts="5" onload-retry-delay="100"
1129
+ // onload-retry-backoff-factor="2" onload-retry-max-delay="500">
1130
+ // Content 1
1131
+ // </span>
1132
+ // Waits would be: 100ms, 200ms, 400ms, 500ms (capped)
1133
+
1134
+ // No Backoff (factor missing/invalid/<=1)
1135
+ // <span id="elem2" onload-retry-property="clientHeight"
1136
+ // onload-retry-attempts="4" onload-retry-delay="300">
1137
+ // Content 2
1138
+ // </span>
1139
+ // Waits would be: 300ms, 300ms, 300ms
1140
+
1141
+ // const element1 = document.getElementById('elem1');
1142
+ // if (element1) handleElementProcessingWithBackoff(element1);
1143
+ // const element2 = document.getElementById('elem2');
1144
+ // if (element2) handleElementProcessingWithBackoff(element2);
1145
+
874
1146
  CoCreateEvents.init();
875
1147
 
876
1148
  export default CoCreateEvents;