powerpagestoolkit 2.5.409 → 2.5.411

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
@@ -19,21 +19,36 @@ A TypeScript/JavaScript utility package for seamless DOM manipulation and DataVe
19
19
  npm install powerpagestoolkit
20
20
  ```
21
21
 
22
- ## Core Modules
22
+ # Core Modules
23
23
 
24
- ### DOMNodeReference
24
+ - ### DOMNodeReference
25
25
 
26
26
  A powerful class for managing DOM elements with automatic value synchronization and event handling.
27
27
 
28
28
  #### Basic Usage
29
29
 
30
+ DOMNodeReferences are instantiated with the help of the following factory function
31
+
32
+ ```typescript
33
+ createRef(
34
+ target: HTMLElement | string, /* You can target an HTMLElement directly,
35
+ or use standard querySelector syntax */
36
+ multiple: (() => boolean) | boolean = false /* are you targeting a single
37
+ element, or multiple? true = multiple. Default is false (single) */
38
+ ): Promise<DOMNodeReference | DOMNodeReferenceArray>;
39
+ ```
40
+
41
+ Import the utility function for creating DOMNodeReference(s)
42
+
30
43
  ```typescript
31
44
  import { createRef } from "powerpagestoolkit";
45
+ ```
32
46
 
33
- // Both methods support standard querySelector syntax:
47
+ Instantiate one, or multiple instances of a DOMNodeReference
34
48
 
49
+ ```typescript
35
50
  // Create a single reference
36
- const node = await createRef("#myElement");
51
+ const node = await createRef("#myElement", false);
37
52
 
38
53
  // Create multiple references
39
54
  const nodes = await createRef(".my-class", true);
@@ -57,14 +72,16 @@ const nodes = await createRef(".my-class", true);
57
72
 
58
73
  ```typescript
59
74
  // Add event listener with proper 'this' context
75
+ // uses standard eventListener API, and so supports all DOM events
60
76
  node.on("change", function (e) {
61
77
  console.log("Current value:", this.value);
62
78
  });
63
79
 
64
- // Wait for element to be loaded
65
- node.onceLoaded((instance) => {
66
- console.log("Element ready:", instance.element);
80
+ node.on("click", function (e) {
81
+ console.log(this, " has been clicked");
67
82
  });
83
+
84
+ ...
68
85
  ```
69
86
 
70
87
  ##### Visibility Control
@@ -73,63 +90,108 @@ node.onceLoaded((instance) => {
73
90
  // Basic visibility
74
91
  node.hide();
75
92
  node.show();
93
+ ```
94
+
95
+ ##### Advanced conditional rendering
96
+
97
+ Out of the box, Microsoft does not provide PowerPages developers the ability to hide or show fields or form elements based on the value of another field. This method allows such configurations
76
98
 
77
- // Advanced conditional rendering
99
+ - Method Signature
100
+
101
+ ```typescript
102
+ DOMNodeReference.configureConditionalRendering(
103
+ condition: () => boolean,
104
+ dependencies?: Array<DOMNodeReference>,
105
+ clearValuesOnHide: boolean = true
106
+ ): DOMNodeReference
107
+ ```
108
+
109
+ - Method Implementation
110
+
111
+ ```typescript
78
112
  node.configureConditionalRendering(
79
113
  // Function to evaluate wether this node should be visible or not
80
114
  function () {
81
- return otherNode.value === "expected";
115
+ return otherNode.value === "some value";
82
116
  },
83
- [otherNode] // Dependency array | if the values or visibility of these change, the function is re-evaluated
117
+ [otherNode] /* Dependency array | if the values or visibility of these
118
+ change, the function is re-evaluated */,
119
+ true /* should the values in the targeted elements (this.element)
120
+ be cleared if this node is hidden? Default = true */
84
121
  );
85
122
  ```
86
123
 
87
124
  ##### Validation and Requirements
88
125
 
126
+ This utility enhances PowerPages forms by adding dynamic field validation and conditional requirements based on other field values.
127
+
128
+ ```typescript
129
+ // Core method for setting up validation
130
+ function configureValidationAndRequirements(
131
+ isRequired: () => boolean, // Determines if field is required
132
+ isValid: () => boolean, // Validates field content
133
+ fieldDisplayName: string, // User-facing field name for error messages
134
+ dependencies: DOMNodeReference[] // Fields that trigger validation checks
135
+ ): DOMNodeReference; /* instance of this is returned for optional
136
+ method chaining */
137
+ ```
138
+
139
+ - Here's a practical example showing how to make a field required only when a "Yes" radio button is selected:
140
+
89
141
  ```typescript
90
142
  node.configureValidationAndRequirements(
91
- // Function to evaluate if this field should be required
92
- function () {
93
- return dependentNode.yesRadio?.checked ?? false;
94
- },
95
- // Function to evaluate if the data in this field is valid
143
+ // Make field required only when "Yes" is checked
144
+ () => dependentNode.yesRadio?.checked ?? false,
145
+
146
+ // Basic validation: ensure field isn't empty
96
147
  function () {
97
148
  return this.value != null && this.value !== "";
98
149
  },
99
- "Field Display Name", // the name that will be displayed along side a validation failure message
100
- [dependentNode] // Dependency array | if the requirement level of these change, this element is re-evaluated
150
+
151
+ "Contact Phone", // Shows in error message: "Contact Phone is required"
152
+
153
+ [dependentNode] // Revalidate when dependentNode changes
101
154
  );
102
155
  ```
103
156
 
104
157
  ##### Element Manipulation
105
158
 
106
159
  ```typescript
107
- // Value management
108
- node.setValue("new value"); // set a static value
160
+ /****/ Value management /****/
161
+
162
+ // set a static value
163
+ node.setValue("new value");
164
+
109
165
  // or set a value by using some sort of logic
110
166
  node.setValue(() => {
111
167
  if (true) {
112
168
  return "value";
113
169
  } else return "default";
114
170
  });
115
- node.updateValue(); // Sync with DOM
116
171
 
117
- // Content manipulation
172
+ // Sync with DOM
173
+ node.updateValue();
174
+
175
+ /****/ Content manipulation /****/
176
+
118
177
  node.setInnerHTML("<span>New content</span>");
119
178
  node.append(childElement);
120
179
  node.prepend(headerElement);
121
180
  node.after(siblingElement);
122
181
  node.before(labelElement);
123
182
 
124
- // Styling
183
+ /****/ Styling /****/
184
+
125
185
  node.setStyle({
126
186
  display: "block",
127
187
  color: "red",
128
188
  });
129
189
 
130
- // State management
190
+ /****/ State management /****/
191
+
131
192
  node.disable();
132
193
  node.enable();
194
+
133
195
  ```
134
196
 
135
197
  ##### Label and Tooltip Management
@@ -151,7 +213,7 @@ node.addTooltip(
151
213
  );
152
214
  ```
153
215
 
154
- ### DataVerse API
216
+ - ### DataVerse API
155
217
 
156
218
  Type-safe wrapper for DataVerse API operations.
157
219
 
@@ -6,14 +6,12 @@ export default class DOMNodeReference {
6
6
  /**
7
7
  * The value of the element that this node represents
8
8
  * stays in syncs with the live DOM elements?.,m via event handler
9
- * @type {any}
10
9
  */
11
10
  value: any;
12
11
  /**
13
12
  * The element targeted when instantiating DOMNodeReference.
14
13
  * Made available in order to perform normal DOM traversal,
15
14
  * or access properties not available through this class.
16
- * @property {HTMLElement | null}
17
15
  */
18
16
  element: Element;
19
17
  private visibilityController;
@@ -22,19 +20,17 @@ export default class DOMNodeReference {
22
20
  * Represents the 'yes' option of a boolean radio field.
23
21
  * This property is only available when the parent node
24
22
  * is a main field for a boolean radio input.
25
- * @property {DOMNodeReferenceProxy | null}
26
23
  */
27
24
  yesRadio?: DOMNodeReference | null;
28
25
  /**
29
26
  * Represents the 'no' option of a boolean radio field.
30
27
  * This property is only available when the parent node
31
28
  * is a main field for a boolean radio input.
32
- * @property {DOMNodeReferenceProxy | null}
33
29
  */
34
30
  noRadio?: DOMNodeReference | null;
35
31
  /**
36
32
  * Creates an instance of DOMNodeReference.
37
- * @param {string} target - The CSS selector to find the desired DOM element.
33
+ * @param target - The CSS selector to find the desired DOM element.
38
34
  */
39
35
  /******/ /******/ constructor(target: HTMLElement | string);
40
36
  [_init](): Promise<void>;
@@ -206,10 +202,13 @@ export default class DOMNodeReference {
206
202
  */
207
203
  configureValidationAndRequirements(isRequired: () => boolean, isValid: () => boolean, fieldDisplayName: string, dependencies: Array<DOMNodeReference>): DOMNodeReference;
208
204
  /**
209
- * Sets up tracking for dependent fields using both event listeners and mutation observers.
205
+ * Sets up tracking for dependencies using both event listeners and mutation observers.
210
206
  * @private
207
+ * @param handler - The function to execute when dependencies change
208
+ * @param dependencies - Array of dependent DOM nodes to track
209
+ * @param options - Additional configuration options
211
210
  */
212
- private _setupDependencyTracking;
211
+ private _configDependencyTracking;
213
212
  /**
214
213
  * Sets the required level for the field by adding or removing the "required-field" class on the label.
215
214
  *
package/dist/bundle.js CHANGED
@@ -237,12 +237,11 @@ var DOMNodeReference = class _DOMNodeReference {
237
237
  /**
238
238
  * The value of the element that this node represents
239
239
  * stays in syncs with the live DOM elements?.,m via event handler
240
- * @type {any}
241
240
  */
242
241
  value;
243
242
  /**
244
243
  * Creates an instance of DOMNodeReference.
245
- * @param {string} target - The CSS selector to find the desired DOM element.
244
+ * @param target - The CSS selector to find the desired DOM element.
246
245
  */
247
246
  /******/
248
247
  /******/
@@ -710,40 +709,16 @@ var DOMNodeReference = class _DOMNodeReference {
710
709
  );
711
710
  return this;
712
711
  }
713
- dependencies.forEach((node) => {
714
- if (!node || !(node instanceof _DOMNodeReference)) {
715
- throw new TypeError(
716
- "Each dependency must be a valid DOMNodeReference instance"
717
- );
712
+ this._configDependencyTracking(
713
+ () => this.toggleVisibility(condition()),
714
+ dependencies,
715
+ {
716
+ clearValuesOnHide,
717
+ observeVisibility: true,
718
+ trackInputEvents: false,
719
+ trackRadioButtons: false
718
720
  }
719
- const handleChange = () => {
720
- try {
721
- this.toggleVisibility(condition());
722
- if (condition() === false && clearValuesOnHide) {
723
- this.clearValues();
724
- }
725
- } catch (error) {
726
- console.error("Error in change handler:", error);
727
- }
728
- };
729
- node.on("change", handleChange);
730
- const observer = new MutationObserver(() => {
731
- try {
732
- const display = window.getComputedStyle(
733
- node.visibilityController
734
- ).display;
735
- this.toggleVisibility(display !== "none" && condition());
736
- } catch (error) {
737
- 0;
738
- console.error("Error in mutation observer:", error);
739
- observer.disconnect();
740
- }
741
- });
742
- observer.observe(node.visibilityController, {
743
- attributes: true,
744
- attributeFilter: ["style"]
745
- });
746
- });
721
+ );
747
722
  return this;
748
723
  } catch (error) {
749
724
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -792,7 +767,10 @@ var DOMNodeReference = class _DOMNodeReference {
792
767
  Object.assign(newValidator, validatorConfig);
793
768
  Page_Validators.push(newValidator);
794
769
  this.setRequiredLevel(isRequired());
795
- this._setupDependencyTracking(isRequired, dependencies);
770
+ this._configDependencyTracking(
771
+ () => this.setRequiredLevel(isRequired()),
772
+ dependencies
773
+ );
796
774
  } catch (error) {
797
775
  throw new ValidationConfigError(
798
776
  this,
@@ -802,35 +780,64 @@ var DOMNodeReference = class _DOMNodeReference {
802
780
  return this;
803
781
  }
804
782
  /**
805
- * Sets up tracking for dependent fields using both event listeners and mutation observers.
783
+ * Sets up tracking for dependencies using both event listeners and mutation observers.
806
784
  * @private
807
- */
808
- _setupDependencyTracking(isRequired, dependencies) {
809
- if (dependencies.length === 0) {
785
+ * @param handler - The function to execute when dependencies change
786
+ * @param dependencies - Array of dependent DOM nodes to track
787
+ * @param options - Additional configuration options
788
+ */
789
+ _configDependencyTracking(handler, dependencies, options = {
790
+ clearValuesOnHide: false,
791
+ observeVisibility: true,
792
+ trackInputEvents: true,
793
+ trackRadioButtons: true
794
+ }) {
795
+ const {
796
+ clearValuesOnHide = false,
797
+ observeVisibility = true,
798
+ trackInputEvents = true,
799
+ trackRadioButtons = true
800
+ } = options;
801
+ if (!dependencies?.length) {
810
802
  console.warn(
811
- `powerpagestoolkit: No dependencies specified for ${this.element.id}. Include all referenced nodes in the dependency array for proper validation.`
803
+ `powerpagestoolkit: No dependencies specified for ${this.element.id}. Include all referenced nodes in the dependency array for proper tracking.`
812
804
  );
813
805
  return;
814
806
  }
815
807
  dependencies.forEach((dep) => {
816
- dep.on("change", () => this.setRequiredLevel(isRequired(this)));
817
- dep.on("input", () => this.setRequiredLevel(isRequired(this)));
818
- const observer = new MutationObserver(() => {
819
- const display = window.getComputedStyle(
820
- dep.visibilityController
821
- ).display;
822
- if (display !== "none") {
823
- this.setRequiredLevel(isRequired(this));
808
+ if (!dep || !(dep instanceof _DOMNodeReference)) {
809
+ throw new TypeError(
810
+ "Each dependency must be a valid DOMNodeReference instance"
811
+ );
812
+ }
813
+ const handleChange = () => {
814
+ handler();
815
+ if (clearValuesOnHide && window.getComputedStyle(this.visibilityController).display === "none") {
816
+ this.clearValues();
824
817
  }
825
- });
826
- observer.observe(dep.visibilityController, {
827
- attributes: true,
828
- attributeFilter: ["style"],
829
- subtree: false
830
- });
831
- if (dep.yesRadio || dep.noRadio) {
818
+ };
819
+ dep.on("change", handleChange);
820
+ if (trackInputEvents) {
821
+ dep.on("input", handleChange);
822
+ }
823
+ if (observeVisibility) {
824
+ const observer = new MutationObserver(() => {
825
+ const display = window.getComputedStyle(
826
+ dep.visibilityController
827
+ ).display;
828
+ if (display !== "none") {
829
+ handler();
830
+ }
831
+ });
832
+ observer.observe(dep.visibilityController, {
833
+ attributes: true,
834
+ attributeFilter: ["style"],
835
+ subtree: false
836
+ });
837
+ }
838
+ if (trackRadioButtons && (dep.yesRadio || dep.noRadio)) {
832
839
  [dep.yesRadio, dep.noRadio].forEach((radio) => {
833
- radio?.on("change", () => this.setRequiredLevel(isRequired(this)));
840
+ radio?.on("change", handleChange);
834
841
  });
835
842
  }
836
843
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "powerpagestoolkit",
3
- "version": "2.5.409",
3
+ "version": "2.5.411",
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/bundle.js",
6
6
  "types": "./dist/index.d.ts",