@cocreate/element-prototype 1.35.0 → 2.0.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/src/getValue.js CHANGED
@@ -17,21 +17,20 @@
17
17
  ********************************************************************************/
18
18
 
19
19
  import { astSync, astAsync } from "@cocreate/utils";
20
+ import { getValueAttribute, transformValue, parseJson, toBoolean, toArray } from "@cocreate/utils";
20
21
 
21
- const storage = new Map();
22
-
23
- HTMLElement.prototype.getValue = function () {
24
- return getValue(this);
22
+ HTMLElement.prototype.getValue = function (valueType) {
23
+ return getValue(this, valueType);
25
24
  };
26
- SVGElement.prototype.getValue = function () {
27
- return getValue(this);
25
+ SVGElement.prototype.getValue = function (valueType) {
26
+ return getValue(this, valueType);
28
27
  };
29
28
 
30
- HTMLElement.prototype.getValueAsync = async function () {
31
- return await getValueAsync(this);
29
+ HTMLElement.prototype.getValueAsync = async function (valueType) {
30
+ return await getValueAsync(this, valueType);
32
31
  };
33
- SVGElement.prototype.getValueAsync = async function () {
34
- return await getValueAsync(this);
32
+ SVGElement.prototype.getValueAsync = async function (valueType) {
33
+ return await getValueAsync(this, valueType);
35
34
  };
36
35
 
37
36
  /**
@@ -42,121 +41,131 @@ SVGElement.prototype.getValueAsync = async function () {
42
41
  * @returns {any} - The processed value.
43
42
  */
44
43
  const getValue = (element, valueType) => {
45
- if (!valueType) {
46
- valueType = element.getAttribute("value-type") || "";
47
- }
48
-
49
- let value = element.value || element.getAttribute("value") || "";
50
-
51
- if (
52
- element.hasAttribute("component") ||
53
- element.type === "file" ||
54
- element.getAttribute("type") === "file"
55
- ) {
56
- value = storage.get(element);
57
- storage.delete(element);
58
- return value;
59
- }
60
-
61
- let prefix = element.getAttribute("value-prefix") || "";
62
- let suffix = element.getAttribute("value-suffix") || "";
63
-
64
- const elementType = element.getAttribute("type") || element.type;
65
- const tagName = element.tagName.toUpperCase();
66
-
67
- switch (elementType) {
68
- case "checkbox":
69
- value = handleCheckbox(element, prefix, suffix);
70
- break;
71
-
72
- case "radio": {
73
- const key = element.getAttribute("key");
74
- let el = document.querySelector(`input[key="${key}"]:checked`);
75
- if (el) {
76
- value = el.value;
77
- }
78
- break;
79
- }
80
-
81
- case "number":
82
- value = Number(value);
83
- break;
84
-
85
- case "range":
86
- value = element.min
87
- ? [Number(element.min), Number(element.value)]
88
- : Number(element.value);
89
- break;
90
-
91
- case "password":
92
- value = btoa(value || "");
93
- break;
94
-
95
- case "email":
96
- value = value.toLowerCase();
97
- break;
98
-
99
- case "url":
100
- break;
101
-
102
- case "time":
103
- case "date":
104
- case "datetime":
105
- case "datetime-local":
106
- value = handleDateTime(element, value, valueType);
107
- break;
108
-
109
- default:
110
- switch (tagName) {
111
- case "INPUT":
112
- value = element.value;
113
- break;
114
-
115
- case "SELECT":
116
- value = element.hasAttribute("multiple")
117
- ? handleMultipleSelect(element, prefix, suffix)
118
- : element.value;
119
- break;
120
-
121
- case "TEXTAREA":
122
- value = element.hasAttribute("value")
123
- ? element.getAttribute("value")
124
- : element.value;
125
- break;
126
-
127
- case "IFRAME":
128
- value = element.srcdoc;
129
- break;
130
-
131
- default:
132
- value = handleElement(element, valueType);
133
- break;
134
- }
135
- break;
136
- }
137
-
138
- if (valueType === "boolean") {
139
- return value && value !== "false";
140
- }
141
-
142
- if (value) {
143
- value = astSync({ executeAST: value, node: element, exclude: ["$value"] });
144
- value = caseHandler(element, value);
145
- value = regex(element, value);
146
- value = encodeValue(value, element.getAttribute("value-encode") || "");
147
- value = decodeValue(value, element.getAttribute("value-decode") || "");
148
- }
149
-
150
- if (typeof value === "string" || typeof value === "number") {
151
- if (prefix || suffix) {
152
- value = prefix + value + suffix;
153
- }
154
- }
155
-
156
- value = parseJson(value, valueType);
157
- value = toArray(value, valueType);
158
-
159
- return value;
44
+ if (!valueType) {
45
+ valueType = getValueAttribute(element, "type", "get-value") || "";
46
+ }
47
+
48
+ const evaluateValue = getValueAttribute(element, "evaluate", "get-value", true) !== "false";
49
+ const readValueAttribute = () => evaluateValue
50
+ ? element.getAttribute("value")
51
+ : element.attributes.getNamedItem("value")?.value;
52
+ let value = element.value || readValueAttribute() || "";
53
+
54
+ if (
55
+ (!["INPUT", "TEXTAREA", "SELECT"].includes(element.tagName) && (
56
+ element.hasAttribute("component") ||
57
+ ((element.__cocreateEditor || element.hasAttribute("editor") ||
58
+ (element.hasAttribute("contenteditable") && element.getAttribute("contenteditable") !== "false")) &&
59
+ "value" in element)
60
+ )) ||
61
+ element.type === "file" ||
62
+ element.getAttribute("type") === "file"
63
+ ) {
64
+ return element.value;
65
+ }
66
+
67
+ let prefix = getValueAttribute(element, "prefix", "get-value") || "";
68
+ let suffix = getValueAttribute(element, "suffix", "get-value") || "";
69
+
70
+ const elementType = element.getAttribute("type") || element.type;
71
+ const tagName = element.tagName.toUpperCase();
72
+
73
+ switch (elementType) {
74
+ case "checkbox":
75
+ value = handleCheckbox(element, prefix, suffix, valueType);
76
+ break;
77
+
78
+ case "radio": {
79
+ const key = element.getAttribute("key");
80
+ let el = document.querySelector(`input[key="${key}"]:checked`);
81
+ if (el) {
82
+ value = el.value;
83
+ }
84
+ break;
85
+ }
86
+
87
+ case "number":
88
+ value = value === "" ? "" : Number(value);
89
+ break;
90
+ case "range":
91
+ value = element.min
92
+ ? [Number(element.min), Number(element.value)]
93
+ : Number(element.value);
94
+ break;
95
+
96
+ case "password":
97
+ value = btoa(value || "");
98
+ break;
99
+
100
+ case "email":
101
+ value = value.toLowerCase();
102
+ break;
103
+
104
+ case "url":
105
+ break;
106
+
107
+ case "time":
108
+ case "date":
109
+ case "datetime":
110
+ case "datetime-local":
111
+ value = handleDateTime(element, value, valueType);
112
+ break;
113
+
114
+ default:
115
+ switch (tagName) {
116
+ case "INPUT":
117
+ case "OPTION":
118
+ value = element.value;
119
+ break;
120
+
121
+ case "SELECT":
122
+ value = handleSelectedValues(element,
123
+ Array.from(element.selectedOptions, option => getValue(option)),
124
+ prefix, suffix);
125
+ break;
126
+
127
+ case "TEXTAREA":
128
+ value = element.hasAttribute("value")
129
+ ? readValueAttribute()
130
+ : element.value;
131
+ break;
132
+
133
+ case "IFRAME":
134
+ value = readFrame(element);
135
+ break;
136
+
137
+ case "IMG":
138
+ value = element.src;
139
+ break;
140
+
141
+ default:
142
+ value = handleElement(element, valueType, evaluateValue);
143
+ break;
144
+ }
145
+ break;
146
+ }
147
+
148
+ if (valueType === "boolean") {
149
+ return toBoolean(value);
150
+ }
151
+
152
+ if (value) {
153
+ if (evaluateValue) {
154
+ value = astSync({ executeAST: value, node: element, exclude: ["$value"] });
155
+ }
156
+ value = transformValue(element, value, "get-value");
157
+ }
158
+
159
+ if (typeof value === "string" || typeof value === "number") {
160
+ if (prefix || suffix) {
161
+ value = prefix + value + suffix;
162
+ }
163
+ }
164
+
165
+ value = parseJson(value, valueType);
166
+ value = toArray(value, valueType);
167
+
168
+ return value;
160
169
  };
161
170
 
162
171
  /**
@@ -167,151 +176,161 @@ const getValue = (element, valueType) => {
167
176
  * @returns {Promise<any>} - A promise that resolves to the processed value.
168
177
  */
169
178
  const getValueAsync = async (element, valueType) => {
170
- if (!valueType) {
171
- valueType = element.getAttribute("value-type") || "";
172
- }
173
-
174
- let value = element.value || element.getAttribute("value") || "";
175
-
176
- if (
177
- element.hasAttribute("component") ||
178
- element.type === "file" ||
179
- element.getAttribute("type") === "file"
180
- ) {
181
- value = storage.get(element);
182
- storage.delete(element);
183
- return value;
184
- }
185
-
186
- let prefix = element.getAttribute("value-prefix") || "";
187
- let suffix = element.getAttribute("value-suffix") || "";
188
-
189
- const elementType = element.getAttribute("type") || element.type;
190
- const tagName = element.tagName.toUpperCase();
191
-
192
- switch (elementType) {
193
- case "checkbox":
194
- value = handleCheckbox(element, prefix, suffix);
195
- break;
196
-
197
- case "radio": {
198
- const key = element.getAttribute("key");
199
- let el = document.querySelector(`input[key="${key}"]:checked`);
200
- if (el) {
201
- value = el.value;
202
- }
203
- break;
204
- }
205
-
206
- case "number":
207
- value = Number(value);
208
- break;
209
-
210
- case "range":
211
- value = element.min
212
- ? [Number(element.min), Number(element.value)]
213
- : Number(element.value);
214
- break;
215
-
216
- case "password":
217
- value = btoa(value || "");
218
- break;
219
-
220
- case "email":
221
- value = value.toLowerCase();
222
- break;
223
-
224
- case "url":
225
- break;
226
-
227
- case "time":
228
- case "date":
229
- case "datetime":
230
- case "datetime-local":
231
- value = handleDateTime(element, value, valueType);
232
- break;
233
-
234
- default:
235
- switch (tagName) {
236
- case "INPUT":
237
- value = element.value;
238
- break;
239
-
240
- case "SELECT":
241
- value = element.hasAttribute("multiple")
242
- ? handleMultipleSelect(element, prefix, suffix)
243
- : element.value;
244
- break;
245
-
246
- case "TEXTAREA":
247
- value = element.hasAttribute("value")
248
- ? element.getAttribute("value")
249
- : element.value;
250
- break;
251
-
252
- case "IFRAME":
253
- value = element.srcdoc;
254
- break;
255
-
256
- default:
257
- value = handleElement(element, valueType);
258
- break;
259
- }
260
- break;
261
- }
262
-
263
- if (valueType === "boolean") {
264
- return value && value !== "false";
265
- }
266
-
267
- if (value) {
268
- value = await astAsync({ executeAST: value, node: element, exclude: ["$value"] });
269
- value = caseHandler(element, value);
270
- value = regex(element, value);
271
- value = encodeValue(value, element.getAttribute("value-encode") || "");
272
- value = decodeValue(value, element.getAttribute("value-decode") || "");
273
- }
274
-
275
- if (typeof value === "string" || typeof value === "number") {
276
- if (prefix || suffix) {
277
- value = prefix + value + suffix;
278
- }
279
- }
280
-
281
- value = parseJson(value, valueType);
282
- value = toArray(value, valueType);
283
-
284
- return value;
179
+ if (!valueType) {
180
+ valueType = getValueAttribute(element, "type", "get-value") || "";
181
+ }
182
+
183
+ const evaluateValue = getValueAttribute(element, "evaluate", "get-value", true) !== "false";
184
+ const readValueAttribute = () => evaluateValue
185
+ ? element.getAttribute("value")
186
+ : element.attributes.getNamedItem("value")?.value;
187
+ let value = element.value || readValueAttribute() || "";
188
+
189
+ if (
190
+ (!["INPUT", "TEXTAREA", "SELECT"].includes(element.tagName) && (
191
+ element.hasAttribute("component") ||
192
+ ((element.__cocreateEditor || element.hasAttribute("editor") ||
193
+ (element.hasAttribute("contenteditable") && element.getAttribute("contenteditable") !== "false")) &&
194
+ "value" in element)
195
+ )) ||
196
+ element.type === "file" ||
197
+ element.getAttribute("type") === "file"
198
+ ) {
199
+ return element.value;
200
+ }
201
+
202
+ let prefix = getValueAttribute(element, "prefix", "get-value") || "";
203
+ let suffix = getValueAttribute(element, "suffix", "get-value") || "";
204
+
205
+ const elementType = element.getAttribute("type") || element.type;
206
+ const tagName = element.tagName.toUpperCase();
207
+
208
+ switch (elementType) {
209
+ case "checkbox":
210
+ value = handleCheckbox(element, prefix, suffix, valueType);
211
+ break;
212
+
213
+ case "radio": {
214
+ const key = element.getAttribute("key");
215
+ let el = document.querySelector(`input[key="${key}"]:checked`);
216
+ if (el) {
217
+ value = el.value;
218
+ }
219
+ break;
220
+ }
221
+
222
+ case "number":
223
+ value = Number(value);
224
+ break;
225
+
226
+ case "range":
227
+ value = element.min
228
+ ? [Number(element.min), Number(element.value)]
229
+ : Number(element.value);
230
+ break;
231
+
232
+ case "password":
233
+ value = btoa(value || "");
234
+ break;
235
+
236
+ case "email":
237
+ value = value.toLowerCase();
238
+ break;
239
+
240
+ case "url":
241
+ break;
242
+
243
+ case "time":
244
+ case "date":
245
+ case "datetime":
246
+ case "datetime-local":
247
+ value = handleDateTime(element, value, valueType);
248
+ break;
249
+
250
+ default:
251
+ switch (tagName) {
252
+ case "INPUT":
253
+ case "OPTION":
254
+ value = element.value;
255
+ break;
256
+
257
+ case "SELECT":
258
+ value = handleSelectedValues(element,
259
+ await Promise.all(Array.from(element.selectedOptions, option => getValueAsync(option))),
260
+ prefix, suffix);
261
+ break;
262
+
263
+ case "TEXTAREA":
264
+ value = element.hasAttribute("value")
265
+ ? readValueAttribute()
266
+ : element.value;
267
+ break;
268
+
269
+ case "IFRAME":
270
+ value = readFrame(element);
271
+ break;
272
+
273
+ default:
274
+ value = handleElement(element, valueType, evaluateValue);
275
+ break;
276
+ }
277
+ break;
278
+ }
279
+
280
+ if (valueType === "boolean") {
281
+ return toBoolean(value);
282
+ }
283
+
284
+ if (value) {
285
+ if (evaluateValue) {
286
+ value = await astAsync({ executeAST: value, node: element, exclude: ["$value"] });
287
+ }
288
+ value = transformValue(element, value, "get-value");
289
+ }
290
+
291
+ if (typeof value === "string" || typeof value === "number") {
292
+ if (prefix || suffix) {
293
+ value = prefix + value + suffix;
294
+ }
295
+ }
296
+
297
+ value = parseJson(value, valueType);
298
+ value = toArray(value, valueType);
299
+
300
+ return value;
285
301
  };
286
302
 
287
303
  /**
288
304
  * Processes a checkbox or a group of checkboxes to determine their checked values.
289
305
  */
290
- const handleCheckbox = (element, prefix = "", suffix = "") => {
291
- const inputs = element.getAttribute("key")
292
- ? document.querySelectorAll(
293
- `input[type="${element.type}"][key="${element.getAttribute(
294
- "key"
295
- )}"]`
296
- )
297
- : [element];
298
-
299
- if (inputs.length === 1) {
300
- return element.checked ? element.value || true : false;
301
- } else {
302
- return Array.from(inputs)
303
- .filter((el) => el.checked)
304
- .map((el) => `${prefix}${el.value}${suffix}`);
305
- }
306
+ const handleCheckbox = (element, prefix = "", suffix = "", valueType = "") => {
307
+ const inputs = element.getAttribute("key")
308
+ ? document.querySelectorAll(
309
+ `input[type="${element.type}"][key="${element.getAttribute(
310
+ "key"
311
+ )}"]`
312
+ )
313
+ : [element];
314
+
315
+ if (inputs.length === 1) {
316
+ if (valueType.startsWith("array"))
317
+ return element.checked ? [element.value || true] : [];
318
+ return element.checked ? element.value || true : false;
319
+ } else {
320
+ return Array.from(inputs)
321
+ .filter((el) => el.checked)
322
+ .map((el) => `${prefix}${el.value}${suffix}`);
323
+ }
306
324
  };
307
325
 
308
326
  /**
309
327
  * Handles and transforms a date/time value based on the specified valueType.
310
328
  */
311
329
  const handleDateTime = (element, value, valueType) => {
330
+ if ((value === "" || value === null || value === undefined) && !element.hasAttribute("now")) return "";
312
331
  const inputType = (element.getAttribute("type") || element.type || "").toLowerCase();
313
332
  let date;
314
-
333
+
315
334
  if (value === "$now" || element.hasAttribute("now")) {
316
335
  date = new Date();
317
336
  } else if (value instanceof Date) {
@@ -464,7 +483,7 @@ const handleDateTime = (element, value, valueType) => {
464
483
  case "timeAgo": {
465
484
  const diffMs = Date.now() - date.getTime();
466
485
  const absSecs = Math.floor(Math.abs(diffMs) / 1000);
467
-
486
+
468
487
  const limitAttr = element.getAttribute("time-ago-limit");
469
488
  if (limitAttr) {
470
489
  const match = limitAttr.match(/^(\d+)([a-z]+)$/i);
@@ -472,7 +491,7 @@ const handleDateTime = (element, value, valueType) => {
472
491
  const amount = parseInt(match[1], 10);
473
492
  const limitUnit = match[2].toLowerCase();
474
493
  let multiplier = 0;
475
-
494
+
476
495
  switch (limitUnit) {
477
496
  case 's': multiplier = 1; break;
478
497
  case 'm': multiplier = 60; break;
@@ -482,9 +501,9 @@ const handleDateTime = (element, value, valueType) => {
482
501
  case 'mo': multiplier = 2592000; break;
483
502
  case 'y': multiplier = 31536000; break;
484
503
  }
485
-
504
+
486
505
  const limitInSeconds = amount * multiplier;
487
-
506
+
488
507
  if (absSecs > limitInSeconds) {
489
508
  const locale = element.getAttribute("locale") || "en-US";
490
509
  return date.toLocaleString(locale);
@@ -532,308 +551,67 @@ const handleDateTime = (element, value, valueType) => {
532
551
  };
533
552
 
534
553
  /**
535
- * Processes a <select> element with the "multiple" attribute.
554
+ * Collects processed option values, retaining select-level multi-value affixes.
536
555
  */
537
- const handleMultipleSelect = (element, prefix, suffix) => {
538
- let value = [];
539
- let options = element.selectedOptions;
540
-
541
- for (let i = 0; i < options.length; i++) {
542
- let optionValue = options[i].value;
543
- if (prefix || suffix) {
544
- optionValue = prefix + optionValue + suffix;
545
- }
546
- value.push(optionValue);
547
- }
548
-
549
- return value;
556
+ const handleSelectedValues = (element, values, prefix, suffix) => {
557
+ if (!element.hasAttribute("multiple")) return values.length ? values[0] : "";
558
+ return prefix || suffix
559
+ ? values.map(value => prefix + value + suffix)
560
+ : values;
550
561
  };
551
562
 
552
563
  /**
553
564
  * Retrieves a value from a standard element.
554
565
  */
555
- const handleElement = (element, valueType) => {
556
- if (element.hasAttribute("value")) {
557
- return element.getAttribute("value");
558
- }
559
-
560
- let targetElement = element;
561
- const excludeSelector = element.getAttribute("value-remove-query");
562
-
563
- if (excludeSelector) {
564
- targetElement = element.cloneNode(true);
565
- targetElement
566
- .querySelectorAll(excludeSelector)
567
- .forEach((el) => el.remove());
568
- }
569
-
570
- switch (valueType) {
571
- case "text":
572
- return targetElement.innerText;
573
- case "outerHTML":
574
- case "element":
575
- case "node":
576
- return targetElement.outerHTML;
577
- default:
578
- return targetElement.innerHTML;
579
- }
566
+ const readFrame = (element) => {
567
+ if ("value" in element) return element.value;
568
+ if (element.hasAttribute("srcdoc")) return element.srcdoc;
569
+ const doc = element.contentDocument;
570
+ const declaration = doc.doctype
571
+ ? new element.ownerDocument.defaultView.XMLSerializer().serializeToString(doc.doctype)
572
+ : "";
573
+ return declaration + doc.documentElement.outerHTML;
580
574
  };
581
575
 
582
- /**
583
- * Adjusts casing transformations on attributes.
584
- */
585
- function caseHandler(element, value) {
586
- const lowercase = element.getAttribute("value-lowercase");
587
- if (lowercase !== null && lowercase !== "false") {
588
- value = value.toLowerCase();
589
- }
590
-
591
- const uppercase = element.getAttribute("value-uppercase");
592
- if (uppercase !== null && uppercase !== "false") {
593
- value = value.toUpperCase();
594
- }
576
+ const handleElement = (element, valueType, evaluateValue) => {
577
+ const readDOM = [
578
+ "text", "innerText", "textContent", "innerHTML", "outerHTML", "element", "node"
579
+ ].includes(valueType);
580
+
581
+ // Explicit DOM reads bypass stored values. Conversion types retain the
582
+ // normal attribute -> property -> DOM precedence, including empty values.
583
+ if (!readDOM) {
584
+ if (element.hasAttribute("value")) {
585
+ return evaluateValue
586
+ ? element.getAttribute("value")
587
+ : element.attributes.getNamedItem("value")?.value;
588
+ }
589
+ if ("value" in element) return element.value;
590
+ }
595
591
 
596
- return value;
597
- }
592
+ let targetElement = element;
593
+ const excludeSelector = getValueAttribute(element, "remove-query", "get-value");
598
594
 
599
- /**
600
- * Transforms output based on Regular Expression definitions.
601
- */
602
- function regex(element, value) {
603
- try {
604
- const attributes = element.attributes;
605
- const regexAttribute = [
606
- "value-replace",
607
- "value-replaceall",
608
- "value-test",
609
- "value-match",
610
- "value-split",
611
- "value-lastindex",
612
- "value-search",
613
- "value-exec"
614
- ];
615
-
616
- for (let i = 0; i < attributes.length; i++) {
617
- if (value === null || value === undefined) break;
618
- if (!regexAttribute.includes(attributes[i].name)) continue;
619
-
620
- let regexAttributeValue = attributes[i].value;
621
- if (!regexAttributeValue) continue;
622
-
623
- let { regex, replacement } = regexParser(regexAttributeValue);
624
- if (regex) regexAttributeValue = regex;
625
-
626
- replacement =
627
- replacement || element.getAttribute("value-replacement") || "";
628
-
629
- switch (attributes[i].name) {
630
- case "value-replace":
631
- value = value.replace(regexAttributeValue, replacement);
632
- break;
633
- case "value-replaceall":
634
- value = value.replaceAll(regexAttributeValue, replacement);
635
- break;
636
- case "value-test":
637
- value = regex.test(value);
638
- break;
639
- case "value-match": {
640
- const matches = value.match(regexAttributeValue);
641
- if (matches) {
642
- value = matches[1] || matches[0];
643
- }
644
- break;
645
- }
646
- case "value-split":
647
- value = value.split(regexAttributeValue);
648
- break;
649
- case "value-lastindex":
650
- regex.lastIndex = 0;
651
- regex.test(value);
652
- value = regex.lastIndex;
653
- break;
654
- case "value-search":
655
- value = value.search(regexAttributeValue);
656
- break;
657
- case "value-exec": {
658
- const execResult = regex.exec(value);
659
- if (execResult) {
660
- value = execResult[1] || execResult[2] || execResult[0];
661
- }
662
- break;
663
- }
664
- }
665
- }
666
-
667
- return value;
668
- } catch (error) {
669
- console.warn(
670
- "Warning: Transformation error during regex operation:",
671
- error,
672
- element
673
- );
674
- return value;
675
- }
676
- }
677
-
678
- function regexParser(string) {
679
- let regex, replacement;
680
- let regexMatch = string.match(/\/(.+)\/([gimuy]*)/);
681
-
682
- if (regexMatch) {
683
- regex = new RegExp(regexMatch[1], regexMatch[2]);
684
- const splitReplace = string.split(", ");
685
- replacement =
686
- splitReplace.length > 1 ? splitReplace[1].slice(1, -1) : "";
687
- }
688
-
689
- return { regex, replacement };
690
- }
595
+ if (excludeSelector) {
596
+ targetElement = element.cloneNode(true);
597
+ targetElement
598
+ .querySelectorAll(excludeSelector)
599
+ .forEach((el) => el.remove());
600
+ }
691
601
 
692
- /**
693
- * Encodes calculated structures securely.
694
- */
695
- function encodeValue(value, encodingType) {
696
- if (!encodingType) {
697
- return value;
698
- }
699
-
700
- switch (encodingType.toLowerCase()) {
701
- case "url":
702
- case "uri":
703
- return encodeURI(value.replace(/ /g, "%20"));
704
-
705
- case "uri-component":
706
- return encodeURIComponent(value.replace(/ /g, "%20"));
707
-
708
- case "base64":
709
- case "atob":
710
- try {
711
- const encoder = new TextEncoder();
712
- const uint8Array = encoder.encode(value);
713
- return btoa(String.fromCharCode(...uint8Array));
714
- } catch (error) {
715
- console.warn(`Failed to encode as Base64: ${error.message}`);
716
- return value;
717
- }
718
-
719
- case "html-entities":
720
- return value.replace(/[\u00A0-\u9999<>\&]/g, (i) => {
721
- return `&#${i.charCodeAt(0)};`;
722
- });
723
-
724
- case "json":
725
- try {
726
- return JSON.stringify(value);
727
- } catch (error) {
728
- console.warn(`Failed to convert to JSON: ${error.message}`);
729
- return value;
730
- }
731
-
732
- default:
733
- console.warn(`Unsupported encoding type: ${encodingType}`);
734
- return value;
735
- }
736
- }
602
+ switch (valueType) {
603
+ case "text":
604
+ case "innerText":
605
+ return targetElement.innerText;
606
+ case "textContent":
607
+ return targetElement.textContent;
608
+ case "outerHTML":
609
+ case "element":
610
+ case "node":
611
+ return targetElement.outerHTML;
612
+ default:
613
+ return targetElement.innerHTML;
614
+ }
615
+ };
737
616
 
738
- /**
739
- * Decodes calculated structures securely.
740
- */
741
- function decodeValue(value, decodingType) {
742
- if (!decodingType) {
743
- return value;
744
- }
745
-
746
- switch (decodingType.toLowerCase()) {
747
- case "url":
748
- case "uri":
749
- return decodeURI(value);
750
-
751
- case "uri-component":
752
- return decodeURIComponent(value);
753
-
754
- case "base64":
755
- case "btoa":
756
- try {
757
- const decodedArray = Uint8Array.from(atob(value), (c) =>
758
- c.charCodeAt(0)
759
- );
760
- const decoder = new TextDecoder();
761
- return decoder.decode(decodedArray);
762
- } catch (error) {
763
- console.warn(`Failed to decode Base64: ${error.message}`);
764
- return value;
765
- }
766
-
767
- case "html-entities": {
768
- const tempElement = document.createElement("div");
769
- tempElement.innerHTML = value;
770
- return tempElement.textContent;
771
- }
772
-
773
- case "json":
774
- try {
775
- return JSON.parse(value);
776
- } catch (error) {
777
- console.warn(`Failed to parse JSON: ${error.message}`);
778
- return value;
779
- }
780
-
781
- default:
782
- console.warn(`Unsupported decoding type: ${decodingType}`);
783
- return value;
784
- }
785
- }
786
-
787
- function parseJson(value, valueType) {
788
- if (
789
- value &&
790
- (valueType === "object" ||
791
- valueType === "json" ||
792
- valueType.startsWith("array"))
793
- ) {
794
- try {
795
- value = JSON.parse(value);
796
- } catch {
797
- const jsonRegex = /(\{[\s\S]*}|\[[\s\S]*\])/;
798
- const match = value.match(jsonRegex);
799
-
800
- if (match) {
801
- try {
802
- value = JSON.parse(match[0]);
803
- } catch {
804
- console.warn(
805
- "Warning: Failed to parse JSON after extraction. Returning original value."
806
- );
807
- }
808
- } else {
809
- console.warn(
810
- "Warning: No valid JSON structure found in the string. Returning original value."
811
- );
812
- }
813
- }
814
- }
815
- return value;
816
- }
817
-
818
- function toArray(value, valueType) {
819
- if (valueType.startsWith("array")) {
820
- if (!Array.isArray(value)) {
821
- if (typeof value === "object" && value !== null) {
822
- if (valueType === "array.$keys") {
823
- value = Object.keys(value);
824
- } else if (valueType === "array.$values") {
825
- value = Object.values(value);
826
- } else if (valueType === "array.$entries") {
827
- value = Object.entries(value);
828
- } else {
829
- value = [value];
830
- }
831
- } else {
832
- value = [value];
833
- }
834
- }
835
- }
836
- return value;
837
- }
838
-
839
- export { getValue, getValueAsync, storage };
617
+ export { getValue, getValueAsync };