powerpagestoolkit 2.6.33311 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/API.d.ts +1 -1
- package/dist/DOMNodeReference.d.ts +61 -20
- 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 +257 -50
- package/dist/createDOMNodeReferences.d.ts +32 -7
- package/dist/index.d.ts +2 -1
- package/dist/waitFor.d.ts +2 -2
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -95,7 +95,8 @@ const nodes = await createRef(".my-class", { multiple: true });
|
|
|
95
95
|
// ADVANCED OPTIONS
|
|
96
96
|
// in the event that you need to be more granular with how you are targeting
|
|
97
97
|
// and retrieving elements, there are additional options
|
|
98
|
-
|
|
98
|
+
|
|
99
|
+
// If the node you are targeting is not available at the initial execution
|
|
99
100
|
// of the script, set a timeout for 2 seconds
|
|
100
101
|
const node2 = await createRef("#target", { timeout: 2000 });
|
|
101
102
|
|
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,33 @@
|
|
|
1
|
+
interface IBusinessRule {
|
|
2
|
+
/**
|
|
3
|
+
* @param condition A function that returns a boolean to determine
|
|
4
|
+
* the visibility of the target element. If `condition()` returns true, the element is shown;
|
|
5
|
+
* otherwise, it is hidden.
|
|
6
|
+
|
|
7
|
+
* @param clearValuesOnHide Should the values in the targeted field be cleared when hidden? Defaults to true
|
|
8
|
+
*/
|
|
9
|
+
setVisibility?: [condition: () => boolean, clearValuesOnHide?: boolean];
|
|
10
|
+
/**
|
|
11
|
+
* @param isRequired Function determining if field is required
|
|
12
|
+
* @param isValid Function validating field input. allows access to the invoked expression passed by {@link isRequired}
|
|
13
|
+
*/
|
|
14
|
+
setRequired?: [
|
|
15
|
+
isRequired: () => boolean,
|
|
16
|
+
isValid: (isRequired: () => boolean) => boolean
|
|
17
|
+
];
|
|
18
|
+
/**
|
|
19
|
+
* @param condition A function to determine if the value provided should be applied to this field
|
|
20
|
+
* @param value The value to set for the HTML element.
|
|
21
|
+
* for parents of boolean radios, pass true or false as value, or
|
|
22
|
+
* an expression returning a boolean
|
|
23
|
+
*/
|
|
24
|
+
setValue?: [condition: () => boolean, value: any];
|
|
25
|
+
/**
|
|
26
|
+
* @param condition A function to determine if this field
|
|
27
|
+
* should be enabled in a form, or disabled. True || 1 = disabled. False || 0 = enabled
|
|
28
|
+
*/
|
|
29
|
+
setDisabled?: [condition: () => boolean];
|
|
30
|
+
}
|
|
1
31
|
export declare const _init: unique symbol;
|
|
2
32
|
declare const _destroy: unique symbol;
|
|
3
33
|
declare const _valueSync: unique symbol;
|
|
@@ -11,8 +41,9 @@ declare const _debounceTime: unique symbol;
|
|
|
11
41
|
declare const _observers: unique symbol;
|
|
12
42
|
declare const _boundEventListeners: unique symbol;
|
|
13
43
|
export default class DOMNodeReference {
|
|
14
|
-
target:
|
|
15
|
-
|
|
44
|
+
target: Element | string;
|
|
45
|
+
logicalName?: string;
|
|
46
|
+
root: Element;
|
|
16
47
|
private [_debounceTime];
|
|
17
48
|
private isLoaded;
|
|
18
49
|
private defaultDisplay;
|
|
@@ -49,8 +80,9 @@ export default class DOMNodeReference {
|
|
|
49
80
|
* @param root - Optionally specify the element within to search for the element targeted by 'target'
|
|
50
81
|
* Defaults to 'document.body'
|
|
51
82
|
*/
|
|
52
|
-
/******/ /******/ constructor(target:
|
|
83
|
+
/******/ /******/ constructor(target: Element | string, root: Element | undefined, debounceTime: number);
|
|
53
84
|
[_init](): Promise<void>;
|
|
85
|
+
private eventMapping;
|
|
54
86
|
/**
|
|
55
87
|
* Initializes value synchronization with appropriate event listeners
|
|
56
88
|
* based on element type.
|
|
@@ -196,52 +228,61 @@ export default class DOMNodeReference {
|
|
|
196
228
|
* @returns - Instance of this [provides option to method chain]
|
|
197
229
|
*/
|
|
198
230
|
uncheckRadios(): DOMNodeReference;
|
|
231
|
+
/**
|
|
232
|
+
* Applies a business rule to manage visibility, required state, value, and disabled state dynamically.
|
|
233
|
+
*
|
|
234
|
+
* @param rule The business rule containing conditions for various actions.
|
|
235
|
+
* @param dependencies For re-evaluation conditions when the state of the dependencies change
|
|
236
|
+
* @returns Instance of this for method chaining.
|
|
237
|
+
*/
|
|
238
|
+
applyBusinessRule(rule: IBusinessRule, dependencies: DOMNodeReference[]): DOMNodeReference;
|
|
199
239
|
/**
|
|
200
240
|
* Configures conditional rendering for the target element based on a condition
|
|
201
241
|
* and the visibility of one or more trigger elements.
|
|
202
|
-
*
|
|
203
|
-
* @param condition
|
|
242
|
+
* @deprecated Use the new 'applyBusinessRule Method
|
|
243
|
+
* @param condition A function that returns a boolean to determine
|
|
204
244
|
* the visibility of the target element. If `condition()` returns true, the element is shown;
|
|
205
245
|
* otherwise, it is hidden.
|
|
206
246
|
* @param dependencies - An array of `DOMNodeReference` instances. Event listeners are
|
|
207
247
|
* registered on each to toggle the visibility of the target element based on the `condition` and the visibility of
|
|
208
248
|
* the target node.
|
|
209
|
-
* @throws
|
|
210
|
-
* @returns
|
|
249
|
+
* @throws When there's an error in setting up conditional rendering
|
|
250
|
+
* @returns Instance of this [provides option to method chain]
|
|
211
251
|
*/
|
|
212
252
|
configureConditionalRendering(condition: () => boolean, dependencies?: Array<DOMNodeReference>, clearValuesOnHide?: boolean): DOMNodeReference;
|
|
213
253
|
/**
|
|
214
254
|
* Sets up validation and requirement rules for the field with enhanced error handling and dynamic updates.
|
|
215
|
-
*
|
|
216
|
-
* @param isRequired
|
|
217
|
-
* @param isValid
|
|
218
|
-
* @param fieldDisplayName
|
|
219
|
-
* @param dependencies
|
|
220
|
-
* @returns
|
|
221
|
-
* @throws
|
|
255
|
+
* @deprecated Use the new 'applyBusinessRule Method
|
|
256
|
+
* @param isRequired Function determining if field is required
|
|
257
|
+
* @param isValid Function validating field input
|
|
258
|
+
* @param fieldDisplayName Display name for error messages
|
|
259
|
+
* @param dependencies Fields that trigger requirement/validation updates
|
|
260
|
+
* @returns Instance of this
|
|
261
|
+
* @throws If validation setup fails
|
|
222
262
|
*/
|
|
223
263
|
configureValidationAndRequirements(isRequired: () => boolean, isValid: () => boolean, fieldDisplayName: string, dependencies: Array<DOMNodeReference>): DOMNodeReference;
|
|
224
264
|
/**
|
|
225
265
|
* Sets up tracking for dependencies using both event listeners and mutation observers.
|
|
226
266
|
* @private
|
|
227
|
-
* @param handler
|
|
228
|
-
* @param dependencies
|
|
229
|
-
* @param options
|
|
267
|
+
* @param handler The function to execute when dependencies change
|
|
268
|
+
* @param dependencies Array of dependent DOM nodes to track
|
|
269
|
+
* @param options Additional configuration options. clearValuesOnHide defaults to false.
|
|
270
|
+
* all other options defaults to true
|
|
230
271
|
*/
|
|
231
272
|
private _configDependencyTracking;
|
|
232
273
|
/**
|
|
233
274
|
* Sets the required level for the field by adding or removing the "required-field" class on the label.
|
|
234
275
|
*
|
|
235
|
-
* @param isRequired
|
|
276
|
+
* @param isRequired Determines whether the field should be marked as required.
|
|
236
277
|
* If true, the "required-field" class is added to the label; if false, it is removed.
|
|
237
|
-
* @returns
|
|
278
|
+
* @returns Instance of this [provides option to method chain]
|
|
238
279
|
*/
|
|
239
280
|
setRequiredLevel(isRequired: (() => boolean) | boolean): DOMNodeReference;
|
|
240
281
|
/**
|
|
241
282
|
* Executes a callback function once the element is fully loaded.
|
|
242
283
|
* If the element is already loaded, the callback is called immediately.
|
|
243
284
|
* Otherwise, a MutationObserver is used to detect when the element is added to the DOM.
|
|
244
|
-
* @param callback
|
|
285
|
+
* @param callback A callback function to execute once the element is loaded.
|
|
245
286
|
* Receives instance of 'this' as an argument
|
|
246
287
|
*/
|
|
247
288
|
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,6 +102,40 @@ var API = {
|
|
|
102
102
|
};
|
|
103
103
|
var API_default = API;
|
|
104
104
|
|
|
105
|
+
// src/DOMNodeReferenceArray.ts
|
|
106
|
+
var DOMNodeReferenceArray = class extends Array {
|
|
107
|
+
/**
|
|
108
|
+
* Hides all the containers of the DOMNodeReference instances in the array.
|
|
109
|
+
*/
|
|
110
|
+
hideAll() {
|
|
111
|
+
this.forEach((instance) => instance.hide());
|
|
112
|
+
return this;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Shows all the containers of the DOMNodeReference instances in the array.
|
|
116
|
+
*/
|
|
117
|
+
showAll() {
|
|
118
|
+
this.forEach((instance) => instance.show());
|
|
119
|
+
return this;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
function enhanceArray(array) {
|
|
123
|
+
const enhancedArray = new DOMNodeReferenceArray(...array);
|
|
124
|
+
return new Proxy(enhancedArray, {
|
|
125
|
+
get(target, prop, receiver) {
|
|
126
|
+
if (prop in target) {
|
|
127
|
+
return Reflect.get(target, prop, receiver);
|
|
128
|
+
}
|
|
129
|
+
if (typeof prop === "string") {
|
|
130
|
+
return target.find(
|
|
131
|
+
(instance) => instance.target.toString().replace(/[#\[\]]/g, "") === prop || instance.logicalName === prop
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
return void 0;
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
105
139
|
// src/waitFor.ts
|
|
106
140
|
function waitFor(target, root = document, multiple = false, debounceTime) {
|
|
107
141
|
return new Promise((resolve, reject) => {
|
|
@@ -130,7 +164,7 @@ function waitFor(target, root = document, multiple = false, debounceTime) {
|
|
|
130
164
|
} else {
|
|
131
165
|
reject(
|
|
132
166
|
new Error(
|
|
133
|
-
`No elements found with target: "${target}" within ${debounceTime / 1e3} seconds. If the element you are
|
|
167
|
+
`No elements found with target: "${target}" within ${debounceTime / 1e3} seconds. If the element you are expecting has not loaded yet, consider raising your timeout.`
|
|
134
168
|
)
|
|
135
169
|
);
|
|
136
170
|
}
|
|
@@ -154,7 +188,7 @@ function waitFor(target, root = document, multiple = false, debounceTime) {
|
|
|
154
188
|
observer.disconnect();
|
|
155
189
|
reject(
|
|
156
190
|
new Error(
|
|
157
|
-
`Element not found by target: "${target}" within ${debounceTime / 1e3} second. If the element you are
|
|
191
|
+
`Element not found by target: "${target}" within ${debounceTime / 1e3} second. If the element you are expecting has not loaded yet, consider raising your timeout.`
|
|
158
192
|
)
|
|
159
193
|
);
|
|
160
194
|
}, debounceTime);
|
|
@@ -285,6 +319,7 @@ var _boundEventListeners = Symbol("BEV");
|
|
|
285
319
|
var DOMNodeReference = class _DOMNodeReference {
|
|
286
320
|
// properties initialized in the constructor
|
|
287
321
|
target;
|
|
322
|
+
logicalName;
|
|
288
323
|
root;
|
|
289
324
|
[_debounceTime];
|
|
290
325
|
isLoaded;
|
|
@@ -306,6 +341,18 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
306
341
|
/******/
|
|
307
342
|
constructor(target, root = document.body, debounceTime) {
|
|
308
343
|
this.target = target;
|
|
344
|
+
if (typeof target === "string") {
|
|
345
|
+
let lName = null;
|
|
346
|
+
const bracketMatch = target.match(/\[([^\]]+)\]/);
|
|
347
|
+
if (bracketMatch) {
|
|
348
|
+
lName = bracketMatch[1];
|
|
349
|
+
const quoteMatch = lName.match(/["']([^"']+)["']/);
|
|
350
|
+
if (quoteMatch) {
|
|
351
|
+
lName = quoteMatch[1];
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
this.logicalName = (lName || target).replace(/[#\[\]]/g, "");
|
|
355
|
+
}
|
|
309
356
|
this.root = root;
|
|
310
357
|
this[_debounceTime] = debounceTime;
|
|
311
358
|
this.isLoaded = false;
|
|
@@ -348,6 +395,14 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
348
395
|
throw new DOMNodeInitializationError(this, errorMessage);
|
|
349
396
|
}
|
|
350
397
|
}
|
|
398
|
+
eventMapping = {
|
|
399
|
+
checkbox: "click",
|
|
400
|
+
radio: "click",
|
|
401
|
+
select: "change",
|
|
402
|
+
"select-multiple": "change",
|
|
403
|
+
textarea: "keyup"
|
|
404
|
+
// Add other input types as needed
|
|
405
|
+
};
|
|
351
406
|
/**
|
|
352
407
|
* Initializes value synchronization with appropriate event listeners
|
|
353
408
|
* based on element type.
|
|
@@ -356,30 +411,20 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
356
411
|
async [_valueSync]() {
|
|
357
412
|
try {
|
|
358
413
|
this.updateValue();
|
|
359
|
-
if (!(this.element instanceof HTMLElement)) {
|
|
360
|
-
throw new Error("Element is not a valid HTML element");
|
|
361
|
-
}
|
|
362
|
-
const eventMapping = {
|
|
363
|
-
checkbox: "click",
|
|
364
|
-
radio: "click",
|
|
365
|
-
select: "change",
|
|
366
|
-
"select-multiple": "change"
|
|
367
|
-
// Add other input types as needed
|
|
368
|
-
};
|
|
369
414
|
let eventType;
|
|
370
415
|
if (this.element instanceof HTMLSelectElement) {
|
|
371
416
|
eventType = "change";
|
|
372
417
|
} else if (this.element instanceof HTMLInputElement) {
|
|
373
|
-
eventType = eventMapping[this.element.type]
|
|
418
|
+
eventType = this.eventMapping[this.element.type] ?? "input";
|
|
419
|
+
} else if (this.element instanceof HTMLTextAreaElement) {
|
|
420
|
+
eventType = this.eventMapping[this.element.type] ?? "input";
|
|
374
421
|
} else {
|
|
375
422
|
eventType = "input";
|
|
376
423
|
}
|
|
377
424
|
this.element.addEventListener(eventType, this.updateValue);
|
|
378
|
-
const _element = this.element;
|
|
379
|
-
const _updateValue = this.updateValue;
|
|
380
425
|
this[_boundEventListeners].push({
|
|
381
|
-
element:
|
|
382
|
-
handler:
|
|
426
|
+
element: this.element,
|
|
427
|
+
handler: this.updateValue,
|
|
383
428
|
event: eventType
|
|
384
429
|
});
|
|
385
430
|
if (this.element instanceof HTMLInputElement && this.element.dataset.type === "date") {
|
|
@@ -436,8 +481,11 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
436
481
|
value: input.value !== "" ? Number(input.value) : null
|
|
437
482
|
};
|
|
438
483
|
default:
|
|
484
|
+
let cleanValue = input.value;
|
|
485
|
+
if (this.element.classList.contains("decimal") || this.element.classList.contains("money"))
|
|
486
|
+
cleanValue = input.value.replace(/[$,]/g, "");
|
|
439
487
|
return {
|
|
440
|
-
value: this.element.classList.contains("decimal") || this.element.classList.contains("money") ? parseFloat(
|
|
488
|
+
value: this.element.classList.contains("decimal") || this.element.classList.contains("money") ? parseFloat(cleanValue) : cleanValue
|
|
441
489
|
};
|
|
442
490
|
}
|
|
443
491
|
}
|
|
@@ -580,9 +628,21 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
580
628
|
if (value instanceof Function) {
|
|
581
629
|
value = value();
|
|
582
630
|
}
|
|
631
|
+
let eventType;
|
|
632
|
+
if (this.element instanceof HTMLSelectElement) {
|
|
633
|
+
eventType = "change";
|
|
634
|
+
} else if (this.element instanceof HTMLInputElement) {
|
|
635
|
+
eventType = this.eventMapping[this.element.type] ?? "input";
|
|
636
|
+
} else if (this.element instanceof HTMLTextAreaElement) {
|
|
637
|
+
eventType = this.eventMapping[this.element.type] ?? "input";
|
|
638
|
+
} else {
|
|
639
|
+
eventType = "input";
|
|
640
|
+
}
|
|
641
|
+
this.element.dispatchEvent(new Event(eventType, { bubbles: false }));
|
|
583
642
|
if (this.element.classList.contains("boolean-radio") && this.yesRadio instanceof _DOMNodeReference && this.noRadio instanceof _DOMNodeReference) {
|
|
584
643
|
this.yesRadio.element.checked = value;
|
|
585
644
|
this.noRadio.element.checked = !value;
|
|
645
|
+
this.value = value;
|
|
586
646
|
} else {
|
|
587
647
|
this.element.value = value;
|
|
588
648
|
}
|
|
@@ -801,18 +861,127 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
801
861
|
}
|
|
802
862
|
return this;
|
|
803
863
|
}
|
|
864
|
+
/**
|
|
865
|
+
* Applies a business rule to manage visibility, required state, value, and disabled state dynamically.
|
|
866
|
+
*
|
|
867
|
+
* @param rule The business rule containing conditions for various actions.
|
|
868
|
+
* @param dependencies For re-evaluation conditions when the state of the dependencies change
|
|
869
|
+
* @returns Instance of this for method chaining.
|
|
870
|
+
*/
|
|
871
|
+
applyBusinessRule(rule, dependencies) {
|
|
872
|
+
try {
|
|
873
|
+
if (rule.setVisibility) {
|
|
874
|
+
const [condition, clearValuesOnHide = true] = rule.setVisibility;
|
|
875
|
+
const initialState = condition.bind(this)();
|
|
876
|
+
this.toggleVisibility(initialState);
|
|
877
|
+
if (dependencies.length) {
|
|
878
|
+
this._configDependencyTracking(
|
|
879
|
+
() => this.toggleVisibility(condition.bind(this)()),
|
|
880
|
+
dependencies,
|
|
881
|
+
{
|
|
882
|
+
clearValuesOnHide,
|
|
883
|
+
observeVisibility: true,
|
|
884
|
+
trackInputEvents: false,
|
|
885
|
+
trackRadioButtons: false
|
|
886
|
+
}
|
|
887
|
+
);
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
if (rule.setRequired) {
|
|
891
|
+
const [isRequired, isValid] = rule.setRequired;
|
|
892
|
+
const fieldDisplayName = (() => {
|
|
893
|
+
let label = this.getLabel();
|
|
894
|
+
if (!label)
|
|
895
|
+
return new Error(
|
|
896
|
+
`There was an error accessing the label for this element: ${String(
|
|
897
|
+
this.target
|
|
898
|
+
)}`
|
|
899
|
+
);
|
|
900
|
+
label = label.innerHTML;
|
|
901
|
+
if (label.length > 50) {
|
|
902
|
+
label = label.substring(0, 50) + "...";
|
|
903
|
+
}
|
|
904
|
+
return label;
|
|
905
|
+
})();
|
|
906
|
+
if (typeof Page_Validators === "undefined") {
|
|
907
|
+
throw new ValidationConfigError(this, "Page_Validators not found");
|
|
908
|
+
}
|
|
909
|
+
const validatorId = `${this.element.id}Validator`;
|
|
910
|
+
const newValidator = document.createElement("span");
|
|
911
|
+
newValidator.style.display = "none";
|
|
912
|
+
newValidator.id = validatorId;
|
|
913
|
+
Object.assign(newValidator, {
|
|
914
|
+
controltovalidate: this.element.id,
|
|
915
|
+
errormessage: `<a href='#${this.element.id}_label'>${fieldDisplayName} is a required field</a>`,
|
|
916
|
+
evaluationfunction: () => {
|
|
917
|
+
const isFieldRequired = isRequired.bind(this)();
|
|
918
|
+
const isFieldVisible = window.getComputedStyle(this.visibilityController).display !== "none";
|
|
919
|
+
return !isFieldRequired || !isFieldVisible || isValid.bind(this)(isRequired.bind(this));
|
|
920
|
+
}
|
|
921
|
+
});
|
|
922
|
+
Page_Validators.push(newValidator);
|
|
923
|
+
this.setRequiredLevel(isRequired.bind(this)());
|
|
924
|
+
this._configDependencyTracking(
|
|
925
|
+
() => this.setRequiredLevel(isRequired.bind(this)()),
|
|
926
|
+
dependencies,
|
|
927
|
+
{ clearValuesOnHide: false }
|
|
928
|
+
);
|
|
929
|
+
}
|
|
930
|
+
if (rule.setValue) {
|
|
931
|
+
const [condition, value] = rule.setValue;
|
|
932
|
+
if (condition.bind(this)()) {
|
|
933
|
+
this.setValue.bind(this)(value);
|
|
934
|
+
}
|
|
935
|
+
if (dependencies.length) {
|
|
936
|
+
this._configDependencyTracking(
|
|
937
|
+
() => {
|
|
938
|
+
if (condition.bind(this)()) {
|
|
939
|
+
this.setValue.bind(this)(value);
|
|
940
|
+
}
|
|
941
|
+
},
|
|
942
|
+
dependencies,
|
|
943
|
+
{ clearValuesOnHide: false }
|
|
944
|
+
);
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
if (rule.setDisabled) {
|
|
948
|
+
const [condition] = rule.setDisabled;
|
|
949
|
+
condition.bind(this)() ? this.disable() : this.enable();
|
|
950
|
+
if (dependencies.length) {
|
|
951
|
+
this._configDependencyTracking(
|
|
952
|
+
() => {
|
|
953
|
+
condition.bind(this)() ? this.enable() : this.disable();
|
|
954
|
+
},
|
|
955
|
+
dependencies,
|
|
956
|
+
{
|
|
957
|
+
clearValuesOnHide: false,
|
|
958
|
+
observeVisibility: true,
|
|
959
|
+
trackInputEvents: true,
|
|
960
|
+
trackRadioButtons: true
|
|
961
|
+
}
|
|
962
|
+
);
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
return this;
|
|
966
|
+
} catch (error) {
|
|
967
|
+
throw new ValidationConfigError(
|
|
968
|
+
this,
|
|
969
|
+
`Failed to apply business rule: ${error}`
|
|
970
|
+
);
|
|
971
|
+
}
|
|
972
|
+
}
|
|
804
973
|
/**
|
|
805
974
|
* Configures conditional rendering for the target element based on a condition
|
|
806
975
|
* and the visibility of one or more trigger elements.
|
|
807
|
-
*
|
|
808
|
-
* @param condition
|
|
976
|
+
* @deprecated Use the new 'applyBusinessRule Method
|
|
977
|
+
* @param condition A function that returns a boolean to determine
|
|
809
978
|
* the visibility of the target element. If `condition()` returns true, the element is shown;
|
|
810
979
|
* otherwise, it is hidden.
|
|
811
980
|
* @param dependencies - An array of `DOMNodeReference` instances. Event listeners are
|
|
812
981
|
* registered on each to toggle the visibility of the target element based on the `condition` and the visibility of
|
|
813
982
|
* the target node.
|
|
814
|
-
* @throws
|
|
815
|
-
* @returns
|
|
983
|
+
* @throws When there's an error in setting up conditional rendering
|
|
984
|
+
* @returns Instance of this [provides option to method chain]
|
|
816
985
|
*/
|
|
817
986
|
configureConditionalRendering(condition, dependencies, clearValuesOnHide = true) {
|
|
818
987
|
try {
|
|
@@ -846,13 +1015,13 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
846
1015
|
}
|
|
847
1016
|
/**
|
|
848
1017
|
* Sets up validation and requirement rules for the field with enhanced error handling and dynamic updates.
|
|
849
|
-
*
|
|
850
|
-
* @param isRequired
|
|
851
|
-
* @param isValid
|
|
852
|
-
* @param fieldDisplayName
|
|
853
|
-
* @param dependencies
|
|
854
|
-
* @returns
|
|
855
|
-
* @throws
|
|
1018
|
+
* @deprecated Use the new 'applyBusinessRule Method
|
|
1019
|
+
* @param isRequired Function determining if field is required
|
|
1020
|
+
* @param isValid Function validating field input
|
|
1021
|
+
* @param fieldDisplayName Display name for error messages
|
|
1022
|
+
* @param dependencies Fields that trigger requirement/validation updates
|
|
1023
|
+
* @returns Instance of this
|
|
1024
|
+
* @throws If validation setup fails
|
|
856
1025
|
*/
|
|
857
1026
|
configureValidationAndRequirements(isRequired, isValid, fieldDisplayName, dependencies) {
|
|
858
1027
|
if (!fieldDisplayName?.trim()) {
|
|
@@ -901,9 +1070,10 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
901
1070
|
/**
|
|
902
1071
|
* Sets up tracking for dependencies using both event listeners and mutation observers.
|
|
903
1072
|
* @private
|
|
904
|
-
* @param handler
|
|
905
|
-
* @param dependencies
|
|
906
|
-
* @param options
|
|
1073
|
+
* @param handler The function to execute when dependencies change
|
|
1074
|
+
* @param dependencies Array of dependent DOM nodes to track
|
|
1075
|
+
* @param options Additional configuration options. clearValuesOnHide defaults to false.
|
|
1076
|
+
* all other options defaults to true
|
|
907
1077
|
*/
|
|
908
1078
|
_configDependencyTracking(handler, dependencies, options = {
|
|
909
1079
|
clearValuesOnHide: false,
|
|
@@ -980,9 +1150,9 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
980
1150
|
/**
|
|
981
1151
|
* Sets the required level for the field by adding or removing the "required-field" class on the label.
|
|
982
1152
|
*
|
|
983
|
-
* @param isRequired
|
|
1153
|
+
* @param isRequired Determines whether the field should be marked as required.
|
|
984
1154
|
* If true, the "required-field" class is added to the label; if false, it is removed.
|
|
985
|
-
* @returns
|
|
1155
|
+
* @returns Instance of this [provides option to method chain]
|
|
986
1156
|
*/
|
|
987
1157
|
setRequiredLevel(isRequired) {
|
|
988
1158
|
if (isRequired instanceof Function) {
|
|
@@ -997,7 +1167,7 @@ var DOMNodeReference = class _DOMNodeReference {
|
|
|
997
1167
|
* Executes a callback function once the element is fully loaded.
|
|
998
1168
|
* If the element is already loaded, the callback is called immediately.
|
|
999
1169
|
* Otherwise, a MutationObserver is used to detect when the element is added to the DOM.
|
|
1000
|
-
* @param callback
|
|
1170
|
+
* @param callback A callback function to execute once the element is loaded.
|
|
1001
1171
|
* Receives instance of 'this' as an argument
|
|
1002
1172
|
*/
|
|
1003
1173
|
onceLoaded(callback) {
|
|
@@ -1104,25 +1274,62 @@ function createProxyHandler() {
|
|
|
1104
1274
|
}
|
|
1105
1275
|
};
|
|
1106
1276
|
}
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1277
|
+
|
|
1278
|
+
// src/bindForm.ts
|
|
1279
|
+
async function bindForm(formId) {
|
|
1280
|
+
try {
|
|
1281
|
+
const form = await API_default.getRecord("systemforms", formId);
|
|
1282
|
+
const { formxml } = form;
|
|
1283
|
+
const parser = new DOMParser();
|
|
1284
|
+
const xmlDoc = parser.parseFromString(formxml, "application/xml");
|
|
1285
|
+
const controls = processElements(xmlDoc.getElementsByTagName("control"));
|
|
1286
|
+
const sections = processElements(xmlDoc.getElementsByTagName("section"));
|
|
1287
|
+
const tabs = processElements(xmlDoc.getElementsByTagName("tab"));
|
|
1288
|
+
const resolvedRefs = await Promise.all([...controls, ...sections, ...tabs]);
|
|
1289
|
+
return enhanceArray(
|
|
1290
|
+
resolvedRefs.filter((ref) => ref !== null)
|
|
1291
|
+
);
|
|
1292
|
+
} catch (error) {
|
|
1293
|
+
if (error instanceof Error) {
|
|
1294
|
+
console.error(error.message);
|
|
1295
|
+
throw error;
|
|
1296
|
+
} else {
|
|
1297
|
+
console.error(error);
|
|
1298
|
+
throw new Error(String(error));
|
|
1120
1299
|
}
|
|
1121
|
-
}
|
|
1122
|
-
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
function processElements(element) {
|
|
1303
|
+
return Array.from(element).map((element2) => {
|
|
1304
|
+
const identifyingAttribute = getIdentifyingAttribute(element2.tagName);
|
|
1305
|
+
const datafieldname = element2.getAttribute(identifyingAttribute);
|
|
1306
|
+
if (!datafieldname) return null;
|
|
1307
|
+
const referenceString = createReferenceString(
|
|
1308
|
+
element2.tagName,
|
|
1309
|
+
datafieldname
|
|
1310
|
+
);
|
|
1311
|
+
if (!referenceString) return null;
|
|
1312
|
+
return createDOMNodeReference(referenceString).catch((error) => {
|
|
1313
|
+
console.warn(
|
|
1314
|
+
`Failed to create a reference to the form field: ${datafieldname}`,
|
|
1315
|
+
error
|
|
1316
|
+
);
|
|
1317
|
+
return null;
|
|
1318
|
+
});
|
|
1319
|
+
}).filter(Boolean);
|
|
1320
|
+
}
|
|
1321
|
+
function getIdentifyingAttribute(tagName) {
|
|
1322
|
+
return tagName === "control" ? "id" : tagName === "tab" || tagName === "section" ? "name" : "id";
|
|
1323
|
+
}
|
|
1324
|
+
function createReferenceString(tagName, datafieldname) {
|
|
1325
|
+
if (tagName === "control") return `#${datafieldname}`;
|
|
1326
|
+
if (tagName === "tab" || tagName === "section")
|
|
1327
|
+
return `[data-name="${datafieldname}"]`;
|
|
1328
|
+
return null;
|
|
1123
1329
|
}
|
|
1124
1330
|
export {
|
|
1125
1331
|
API_default as API,
|
|
1332
|
+
bindForm,
|
|
1126
1333
|
createDOMNodeReference as createRef,
|
|
1127
1334
|
waitFor
|
|
1128
1335
|
};
|
|
@@ -1,11 +1,36 @@
|
|
|
1
|
+
import { DOMNodeReferenceArray } from "./DOMNodeReferenceArray.js";
|
|
1
2
|
import DOMNodeReference from "./DOMNodeReference.js";
|
|
2
|
-
|
|
3
|
-
|
|
3
|
+
interface ICreationOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Should this call return an array of instantiated references, or just a single?
|
|
6
|
+
* Defaults to false, returning a single instance.
|
|
7
|
+
*/
|
|
8
|
+
multiple?: (() => boolean) | boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Optionally specify the element within which to search for the element targeted by 'target'.
|
|
11
|
+
* Defaults to 'document.body'.
|
|
12
|
+
*/
|
|
4
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
|
+
*/
|
|
5
19
|
timeout?: number;
|
|
20
|
+
}
|
|
21
|
+
export default function createDOMNodeReference(target: Element, options?: ICreationOptions): Promise<DOMNodeReference>;
|
|
22
|
+
export default function createDOMNodeReference(target: string, options?: Omit<ICreationOptions, "multiple"> & {
|
|
23
|
+
/**
|
|
24
|
+
* Should this call return an array of instantiated references, or just a single instance?
|
|
25
|
+
* Defaults to false, returning a single instance.
|
|
26
|
+
*/
|
|
27
|
+
multiple?: false;
|
|
6
28
|
}): Promise<DOMNodeReference>;
|
|
7
|
-
export default function createDOMNodeReference(target: string, options?: {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
29
|
+
export default function createDOMNodeReference(target: string, options?: Omit<ICreationOptions, "multiple"> & {
|
|
30
|
+
/**
|
|
31
|
+
* Should this call return an array of instantiated references, or just a single instance?
|
|
32
|
+
* Defaults to false, returning a single instance.
|
|
33
|
+
*/
|
|
34
|
+
multiple?: true;
|
|
35
|
+
}): Promise<DOMNodeReferenceArray>;
|
|
36
|
+
export {};
|
package/dist/index.d.ts
CHANGED
package/dist/waitFor.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export default function waitFor(target:
|
|
2
|
-
export default function waitFor(target:
|
|
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.
|
|
3
|
+
"version": "2.7.0",
|
|
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",
|