powerpagestoolkit 2.7.1 → 2.7.101

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 CHANGED
@@ -85,10 +85,10 @@ import { createRef } from "powerpagestoolkit";
85
85
  Instantiate one, or multiple instances of a DOMNodeReference, and optionally configure advanced options
86
86
 
87
87
  ```javascript
88
- // Create a single reference
88
+ // Create a single reference (i.e. 'querySelector')
89
89
  const node = await createRef("#myElement");
90
90
 
91
- // Create multiple references
91
+ // Create multiple references (i.e. 'querySelectorAll')
92
92
  const nodes = await createRef(".my-class", { multiple: true });
93
93
 
94
94
  /******************/
@@ -161,7 +161,7 @@ applyBusinessRule(
161
161
  ```typescript
162
162
  interface IBusinessRule {
163
163
  setVisibility?: [
164
- condition: () => boolean,
164
+ condition: () => boolean,
165
165
  clearValuesOnHide?: boolean = true
166
166
  ];
167
167
  setRequired?: [
@@ -169,7 +169,7 @@ interface IBusinessRule {
169
169
  isValid: () => boolean
170
170
  ];
171
171
  setValue?: [
172
- condition: () => boolean,
172
+ condition: () => boolean,
173
173
  value: () => any | any
174
174
  ];
175
175
  setDisabled?: () => boolean;
@@ -192,7 +192,7 @@ taxIdField.applyBusinessRule(
192
192
  [businessTypeField] // Re-evaluate when businessTypeField changes
193
193
  );
194
194
 
195
- // Optionally disable 'clearValuesOnHide:
195
+ // Optionally disable 'clearValuesOnHide':
196
196
  taxIdField.applyBusinessRule(
197
197
  {
198
198
  setVisibility: [
@@ -234,7 +234,10 @@ taxIdField.applyBusinessRule(
234
234
  // Set default industry value when 'businessTypeField' is 'Corporation'
235
235
  industryField.applyBusinessRule(
236
236
  {
237
- setValue: [() => businessTypeField.value === "Corporation", "Corporate"],
237
+ setValue: [
238
+ () => businessTypeField.value === "Corporation",
239
+ "Corporate"
240
+ ],
238
241
  },
239
242
  [businessTypeField] // Apply value when businessTypeField changes
240
243
  );
@@ -246,7 +249,7 @@ industryField.applyBusinessRule(
246
249
  // Disable 'taxIdField' when 'businessTypeField' is 'Individual'
247
250
  taxIdField.applyBusinessRule(
248
251
  {
249
- setDisabled: [() => businessTypeField.value === "Individual"],
252
+ setDisabled: () => businessTypeField.value === "Individual",
250
253
  },
251
254
  [businessTypeField] // Enable/disable when businessTypeField changes
252
255
  );
package/dist/bundle.js CHANGED
@@ -1,4 +1,4 @@
1
- // src/safeAjax.ts
1
+ // src/utils/safeAjax.ts
2
2
  function safeAjax(ajaxOptions) {
3
3
  const deferredAjax = $.Deferred();
4
4
  shell.getTokenDeferred().done(function(token) {
@@ -20,7 +20,7 @@ function safeAjax(ajaxOptions) {
20
20
  return deferredAjax.promise();
21
21
  }
22
22
 
23
- // src/API.ts
23
+ // src/core/API.ts
24
24
  var API = {
25
25
  /**
26
26
  * @param tableSetName The dataverse set name for the table that you are updating a record in
@@ -102,48 +102,14 @@ var API = {
102
102
  };
103
103
  var API_default = API;
104
104
 
105
- // src/DOMNodeReferenceArray.ts
106
- var DOMNodeReferenceArray = class extends Array {
107
- /**
108
- * Hides all the containers of the DOMNodeReference instances in the array.
109
- */
110
- hideAll() {
111
- this.forEach((instance) => instance.hide());
112
- return this;
113
- }
114
- /**
115
- * Shows all the containers of the DOMNodeReference instances in the array.
116
- */
117
- showAll() {
118
- this.forEach((instance) => instance.show());
119
- return this;
120
- }
121
- };
122
- function enhanceArray(array) {
123
- const enhancedArray = new DOMNodeReferenceArray(...array);
124
- return new Proxy(enhancedArray, {
125
- get(target, prop, receiver) {
126
- if (prop in target) {
127
- return Reflect.get(target, prop, receiver);
128
- }
129
- if (typeof prop === "string") {
130
- return target.find(
131
- (instance) => instance.target.toString().replace(/[#\[\]]/g, "") === prop || instance.logicalName === prop
132
- );
133
- }
134
- return void 0;
135
- }
136
- });
137
- }
138
-
139
- // src/waitFor.ts
140
- function waitFor(target, root = document, multiple = false, debounceTime) {
105
+ // src/utils/waitFor.ts
106
+ function waitFor(target, root = document, multiple = false, debounceTime2) {
141
107
  return new Promise((resolve, reject) => {
142
108
  if (multiple) {
143
109
  let timeout;
144
110
  const observedElements = [];
145
111
  const observedSet = /* @__PURE__ */ new Set();
146
- if (debounceTime < 1) {
112
+ if (debounceTime2 < 1) {
147
113
  return resolve(
148
114
  Array.from(root.querySelectorAll(target))
149
115
  );
@@ -164,11 +130,11 @@ function waitFor(target, root = document, multiple = false, debounceTime) {
164
130
  } else {
165
131
  reject(
166
132
  new Error(
167
- `No elements found with target: "${target}" within ${debounceTime / 1e3} seconds. If the element you are expecting has not loaded yet, consider raising your timeout.`
133
+ `No elements found with target: "${target}" within ${debounceTime2 / 1e3} seconds. If the element you are expecting has not loaded yet, consider raising your timeout.`
168
134
  )
169
135
  );
170
136
  }
171
- }, debounceTime);
137
+ }, debounceTime2);
172
138
  });
173
139
  observer.observe(root, {
174
140
  childList: true,
@@ -188,10 +154,10 @@ function waitFor(target, root = document, multiple = false, debounceTime) {
188
154
  observer.disconnect();
189
155
  reject(
190
156
  new Error(
191
- `Element not found by target: "${target}" within ${debounceTime / 1e3} second. If the element you are expecting has not loaded yet, consider raising your timeout.`
157
+ `Element not found by target: "${target}" within ${debounceTime2 / 1e3} second. If the element you are expecting has not loaded yet, consider raising your timeout.`
192
158
  )
193
159
  );
194
- }, debounceTime);
160
+ }, debounceTime2);
195
161
  if (target instanceof HTMLElement) {
196
162
  clearTimeout(timeout);
197
163
  return resolve(target);
@@ -211,7 +177,7 @@ function waitFor(target, root = document, multiple = false, debounceTime) {
211
177
  });
212
178
  }
213
179
 
214
- // src/createInfoElement.ts
180
+ // src/utils/createInfoElement.ts
215
181
  function CreateInfoEl(titleString, iconStyle) {
216
182
  if (typeof titleString !== "string") {
217
183
  throw new Error(
@@ -275,7 +241,22 @@ function CreateInfoEl(titleString, iconStyle) {
275
241
  return span;
276
242
  }
277
243
 
278
- // src/errors.ts
244
+ // src/constants/symbols.ts
245
+ var init = Symbol("__I");
246
+ var destroy = Symbol("__D");
247
+ var valueSync = Symbol("__VS");
248
+ var dateSync = Symbol("__DS");
249
+ var getElementValue = Symbol("__GEV");
250
+ var attachVisibilityController = Symbol("__AVC");
251
+ var attachRadioButtons = Symbol("__ARB");
252
+ var bindMethods = Symbol("__B");
253
+ var debounceTime = Symbol("__DT");
254
+ var observers = Symbol("__O");
255
+ var boundEventListeners = Symbol("__BEV");
256
+ var isValidFormElement = Symbol("__VFE");
257
+ var registerEventListener = Symbol("__REV");
258
+
259
+ // src/errors/errors.ts
279
260
  var DOMNodeInitializationError = class extends Error {
280
261
  constructor(instance, error) {
281
262
  super(
@@ -303,29 +284,27 @@ var ValidationConfigError = class extends Error {
303
284
  }
304
285
  };
305
286
 
306
- // src/DOMNodeReference.ts
307
- var _init = Symbol("_I");
308
- var _destroy = Symbol("_D");
309
- var _valueSync = Symbol("_VS");
310
- var _dateSync = Symbol("_DS");
311
- var _getElementValue = Symbol("_GEV");
312
- var _updateRadioGroup = Symbol("_URG");
313
- var _attachVisibilityController = Symbol("_AVC");
314
- var _attachRadioButtons = Symbol("_ARB");
315
- var _bindMethods = Symbol("_B");
316
- var _debounceTime = Symbol("DT");
317
- var _observers = Symbol("O");
318
- var _boundEventListeners = Symbol("BEV");
287
+ // src/core/DOMNodeReference.ts
288
+ var eventMapping = {
289
+ checkbox: "click",
290
+ radio: "click",
291
+ select: "change",
292
+ "select-multiple": "change",
293
+ textarea: "keyup"
294
+ // Add other input types as needed
295
+ };
319
296
  var DOMNodeReference = class _DOMNodeReference {
320
297
  // properties initialized in the constructor
321
298
  target;
322
299
  logicalName;
323
300
  root;
324
- [_debounceTime];
301
+ [debounceTime];
325
302
  isLoaded;
326
303
  defaultDisplay;
327
- [_observers] = [];
328
- [_boundEventListeners] = [];
304
+ [observers] = [];
305
+ [boundEventListeners] = [];
306
+ isRadio = false;
307
+ radioType = null;
329
308
  /**
330
309
  * The value of the element that this node represents
331
310
  * stays in syncs with the live DOM elements?.,m via event handler
@@ -339,7 +318,7 @@ var DOMNodeReference = class _DOMNodeReference {
339
318
  */
340
319
  /******/
341
320
  /******/
342
- constructor(target, root = document.body, debounceTime) {
321
+ constructor(target, root = document.body, debounceTime2) {
343
322
  this.target = target;
344
323
  if (typeof target === "string") {
345
324
  let lName = null;
@@ -354,32 +333,39 @@ var DOMNodeReference = class _DOMNodeReference {
354
333
  this.logicalName = (lName || target).replace(/[#\[\]]/g, "");
355
334
  }
356
335
  this.root = root;
357
- this[_debounceTime] = debounceTime;
336
+ this[debounceTime] = debounceTime2;
358
337
  this.isLoaded = false;
359
338
  this.defaultDisplay = "";
360
339
  this.value = null;
361
- this[_bindMethods]();
340
+ this[bindMethods]();
362
341
  }
363
- async [_init]() {
342
+ async [init]() {
364
343
  try {
365
344
  if (this.target instanceof HTMLElement) {
366
345
  this.element = this.target;
367
346
  } else {
368
- this.element = await waitFor(this.target, this.root, false, this[_debounceTime]);
347
+ this.element = await waitFor(
348
+ this.target,
349
+ this.root,
350
+ false,
351
+ this[debounceTime]
352
+ );
369
353
  }
370
354
  if (!this.element) {
371
355
  throw new DOMNodeNotFoundError(this);
372
356
  }
373
- if (this.element.classList.contains("boolean-radio")) {
374
- await this[_attachRadioButtons]();
357
+ if (this.element.id && this.element.querySelectorAll(
358
+ `#${this.element.id} > input[type="radio"]`
359
+ ).length > 0) {
360
+ await this[attachRadioButtons]();
375
361
  }
376
- this[_valueSync]();
377
- this[_attachVisibilityController]();
362
+ this[valueSync]();
363
+ this[attachVisibilityController]();
378
364
  this.defaultDisplay = this.visibilityController.style.display;
379
365
  const observer = new MutationObserver((mutations) => {
380
366
  for (const mutation of mutations) {
381
367
  if (Array.from(mutation.removedNodes).includes(this.element)) {
382
- this[_destroy]();
368
+ this[destroy]();
383
369
  observer.disconnect();
384
370
  break;
385
371
  }
@@ -395,40 +381,27 @@ var DOMNodeReference = class _DOMNodeReference {
395
381
  throw new DOMNodeInitializationError(this, errorMessage);
396
382
  }
397
383
  }
398
- eventMapping = {
399
- checkbox: "click",
400
- radio: "click",
401
- select: "change",
402
- "select-multiple": "change",
403
- textarea: "keyup"
404
- // Add other input types as needed
405
- };
406
384
  /**
407
385
  * Initializes value synchronization with appropriate event listeners
408
386
  * based on element type.
409
- * @private
410
387
  */
411
- async [_valueSync]() {
388
+ async [valueSync]() {
412
389
  try {
390
+ if (!this[isValidFormElement](this.element)) return;
413
391
  this.updateValue();
414
392
  let eventType;
415
393
  if (this.element instanceof HTMLSelectElement) {
416
394
  eventType = "change";
417
395
  } else if (this.element instanceof HTMLInputElement) {
418
- eventType = this.eventMapping[this.element.type] ?? "input";
396
+ eventType = eventMapping[this.element.type] ?? "input";
419
397
  } else if (this.element instanceof HTMLTextAreaElement) {
420
- eventType = this.eventMapping[this.element.type] ?? "input";
398
+ eventType = eventMapping[this.element.type] ?? "input";
421
399
  } else {
422
400
  eventType = "input";
423
401
  }
424
- this.element.addEventListener(eventType, this.updateValue);
425
- this[_boundEventListeners].push({
426
- element: this.element,
427
- handler: this.updateValue,
428
- event: eventType
429
- });
402
+ this[registerEventListener](this.element, eventType, this.updateValue);
430
403
  if (this.element instanceof HTMLInputElement && this.element.dataset.type === "date") {
431
- await this[_dateSync](this.element);
404
+ await this[dateSync](this.element);
432
405
  }
433
406
  } catch (error) {
434
407
  throw new DOMNodeInitializationError(
@@ -437,28 +410,44 @@ var DOMNodeReference = class _DOMNodeReference {
437
410
  );
438
411
  }
439
412
  }
440
- async [_dateSync](element) {
413
+ [isValidFormElement](element) {
414
+ return element instanceof HTMLInputElement || element instanceof HTMLSelectElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSpanElement || element instanceof HTMLButtonElement || element instanceof HTMLFieldSetElement;
415
+ }
416
+ [registerEventListener](element, eventType, handler) {
417
+ element.addEventListener(eventType, handler);
418
+ this[boundEventListeners].push({
419
+ element,
420
+ handler,
421
+ event: eventType
422
+ });
423
+ }
424
+ async [dateSync](element) {
441
425
  const parentElement = element.parentElement;
442
426
  if (!parentElement) {
443
427
  throw new Error("Date input must have a parent element");
444
428
  }
445
- const dateNode = await waitFor("[data-date-format]", parentElement, false, 1500);
446
- dateNode.addEventListener("select", this.updateValue);
447
- const _handler = this.updateValue;
448
- this[_boundEventListeners].push({
449
- element: dateNode,
450
- handler: _handler,
451
- event: "select"
452
- });
429
+ const dateNode = await waitFor(
430
+ "[data-date-format]",
431
+ parentElement,
432
+ false,
433
+ 1500
434
+ );
435
+ this[registerEventListener](dateNode, "select", this.updateValue);
453
436
  }
454
437
  /**
455
438
  * Gets the current value of the element based on its type
456
- * @private
439
+ * @protected
457
440
  * @returns Object containing value and optional checked state
458
441
  */
459
- [_getElementValue]() {
442
+ [getElementValue]() {
460
443
  const input = this.element;
461
444
  const select = this.element;
445
+ if (this.yesRadio instanceof _DOMNodeReference && this.noRadio instanceof _DOMNodeReference) {
446
+ return {
447
+ value: this.yesRadio.checked,
448
+ checked: this.yesRadio.checked
449
+ };
450
+ }
462
451
  switch (input.type) {
463
452
  case "checkbox":
464
453
  case "radio":
@@ -489,19 +478,7 @@ var DOMNodeReference = class _DOMNodeReference {
489
478
  };
490
479
  }
491
480
  }
492
- /**
493
- * Updates related radio buttons if this is part of a radio group
494
- * @private
495
- */
496
- [_updateRadioGroup]() {
497
- if (this.yesRadio instanceof _DOMNodeReference && this.noRadio instanceof _DOMNodeReference) {
498
- this.yesRadio.updateValue();
499
- this.noRadio?.updateValue();
500
- this.checked = this.yesRadio.checked;
501
- this.value = this.yesRadio.checked;
502
- }
503
- }
504
- [_attachVisibilityController]() {
481
+ [attachVisibilityController]() {
505
482
  this.visibilityController = this.element;
506
483
  if (this.element.tagName === "TABLE") {
507
484
  const fieldset = this.element.closest("fieldset");
@@ -524,11 +501,26 @@ var DOMNodeReference = class _DOMNodeReference {
524
501
  }
525
502
  }
526
503
  }
527
- async [_attachRadioButtons]() {
528
- this.yesRadio = await createDOMNodeReference(`#${this.element.id}_1`);
529
- this.noRadio = await createDOMNodeReference(`#${this.element.id}_0`);
504
+ async [attachRadioButtons]() {
505
+ if (!this.element) {
506
+ console.error(
507
+ "'this.element' not found: cannot attach radio buttons for ",
508
+ this.target
509
+ );
510
+ return;
511
+ }
512
+ this.yesRadio = await createDOMNodeReference('input[type="radio"][value="1"]', {
513
+ root: this.element
514
+ });
515
+ this.yesRadio.isRadio = true;
516
+ this.yesRadio.radioType = "truthy";
517
+ this.noRadio = await createDOMNodeReference('input[type="radio"][value="0"]', {
518
+ root: this.element
519
+ });
520
+ this.noRadio.isRadio = true;
521
+ this.noRadio.radioType = "falsy";
530
522
  }
531
- [_bindMethods]() {
523
+ [bindMethods]() {
532
524
  const prototype = Object.getPrototypeOf(this);
533
525
  for (const key of Object.getOwnPropertyNames(prototype)) {
534
526
  const value = this[key];
@@ -537,15 +529,15 @@ var DOMNodeReference = class _DOMNodeReference {
537
529
  }
538
530
  }
539
531
  }
540
- [_destroy]() {
541
- this[_boundEventListeners]?.forEach((binding) => {
532
+ [destroy]() {
533
+ this[boundEventListeners]?.forEach((binding) => {
542
534
  binding.element?.removeEventListener(binding.event, binding.handler);
543
535
  });
544
- this[_observers]?.forEach((observer) => {
536
+ this[observers]?.forEach((observer) => {
545
537
  observer.disconnect();
546
538
  });
547
- this.yesRadio?.[_destroy]();
548
- this.noRadio?.[_destroy]();
539
+ this.yesRadio?.[destroy]();
540
+ this.noRadio?.[destroy]();
549
541
  this.yesRadio = null;
550
542
  this.noRadio = null;
551
543
  this.isLoaded = false;
@@ -555,13 +547,19 @@ var DOMNodeReference = class _DOMNodeReference {
555
547
  * Updates the value and checked state based on element type
556
548
  * @public
557
549
  */
558
- updateValue() {
559
- const elementValue = this[_getElementValue]();
550
+ updateValue(e) {
551
+ if (e) {
552
+ e.stopPropagation();
553
+ }
554
+ if (this.yesRadio && this.noRadio) {
555
+ this.yesRadio.updateValue();
556
+ this.noRadio.updateValue();
557
+ }
558
+ const elementValue = this[getElementValue]();
560
559
  this.value = elementValue.value;
561
560
  if (elementValue.checked !== void 0) {
562
561
  this.checked = elementValue.checked;
563
562
  }
564
- this[_updateRadioGroup]();
565
563
  }
566
564
  /**
567
565
  * Sets up an event listener based on the specified event type, executing the specified
@@ -577,14 +575,11 @@ var DOMNodeReference = class _DOMNodeReference {
577
575
  `Argument "eventHandler" must be a Function. Received: ${typeof eventHandler}`
578
576
  );
579
577
  }
580
- this.element.addEventListener(eventType, eventHandler.bind(this));
581
- const _element = this.element;
582
- const _handler = eventHandler;
583
- this[_boundEventListeners].push({
584
- element: _element,
585
- handler: _handler,
586
- event: eventType
587
- });
578
+ this[registerEventListener](
579
+ this.element,
580
+ eventType,
581
+ eventHandler.bind(this)
582
+ );
588
583
  return this;
589
584
  }
590
585
  /**
@@ -632,9 +627,9 @@ var DOMNodeReference = class _DOMNodeReference {
632
627
  if (this.element instanceof HTMLSelectElement) {
633
628
  eventType = "change";
634
629
  } else if (this.element instanceof HTMLInputElement) {
635
- eventType = this.eventMapping[this.element.type] ?? "input";
630
+ eventType = eventMapping[this.element.type] ?? "input";
636
631
  } else if (this.element instanceof HTMLTextAreaElement) {
637
- eventType = this.eventMapping[this.element.type] ?? "input";
632
+ eventType = eventMapping[this.element.type] ?? "input";
638
633
  } else {
639
634
  eventType = "input";
640
635
  }
@@ -711,7 +706,9 @@ var DOMNodeReference = class _DOMNodeReference {
711
706
  );
712
707
  if (childInputs.length > 0) {
713
708
  const promises = childInputs.map(async (input) => {
714
- const inputRef = await createDOMNodeReference(input, { multiple: false });
709
+ const inputRef = await createDOMNodeReference(input, {
710
+ multiple: false
711
+ });
715
712
  return inputRef.clearValue();
716
713
  });
717
714
  await Promise.all(promises);
@@ -851,7 +848,7 @@ var DOMNodeReference = class _DOMNodeReference {
851
848
  * @returns - Instance of this [provides option to method chain]
852
849
  */
853
850
  uncheckRadios() {
854
- if (this.yesRadio && this.noRadio) {
851
+ if (this.yesRadio instanceof _DOMNodeReference && this.noRadio instanceof _DOMNodeReference) {
855
852
  this.yesRadio.element.checked = false;
856
853
  this.noRadio.element.checked = false;
857
854
  } else {
@@ -1070,7 +1067,7 @@ var DOMNodeReference = class _DOMNodeReference {
1070
1067
  }
1071
1068
  /**
1072
1069
  * Sets up tracking for dependencies using both event listeners and mutation observers.
1073
- * @private
1070
+ * @protected
1074
1071
  * @param handler The function to execute when dependencies change
1075
1072
  * @param dependencies Array of dependent DOM nodes to track
1076
1073
  * @param options Additional configuration options. clearValuesOnHide defaults to false.
@@ -1106,19 +1103,9 @@ var DOMNodeReference = class _DOMNodeReference {
1106
1103
  this.clearValue();
1107
1104
  }
1108
1105
  };
1109
- dep.on("change", handleChange);
1110
- this[_boundEventListeners].push({
1111
- element: dep.element,
1112
- event: "change",
1113
- handler: handleChange
1114
- });
1106
+ this[registerEventListener](dep.element, "change", handleChange);
1115
1107
  if (trackInputEvents) {
1116
- dep.on("input", handleChange);
1117
- this[_boundEventListeners].push({
1118
- element: dep.element,
1119
- event: "input",
1120
- handler: handleChange
1121
- });
1108
+ this[registerEventListener](dep.element, "input", handleChange);
1122
1109
  }
1123
1110
  if (observeVisibility) {
1124
1111
  const observer = new MutationObserver(() => {
@@ -1134,12 +1121,12 @@ var DOMNodeReference = class _DOMNodeReference {
1134
1121
  attributeFilter: ["style"],
1135
1122
  subtree: false
1136
1123
  });
1137
- this[_observers].push(observer);
1124
+ this[observers].push(observer);
1138
1125
  }
1139
1126
  if (trackRadioButtons && dep.yesRadio && dep.noRadio) {
1140
1127
  [dep.yesRadio, dep.noRadio].forEach((radio) => {
1141
1128
  radio.on("change", handleChange);
1142
- this[_boundEventListeners].push({
1129
+ this[boundEventListeners].push({
1143
1130
  element: radio.element,
1144
1131
  event: "change",
1145
1132
  handler: handleChange
@@ -1191,11 +1178,47 @@ var DOMNodeReference = class _DOMNodeReference {
1191
1178
  subtree: true,
1192
1179
  childList: true
1193
1180
  });
1194
- this[_observers].push(observer);
1181
+ this[observers].push(observer);
1182
+ }
1183
+ };
1184
+
1185
+ // src/core/DOMNodeReferenceArray.ts
1186
+ var DOMNodeReferenceArray = class extends Array {
1187
+ /**
1188
+ * Hides all the containers of the DOMNodeReference instances in the array.
1189
+ */
1190
+ hideAll() {
1191
+ this.forEach((instance) => instance.hide());
1192
+ return this;
1193
+ }
1194
+ /**
1195
+ * Shows all the containers of the DOMNodeReference instances in the array.
1196
+ */
1197
+ showAll() {
1198
+ this.forEach((instance) => instance.show());
1199
+ return this;
1195
1200
  }
1196
1201
  };
1197
1202
 
1198
- // src/createDOMNodeReferences.ts
1203
+ // src/utils/enhanceArray.ts
1204
+ function enhanceArray(array) {
1205
+ const enhancedArray = new DOMNodeReferenceArray(...array);
1206
+ return new Proxy(enhancedArray, {
1207
+ get(target, prop, receiver) {
1208
+ if (prop in target) {
1209
+ return Reflect.get(target, prop, receiver);
1210
+ }
1211
+ if (typeof prop === "string") {
1212
+ return target.find(
1213
+ (instance) => instance.target.toString().replace(/[#\[\]]/g, "") === prop || instance.logicalName === prop
1214
+ );
1215
+ }
1216
+ return void 0;
1217
+ }
1218
+ });
1219
+ }
1220
+
1221
+ // src/core/createDOMNodeReferences.ts
1199
1222
  async function createDOMNodeReference(target, options = {
1200
1223
  multiple: false,
1201
1224
  root: document.body,
@@ -1220,14 +1243,14 @@ async function createDOMNodeReference(target, options = {
1220
1243
  const initializedElements = await Promise.all(
1221
1244
  elements.map(async (element) => {
1222
1245
  const instance2 = new DOMNodeReference(element, root, timeout);
1223
- await instance2[_init]();
1246
+ await instance2[init]();
1224
1247
  return new Proxy(instance2, createProxyHandler());
1225
1248
  })
1226
1249
  );
1227
1250
  return enhanceArray(initializedElements);
1228
1251
  }
1229
1252
  const instance = new DOMNodeReference(target, root, timeout);
1230
- await instance[_init]();
1253
+ await instance[init]();
1231
1254
  return new Proxy(instance, createProxyHandler());
1232
1255
  } catch (e) {
1233
1256
  throw new Error(e);
@@ -1276,7 +1299,7 @@ function createProxyHandler() {
1276
1299
  };
1277
1300
  }
1278
1301
 
1279
- // src/bindForm.ts
1302
+ // src/core/bindForm.ts
1280
1303
  async function bindForm(formId) {
1281
1304
  try {
1282
1305
  const form = await API_default.getRecord("systemforms", formId);
@@ -0,0 +1,2 @@
1
+ declare const eventMapping: Record<string, keyof HTMLElementEventMap>;
2
+ export default eventMapping;
@@ -0,0 +1,13 @@
1
+ export declare const init: unique symbol;
2
+ export declare const destroy: unique symbol;
3
+ export declare const valueSync: unique symbol;
4
+ export declare const dateSync: unique symbol;
5
+ export declare const getElementValue: unique symbol;
6
+ export declare const attachVisibilityController: unique symbol;
7
+ export declare const attachRadioButtons: unique symbol;
8
+ export declare const bindMethods: unique symbol;
9
+ export declare const debounceTime: unique symbol;
10
+ export declare const observers: unique symbol;
11
+ export declare const boundEventListeners: unique symbol;
12
+ export declare const isValidFormElement: unique symbol;
13
+ export declare const registerEventListener: unique symbol;
@@ -1,51 +1,15 @@
1
- interface IBusinessRule {
2
- /**
3
- * @param condition A function that returns a boolean to determine
4
- * the visibility of the target element. If `condition()` returns true, the element is shown;
5
- * otherwise, it is hidden.
6
-
7
- * @param clearValuesOnHide Should the values in the targeted field be cleared when hidden? Defaults to true
8
- */
9
- setVisibility?: [condition: () => boolean, clearValuesOnHide?: boolean];
10
- /**
11
- * @param isRequired Function determining if field is required
12
- * @param isValid Function validating field input.
13
- */
14
- setRequired?: [isRequired: () => boolean, isValid: () => boolean];
15
- /**
16
- * @param condition A function to determine if the value provided should be applied to this field
17
- * @param value The value to set for the HTML element.
18
- * for parents of boolean radios, pass true or false as value, or
19
- * an expression returning a boolean
20
- */
21
- setValue?: [condition: () => boolean, value: () => any | any];
22
- /**
23
- * @param condition A function to determine if this field
24
- * should be enabled in a form, or disabled. True || 1 = disabled. False || 0 = enabled
25
- */
26
- setDisabled?: () => boolean;
27
- }
28
- export declare const _init: unique symbol;
29
- declare const _destroy: unique symbol;
30
- declare const _valueSync: unique symbol;
31
- declare const _dateSync: unique symbol;
32
- declare const _getElementValue: unique symbol;
33
- declare const _updateRadioGroup: unique symbol;
34
- declare const _attachVisibilityController: unique symbol;
35
- declare const _attachRadioButtons: unique symbol;
36
- declare const _bindMethods: unique symbol;
37
- declare const _debounceTime: unique symbol;
38
- declare const _observers: unique symbol;
39
- declare const _boundEventListeners: unique symbol;
1
+ import * as s from "@/constants/symbols.js";
40
2
  export default class DOMNodeReference {
41
3
  target: Element | string;
42
4
  logicalName?: string;
43
5
  root: Element;
44
- private [_debounceTime];
45
- private isLoaded;
46
- private defaultDisplay;
47
- private [_observers];
48
- private [_boundEventListeners];
6
+ protected [s.debounceTime]: number;
7
+ protected isLoaded: boolean;
8
+ protected defaultDisplay: string;
9
+ protected [s.observers]: Array<MutationObserver>;
10
+ protected [s.boundEventListeners]: Array<IBoundEventListener>;
11
+ protected isRadio: boolean;
12
+ protected radioType: RadioType | null;
49
13
  /**
50
14
  * The value of the element that this node represents
51
15
  * stays in syncs with the live DOM elements?.,m via event handler
@@ -57,7 +21,7 @@ export default class DOMNodeReference {
57
21
  * or access properties not available through this class.
58
22
  */
59
23
  element: HTMLElement;
60
- private visibilityController;
24
+ protected visibilityController: HTMLElement;
61
25
  checked: boolean;
62
26
  /**
63
27
  * Represents the 'yes' option of a boolean radio field.
@@ -78,35 +42,30 @@ export default class DOMNodeReference {
78
42
  * Defaults to 'document.body'
79
43
  */
80
44
  /******/ /******/ constructor(target: Element | string, root: Element | undefined, debounceTime: number);
81
- [_init](): Promise<void>;
82
- private eventMapping;
45
+ [s.init](): Promise<void>;
83
46
  /**
84
47
  * Initializes value synchronization with appropriate event listeners
85
48
  * based on element type.
86
- * @private
87
49
  */
88
- private [_valueSync];
89
- private [_dateSync];
50
+ protected [s.valueSync](): Promise<void>;
51
+ protected [s.isValidFormElement](element: Element): element is FormElement;
52
+ protected [s.registerEventListener](element: Element, eventType: keyof HTMLElementEventMap, handler: (e: Event) => unknown): void;
53
+ protected [s.dateSync](element: HTMLInputElement): Promise<void>;
90
54
  /**
91
55
  * Gets the current value of the element based on its type
92
- * @private
56
+ * @protected
93
57
  * @returns Object containing value and optional checked state
94
58
  */
95
- private [_getElementValue];
96
- /**
97
- * Updates related radio buttons if this is part of a radio group
98
- * @private
99
- */
100
- private [_updateRadioGroup];
101
- private [_attachVisibilityController];
102
- private [_attachRadioButtons];
103
- private [_bindMethods];
104
- private [_destroy];
59
+ protected [s.getElementValue](): ElementValue;
60
+ protected [s.attachVisibilityController](): void;
61
+ protected [s.attachRadioButtons](): Promise<void>;
62
+ protected [s.bindMethods](): void;
63
+ protected [s.destroy](): void;
105
64
  /**
106
65
  * Updates the value and checked state based on element type
107
66
  * @public
108
67
  */
109
- updateValue(): void;
68
+ updateValue(e?: Event): void;
110
69
  /**
111
70
  * Sets up an event listener based on the specified event type, executing the specified
112
71
  * event handler
@@ -260,13 +219,18 @@ export default class DOMNodeReference {
260
219
  configureValidationAndRequirements(isRequired: () => boolean, isValid: () => boolean, fieldDisplayName: string, dependencies: Array<DOMNodeReference>): DOMNodeReference;
261
220
  /**
262
221
  * Sets up tracking for dependencies using both event listeners and mutation observers.
263
- * @private
222
+ * @protected
264
223
  * @param handler The function to execute when dependencies change
265
224
  * @param dependencies Array of dependent DOM nodes to track
266
225
  * @param options Additional configuration options. clearValuesOnHide defaults to false.
267
226
  * all other options defaults to true
268
227
  */
269
- private _configDependencyTracking;
228
+ protected _configDependencyTracking(handler: () => void, dependencies: Array<DOMNodeReference>, options?: {
229
+ clearValuesOnHide?: boolean;
230
+ observeVisibility?: boolean;
231
+ trackInputEvents?: boolean;
232
+ trackRadioButtons?: boolean;
233
+ }): void;
270
234
  /**
271
235
  * Sets the required level for the field by adding or removing the "required-field" class on the label.
272
236
  *
@@ -284,4 +248,3 @@ export default class DOMNodeReference {
284
248
  */
285
249
  onceLoaded(callback: (instance: DOMNodeReference) => any): any;
286
250
  }
287
- export {};
@@ -1,5 +1,5 @@
1
1
  import DOMNodeReference from "./DOMNodeReference.js";
2
- export declare class DOMNodeReferenceArray extends Array<DOMNodeReference> {
2
+ export default class DOMNodeReferenceArray extends Array<DOMNodeReference> {
3
3
  /**
4
4
  * Hides all the containers of the DOMNodeReference instances in the array.
5
5
  */
@@ -9,4 +9,3 @@ export declare class DOMNodeReferenceArray extends Array<DOMNodeReference> {
9
9
  */
10
10
  showAll(this: DOMNodeReferenceArray): DOMNodeReferenceArray;
11
11
  }
12
- export declare function enhanceArray<T extends string>(array: DOMNodeReference[]): DOMNodeReferenceArray & Record<T, DOMNodeReference>;
@@ -1,5 +1,5 @@
1
1
  import DOMNodeReference from "./DOMNodeReference.js";
2
- import { DOMNodeReferenceArray } from "./DOMNodeReferenceArray.js";
2
+ import DOMNodeReferenceArray from "./DOMNodeReferenceArray.js";
3
3
  /**
4
4
  * @function
5
5
  * Get all controls related to the form for manipulating with the
@@ -0,0 +1,21 @@
1
+ import DOMNodeReference from "./DOMNodeReference.js";
2
+ import DOMNodeReferenceArray from "./DOMNodeReferenceArray.js";
3
+ export default function createDOMNodeReference<T extends string>(target: Element, options?: ICreationOptions): Promise<DOMNodeReference>;
4
+ export default function createDOMNodeReference(target: string, options?: Omit<ICreationOptions, "multiple"> & {
5
+ /**
6
+ * Should this call return an array of instantiated references, or just a single instance?
7
+ * Defaults to false, returning a single instance.
8
+ */
9
+ multiple?: false;
10
+ }): Promise<DOMNodeReference>;
11
+ export default function createDOMNodeReference<T extends string>(target: string, options?: Omit<ICreationOptions, "multiple"> & {
12
+ /**
13
+ * Should this call return an array of instantiated references, or just a single instance?
14
+ * Defaults to false, returning a single instance.
15
+ */
16
+ multiple?: true;
17
+ }): Promise<DOMNodeReferenceArray>;
18
+ export declare function validateOptions(options: any): void;
19
+ export declare function createProxyHandler(): {
20
+ get: (target: DOMNodeReference, prop: string | symbol) => any;
21
+ };
@@ -1,4 +1,4 @@
1
- import DOMNodeReference from "./DOMNodeReference.js";
1
+ import DOMNodeReference from "../core/DOMNodeReference.js";
2
2
  export declare class DOMNodeInitializationError extends Error {
3
3
  constructor(instance: DOMNodeReference, error: string);
4
4
  }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import "./style.css";
2
- import API from "./API.js";
3
- import createRef from "./createDOMNodeReferences.js";
4
- import waitFor from "./waitFor.js";
5
- import bindForm from "./bindForm.js";
2
+ import API from "./core/API.js";
3
+ import createRef from "./core/createDOMNodeReferences.js";
4
+ import waitFor from "./utils/waitFor.js";
5
+ import bindForm from "./core/bindForm.js";
6
6
  export { API, createRef, waitFor, bindForm };
@@ -0,0 +1,5 @@
1
+ import DOMNodeReference from "@/core/DOMNodeReference.js";
2
+ export default abstract class ReferenceManager {
3
+ static instances: Set<DOMNodeReference>;
4
+ static getInstance<T>(target: T): DOMNodeReference | undefined;
5
+ }
@@ -0,0 +1,3 @@
1
+ import DOMNodeReference from "@/core/DOMNodeReference.js";
2
+ import DOMNodeReferenceArray from "@/core/DOMNodeReferenceArray.js";
3
+ export default function enhanceArray<T extends string>(array: DOMNodeReference[]): DOMNodeReferenceArray & Record<T, DOMNodeReference>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "powerpagestoolkit",
3
- "version": "2.7.001",
3
+ "version": "2.7.101",
4
4
  "description": "Reference, manipulate, and engage with Power Pages sites through the nodes in the DOM; use a variety of custom methods that allow customizing your power pages site quicker and easier. ",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
package/dist/List.d.ts DELETED
@@ -1,29 +0,0 @@
1
- /**
2
- * so far this whole thing is a moot point
3
- * Microsoft provides no way to get important specific information
4
- * about the records represented by each 'row' in a list
5
- * rendering this effort particularly useless
6
- *
7
- * Saving for in case things change in the future and this
8
- * could be re-factored/extended to provide some usable value
9
- */
10
- export declare const _init: symbol;
11
- /**
12
- * Provides information about how to target elements in
13
- * the construction of the list
14
- */
15
- interface ListOptions {
16
- containerSelector: string;
17
- rowSelector: string;
18
- cellSelector: string;
19
- }
20
- interface ListItem extends Array<Element> {
21
- }
22
- export default class List {
23
- [x: symbol]: () => Promise<List>;
24
- items: ListItem[];
25
- private options;
26
- private container;
27
- constructor(options?: Partial<ListOptions>);
28
- }
29
- export {};
@@ -1,36 +0,0 @@
1
- import { DOMNodeReferenceArray } from "./DOMNodeReferenceArray.js";
2
- import DOMNodeReference from "./DOMNodeReference.js";
3
- interface ICreationOptions {
4
- /**
5
- * Should this call return an array of instantiated references, or just a single?
6
- * Defaults to false, returning a single instance.
7
- */
8
- multiple?: (() => boolean) | boolean;
9
- /**
10
- * Optionally specify the element within which to search for the element targeted by 'target'.
11
- * Defaults to 'document.body'.
12
- */
13
- root?: HTMLElement;
14
- /**
15
- * Optionally specify the amount of time that should be waited to find the targeted element before throwing an error.
16
- * Useful for async DOM loading. Relies on MutationObserver.
17
- * WARNING: Implementing multiple references with timeout can result in infinite loading.
18
- */
19
- timeout?: number;
20
- }
21
- export default function createDOMNodeReference(target: Element, options?: ICreationOptions): Promise<DOMNodeReference>;
22
- export default function createDOMNodeReference(target: string, options?: Omit<ICreationOptions, "multiple"> & {
23
- /**
24
- * Should this call return an array of instantiated references, or just a single instance?
25
- * Defaults to false, returning a single instance.
26
- */
27
- multiple?: false;
28
- }): Promise<DOMNodeReference>;
29
- export default function createDOMNodeReference(target: string, options?: Omit<ICreationOptions, "multiple"> & {
30
- /**
31
- * Should this call return an array of instantiated references, or just a single instance?
32
- * Defaults to false, returning a single instance.
33
- */
34
- multiple?: true;
35
- }): Promise<DOMNodeReferenceArray>;
36
- export {};
File without changes
File without changes
File without changes