powerpagestoolkit 2.5.405 → 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 +89 -30
- package/dist/DOMNodeReference.d.ts +10 -10
- package/dist/bundle.js +156 -113
- package/dist/createDOMNodeReferences.d.ts +4 -10
- package/dist/index.d.ts +3 -5
- package/dist/waitFor.d.ts +7 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,27 +19,39 @@ A TypeScript/JavaScript utility package for seamless DOM manipulation and DataVe
|
|
|
19
19
|
npm install powerpagestoolkit
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
|
|
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
|
+
|
|
30
32
|
```typescript
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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)
|
|
35
42
|
|
|
36
|
-
|
|
43
|
+
```typescript
|
|
44
|
+
import { createRef } from "powerpagestoolkit";
|
|
45
|
+
```
|
|
37
46
|
|
|
47
|
+
Instantiate one, or multiple instances of a DOMNodeReference
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
38
50
|
// Create a single reference
|
|
39
|
-
const node = await
|
|
51
|
+
const node = await createRef("#myElement", false);
|
|
40
52
|
|
|
41
53
|
// Create multiple references
|
|
42
|
-
const nodes = await
|
|
54
|
+
const nodes = await createRef(".my-class", true);
|
|
43
55
|
```
|
|
44
56
|
|
|
45
57
|
#### Properties
|
|
@@ -60,14 +72,16 @@ const nodes = await createMultipleDOMNodeReferences(".my-class");
|
|
|
60
72
|
|
|
61
73
|
```typescript
|
|
62
74
|
// Add event listener with proper 'this' context
|
|
75
|
+
// uses standard eventListener API, and so supports all DOM events
|
|
63
76
|
node.on("change", function (e) {
|
|
64
77
|
console.log("Current value:", this.value);
|
|
65
78
|
});
|
|
66
79
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
console.log("Element ready:", instance.element);
|
|
80
|
+
node.on("click", function (e) {
|
|
81
|
+
console.log(this, " has been clicked");
|
|
70
82
|
});
|
|
83
|
+
|
|
84
|
+
...
|
|
71
85
|
```
|
|
72
86
|
|
|
73
87
|
##### Visibility Control
|
|
@@ -76,63 +90,108 @@ node.onceLoaded((instance) => {
|
|
|
76
90
|
// Basic visibility
|
|
77
91
|
node.hide();
|
|
78
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
|
|
79
98
|
|
|
80
|
-
|
|
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
|
|
81
112
|
node.configureConditionalRendering(
|
|
82
113
|
// Function to evaluate wether this node should be visible or not
|
|
83
114
|
function () {
|
|
84
|
-
return otherNode.value === "
|
|
115
|
+
return otherNode.value === "some value";
|
|
85
116
|
},
|
|
86
|
-
[otherNode]
|
|
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 */
|
|
87
121
|
);
|
|
88
122
|
```
|
|
89
123
|
|
|
90
124
|
##### Validation and Requirements
|
|
91
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
|
+
|
|
92
141
|
```typescript
|
|
93
142
|
node.configureValidationAndRequirements(
|
|
94
|
-
//
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
// 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
|
|
99
147
|
function () {
|
|
100
148
|
return this.value != null && this.value !== "";
|
|
101
149
|
},
|
|
102
|
-
|
|
103
|
-
|
|
150
|
+
|
|
151
|
+
"Contact Phone", // Shows in error message: "Contact Phone is required"
|
|
152
|
+
|
|
153
|
+
[dependentNode] // Revalidate when dependentNode changes
|
|
104
154
|
);
|
|
105
155
|
```
|
|
106
156
|
|
|
107
157
|
##### Element Manipulation
|
|
108
158
|
|
|
109
159
|
```typescript
|
|
110
|
-
|
|
111
|
-
|
|
160
|
+
/****/ Value management /****/
|
|
161
|
+
|
|
162
|
+
// set a static value
|
|
163
|
+
node.setValue("new value");
|
|
164
|
+
|
|
112
165
|
// or set a value by using some sort of logic
|
|
113
166
|
node.setValue(() => {
|
|
114
167
|
if (true) {
|
|
115
168
|
return "value";
|
|
116
169
|
} else return "default";
|
|
117
170
|
});
|
|
118
|
-
node.updateValue(); // Sync with DOM
|
|
119
171
|
|
|
120
|
-
//
|
|
172
|
+
// Sync with DOM
|
|
173
|
+
node.updateValue();
|
|
174
|
+
|
|
175
|
+
/****/ Content manipulation /****/
|
|
176
|
+
|
|
121
177
|
node.setInnerHTML("<span>New content</span>");
|
|
122
178
|
node.append(childElement);
|
|
123
179
|
node.prepend(headerElement);
|
|
124
180
|
node.after(siblingElement);
|
|
125
181
|
node.before(labelElement);
|
|
126
182
|
|
|
127
|
-
|
|
183
|
+
/****/ Styling /****/
|
|
184
|
+
|
|
128
185
|
node.setStyle({
|
|
129
186
|
display: "block",
|
|
130
187
|
color: "red",
|
|
131
188
|
});
|
|
132
189
|
|
|
133
|
-
|
|
190
|
+
/****/ State management /****/
|
|
191
|
+
|
|
134
192
|
node.disable();
|
|
135
193
|
node.enable();
|
|
194
|
+
|
|
136
195
|
```
|
|
137
196
|
|
|
138
197
|
##### Label and Tooltip Management
|
|
@@ -154,7 +213,7 @@ node.addTooltip(
|
|
|
154
213
|
);
|
|
155
214
|
```
|
|
156
215
|
|
|
157
|
-
### DataVerse API
|
|
216
|
+
- ### DataVerse API
|
|
158
217
|
|
|
159
218
|
Type-safe wrapper for DataVerse API operations.
|
|
160
219
|
|
|
@@ -204,7 +263,7 @@ await API.updateRecord("contacts", "record-guid", {
|
|
|
204
263
|
1. Always await DOMNodeReference creation:
|
|
205
264
|
|
|
206
265
|
```typescript
|
|
207
|
-
const node = await
|
|
266
|
+
const node = await createRef("#element");
|
|
208
267
|
```
|
|
209
268
|
|
|
210
269
|
2. Include all referenced nodes in dependency arrays:
|
|
@@ -6,35 +6,31 @@ 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
|
-
element:
|
|
16
|
+
element: Element;
|
|
19
17
|
private visibilityController;
|
|
20
18
|
checked: boolean;
|
|
21
19
|
/**
|
|
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
|
|
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>;
|
|
@@ -44,6 +40,7 @@ export default class DOMNodeReference {
|
|
|
44
40
|
* @private
|
|
45
41
|
*/
|
|
46
42
|
private _initValueSync;
|
|
43
|
+
private _initDateSync;
|
|
47
44
|
/**
|
|
48
45
|
* Updates the value and checked state based on element type
|
|
49
46
|
* @public
|
|
@@ -54,12 +51,12 @@ export default class DOMNodeReference {
|
|
|
54
51
|
* @private
|
|
55
52
|
* @returns {ElementValue} Object containing value and optional checked state
|
|
56
53
|
*/
|
|
57
|
-
private
|
|
54
|
+
private _getElementValue;
|
|
58
55
|
/**
|
|
59
56
|
* Updates related radio buttons if this is part of a radio group
|
|
60
57
|
* @private
|
|
61
58
|
*/
|
|
62
|
-
private
|
|
59
|
+
private _updateRadioGroup;
|
|
63
60
|
private _attachVisibilityController;
|
|
64
61
|
private _attachRadioButtons;
|
|
65
62
|
/**
|
|
@@ -205,10 +202,13 @@ export default class DOMNodeReference {
|
|
|
205
202
|
*/
|
|
206
203
|
configureValidationAndRequirements(isRequired: () => boolean, isValid: () => boolean, fieldDisplayName: string, dependencies: Array<DOMNodeReference>): DOMNodeReference;
|
|
207
204
|
/**
|
|
208
|
-
* Sets up tracking for
|
|
205
|
+
* Sets up tracking for dependencies using both event listeners and mutation observers.
|
|
209
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
|
|
210
210
|
*/
|
|
211
|
-
private
|
|
211
|
+
private _configDependencyTracking;
|
|
212
212
|
/**
|
|
213
213
|
* Sets the required level for the field by adding or removing the "required-field" class on the label.
|
|
214
214
|
*
|
package/dist/bundle.js
CHANGED
|
@@ -103,10 +103,10 @@ var API = {
|
|
|
103
103
|
var API_default = API;
|
|
104
104
|
|
|
105
105
|
// src/waitFor.ts
|
|
106
|
-
function waitFor(target) {
|
|
106
|
+
function waitFor(target, root = document) {
|
|
107
107
|
return new Promise((resolve, reject) => {
|
|
108
108
|
const observer = new MutationObserver(() => {
|
|
109
|
-
const observedElement =
|
|
109
|
+
const observedElement = root.querySelector(target);
|
|
110
110
|
if (observedElement) {
|
|
111
111
|
clearTimeout(timeout);
|
|
112
112
|
observer.disconnect();
|
|
@@ -121,7 +121,7 @@ function waitFor(target) {
|
|
|
121
121
|
clearTimeout(timeout);
|
|
122
122
|
return resolve(target);
|
|
123
123
|
}
|
|
124
|
-
const element =
|
|
124
|
+
const element = root.querySelector(target);
|
|
125
125
|
if (element) {
|
|
126
126
|
clearTimeout(timeout);
|
|
127
127
|
return resolve(element);
|
|
@@ -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
|
|
244
|
+
* @param target - The CSS selector to find the desired DOM element.
|
|
246
245
|
*/
|
|
247
246
|
/******/
|
|
248
247
|
/******/
|
|
@@ -251,6 +250,7 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
251
250
|
this.isLoaded = false;
|
|
252
251
|
this.defaultDisplay = "";
|
|
253
252
|
this.value = null;
|
|
253
|
+
this.updateValue = this.updateValue.bind(this);
|
|
254
254
|
}
|
|
255
255
|
async [_init]() {
|
|
256
256
|
try {
|
|
@@ -275,38 +275,64 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
275
275
|
* based on element type.
|
|
276
276
|
* @private
|
|
277
277
|
*/
|
|
278
|
-
_initValueSync() {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
278
|
+
async _initValueSync() {
|
|
279
|
+
try {
|
|
280
|
+
this.updateValue();
|
|
281
|
+
if (!(this.element instanceof HTMLElement)) {
|
|
282
|
+
throw new Error("Element is not a valid HTML element");
|
|
283
|
+
}
|
|
284
|
+
const eventMapping = {
|
|
285
|
+
checkbox: "click",
|
|
286
|
+
radio: "click",
|
|
287
|
+
select: "change",
|
|
288
|
+
"select-multiple": "change"
|
|
289
|
+
// Add other input types as needed
|
|
290
|
+
};
|
|
291
|
+
let eventType;
|
|
292
|
+
if (this.element instanceof HTMLSelectElement) {
|
|
293
|
+
eventType = "change";
|
|
294
|
+
} else if (this.element instanceof HTMLInputElement) {
|
|
295
|
+
eventType = eventMapping[this.element.type] || "input";
|
|
296
|
+
} else {
|
|
297
|
+
eventType = "input";
|
|
298
|
+
}
|
|
299
|
+
this.element.addEventListener(eventType, this.updateValue);
|
|
300
|
+
if (this.element instanceof HTMLInputElement && this.element.dataset.type === "date") {
|
|
301
|
+
await this._initDateSync(this.element);
|
|
302
|
+
}
|
|
303
|
+
} catch (error) {
|
|
304
|
+
throw new DOMNodeInitializationError(
|
|
305
|
+
this,
|
|
306
|
+
`Failed to initialize value sync: ${error}`
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
async _initDateSync(element) {
|
|
311
|
+
const parentElement = element.parentElement;
|
|
312
|
+
if (!parentElement) {
|
|
313
|
+
throw new Error("Date input must have a parent element");
|
|
314
|
+
}
|
|
315
|
+
const dateNode = await waitFor("[data-date-format]", parentElement);
|
|
316
|
+
dateNode.addEventListener("select", this.updateValue);
|
|
291
317
|
}
|
|
292
318
|
/**
|
|
293
319
|
* Updates the value and checked state based on element type
|
|
294
320
|
* @public
|
|
295
321
|
*/
|
|
296
322
|
updateValue() {
|
|
297
|
-
const elementValue = this.
|
|
323
|
+
const elementValue = this._getElementValue();
|
|
298
324
|
this.value = elementValue.value;
|
|
299
325
|
if (elementValue.checked !== void 0) {
|
|
300
326
|
this.checked = elementValue.checked;
|
|
301
327
|
}
|
|
302
|
-
this.
|
|
328
|
+
this._updateRadioGroup();
|
|
303
329
|
}
|
|
304
330
|
/**
|
|
305
331
|
* Gets the current value of the element based on its type
|
|
306
332
|
* @private
|
|
307
333
|
* @returns {ElementValue} Object containing value and optional checked state
|
|
308
334
|
*/
|
|
309
|
-
|
|
335
|
+
_getElementValue() {
|
|
310
336
|
const input = this.element;
|
|
311
337
|
const select = this.element;
|
|
312
338
|
switch (input.type) {
|
|
@@ -332,7 +358,7 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
332
358
|
};
|
|
333
359
|
default:
|
|
334
360
|
return {
|
|
335
|
-
value: this.element.classList.contains("decimal") ? parseFloat(input.value) : input.value
|
|
361
|
+
value: this.element.classList.contains("decimal") || this.element.classList.contains("money") ? parseFloat(input.value) : input.value
|
|
336
362
|
};
|
|
337
363
|
}
|
|
338
364
|
}
|
|
@@ -340,7 +366,7 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
340
366
|
* Updates related radio buttons if this is part of a radio group
|
|
341
367
|
* @private
|
|
342
368
|
*/
|
|
343
|
-
|
|
369
|
+
_updateRadioGroup() {
|
|
344
370
|
if (this.yesRadio instanceof _DOMNodeReference && this.noRadio instanceof _DOMNodeReference) {
|
|
345
371
|
this.yesRadio.updateValue();
|
|
346
372
|
this.noRadio?.updateValue();
|
|
@@ -507,7 +533,7 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
507
533
|
);
|
|
508
534
|
if (childInputs.length > 0) {
|
|
509
535
|
const clearPromises = childInputs.map(async (input) => {
|
|
510
|
-
const inputRef = await createDOMNodeReference(input);
|
|
536
|
+
const inputRef = await createDOMNodeReference(input, false);
|
|
511
537
|
return inputRef.clearValues();
|
|
512
538
|
});
|
|
513
539
|
await Promise.all(clearPromises);
|
|
@@ -683,40 +709,16 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
683
709
|
);
|
|
684
710
|
return this;
|
|
685
711
|
}
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
712
|
+
this._configDependencyTracking(
|
|
713
|
+
() => this.toggleVisibility(condition()),
|
|
714
|
+
dependencies,
|
|
715
|
+
{
|
|
716
|
+
clearValuesOnHide,
|
|
717
|
+
observeVisibility: true,
|
|
718
|
+
trackInputEvents: false,
|
|
719
|
+
trackRadioButtons: false
|
|
691
720
|
}
|
|
692
|
-
|
|
693
|
-
try {
|
|
694
|
-
this.toggleVisibility(condition());
|
|
695
|
-
if (condition() === false && clearValuesOnHide) {
|
|
696
|
-
this.clearValues();
|
|
697
|
-
}
|
|
698
|
-
} catch (error) {
|
|
699
|
-
console.error("Error in change handler:", error);
|
|
700
|
-
}
|
|
701
|
-
};
|
|
702
|
-
node.on("change", handleChange);
|
|
703
|
-
const observer = new MutationObserver(() => {
|
|
704
|
-
try {
|
|
705
|
-
const display = window.getComputedStyle(
|
|
706
|
-
node.visibilityController
|
|
707
|
-
).display;
|
|
708
|
-
this.toggleVisibility(display !== "none" && condition());
|
|
709
|
-
} catch (error) {
|
|
710
|
-
0;
|
|
711
|
-
console.error("Error in mutation observer:", error);
|
|
712
|
-
observer.disconnect();
|
|
713
|
-
}
|
|
714
|
-
});
|
|
715
|
-
observer.observe(node.visibilityController, {
|
|
716
|
-
attributes: true,
|
|
717
|
-
attributeFilter: ["style"]
|
|
718
|
-
});
|
|
719
|
-
});
|
|
721
|
+
);
|
|
720
722
|
return this;
|
|
721
723
|
} catch (error) {
|
|
722
724
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -765,7 +767,10 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
765
767
|
Object.assign(newValidator, validatorConfig);
|
|
766
768
|
Page_Validators.push(newValidator);
|
|
767
769
|
this.setRequiredLevel(isRequired());
|
|
768
|
-
this.
|
|
770
|
+
this._configDependencyTracking(
|
|
771
|
+
() => this.setRequiredLevel(isRequired()),
|
|
772
|
+
dependencies
|
|
773
|
+
);
|
|
769
774
|
} catch (error) {
|
|
770
775
|
throw new ValidationConfigError(
|
|
771
776
|
this,
|
|
@@ -775,35 +780,64 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
775
780
|
return this;
|
|
776
781
|
}
|
|
777
782
|
/**
|
|
778
|
-
* Sets up tracking for
|
|
783
|
+
* Sets up tracking for dependencies using both event listeners and mutation observers.
|
|
779
784
|
* @private
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
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) {
|
|
783
802
|
console.warn(
|
|
784
|
-
`powerpagestoolkit: No dependencies specified for ${this.element.id}. Include all referenced nodes in the dependency array for proper
|
|
803
|
+
`powerpagestoolkit: No dependencies specified for ${this.element.id}. Include all referenced nodes in the dependency array for proper tracking.`
|
|
785
804
|
);
|
|
786
805
|
return;
|
|
787
806
|
}
|
|
788
807
|
dependencies.forEach((dep) => {
|
|
789
|
-
dep
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
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();
|
|
797
817
|
}
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
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)) {
|
|
805
839
|
[dep.yesRadio, dep.noRadio].forEach((radio) => {
|
|
806
|
-
radio?.on("change",
|
|
840
|
+
radio?.on("change", handleChange);
|
|
807
841
|
});
|
|
808
842
|
}
|
|
809
843
|
});
|
|
@@ -854,50 +888,59 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
854
888
|
};
|
|
855
889
|
|
|
856
890
|
// src/createDOMNodeReferences.ts
|
|
857
|
-
async function createDOMNodeReference(target) {
|
|
891
|
+
async function createDOMNodeReference(target, multiple = false) {
|
|
858
892
|
try {
|
|
893
|
+
const isMultiple = typeof multiple === "function" ? multiple() : multiple;
|
|
894
|
+
if (isMultiple) {
|
|
895
|
+
if (typeof target !== "string") {
|
|
896
|
+
throw new Error(
|
|
897
|
+
`'target' must be of type 'string' if 'multiple' is set to 'true'. Received type: '${typeof target}'`
|
|
898
|
+
);
|
|
899
|
+
}
|
|
900
|
+
const elements = Array.from(
|
|
901
|
+
document.querySelectorAll(target)
|
|
902
|
+
);
|
|
903
|
+
const initializedElements = await Promise.all(
|
|
904
|
+
elements.map(async (element) => {
|
|
905
|
+
const instance2 = new DOMNodeReference(element);
|
|
906
|
+
await instance2[_init]();
|
|
907
|
+
return new Proxy(instance2, createProxyHandler());
|
|
908
|
+
})
|
|
909
|
+
);
|
|
910
|
+
return enhanceArray(initializedElements);
|
|
911
|
+
}
|
|
859
912
|
const instance = new DOMNodeReference(target);
|
|
860
913
|
await instance[_init]();
|
|
861
|
-
return new Proxy(instance,
|
|
862
|
-
get: (target2, prop) => {
|
|
863
|
-
if (prop.toString().startsWith("_")) return void 0;
|
|
864
|
-
const value = target2[prop];
|
|
865
|
-
if (typeof value === "function" && prop !== "onceLoaded") {
|
|
866
|
-
return (...args) => {
|
|
867
|
-
target2.onceLoaded(() => value.apply(target2, args));
|
|
868
|
-
return target2;
|
|
869
|
-
};
|
|
870
|
-
}
|
|
871
|
-
return value;
|
|
872
|
-
}
|
|
873
|
-
});
|
|
914
|
+
return new Proxy(instance, createProxyHandler());
|
|
874
915
|
} catch (e) {
|
|
875
916
|
throw new Error(e);
|
|
876
917
|
}
|
|
877
918
|
}
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
919
|
+
function createProxyHandler() {
|
|
920
|
+
return {
|
|
921
|
+
get: (target, prop) => {
|
|
922
|
+
if (prop.toString().startsWith("_")) return void 0;
|
|
923
|
+
const value = target[prop];
|
|
924
|
+
if (typeof value === "function" && prop !== "onceLoaded") {
|
|
925
|
+
return (...args) => {
|
|
926
|
+
target.onceLoaded(() => value.apply(target, args));
|
|
927
|
+
return target;
|
|
928
|
+
};
|
|
929
|
+
}
|
|
930
|
+
return value;
|
|
931
|
+
}
|
|
932
|
+
};
|
|
933
|
+
}
|
|
934
|
+
function enhanceArray(array) {
|
|
935
|
+
const enhanced = array;
|
|
936
|
+
enhanced.hideAll = () => enhanced.forEach((instance) => instance.hide());
|
|
937
|
+
enhanced.showAll = () => enhanced.forEach((instance) => instance.show());
|
|
938
|
+
return enhanced;
|
|
896
939
|
}
|
|
897
940
|
export {
|
|
898
941
|
API_default as API,
|
|
899
|
-
createDOMNodeReference,
|
|
900
|
-
|
|
942
|
+
createDOMNodeReference as createRef,
|
|
943
|
+
waitFor
|
|
901
944
|
};
|
|
902
945
|
|
|
903
946
|
|
|
@@ -2,14 +2,8 @@ import DOMNodeReference from "./DOMNodeReference.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* Creates and initializes a DOMNodeReference instance.
|
|
4
4
|
* @async
|
|
5
|
-
* @param
|
|
6
|
-
* @
|
|
5
|
+
* @param target - The CSS selector for the desired DOM element, or, optionally, the element itself for which to create a DOMNodeReference.
|
|
6
|
+
* @param multiple Should this call return an array of instantiated references, or just a single? Defaults to false, returning a single instance
|
|
7
|
+
* @returns A promise that resolves to a Proxy of the initialized DOMNodeReference instance.
|
|
7
8
|
*/
|
|
8
|
-
export
|
|
9
|
-
/**
|
|
10
|
-
* Creates and initializes multiple DOMNodeReference instances.
|
|
11
|
-
* @async
|
|
12
|
-
* @param {string} querySelector - The CSS selector for the desired DOM elements.
|
|
13
|
-
* @returns {Promise<DOMNodeReference[]>} A promise that resolves to an array of Proxies of initialized DOMNodeReference instances.
|
|
14
|
-
*/
|
|
15
|
-
export declare function createMultipleDOMNodeReferences(querySelector: string): Promise<DOMNodeReference[]>;
|
|
9
|
+
export default function createDOMNodeReference(target: HTMLElement | string, multiple?: (() => boolean) | boolean): Promise<DOMNodeReference | DOMNodeReferenceArray>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import "./style.css";
|
|
2
2
|
import API from "./API.js";
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
export { API, createDOMNodeReference, createMultipleDOMNodeReferences, DOMNodeRef, };
|
|
3
|
+
import createRef from "./createDOMNodeReferences.js";
|
|
4
|
+
import waitFor from "./waitFor.js";
|
|
5
|
+
export { API, createRef, waitFor };
|
package/dist/waitFor.d.ts
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* @param target basic querySelector syntax to select an element
|
|
4
|
+
* @param root optional parameter to replace document as the root from which to perform the node search
|
|
5
|
+
* @returns
|
|
6
|
+
*/
|
|
7
|
+
export default function waitFor(target: HTMLElement | string, root?: Element | Document): Promise<Element>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "powerpagestoolkit",
|
|
3
|
-
"version": "2.5.
|
|
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",
|