powerpagestoolkit 2.6.2 → 2.6.4
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 +81 -17
- package/dist/API.d.ts +1 -1
- package/dist/DOMNodeReference.d.ts +78 -22
- package/dist/DOMNodeReferenceArray.d.ts +12 -0
- package/dist/List.d.ts +1 -0
- package/dist/bindForm.d.ts +11 -0
- package/dist/bundle.js +327 -91
- package/dist/createDOMNodeReferences.d.ts +35 -8
- package/dist/index.d.ts +14 -1
- package/dist/waitFor.d.ts +2 -7
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -27,31 +27,89 @@ A powerful class for managing DOM elements with automatic value synchronization
|
|
|
27
27
|
|
|
28
28
|
#### Basic Usage
|
|
29
29
|
|
|
30
|
-
DOMNodeReferences are instantiated with the help of the following factory function
|
|
30
|
+
DOMNodeReferences are instantiated with the help of the following factory function: `createRef`
|
|
31
31
|
|
|
32
32
|
```typescript
|
|
33
33
|
createRef(
|
|
34
|
-
target: HTMLElement | string,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
target: HTMLElement | string,
|
|
35
|
+
options: {
|
|
36
|
+
multiple: (() => boolean) | boolean = false,
|
|
37
|
+
root: HTMLElement,
|
|
38
|
+
timeout: number
|
|
39
|
+
}
|
|
40
|
+
): Promise<DOMNodeReference | DOMNodeReference[]>;
|
|
39
41
|
```
|
|
40
42
|
|
|
43
|
+
createRef takes two main arguments:
|
|
44
|
+
|
|
45
|
+
<table style="width: 100%; border-collapse: collapse;">
|
|
46
|
+
<thead>
|
|
47
|
+
<tr>
|
|
48
|
+
<th style="border: 1px solid #ddd; padding: 8px; text-align: left;">Property</th>
|
|
49
|
+
<th style="border: 1px solid #ddd; padding: 8px; text-align: left;">Type</th>
|
|
50
|
+
<th style="border: 1px solid #ddd; padding: 8px; text-align: left;">Details</th>
|
|
51
|
+
</tr>
|
|
52
|
+
</thead>
|
|
53
|
+
<tbody>
|
|
54
|
+
<tr>
|
|
55
|
+
<td style="border: 1px solid #ddd; padding: 8px;">target</td>
|
|
56
|
+
<td style="border: 1px solid #ddd; padding: 8px;">
|
|
57
|
+
<pre><code class="language-javascript">string | HTMLElement</code></pre>
|
|
58
|
+
</td>
|
|
59
|
+
<td style="border: 1px solid #ddd; padding: 8px;">
|
|
60
|
+
Use standard <code>querySelector</code> syntax to target an element, or elements in the DOM, or pass in an instance of the element itself to create a reference.
|
|
61
|
+
</td>
|
|
62
|
+
</tr>
|
|
63
|
+
<tr>
|
|
64
|
+
<td style="border: 1px solid #ddd; padding: 8px;">options</td>
|
|
65
|
+
<td style="border: 1px solid #ddd; padding: 8px;">
|
|
66
|
+
<pre><code class="language-javascript">{
|
|
67
|
+
multiple: () => boolean | boolean,
|
|
68
|
+
root: HTMLElement,
|
|
69
|
+
timeout: number
|
|
70
|
+
}</code></pre>
|
|
71
|
+
</td>
|
|
72
|
+
<td style="border: 1px solid #ddd; padding: 8px;">
|
|
73
|
+
Provides advanced configurations for niche scenarios, such as async DOM element loading, returning arrays of elements, or specifying the parent to search within for the target node.
|
|
74
|
+
</td>
|
|
75
|
+
</tr>
|
|
76
|
+
</tbody>
|
|
77
|
+
</table>
|
|
78
|
+
|
|
41
79
|
Import the utility function for creating DOMNodeReference(s)
|
|
42
80
|
|
|
43
81
|
```typescript
|
|
44
82
|
import { createRef } from "powerpagestoolkit";
|
|
45
83
|
```
|
|
46
84
|
|
|
47
|
-
Instantiate one, or multiple instances of a DOMNodeReference
|
|
85
|
+
Instantiate one, or multiple instances of a DOMNodeReference, and optionally configure advanced options
|
|
48
86
|
|
|
49
|
-
```
|
|
87
|
+
```javascript
|
|
50
88
|
// Create a single reference
|
|
51
|
-
const node = await createRef("#myElement"
|
|
89
|
+
const node = await createRef("#myElement");
|
|
52
90
|
|
|
53
91
|
// Create multiple references
|
|
54
|
-
const nodes = await createRef(".my-class", true);
|
|
92
|
+
const nodes = await createRef(".my-class", { multiple: true });
|
|
93
|
+
|
|
94
|
+
/******************/
|
|
95
|
+
// ADVANCED OPTIONS
|
|
96
|
+
// in the event that you need to be more granular with how you are targeting
|
|
97
|
+
// and retrieving elements, there are additional options
|
|
98
|
+
|
|
99
|
+
// If the node you are targeting is not available at the initial execution
|
|
100
|
+
// of the script, set a timeout for 2 seconds
|
|
101
|
+
const node2 = await createRef("#target", { timeout: 2000 });
|
|
102
|
+
|
|
103
|
+
// need to target a node within a specific node? use that node as the root
|
|
104
|
+
const otherElement = document.getElementById("id");
|
|
105
|
+
const node3 = await createRef("#target", { root: otherElement });
|
|
106
|
+
|
|
107
|
+
// implement all options:
|
|
108
|
+
const nodes2 = await createRef("#target", {
|
|
109
|
+
multiple: true,
|
|
110
|
+
timeout: 4000,
|
|
111
|
+
root: otherElement,
|
|
112
|
+
});
|
|
55
113
|
```
|
|
56
114
|
|
|
57
115
|
#### Properties
|
|
@@ -101,7 +159,7 @@ _Method signature:_
|
|
|
101
159
|
```typescript
|
|
102
160
|
configureConditionalRendering(
|
|
103
161
|
condition: () => boolean,
|
|
104
|
-
dependencies?:
|
|
162
|
+
dependencies?: DOMNodeReference[],
|
|
105
163
|
clearValuesOnHide: boolean = true
|
|
106
164
|
): DOMNodeReference /* Instance of this returned
|
|
107
165
|
for optional method chaining */
|
|
@@ -159,9 +217,9 @@ node.configureValidationAndRequirements(
|
|
|
159
217
|
|
|
160
218
|
##### Element Manipulation
|
|
161
219
|
|
|
162
|
-
|
|
163
|
-
/****/ Value management /****/
|
|
220
|
+
_Value management_
|
|
164
221
|
|
|
222
|
+
```typescript
|
|
165
223
|
// set a static value
|
|
166
224
|
node.setValue("new value");
|
|
167
225
|
|
|
@@ -176,25 +234,31 @@ node.setValue(() => {
|
|
|
176
234
|
node.updateValue();
|
|
177
235
|
|
|
178
236
|
// Clear the value for both the instance and the target element
|
|
179
|
-
node.clearValue()
|
|
237
|
+
node.clearValue();
|
|
238
|
+
```
|
|
180
239
|
|
|
181
|
-
|
|
240
|
+
_Content manipulation_
|
|
182
241
|
|
|
242
|
+
```typescript
|
|
183
243
|
node.setInnerHTML("<span>New content</span>");
|
|
184
244
|
node.append(childElement);
|
|
185
245
|
node.prepend(headerElement);
|
|
186
246
|
node.after(siblingElement);
|
|
187
247
|
node.before(labelElement);
|
|
248
|
+
```
|
|
188
249
|
|
|
189
|
-
|
|
250
|
+
_Styling_
|
|
190
251
|
|
|
252
|
+
```typescript
|
|
191
253
|
node.setStyle({
|
|
192
254
|
display: "block",
|
|
193
255
|
color: "red",
|
|
194
256
|
});
|
|
257
|
+
```
|
|
195
258
|
|
|
196
|
-
|
|
259
|
+
_Enabling/Disabling inputs_
|
|
197
260
|
|
|
261
|
+
```typescript
|
|
198
262
|
node.disable();
|
|
199
263
|
node.enable();
|
|
200
264
|
|
package/dist/API.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ declare const API: {
|
|
|
12
12
|
* @param selectColumns *OPTIONAL* if desired, enter your own custom OData query for advanced GET results. Format = select=column1,column2,column3...
|
|
13
13
|
* @returns a Promise resolving the successful results of the GET request, or rejecting the failed results of the GET request
|
|
14
14
|
*/
|
|
15
|
-
getRecord(tableSetName: string, recordID: string, selectColumns?: string): Promise<
|
|
15
|
+
getRecord<T>(tableSetName: string, recordID: string, selectColumns?: string): Promise<T>;
|
|
16
16
|
/**
|
|
17
17
|
*
|
|
18
18
|
* @param tableSetName The dataverse set name of the table being queried
|
|
@@ -1,3 +1,45 @@
|
|
|
1
|
+
interface BusinessRule {
|
|
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
|
+
* @param dependencies An array of `DOMNodeReference` instances. Event listeners are
|
|
7
|
+
* registered on each to toggle the visibility of the target element based on the `condition` and the visibility of
|
|
8
|
+
* the target node.
|
|
9
|
+
* @param clearValuesOnHide Should the values in the targeted field be cleared when hidden? Defaults to true
|
|
10
|
+
*/
|
|
11
|
+
setVisibility?: [
|
|
12
|
+
condition: () => boolean,
|
|
13
|
+
dependencies: DOMNodeReference[],
|
|
14
|
+
clearValuesOnHide?: boolean
|
|
15
|
+
];
|
|
16
|
+
/**
|
|
17
|
+
* @param isRequired Function determining if field is required
|
|
18
|
+
* @param isValid Function validating field input
|
|
19
|
+
* @param fieldDisplayName Display name for error messages
|
|
20
|
+
* @param dependencies Fields that trigger requirement/validation updates
|
|
21
|
+
*/
|
|
22
|
+
setRequired?: [
|
|
23
|
+
isRequired: () => boolean,
|
|
24
|
+
isValid: () => boolean,
|
|
25
|
+
fieldDisplayName: string,
|
|
26
|
+
dependencies: DOMNodeReference[]
|
|
27
|
+
];
|
|
28
|
+
/**
|
|
29
|
+
* @param condition A function to determine the value of this
|
|
30
|
+
* element, given applied logic
|
|
31
|
+
* @param value The value to set for the HTML element.
|
|
32
|
+
* for parents of boolean radios, pass true or false as value, or
|
|
33
|
+
* an expression returning a boolean
|
|
34
|
+
*/
|
|
35
|
+
setValue?: [condition: () => boolean, value: any];
|
|
36
|
+
/**
|
|
37
|
+
* @param condition A function to determine if this field
|
|
38
|
+
* should be enabled in a form, or disabled. True || 1 = disabled. False || 0 = enabled
|
|
39
|
+
* @param dependencies
|
|
40
|
+
*/
|
|
41
|
+
setDisabled?: [condition: () => boolean, dependencies: DOMNodeReference[]];
|
|
42
|
+
}
|
|
1
43
|
export declare const _init: unique symbol;
|
|
2
44
|
declare const _destroy: unique symbol;
|
|
3
45
|
declare const _valueSync: unique symbol;
|
|
@@ -7,12 +49,17 @@ declare const _updateRadioGroup: unique symbol;
|
|
|
7
49
|
declare const _attachVisibilityController: unique symbol;
|
|
8
50
|
declare const _attachRadioButtons: unique symbol;
|
|
9
51
|
declare const _bindMethods: unique symbol;
|
|
52
|
+
declare const _debounceTime: unique symbol;
|
|
53
|
+
declare const _observers: unique symbol;
|
|
54
|
+
declare const _boundEventListeners: unique symbol;
|
|
10
55
|
export default class DOMNodeReference {
|
|
11
|
-
target:
|
|
56
|
+
target: Element | string;
|
|
57
|
+
root: Element;
|
|
58
|
+
private [_debounceTime];
|
|
12
59
|
private isLoaded;
|
|
13
60
|
private defaultDisplay;
|
|
14
|
-
private
|
|
15
|
-
private
|
|
61
|
+
private [_observers];
|
|
62
|
+
private [_boundEventListeners];
|
|
16
63
|
/**
|
|
17
64
|
* The value of the element that this node represents
|
|
18
65
|
* stays in syncs with the live DOM elements?.,m via event handler
|
|
@@ -41,8 +88,10 @@ export default class DOMNodeReference {
|
|
|
41
88
|
/**
|
|
42
89
|
* Creates an instance of DOMNodeReference.
|
|
43
90
|
* @param target - The CSS selector to find the desired DOM element.
|
|
91
|
+
* @param root - Optionally specify the element within to search for the element targeted by 'target'
|
|
92
|
+
* Defaults to 'document.body'
|
|
44
93
|
*/
|
|
45
|
-
/******/ /******/ constructor(target:
|
|
94
|
+
/******/ /******/ constructor(target: Element | string, root: Element | undefined, debounceTime: number);
|
|
46
95
|
[_init](): Promise<void>;
|
|
47
96
|
/**
|
|
48
97
|
* Initializes value synchronization with appropriate event listeners
|
|
@@ -180,7 +229,7 @@ export default class DOMNodeReference {
|
|
|
180
229
|
remove(): this;
|
|
181
230
|
/**
|
|
182
231
|
*
|
|
183
|
-
* @param
|
|
232
|
+
* @param options and object containing the styles you want to set : {key: value} e.g.: {'display': 'block'}
|
|
184
233
|
* @returns - Instance of this [provides option to method chain]
|
|
185
234
|
*/
|
|
186
235
|
setStyle(options: Partial<CSSStyleDeclaration>): this;
|
|
@@ -189,52 +238,59 @@ export default class DOMNodeReference {
|
|
|
189
238
|
* @returns - Instance of this [provides option to method chain]
|
|
190
239
|
*/
|
|
191
240
|
uncheckRadios(): DOMNodeReference;
|
|
241
|
+
/**
|
|
242
|
+
* Applies a business rule to manage visibility, required state, value, and disabled state dynamically.
|
|
243
|
+
*
|
|
244
|
+
* @param rule The business rule containing conditions for various actions.
|
|
245
|
+
* @returns Instance of this for method chaining.
|
|
246
|
+
*/
|
|
247
|
+
applyBusinessRule(rule: Partial<BusinessRule>): DOMNodeReference;
|
|
192
248
|
/**
|
|
193
249
|
* Configures conditional rendering for the target element based on a condition
|
|
194
250
|
* and the visibility of one or more trigger elements.
|
|
195
|
-
*
|
|
196
|
-
* @param condition
|
|
251
|
+
* @deprecated Use the new 'applyBusinessRule Method
|
|
252
|
+
* @param condition A function that returns a boolean to determine
|
|
197
253
|
* the visibility of the target element. If `condition()` returns true, the element is shown;
|
|
198
254
|
* otherwise, it is hidden.
|
|
199
255
|
* @param dependencies - An array of `DOMNodeReference` instances. Event listeners are
|
|
200
256
|
* registered on each to toggle the visibility of the target element based on the `condition` and the visibility of
|
|
201
257
|
* the target node.
|
|
202
|
-
* @throws
|
|
203
|
-
* @returns
|
|
258
|
+
* @throws When there's an error in setting up conditional rendering
|
|
259
|
+
* @returns Instance of this [provides option to method chain]
|
|
204
260
|
*/
|
|
205
261
|
configureConditionalRendering(condition: () => boolean, dependencies?: Array<DOMNodeReference>, clearValuesOnHide?: boolean): DOMNodeReference;
|
|
206
262
|
/**
|
|
207
263
|
* Sets up validation and requirement rules for the field with enhanced error handling and dynamic updates.
|
|
208
|
-
*
|
|
209
|
-
* @param isRequired
|
|
210
|
-
* @param isValid
|
|
211
|
-
* @param fieldDisplayName
|
|
212
|
-
* @param dependencies
|
|
213
|
-
* @returns
|
|
214
|
-
* @throws
|
|
264
|
+
* @deprecated Use the new 'applyBusinessRule Method
|
|
265
|
+
* @param isRequired Function determining if field is required
|
|
266
|
+
* @param isValid Function validating field input
|
|
267
|
+
* @param fieldDisplayName Display name for error messages
|
|
268
|
+
* @param dependencies Fields that trigger requirement/validation updates
|
|
269
|
+
* @returns Instance of this
|
|
270
|
+
* @throws If validation setup fails
|
|
215
271
|
*/
|
|
216
272
|
configureValidationAndRequirements(isRequired: () => boolean, isValid: () => boolean, fieldDisplayName: string, dependencies: Array<DOMNodeReference>): DOMNodeReference;
|
|
217
273
|
/**
|
|
218
274
|
* Sets up tracking for dependencies using both event listeners and mutation observers.
|
|
219
275
|
* @private
|
|
220
|
-
* @param handler
|
|
221
|
-
* @param dependencies
|
|
222
|
-
* @param options
|
|
276
|
+
* @param handler The function to execute when dependencies change
|
|
277
|
+
* @param dependencies Array of dependent DOM nodes to track
|
|
278
|
+
* @param options Additional configuration options
|
|
223
279
|
*/
|
|
224
280
|
private _configDependencyTracking;
|
|
225
281
|
/**
|
|
226
282
|
* Sets the required level for the field by adding or removing the "required-field" class on the label.
|
|
227
283
|
*
|
|
228
|
-
* @param isRequired
|
|
284
|
+
* @param isRequired Determines whether the field should be marked as required.
|
|
229
285
|
* If true, the "required-field" class is added to the label; if false, it is removed.
|
|
230
|
-
* @returns
|
|
286
|
+
* @returns Instance of this [provides option to method chain]
|
|
231
287
|
*/
|
|
232
288
|
setRequiredLevel(isRequired: (() => boolean) | boolean): DOMNodeReference;
|
|
233
289
|
/**
|
|
234
290
|
* Executes a callback function once the element is fully loaded.
|
|
235
291
|
* If the element is already loaded, the callback is called immediately.
|
|
236
292
|
* Otherwise, a MutationObserver is used to detect when the element is added to the DOM.
|
|
237
|
-
* @param callback
|
|
293
|
+
* @param callback A callback function to execute once the element is loaded.
|
|
238
294
|
* Receives instance of 'this' as an argument
|
|
239
295
|
*/
|
|
240
296
|
onceLoaded(callback: (instance: DOMNodeReference) => any): any;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import DOMNodeReference from "./DOMNodeReference.js";
|
|
2
|
+
export declare class DOMNodeReferenceArray extends Array<DOMNodeReference> {
|
|
3
|
+
/**
|
|
4
|
+
* Hides all the containers of the DOMNodeReference instances in the array.
|
|
5
|
+
*/
|
|
6
|
+
hideAll(this: DOMNodeReferenceArray): DOMNodeReferenceArray;
|
|
7
|
+
/**
|
|
8
|
+
* Shows all the containers of the DOMNodeReference instances in the array.
|
|
9
|
+
*/
|
|
10
|
+
showAll(this: DOMNodeReferenceArray): DOMNodeReferenceArray;
|
|
11
|
+
}
|
|
12
|
+
export declare function enhanceArray<T extends string>(array: DOMNodeReference[]): DOMNodeReferenceArray & Record<T, DOMNodeReference>;
|
package/dist/List.d.ts
CHANGED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import DOMNodeReference from "./DOMNodeReference.js";
|
|
2
|
+
import { DOMNodeReferenceArray } from "./DOMNodeReferenceArray.js";
|
|
3
|
+
/**
|
|
4
|
+
* @function
|
|
5
|
+
* Get all controls related to the form for manipulating with the
|
|
6
|
+
* DOMNodeReference class. Rather than having to instantiate each fields that you need manually,
|
|
7
|
+
* you can call this method once with the form ID and gain access to all fields
|
|
8
|
+
* @param formId The string GUID of the form you want to bind to
|
|
9
|
+
* @returns An array of DOMNodeReferences
|
|
10
|
+
*/
|
|
11
|
+
export default function bindForm<T extends string>(formId: string): Promise<DOMNodeReferenceArray & Record<T, DOMNodeReference>>;
|
package/dist/bundle.js
CHANGED
|
@@ -102,36 +102,110 @@ 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((instance) => instance.element.id === prop);
|
|
131
|
+
}
|
|
132
|
+
return void 0;
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
105
137
|
// src/waitFor.ts
|
|
106
|
-
function waitFor(target, root = document) {
|
|
138
|
+
function waitFor(target, root = document, multiple = false, debounceTime) {
|
|
107
139
|
return new Promise((resolve, reject) => {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
140
|
+
if (multiple) {
|
|
141
|
+
let timeout;
|
|
142
|
+
const observedElements = [];
|
|
143
|
+
const observedSet = /* @__PURE__ */ new Set();
|
|
144
|
+
if (debounceTime < 1) {
|
|
145
|
+
return resolve(
|
|
146
|
+
Array.from(root.querySelectorAll(target))
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
const observer = new MutationObserver(() => {
|
|
150
|
+
const found = Array.from(root.querySelectorAll(target));
|
|
151
|
+
found.forEach((element) => {
|
|
152
|
+
if (!observedSet.has(element)) {
|
|
153
|
+
observedSet.add(element);
|
|
154
|
+
observedElements.push(element);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
111
157
|
clearTimeout(timeout);
|
|
158
|
+
timeout = setTimeout(() => {
|
|
159
|
+
if (observedElements.length > 0) {
|
|
160
|
+
observer.disconnect();
|
|
161
|
+
resolve(observedElements);
|
|
162
|
+
} else {
|
|
163
|
+
reject(
|
|
164
|
+
new Error(
|
|
165
|
+
`No elements found with target: "${target}" within ${debounceTime / 1e3} seconds. If the element you are expecting has not loaded yet, consider raising your timeout.`
|
|
166
|
+
)
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
}, debounceTime);
|
|
170
|
+
});
|
|
171
|
+
observer.observe(root, {
|
|
172
|
+
childList: true,
|
|
173
|
+
subtree: true,
|
|
174
|
+
attributes: false
|
|
175
|
+
});
|
|
176
|
+
} else {
|
|
177
|
+
const observer = new MutationObserver(() => {
|
|
178
|
+
const observedElement = root.querySelector(target);
|
|
179
|
+
if (observedElement) {
|
|
180
|
+
clearTimeout(timeout);
|
|
181
|
+
observer.disconnect();
|
|
182
|
+
resolve(observedElement);
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
const timeout = setTimeout(() => {
|
|
112
186
|
observer.disconnect();
|
|
113
|
-
|
|
187
|
+
reject(
|
|
188
|
+
new Error(
|
|
189
|
+
`Element not found by target: "${target}" within ${debounceTime / 1e3} second. If the element you are expecting has not loaded yet, consider raising your timeout.`
|
|
190
|
+
)
|
|
191
|
+
);
|
|
192
|
+
}, debounceTime);
|
|
193
|
+
if (target instanceof HTMLElement) {
|
|
194
|
+
clearTimeout(timeout);
|
|
195
|
+
return resolve(target);
|
|
114
196
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
clearTimeout(timeout);
|
|
127
|
-
return resolve(element);
|
|
197
|
+
const element = root.querySelector(target);
|
|
198
|
+
if (element) {
|
|
199
|
+
clearTimeout(timeout);
|
|
200
|
+
return resolve(element);
|
|
201
|
+
}
|
|
202
|
+
observer.observe(root, {
|
|
203
|
+
subtree: true,
|
|
204
|
+
attributes: true,
|
|
205
|
+
childList: true
|
|
206
|
+
// Detects added/removed child elements
|
|
207
|
+
});
|
|
128
208
|
}
|
|
129
|
-
observer.observe(document.body, {
|
|
130
|
-
subtree: true,
|
|
131
|
-
attributes: true,
|
|
132
|
-
childList: true
|
|
133
|
-
// Detects added/removed child elements
|
|
134
|
-
});
|
|
135
209
|
});
|
|
136
210
|
}
|
|
137
211
|
|
|
@@ -237,13 +311,18 @@ var _updateRadioGroup = Symbol("_URG");
|
|
|
237
311
|
var _attachVisibilityController = Symbol("_AVC");
|
|
238
312
|
var _attachRadioButtons = Symbol("_ARB");
|
|
239
313
|
var _bindMethods = Symbol("_B");
|
|
314
|
+
var _debounceTime = Symbol("DT");
|
|
315
|
+
var _observers = Symbol("O");
|
|
316
|
+
var _boundEventListeners = Symbol("BEV");
|
|
240
317
|
var DOMNodeReference = class _DOMNodeReference {
|
|
241
318
|
// properties initialized in the constructor
|
|
242
319
|
target;
|
|
320
|
+
root;
|
|
321
|
+
[_debounceTime];
|
|
243
322
|
isLoaded;
|
|
244
323
|
defaultDisplay;
|
|
245
|
-
|
|
246
|
-
|
|
324
|
+
[_observers] = [];
|
|
325
|
+
[_boundEventListeners] = [];
|
|
247
326
|
/**
|
|
248
327
|
* The value of the element that this node represents
|
|
249
328
|
* stays in syncs with the live DOM elements?.,m via event handler
|
|
@@ -252,11 +331,15 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
252
331
|
/**
|
|
253
332
|
* Creates an instance of DOMNodeReference.
|
|
254
333
|
* @param target - The CSS selector to find the desired DOM element.
|
|
334
|
+
* @param root - Optionally specify the element within to search for the element targeted by 'target'
|
|
335
|
+
* Defaults to 'document.body'
|
|
255
336
|
*/
|
|
256
337
|
/******/
|
|
257
338
|
/******/
|
|
258
|
-
constructor(target) {
|
|
339
|
+
constructor(target, root = document.body, debounceTime) {
|
|
259
340
|
this.target = target;
|
|
341
|
+
this.root = root;
|
|
342
|
+
this[_debounceTime] = debounceTime;
|
|
260
343
|
this.isLoaded = false;
|
|
261
344
|
this.defaultDisplay = "";
|
|
262
345
|
this.value = null;
|
|
@@ -264,8 +347,11 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
264
347
|
}
|
|
265
348
|
async [_init]() {
|
|
266
349
|
try {
|
|
267
|
-
|
|
268
|
-
|
|
350
|
+
if (this.target instanceof HTMLElement) {
|
|
351
|
+
this.element = this.target;
|
|
352
|
+
} else {
|
|
353
|
+
this.element = await waitFor(this.target, this.root, false, this[_debounceTime]);
|
|
354
|
+
}
|
|
269
355
|
if (!this.element) {
|
|
270
356
|
throw new DOMNodeNotFoundError(this);
|
|
271
357
|
}
|
|
@@ -302,30 +388,28 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
302
388
|
async [_valueSync]() {
|
|
303
389
|
try {
|
|
304
390
|
this.updateValue();
|
|
305
|
-
if (!(this.element instanceof HTMLElement)) {
|
|
306
|
-
throw new Error("Element is not a valid HTML element");
|
|
307
|
-
}
|
|
308
391
|
const eventMapping = {
|
|
309
392
|
checkbox: "click",
|
|
310
393
|
radio: "click",
|
|
311
394
|
select: "change",
|
|
312
|
-
"select-multiple": "change"
|
|
395
|
+
"select-multiple": "change",
|
|
396
|
+
textarea: "keyup"
|
|
313
397
|
// Add other input types as needed
|
|
314
398
|
};
|
|
315
399
|
let eventType;
|
|
316
400
|
if (this.element instanceof HTMLSelectElement) {
|
|
317
401
|
eventType = "change";
|
|
318
402
|
} else if (this.element instanceof HTMLInputElement) {
|
|
319
|
-
eventType = eventMapping[this.element.type]
|
|
403
|
+
eventType = eventMapping[this.element.type] ?? "input";
|
|
404
|
+
} else if (this.element instanceof HTMLTextAreaElement) {
|
|
405
|
+
eventType = eventMapping[this.element.type] ?? "input";
|
|
320
406
|
} else {
|
|
321
407
|
eventType = "input";
|
|
322
408
|
}
|
|
323
409
|
this.element.addEventListener(eventType, this.updateValue);
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
element: _element,
|
|
328
|
-
handler: _updateValue,
|
|
410
|
+
this[_boundEventListeners].push({
|
|
411
|
+
element: this.element,
|
|
412
|
+
handler: this.updateValue,
|
|
329
413
|
event: eventType
|
|
330
414
|
});
|
|
331
415
|
if (this.element instanceof HTMLInputElement && this.element.dataset.type === "date") {
|
|
@@ -343,10 +427,10 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
343
427
|
if (!parentElement) {
|
|
344
428
|
throw new Error("Date input must have a parent element");
|
|
345
429
|
}
|
|
346
|
-
const dateNode = await waitFor("[data-date-format]", parentElement);
|
|
430
|
+
const dateNode = await waitFor("[data-date-format]", parentElement, false, 1500);
|
|
347
431
|
dateNode.addEventListener("select", this.updateValue);
|
|
348
432
|
const _handler = this.updateValue;
|
|
349
|
-
this.
|
|
433
|
+
this[_boundEventListeners].push({
|
|
350
434
|
element: dateNode,
|
|
351
435
|
handler: _handler,
|
|
352
436
|
event: "select"
|
|
@@ -427,7 +511,8 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
427
511
|
this.noRadio = await createDOMNodeReference(`#${this.element.id}_0`);
|
|
428
512
|
}
|
|
429
513
|
[_bindMethods]() {
|
|
430
|
-
|
|
514
|
+
const prototype = Object.getPrototypeOf(this);
|
|
515
|
+
for (const key of Object.getOwnPropertyNames(prototype)) {
|
|
431
516
|
const value = this[key];
|
|
432
517
|
if (key !== "constructor" && typeof value === "function") {
|
|
433
518
|
this[key] = value.bind(this);
|
|
@@ -435,10 +520,10 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
435
520
|
}
|
|
436
521
|
}
|
|
437
522
|
[_destroy]() {
|
|
438
|
-
this
|
|
523
|
+
this[_boundEventListeners]?.forEach((binding) => {
|
|
439
524
|
binding.element?.removeEventListener(binding.event, binding.handler);
|
|
440
525
|
});
|
|
441
|
-
this
|
|
526
|
+
this[_observers]?.forEach((observer) => {
|
|
442
527
|
observer.disconnect();
|
|
443
528
|
});
|
|
444
529
|
this.yesRadio?.[_destroy]();
|
|
@@ -477,7 +562,7 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
477
562
|
this.element.addEventListener(eventType, eventHandler.bind(this));
|
|
478
563
|
const _element = this.element;
|
|
479
564
|
const _handler = eventHandler;
|
|
480
|
-
this.
|
|
565
|
+
this[_boundEventListeners].push({
|
|
481
566
|
element: _element,
|
|
482
567
|
handler: _handler,
|
|
483
568
|
event: eventType
|
|
@@ -525,7 +610,7 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
525
610
|
if (value instanceof Function) {
|
|
526
611
|
value = value();
|
|
527
612
|
}
|
|
528
|
-
if (this.element.classList.contains("boolean-radio")) {
|
|
613
|
+
if (this.element.classList.contains("boolean-radio") && this.yesRadio instanceof _DOMNodeReference && this.noRadio instanceof _DOMNodeReference) {
|
|
529
614
|
this.yesRadio.element.checked = value;
|
|
530
615
|
this.noRadio.element.checked = !value;
|
|
531
616
|
} else {
|
|
@@ -596,7 +681,7 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
596
681
|
);
|
|
597
682
|
if (childInputs.length > 0) {
|
|
598
683
|
const promises = childInputs.map(async (input) => {
|
|
599
|
-
const inputRef = await createDOMNodeReference(input, false);
|
|
684
|
+
const inputRef = await createDOMNodeReference(input, { multiple: false });
|
|
600
685
|
return inputRef.clearValue();
|
|
601
686
|
});
|
|
602
687
|
await Promise.all(promises);
|
|
@@ -716,7 +801,7 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
716
801
|
}
|
|
717
802
|
/**
|
|
718
803
|
*
|
|
719
|
-
* @param
|
|
804
|
+
* @param options and object containing the styles you want to set : {key: value} e.g.: {'display': 'block'}
|
|
720
805
|
* @returns - Instance of this [provides option to method chain]
|
|
721
806
|
*/
|
|
722
807
|
setStyle(options) {
|
|
@@ -725,7 +810,8 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
725
810
|
`powerpagestoolkit: 'DOMNodeReference.setStyle' required options to be in the form of an object. Argument passed was of type: ${typeof options}`
|
|
726
811
|
);
|
|
727
812
|
}
|
|
728
|
-
for (const
|
|
813
|
+
for (const _key in options) {
|
|
814
|
+
const key = _key;
|
|
729
815
|
this.element.style[key] = options[key];
|
|
730
816
|
}
|
|
731
817
|
return this;
|
|
@@ -745,18 +831,106 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
745
831
|
}
|
|
746
832
|
return this;
|
|
747
833
|
}
|
|
834
|
+
/**
|
|
835
|
+
* Applies a business rule to manage visibility, required state, value, and disabled state dynamically.
|
|
836
|
+
*
|
|
837
|
+
* @param rule The business rule containing conditions for various actions.
|
|
838
|
+
* @returns Instance of this for method chaining.
|
|
839
|
+
*/
|
|
840
|
+
applyBusinessRule(rule) {
|
|
841
|
+
try {
|
|
842
|
+
if (rule.setVisibility) {
|
|
843
|
+
const [condition, dependencies = [], clearValuesOnHide = true] = rule.setVisibility;
|
|
844
|
+
const initialState = condition();
|
|
845
|
+
this.toggleVisibility(initialState);
|
|
846
|
+
if (dependencies.length) {
|
|
847
|
+
this._configDependencyTracking(
|
|
848
|
+
() => this.toggleVisibility(condition()),
|
|
849
|
+
dependencies,
|
|
850
|
+
{
|
|
851
|
+
clearValuesOnHide,
|
|
852
|
+
observeVisibility: true,
|
|
853
|
+
trackInputEvents: false,
|
|
854
|
+
trackRadioButtons: false
|
|
855
|
+
}
|
|
856
|
+
);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
if (rule.setRequired) {
|
|
860
|
+
const [isRequired, isValid, fieldDisplayName, dependencies] = rule.setRequired;
|
|
861
|
+
if (!fieldDisplayName.trim()) {
|
|
862
|
+
throw new ValidationConfigError(
|
|
863
|
+
this,
|
|
864
|
+
"Field display name is required"
|
|
865
|
+
);
|
|
866
|
+
}
|
|
867
|
+
if (typeof Page_Validators === "undefined") {
|
|
868
|
+
throw new ValidationConfigError(this, "Page_Validators not found");
|
|
869
|
+
}
|
|
870
|
+
const validatorId = `${this.element.id}Validator`;
|
|
871
|
+
const newValidator = document.createElement("span");
|
|
872
|
+
newValidator.style.display = "none";
|
|
873
|
+
newValidator.id = validatorId;
|
|
874
|
+
Object.assign(newValidator, {
|
|
875
|
+
controltovalidate: this.element.id,
|
|
876
|
+
errormessage: `<a href='#${this.element.id}_label'>${fieldDisplayName} is a required field</a>`,
|
|
877
|
+
evaluationfunction: () => {
|
|
878
|
+
const isFieldRequired = isRequired();
|
|
879
|
+
const isFieldVisible = window.getComputedStyle(this.visibilityController).display !== "none";
|
|
880
|
+
return !isFieldRequired || !isFieldVisible || isValid();
|
|
881
|
+
}
|
|
882
|
+
});
|
|
883
|
+
Page_Validators.push(newValidator);
|
|
884
|
+
this.setRequiredLevel(isRequired());
|
|
885
|
+
this._configDependencyTracking(
|
|
886
|
+
() => this.setRequiredLevel(isRequired()),
|
|
887
|
+
dependencies
|
|
888
|
+
);
|
|
889
|
+
}
|
|
890
|
+
if (rule.setValue) {
|
|
891
|
+
const [condition, value] = rule.setValue;
|
|
892
|
+
if (condition()) {
|
|
893
|
+
this.setValue(value);
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
if (rule.setDisabled) {
|
|
897
|
+
const [condition, dependencies = []] = rule.setDisabled;
|
|
898
|
+
condition() ? this.disable() : this.enable();
|
|
899
|
+
const initialState = condition();
|
|
900
|
+
if (dependencies.length) {
|
|
901
|
+
this._configDependencyTracking(
|
|
902
|
+
() => {
|
|
903
|
+
condition() ? this.enable() : this.disable();
|
|
904
|
+
},
|
|
905
|
+
dependencies,
|
|
906
|
+
{
|
|
907
|
+
observeVisibility: true,
|
|
908
|
+
trackInputEvents: true,
|
|
909
|
+
trackRadioButtons: true
|
|
910
|
+
}
|
|
911
|
+
);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
return this;
|
|
915
|
+
} catch (error) {
|
|
916
|
+
throw new ValidationConfigError(
|
|
917
|
+
this,
|
|
918
|
+
`Failed to apply business rule: ${error}`
|
|
919
|
+
);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
748
922
|
/**
|
|
749
923
|
* Configures conditional rendering for the target element based on a condition
|
|
750
924
|
* and the visibility of one or more trigger elements.
|
|
751
|
-
*
|
|
752
|
-
* @param condition
|
|
925
|
+
* @deprecated Use the new 'applyBusinessRule Method
|
|
926
|
+
* @param condition A function that returns a boolean to determine
|
|
753
927
|
* the visibility of the target element. If `condition()` returns true, the element is shown;
|
|
754
928
|
* otherwise, it is hidden.
|
|
755
929
|
* @param dependencies - An array of `DOMNodeReference` instances. Event listeners are
|
|
756
930
|
* registered on each to toggle the visibility of the target element based on the `condition` and the visibility of
|
|
757
931
|
* the target node.
|
|
758
|
-
* @throws
|
|
759
|
-
* @returns
|
|
932
|
+
* @throws When there's an error in setting up conditional rendering
|
|
933
|
+
* @returns Instance of this [provides option to method chain]
|
|
760
934
|
*/
|
|
761
935
|
configureConditionalRendering(condition, dependencies, clearValuesOnHide = true) {
|
|
762
936
|
try {
|
|
@@ -790,13 +964,13 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
790
964
|
}
|
|
791
965
|
/**
|
|
792
966
|
* Sets up validation and requirement rules for the field with enhanced error handling and dynamic updates.
|
|
793
|
-
*
|
|
794
|
-
* @param isRequired
|
|
795
|
-
* @param isValid
|
|
796
|
-
* @param fieldDisplayName
|
|
797
|
-
* @param dependencies
|
|
798
|
-
* @returns
|
|
799
|
-
* @throws
|
|
967
|
+
* @deprecated Use the new 'applyBusinessRule Method
|
|
968
|
+
* @param isRequired Function determining if field is required
|
|
969
|
+
* @param isValid Function validating field input
|
|
970
|
+
* @param fieldDisplayName Display name for error messages
|
|
971
|
+
* @param dependencies Fields that trigger requirement/validation updates
|
|
972
|
+
* @returns Instance of this
|
|
973
|
+
* @throws If validation setup fails
|
|
800
974
|
*/
|
|
801
975
|
configureValidationAndRequirements(isRequired, isValid, fieldDisplayName, dependencies) {
|
|
802
976
|
if (!fieldDisplayName?.trim()) {
|
|
@@ -845,9 +1019,9 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
845
1019
|
/**
|
|
846
1020
|
* Sets up tracking for dependencies using both event listeners and mutation observers.
|
|
847
1021
|
* @private
|
|
848
|
-
* @param handler
|
|
849
|
-
* @param dependencies
|
|
850
|
-
* @param options
|
|
1022
|
+
* @param handler The function to execute when dependencies change
|
|
1023
|
+
* @param dependencies Array of dependent DOM nodes to track
|
|
1024
|
+
* @param options Additional configuration options
|
|
851
1025
|
*/
|
|
852
1026
|
_configDependencyTracking(handler, dependencies, options = {
|
|
853
1027
|
clearValuesOnHide: false,
|
|
@@ -880,14 +1054,14 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
880
1054
|
}
|
|
881
1055
|
};
|
|
882
1056
|
dep.on("change", handleChange);
|
|
883
|
-
this.
|
|
1057
|
+
this[_boundEventListeners].push({
|
|
884
1058
|
element: dep.element,
|
|
885
1059
|
event: "change",
|
|
886
1060
|
handler: handleChange
|
|
887
1061
|
});
|
|
888
1062
|
if (trackInputEvents) {
|
|
889
1063
|
dep.on("input", handleChange);
|
|
890
|
-
this.
|
|
1064
|
+
this[_boundEventListeners].push({
|
|
891
1065
|
element: dep.element,
|
|
892
1066
|
event: "input",
|
|
893
1067
|
handler: handleChange
|
|
@@ -907,12 +1081,12 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
907
1081
|
attributeFilter: ["style"],
|
|
908
1082
|
subtree: false
|
|
909
1083
|
});
|
|
910
|
-
this.
|
|
1084
|
+
this[_observers].push(observer);
|
|
911
1085
|
}
|
|
912
1086
|
if (trackRadioButtons && dep.yesRadio && dep.noRadio) {
|
|
913
1087
|
[dep.yesRadio, dep.noRadio].forEach((radio) => {
|
|
914
1088
|
radio.on("change", handleChange);
|
|
915
|
-
this.
|
|
1089
|
+
this[_boundEventListeners].push({
|
|
916
1090
|
element: radio.element,
|
|
917
1091
|
event: "change",
|
|
918
1092
|
handler: handleChange
|
|
@@ -924,9 +1098,9 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
924
1098
|
/**
|
|
925
1099
|
* Sets the required level for the field by adding or removing the "required-field" class on the label.
|
|
926
1100
|
*
|
|
927
|
-
* @param isRequired
|
|
1101
|
+
* @param isRequired Determines whether the field should be marked as required.
|
|
928
1102
|
* If true, the "required-field" class is added to the label; if false, it is removed.
|
|
929
|
-
* @returns
|
|
1103
|
+
* @returns Instance of this [provides option to method chain]
|
|
930
1104
|
*/
|
|
931
1105
|
setRequiredLevel(isRequired) {
|
|
932
1106
|
if (isRequired instanceof Function) {
|
|
@@ -941,7 +1115,7 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
941
1115
|
* Executes a callback function once the element is fully loaded.
|
|
942
1116
|
* If the element is already loaded, the callback is called immediately.
|
|
943
1117
|
* Otherwise, a MutationObserver is used to detect when the element is added to the DOM.
|
|
944
|
-
* @param callback
|
|
1118
|
+
* @param callback A callback function to execute once the element is loaded.
|
|
945
1119
|
* Receives instance of 'this' as an argument
|
|
946
1120
|
*/
|
|
947
1121
|
onceLoaded(callback) {
|
|
@@ -964,13 +1138,24 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
964
1138
|
subtree: true,
|
|
965
1139
|
childList: true
|
|
966
1140
|
});
|
|
967
|
-
this.
|
|
1141
|
+
this[_observers].push(observer);
|
|
968
1142
|
}
|
|
969
1143
|
};
|
|
970
1144
|
|
|
971
1145
|
// src/createDOMNodeReferences.ts
|
|
972
|
-
async function createDOMNodeReference(target,
|
|
1146
|
+
async function createDOMNodeReference(target, options = {
|
|
1147
|
+
multiple: false,
|
|
1148
|
+
root: document.body,
|
|
1149
|
+
timeout: 0
|
|
1150
|
+
}) {
|
|
973
1151
|
try {
|
|
1152
|
+
if (typeof options !== "object") {
|
|
1153
|
+
throw new Error(
|
|
1154
|
+
`'options' must be of type 'object'. Received type: '${typeof options}'`
|
|
1155
|
+
);
|
|
1156
|
+
}
|
|
1157
|
+
validateOptions(options);
|
|
1158
|
+
const { multiple = false, root = document.body, timeout = 0 } = options;
|
|
974
1159
|
const isMultiple = typeof multiple === "function" ? multiple() : multiple;
|
|
975
1160
|
if (isMultiple) {
|
|
976
1161
|
if (typeof target !== "string") {
|
|
@@ -978,25 +1163,50 @@ async function createDOMNodeReference(target, multiple = false) {
|
|
|
978
1163
|
`'target' must be of type 'string' if 'multiple' is set to 'true'. Received type: '${typeof target}'`
|
|
979
1164
|
);
|
|
980
1165
|
}
|
|
981
|
-
const elements =
|
|
982
|
-
document.querySelectorAll(target)
|
|
983
|
-
);
|
|
1166
|
+
const elements = await waitFor(target, root, true, timeout);
|
|
984
1167
|
const initializedElements = await Promise.all(
|
|
985
1168
|
elements.map(async (element) => {
|
|
986
|
-
const instance2 = new DOMNodeReference(element);
|
|
1169
|
+
const instance2 = new DOMNodeReference(element, root, timeout);
|
|
987
1170
|
await instance2[_init]();
|
|
988
1171
|
return new Proxy(instance2, createProxyHandler());
|
|
989
1172
|
})
|
|
990
1173
|
);
|
|
991
1174
|
return enhanceArray(initializedElements);
|
|
992
1175
|
}
|
|
993
|
-
const instance = new DOMNodeReference(target);
|
|
1176
|
+
const instance = new DOMNodeReference(target, root, timeout);
|
|
994
1177
|
await instance[_init]();
|
|
995
1178
|
return new Proxy(instance, createProxyHandler());
|
|
996
1179
|
} catch (e) {
|
|
997
1180
|
throw new Error(e);
|
|
998
1181
|
}
|
|
999
1182
|
}
|
|
1183
|
+
function validateOptions(options) {
|
|
1184
|
+
const { multiple = false, root = document.body, timeout = 0 } = options;
|
|
1185
|
+
if (typeof multiple !== "boolean" && typeof multiple !== "function") {
|
|
1186
|
+
throw new Error(
|
|
1187
|
+
`'multiple' must be of type 'boolean' or 'function'. Received type: '${typeof multiple}'`
|
|
1188
|
+
);
|
|
1189
|
+
}
|
|
1190
|
+
if (typeof multiple === "function") {
|
|
1191
|
+
const value = multiple();
|
|
1192
|
+
if (typeof value !== "boolean") {
|
|
1193
|
+
throw new Error(
|
|
1194
|
+
`'multiple' function must return a boolean. Received type: '${typeof value}'`
|
|
1195
|
+
);
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
if (!(root instanceof HTMLElement)) {
|
|
1199
|
+
throw new Error(
|
|
1200
|
+
`'root' must be of type 'HTMLElement'. Received type: '${typeof root}'`
|
|
1201
|
+
);
|
|
1202
|
+
}
|
|
1203
|
+
if (typeof timeout !== "number") {
|
|
1204
|
+
throw new Error(
|
|
1205
|
+
`'timeout' must be of type 'number'. Received type: '${typeof timeout}'`
|
|
1206
|
+
);
|
|
1207
|
+
}
|
|
1208
|
+
return;
|
|
1209
|
+
}
|
|
1000
1210
|
function createProxyHandler() {
|
|
1001
1211
|
return {
|
|
1002
1212
|
get: (target, prop) => {
|
|
@@ -1012,26 +1222,52 @@ function createProxyHandler() {
|
|
|
1012
1222
|
}
|
|
1013
1223
|
};
|
|
1014
1224
|
}
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1225
|
+
|
|
1226
|
+
// src/bindForm.ts
|
|
1227
|
+
async function bindForm(formId) {
|
|
1228
|
+
try {
|
|
1229
|
+
const form = await API_default.getRecord("systemforms", formId);
|
|
1230
|
+
const { formxml } = form;
|
|
1231
|
+
const parser = new DOMParser();
|
|
1232
|
+
const xmlDoc = parser.parseFromString(formxml, "application/xml");
|
|
1233
|
+
const controls = xmlDoc.getElementsByTagName("control");
|
|
1234
|
+
const dataFields = [];
|
|
1235
|
+
for (let i = 0; i < controls.length; i++) {
|
|
1236
|
+
const datafieldname = controls[i].getAttribute("datafieldname");
|
|
1237
|
+
if (datafieldname) {
|
|
1238
|
+
const refPromise = createDOMNodeReference(`#${datafieldname}`).catch((error) => {
|
|
1239
|
+
console.warn(
|
|
1240
|
+
`Failed to create a reference to the form field: ${datafieldname}`,
|
|
1241
|
+
error
|
|
1242
|
+
);
|
|
1243
|
+
return null;
|
|
1244
|
+
});
|
|
1245
|
+
dataFields.push(refPromise);
|
|
1027
1246
|
}
|
|
1028
1247
|
}
|
|
1029
|
-
|
|
1030
|
-
|
|
1248
|
+
const resolvedRefs = await Promise.all(dataFields);
|
|
1249
|
+
return enhanceArray(
|
|
1250
|
+
resolvedRefs.filter((ref) => ref !== null)
|
|
1251
|
+
);
|
|
1252
|
+
} catch (error) {
|
|
1253
|
+
if (error instanceof Error) {
|
|
1254
|
+
console.error(error.message);
|
|
1255
|
+
throw error;
|
|
1256
|
+
} else {
|
|
1257
|
+
console.error(error);
|
|
1258
|
+
throw new Error(String(error));
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1031
1261
|
}
|
|
1262
|
+
|
|
1263
|
+
// src/index.ts
|
|
1264
|
+
var toolkit = { API: API_default, createRef: createDOMNodeReference, waitFor, bindForm };
|
|
1265
|
+
var src_default = toolkit;
|
|
1032
1266
|
export {
|
|
1033
1267
|
API_default as API,
|
|
1268
|
+
bindForm,
|
|
1034
1269
|
createDOMNodeReference as createRef,
|
|
1270
|
+
src_default as default,
|
|
1035
1271
|
waitFor
|
|
1036
1272
|
};
|
|
1037
1273
|
|
|
@@ -1,9 +1,36 @@
|
|
|
1
|
+
import { DOMNodeReferenceArray } from "./DOMNodeReferenceArray.js";
|
|
1
2
|
import DOMNodeReference from "./DOMNodeReference.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
interface CreationOptions {
|
|
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?: CreationOptions): Promise<DOMNodeReference>;
|
|
22
|
+
export default function createDOMNodeReference(target: string, options?: Omit<CreationOptions, "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<CreationOptions, "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 {};
|
package/dist/index.d.ts
CHANGED
|
@@ -2,4 +2,17 @@ import "./style.css";
|
|
|
2
2
|
import API from "./API.js";
|
|
3
3
|
import createRef from "./createDOMNodeReferences.js";
|
|
4
4
|
import waitFor from "./waitFor.js";
|
|
5
|
-
|
|
5
|
+
import bindForm from "./bindForm.js";
|
|
6
|
+
export { API, createRef, waitFor, bindForm };
|
|
7
|
+
declare const toolkit: {
|
|
8
|
+
API: {
|
|
9
|
+
createRecord(tableSetName: string, data: object): Promise<string>;
|
|
10
|
+
getRecord<T>(tableSetName: string, recordID: string, selectColumns?: string): Promise<T>;
|
|
11
|
+
getMultiple(tableSetName: string, queryParameters?: string): Promise<Array<object>>;
|
|
12
|
+
updateRecord(tableSetName: string, recordId: string, data: object): Promise<any>;
|
|
13
|
+
};
|
|
14
|
+
createRef: typeof createRef;
|
|
15
|
+
waitFor: typeof waitFor;
|
|
16
|
+
bindForm: typeof bindForm;
|
|
17
|
+
};
|
|
18
|
+
export default toolkit;
|
package/dist/waitFor.d.ts
CHANGED
|
@@ -1,7 +1,2 @@
|
|
|
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?: HTMLElement | Document): Promise<HTMLElement>;
|
|
1
|
+
export default function waitFor(target: Element | string, root: Element | Document, multiple: false, debounceTime: number): Promise<HTMLElement>;
|
|
2
|
+
export default function waitFor(target: Element | string, root: Element | Document, multiple: true, debounceTime: number): Promise<HTMLElement[]>;
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "powerpagestoolkit",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.4",
|
|
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
|
-
"main": "./dist/
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"typecheck": "tsc",
|
|
@@ -15,11 +15,13 @@
|
|
|
15
15
|
"devDependencies": {
|
|
16
16
|
"@babel/preset-env": "^7.25.8",
|
|
17
17
|
"@types/node": "^22.8.6",
|
|
18
|
+
"@typescript-eslint/parser": "^8.20.0",
|
|
18
19
|
"css-loader": "^7.1.2",
|
|
19
20
|
"esbuild": "^0.24.0",
|
|
20
21
|
"esbuild-css-modules-plugin": "^3.1.2",
|
|
21
22
|
"eslint": "^8.57.1",
|
|
22
23
|
"eslint-plugin-import": "^2.31.0",
|
|
24
|
+
"globals": "^15.14.0",
|
|
23
25
|
"rimraf": "^6.0.1",
|
|
24
26
|
"ts-loader": "^9.5.1",
|
|
25
27
|
"typescript": "^5.6.3",
|