PageSourceSearch

https://www.wijzijnde.it/App_Plugins/PanoramaStudiosForms/logic/conditionals.js

js wijzijnde.it collected 2026-10-04 15:44:39 UTC 8,323 bytes, 297 lines download raw bytes

1class PsFormsConditionalLogic {
2	constructor(root = document) {
3		this.root = root;
4		this.conditionalFields = Array.from(
5			this.root.querySelectorAll("[data-psforms-conditional]")
6		);
7	}
8
9	init() {
10		if (!this.conditionalFields.length) return;
11		this.storeInitialRequiredState();
12		this.bindInputs();
13		this.evaluateAll();
14	}
15
16	storeInitialRequiredState() {
17		const inputs = this.root.querySelectorAll("input, select, textarea");
18
19		inputs.forEach((input) => {
20			input.dataset.psformsOriginallyRequired = input.required ? "true" : "false";
21		});
22	}
23
24	bindInputs() {
25		const sourceFields = Array.from(
26			this.root.querySelectorAll("[data-condition-key]")
27		);
28
29		sourceFields.forEach((fieldWrapper) => {
30			const inputs = fieldWrapper.querySelectorAll("input, select, textarea");
31
32			inputs.forEach((input) => {
33				input.addEventListener("change", () => this.evaluateAll());
34
35				if (this.shouldListenToInput(input)) {
36					input.addEventListener("input", () => this.evaluateAll());
37				}
38			});
39		});
40	}
41
42	shouldListenToInput(input) {
43		const tag = input.tagName.toLowerCase();
44		const type = (input.getAttribute("type") || "").toLowerCase();
45
46		if (tag === "textarea") return true;
47		if (tag === "select") return false;
48		if (type === "radio" || type === "checkbox") return false;
49
50		return true;
51	}
52
53	evaluateAll() {
54		this.conditionalFields.forEach((targetField) => {
55			this.evaluateField(targetField);
56		});
57	}
58
59	evaluateField(targetField) {
60		const rawConfig = targetField.dataset.psformsConditional;
61		if (!rawConfig) return;
62
63		let config;
64
65		try {
66			config = JSON.parse(rawConfig);
67		} catch {
68			return;
69		}
70
71		const results = (config.conditions || []).map((condition) =>
72			this.evaluateCondition(condition)
73		);
74
75		const matched = config.match === "any"
76			? results.some(Boolean)
77			: results.every(Boolean);
78
79		const shouldShow = config.action === "show" ? matched : !matched;
80
81		this.applyVisibility(targetField, shouldShow);
82	}
83
84	evaluateCondition(condition) {
85		const sourceField = this.root.querySelector(
86			`[data-condition-key="${CSS.escape(condition.field)}"]`
87		);
88
89		if (!sourceField) return false;
90
91		const currentValue = this.getFieldValue(sourceField);
92		const expectedValue = condition.value ?? "";
93		const operator = condition.matchOperator ?? condition.operator ?? "";
94
95		return this.compareValues(currentValue, operator, expectedValue, sourceField);
96	}
97
98	getFieldValue(fieldWrapper) {
99		const inputs = Array.from(
100			fieldWrapper.querySelectorAll("input, select, textarea")
101		);
102
103		if (!inputs.length) return "";
104
105		const radios = inputs.filter((input) => input.type === "radio");
106		if (radios.length) {
107			const checked = radios.find((radio) => radio.checked);
108			return checked ? checked.value : "";
109		}
110
111		const checkboxes = inputs.filter((input) => input.type === "checkbox");
112		if (checkboxes.length) {
113			if (checkboxes.length === 1) {
114				return checkboxes[0].checked ? "true" : "false";
115			}
116
117			return checkboxes
118				.filter((checkbox) => checkbox.checked)
119				.map((checkbox) => checkbox.value);
120		}
121
122		const select = inputs.find((input) => input.tagName.toLowerCase() === "select");
123		if (select) {
124			return select.value ?? "";
125		}
126
127		const textarea = inputs.find((input) => input.tagName.toLowerCase() === "textarea");
128		if (textarea) {
129			return textarea.value ?? "";
130		}
131
132		return inputs[0].value ?? "";
133	}
134
135	compareValues(currentValue, operator, expectedValue, sourceField = null) {
136		if (Array.isArray(currentValue)) {
137			return this.compareArrayValues(currentValue, operator, expectedValue);
138		}
139
140		const actual = String(currentValue ?? "");
141		const expected = String(expectedValue ?? "");
142
143		switch (operator) {
144			case "eq":
145				return actual === expected;
146			case "neq":
147				return actual !== expected;
148			case "gt": {
149				if (this.isDateField(sourceField)) {
150					const actualDate = this.toDateValue(actual);
151					const expectedDate = this.toDateValue(expected);
152
153					if (actualDate === null || expectedDate === null) return false;
154					return actualDate > expectedDate;
155				}
156
157				const actualNumber = this.toNumber(actual);
158				const expectedNumber = this.toNumber(expected);
159
160				if (actualNumber === null || expectedNumber === null) return false;
161				return actualNumber > expectedNumber;
162			}
163
164			case "lt": {
165				if (this.isDateField(sourceField)) {
166					const actualDate = this.toDateValue(actual);
167					const expectedDate = this.toDateValue(expected);
168
169					if (actualDate === null || expectedDate === null) return false;
170					return actualDate < expectedDate;
171				}
172
173				const actualNumber = this.toNumber(actual);
174				const expectedNumber = this.toNumber(expected);
175
176				if (actualNumber === null || expectedNumber === null) return false;
177				return actualNumber < expectedNumber;
178			}
179			case "contains_cs":
180				return actual.includes(expected);
181			case "contains_ci":
182				return actual.toLowerCase().includes(expected.toLowerCase());
183			case "starts_cs":
184				return actual.startsWith(expected);
185			case "starts_ci":
186				return actual.toLowerCase().startsWith(expected.toLowerCase());
187			case "ends_cs":
188				return actual.endsWith(expected);
189			case "ends_ci":
190				return actual.toLowerCase().endsWith(expected.toLowerCase());
191			case "not_contains_cs":
192				return !actual.includes(expected);
193			case "not_contains_ci":
194				return !actual.toLowerCase().includes(expected.toLowerCase());
195			case "not_starts_cs":
196				return !actual.startsWith(expected);
197			case "not_starts_ci":
198				return !actual.toLowerCase().startsWith(expected.toLowerCase());
199			case "not_ends_cs":
200				return !actual.endsWith(expected);
201			case "not_ends_ci":
202				return !actual.toLowerCase().endsWith(expected.toLowerCase());
203			default:
204				return false;
205		}
206	}
207
208	compareArrayValues(currentValues, operator, expectedValue) {
209		switch (operator) {
210			case "contains_cs":
211				return currentValues.includes(expectedValue);
212			case "contains_ci":
213				return currentValues.some(
214					(value) => value.toLowerCase() === expectedValue.toLowerCase()
215				);
216			case "not_contains_cs":
217				return !currentValues.includes(expectedValue);
218			case "not_contains_ci":
219				return !currentValues.some(
220					(value) => value.toLowerCase() === expectedValue.toLowerCase()
221				);
222			case "eq":
223				return currentValues.length === 1 && currentValues[0] === expectedValue;
224			case "neq":
225				return !(currentValues.length === 1 && currentValues[0] === expectedValue);
226			default:
227				return false;
228		}
229	}
230
231	applyVisibility(field, shouldShow) {
232		field.hidden = !shouldShow;
233		field.classList.toggle("psforms-conditionally-hide", !shouldShow);
234		field.classList.toggle("psforms-conditionally-show", shouldShow);
235
236		const inputs = field.querySelectorAll("input, select, textarea");
237
238		inputs.forEach((input) => {
239			if (shouldShow) {
240				input.disabled = false;
241				input.required = input.dataset.psformsOriginallyRequired === "true";
242			} else {
243				input.required = false;
244				input.disabled = true;
245			}
246		});
247	}
248
249	toNumber(value) {
250		if (value === null || value === undefined) return null;
251
252		const trimmed = String(value).trim();
253		if (trimmed === "") return null;
254
255		const parsed = Number(trimmed);
256		return Number.isNaN(parsed) ? null : parsed;
257	}
258
259	isDateField(fieldWrapper) {
260		if (!fieldWrapper) return false;
261
262		const dateInput = fieldWrapper.querySelector('input[type="date"]');
263		return !!dateInput;
264	}
265
266	toDateValue(value) {
267		if (value === null || value === undefined) return null;
268
269		const trimmed = String(value).trim();
270		if (trimmed === "") return null;
271
272		const parts = trimmed.split("-");
273		if (parts.length !== 3) return null;
274
275		const year = Number(parts[0]);
276		const month = Number(parts[1]);
277		const day = Number(parts[2]);
278
279		if (!year || !month || !day) return null;
280
281		const date = new Date(year, month - 1, day);
282
283		if (
284			date.getFullYear() !== year ||
285			date.getMonth() !== month - 1 ||
286			date.getDate() !== day
287		) {
288			return null;
289		}
290
291		return date.getTime();
292	}
293}
294
295document.addEventListener("DOMContentLoaded", () => {
296	new PsFormsConditionalLogic().init();
297});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.