PageSourceSearch

https://askjan.org/commonspot/metadata/form_control/show_hide_common.js

js askjan.org collected 2026-10-01 08:35:20 UTC 16,522 bytes, 545 lines download raw bytes

1function getField(val,byName,byID)
2{
3	"use strict";
4	// we could use $ but when rendered in a simple form we may not have prototype on page.
5	if (byName && val)
6		return document.getElementsByName(val);
7	else if (byID && val)
8		return document.getElementById(val);
9	else
10		return null;
11}
12
13function getFieldValue(fieldName)
14{
15	"use strict";
16	var fieldVal = '';
17	var fld = getField(fieldName,0,1);
18	if (fld.type == 'select-one' && fld.selectedIndex >= 0)
19	{
20		fieldVal = fld.options[fld.selectedIndex].value;
21		if (fld.options[fld.selectedIndex].text == '--Select--')
22			fieldVal = '{{select}}';
23		else if (fld.options[fld.selectedIndex].text == 'Other...')
24			fieldVal = '{{other}}';
25	}
26	return fieldVal.toLowerCase();
27}
28
29function getFieldText(fieldName)
30{
31	"use strict";
32	var fieldVal = '';
33	var fld = getField(fieldName,0,1);
34	if (fld.type == 'select-one' && fld.selectedIndex >= 0)
35	{
36		fieldVal = fld.options[fld.selectedIndex].text;
37	}
38	return fieldVal.toLowerCase();
39}
40
41function getFieldContainer(fieldID)
42{
43	"use strict";
44	return document.getElementById(fieldID + '_container');
45}
46function getFieldLabelContainer(fieldID)
47{
48	"use strict";
49	return document.getElementById(fieldID + '_label');
50}
51
52
53// local util
54// commonspot.util.css.addRemoveClassNameByIDs depends on $, not available here, also requires hard coding required indicator id variant here, as well as in getFieldLabelContainer
55function addRemoveClass(objOrObjIdsList, className, add)
56{
57	"use strict";
58	var aObj = (typeof objOrObjIdsList === 'string') ? objOrObjIdsList.split(',') : [objOrObjIdsList];
59	var re = new RegExp('(^|\\s)' + className + '(\\s|$)');
60	var obj, i;
61	for (i = 0; i < aObj.length; i++)
62	{
63		obj = (typeof aObj[i] === 'string') ? document.getElementById(objOrID) : aObj[i];
64		if (!obj)
65			continue;
66		if (!add)
67			obj.className = obj.className.replace(re, addRemoveClass.removeFn);
68		else if (!obj.className.match(re))
69			obj.className = (obj.className ? obj.className + ' ' + className : className);
70	}
71}
72addRemoveClass.removeFn = function(matchedStr, leadingWhiteSpace, trailingWhiteSpace)
73{
74	"use strict";
75	return (leadingWhiteSpace && trailingWhiteSpace) ? ' ' : '';
76};
77
78
79function setFieldVisible(fieldID, show)
80{
81	"use strict";
82	var display = show ? '' : 'none';
83	var obj;
84
85	obj = getFieldContainer(fieldID);
86	if (obj) // may not exist if there's a custom display template
87		obj.style.display = display;
88	else
89		logMissingObject('[setFieldVisible(' + show + ')] Field container not found for fieldID ' + fieldID);
90	// dmerrill 2017-03-17: description is now inside field container, don't have to hide it separately
91}
92
93function setFieldRequired(fieldID, required)
94{
95	"use strict";
96	var obj = document.getElementById(fieldID)
97	var objs, i;
98	required = !!required;
99
100	// if required, make sure it's visible
101	if (required)
102		setFieldVisible(fieldID, true);
103
104	// field itself
105	if (obj) // not there for multiples
106	{
107		if (notEditable(obj))
108			return;
109		setElementRequired(obj, required);
110	}
111	else // look for multiple objs by name
112	{
113		objs = document.getElementsByName(fieldID);
114		if (objs[0] && notEditable(objs[0]))
115			return;
116		for (i = 0; i < objs.length; i++)
117			setElementRequired(objs[i], required);
118	}
119
120	// required indicator
121	obj = document.getElementById(fieldID + '_required');
122	if (obj)
123	{
124		obj.innerHTML = required ? obj.getAttribute('data-cs-required-msg') : '';
125		obj.title = required ? 'This field is required.' : '';
126	}
127
128	// label class
129	obj = getFieldLabelContainer(fieldID);
130	addRemoveClass(obj, 'CS_Form_Required', required);
131}
132
133function setElementRequired(obj, required)
134{
135	"use strict";
136	if (!obj) // may not exist if there's a custom display template
137	{
138		logMissingObject('[setElementRequired(' + required + ')] Field container not found for fieldID ' + fieldID);
139		return;
140	}
141	obj.setAttribute('aria-required', required);
142	// as of 2014-11-12, setting actual required attribute invokes browser's validation appearance etc, but implementation is still too inconsistent, don't go there
143	//obj.setAttribute('required', required);
144}
145
146function notEditable(obj)
147{
148	"use strict";
149	return (obj.getAttribute('readOnly') !== null || obj.getAttribute('disabled') !== null);
150}
151
152// this gets called if an object we expect to exist doesn't, which happens in custom display templates, since the normal form layout furniture isn't there
153// no error is reported in the js console, and the idea of this function is to make these events visible to a dev who chooses to look
154function logMissingObject(msg)
155{
156	if (console && console.log)
157		console.log(msg);
158}
159			
160function updDisplayStateForFields(fieldStates, jsFieldsStruct, isSimpleForm)
161{
162	"use strict";
163	var i;
164
165	if (fieldStates.errorMsg == '')
166	{
167		for (i = 0; i < fieldStates.hidden.length; i++)
168			setFieldVisible(fieldStates.hidden[i], false);
169
170		for (i = 0; i < fieldStates.show.length; i++)
171		{
172			setFieldVisible(fieldStates.show[i], true);
173			setFieldRequired(fieldStates.show[i], (fieldStates.required.indexOf(fieldStates.show[i]) >= 0));
174		}
175
176		for (i = 0; i < fieldStates.required.length; i++)
177			setFieldRequired(fieldStates.required[i], true);
178	}
179	else
180		alert('ERROR: ' + fieldStates.errorMsg);
181	
182	if (typeof ResizeWindow == 'function')
183		ResizeWindow();
184}
185
186/*
187	checks field rules for circular references
188	rtns error msg if a circular reference is detected, else empty str
189
190	in real life we'd do this on load, not in calcFieldStates, alert the user and close the form if there's a problem
191	but really, it needs to be done on the server when you save each field's configuration, disallow it
192		so optimistically we don't need to check on the client at all
193		can lock up the browser though, so maybe we should check there too
194	this code can serve as a model for how to write this in cf
195*/
196function checkRulesForCircularReferences(jsFieldsStruct)
197{
198	"use strict";
199	var rules = jsFieldsStruct.rules;
200	var fields = jsFieldsStruct.fields;
201	var fieldCount = fields.length;
202	var directEffects = {},
203		maxIterations = ((fieldCount + 1) * 2) + 1, // used by checkField to detect excessive iteration, likely an infinite loop
204		checkResult = '',
205		fieldName, iterationCount;
206	
207	// build object with key for every field that has rules, whose values are an object w a key for every field it affects
208	for (fieldName in rules)
209	{
210		if (rules.hasOwnProperty(fieldName))
211			directEffects[fieldName] = getDirectEffects(fieldName, rules);
212	}
213
214	// check each field with effects for circular references
215	for (fieldName in directEffects)
216	{
217		if (directEffects.hasOwnProperty(fieldName))
218		{
219			iterationCount = 0; // used by checkField to detect excessive iteration, likely an infinite loop
220			checkResult = checkField(fieldName, directEffects);
221			if (checkResult !== '')
222				break;
223		}
224	}
225	return checkResult;
226
227
228	// PRIVATE HELPER METHODS
229
230	// checks one field for circular references in its rules and those of fields it affects
231	function checkField(fieldName, directEffects, ancestors)
232	{
233		"use strict";
234		if (iterationCount++ > maxIterations)
235			return getCheckFieldErrorMsg(fieldName, 'Too many iterations');
236	
237		ancestors = ancestors || [];
238	
239		if (ancestors.indexOf(fieldName) >= 0)
240			return getCheckFieldErrorMsg(fieldName);
241		ancestors.push(fieldName);
242		
243		var effects = directEffects[fieldName] || [],
244			effectsCount = effects.length,
245			checkResult = '',
246			i;
247		
248		for (i = 0; i < effectsCount; i++)
249		{
250			checkResult = checkField(effects[i], directEffects, ancestors);
251			if (checkResult !== '')
252				break;
253		}
254		ancestors.pop();
255		return checkResult;
256	}
257
258	// returns an array of the fields this field's rules affect directly
259	function getDirectEffects(fieldName, rules)
260	{
261		"use strict";
262		var RULE_PARAM_NAMES = ['hide', 'require'],
263			RULE_PARAMS_COUNT = RULE_PARAM_NAMES.length,
264			effects = [],
265			fieldValue, rule, paramN, param, ruleFieldN, ruleField;
266
267		for (fieldValue in rules[fieldName])
268		{
269			if (rules[fieldName].hasOwnProperty(fieldValue))
270			{
271				rule = rules[fieldName][fieldValue];
272				for (paramN = 0; paramN < RULE_PARAMS_COUNT; paramN++)
273				{
274					param = RULE_PARAM_NAMES[paramN];
275					if (rule.hasOwnProperty(param))
276					{
277						for (ruleFieldN = 0; ruleFieldN < rule[param].length; ruleFieldN++)
278						{
279							ruleField = rule[param][ruleFieldN];
280							if (effects.indexOf(ruleField) === -1)
281								effects.push(ruleField);
282						}
283					}
284				}
285			}
286		}
287		return effects;
288	}
289
290	function getCheckFieldErrorMsg(fieldName, unexpectedErrorMsg)
291	{
292		"use strict";
293		var fld = getField(fieldName,1,0);
294		var errFldLabel = '';
295		var fldLabel = '';
296		if (fld[0].type != 'checkbox')
297		{
298			fldLabel = getField(fieldName + '_label',0,1);
299			
300			if (fldLabel == null)
301				fldLabel = getField(fieldName + '_LABEL',0,1);
302			if (typeof fldLabel == 'object' && fldLabel != null)
303			{
304				errFldLabel = fldLabel.innerHTML;
305			}
306		}
307		if (errFldLabel.length > 0)
308			errFldLabel = errFldLabel.slice(0, errFldLabel.length - 1);
309		if (unexpectedErrorMsg)
310			return '[checkRulesForCircularReferences.checkField] ' + unexpectedErrorMsg + ' for ' + errFldLabel;
311		return 'Apparent circular reference in show-hide field rules: ' + errFldLabel;
312	}
313}
314
315
316/*
317	shim version of Array.indexOf() for IE < 9
318	reformatted slightly minimal version of code here:
319		https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf
320*/
321if (!Array.prototype.indexOf)
322{
323	Array.prototype.indexOf = function (value, fromIndex)
324	{
325		var length = this.length >>> 0; // Hack to convert object.length to a UInt32
326
327		fromIndex = +fromIndex || 0;
328		if (Math.abs(fromIndex) === Infinity)
329			fromIndex = 0;
330		if (fromIndex < 0)
331		{
332			fromIndex += length;
333			if (fromIndex < 0)
334				fromIndex = 0;
335		}
336
337		for (; fromIndex < length; fromIndex++)
338		{
339			if (this[fromIndex] === value)
340				return fromIndex;
341		}
342
343		return -1;
344	};
345}
346
347
348/*
349	returns an object with hidden and required members, which are arrays of field names
350	returned object also contains an errorMsg string, non-empty if result can't be calculated, probably because of circular dependencies
351*/
352function calcFieldStates(jsFieldsStruct, isSimpleForm)
353{
354	"use strict";
355	var result = {hidden: [], required: [], show: [], errorMsg: ''};
356	var fields = jsFieldsStruct.fields;
357	var selectFields = jsFieldsStruct.selectfields;
358	var rules = jsFieldsStruct.rules;
359	var fieldCount = fields.length;
360	var selectFieldCount = selectFields.length;
361	var maxIterations = ((fieldCount + 1) * 2) + 1; // TODO: is this right? hope it's not really fieldCount factorial...
362	
363	var done = false;
364	var iterations = 0;
365	var fieldName, fieldValue, fieldText, hidden, required, show, fieldN;
366	
367	// build object w all dynamic rules that apply for current field values, keyed by sponsoring field's name
368	// each rule also has fields indicating hidden and required states of sponsoring field on the last calculation iteration
369	var activeRules = {};
370	
371	for (fieldN = 0; fieldN < selectFieldCount; fieldN++)
372	{
373		fieldName = selectFields[fieldN];
374		fieldValue = getFieldValue(fieldName);
375		fieldText = getFieldText(fieldName);
376		
377		// Handling special case here when source is ce for a selection list
378		if (rules[fieldName] && rules[fieldName][fieldValue] && 
379			(rules[fieldName][fieldValue].displayvalue.toLowerCase() == fieldText || rules[fieldName][fieldValue].displayvalue.toLowerCase() == '{{valueselected}}'))
380		{
381			activeRules[fieldName] =
382			{
383				hide: rules[fieldName][fieldValue].hide || [],
384				require: rules[fieldName][fieldValue].require || [],
385				hidden: false,
386				required: false
387			};
388		}
389	}
390	
391	// examine rules for ones that are indirectly disabled, keep looking as long as new implications are found
392	// maxIterations check is theoretically not needed if there aren't any circular references, still seems wise
393	while (!done && iterations++ < maxIterations)
394	{
395		done = true; // unless we find new info during this iterations, we're done
396		for (fieldName in activeRules)
397		{
398			if (activeRules.hasOwnProperty(fieldName))
399			{
400				hidden = isHidden(fieldName, activeRules);
401				required = isRequired(fieldName, activeRules);
402
403				if (activeRules[fieldName].hidden !== hidden)
404				{
405					activeRules[fieldName].hidden = hidden;
406					done = false;
407				}
408				if (activeRules[fieldName].required !== required)
409				{
410					activeRules[fieldName].required = required;
411					done = false;
412				}
413			}
414		}
415	}
416	
417	// check if we're here because we bailed out after too many iterations
418	if (iterations >= maxIterations)
419		return 'Apparent circular reference in dynamic field rules, stopped after ' + maxIterations + ' iterations.';
420	
421	// build result object and return it
422	for (fieldN = 0; fieldN < fieldCount; fieldN++)
423	{
424		fieldName = fields[fieldN];
425		if (isRequired(fieldName, activeRules))
426			result.required.push(fieldName);
427		else if (isHidden(fieldName, activeRules))
428			result.hidden.push(fieldName);
429		else if (isShown(fieldName, activeRules))
430			result.show.push(fieldName);
431	}
432
433	updDisplayStateForFields(result, jsFieldsStruct, isSimpleForm);
434	return result;
435
436
437	// functions to return whether given field should be hidden or required, based on currently active rules
438	function isHidden(fieldName, activeRules)
439	{
440		"use strict";
441		var hidden = false,
442			ruleFieldName;
443		for (ruleFieldName in activeRules)
444		{
445			if (activeRules.hasOwnProperty(ruleFieldName))
446			{
447				if (!activeRules[ruleFieldName].hidden)
448				{
449					if (activeRules[ruleFieldName].require.indexOf(fieldName) >= 0)
450						return false;
451					if (activeRules[ruleFieldName].hide.indexOf(fieldName) >= 0)
452						hidden = true;
453				}
454			}
455		}
456		return hidden;
457	}
458	function isRequired(fieldName, activeRules)
459	{
460		"use strict";
461		var ruleFieldName;
462		for (ruleFieldName in activeRules)
463		{
464			if (activeRules.hasOwnProperty(ruleFieldName))
465			{
466				if (!activeRules[ruleFieldName].hidden)
467				{
468					if (activeRules[ruleFieldName].require.indexOf(fieldName) >= 0)
469						return true;
470				}
471			}
472		}
473		return false;
474	}
475	function isShown(fieldName, activeRules)
476	{
477		"use strict";
478		var ruleFieldName;
479		for (ruleFieldName in activeRules)
480		{
481			if (activeRules.hasOwnProperty(ruleFieldName))
482			{
483				if (!activeRules[ruleFieldName].hidden)
484				{
485					if (activeRules[ruleFieldName].require.indexOf(fieldName) >= 0)
486						return false;
487					if (activeRules[ruleFieldName].hide.indexOf(fieldName) >= 0)
488						return false;
489				}
490			}
491		}
492		return true;
493	}
494}
495
496function formOnLoadHandler(jsFieldsStruct, isSimpleForm)
497{
498	"use strict";
499	var result = {errorMsg: ''};
500	result.errorMsg = checkRulesForCircularReferences(jsFieldsStruct);												
501	if (result.errorMsg != '')
502	{
503		updDisplayStateForFields(result, jsFieldsStruct, isSimpleForm);
504		CloseWindow();
505	}
506	else
507		calcFieldStates(jsFieldsStruct, isSimpleForm);
508}
509
510function removeDuplicatesFromValList(valueList,doTrim)
511{
512	"use strict";
513	valueList = valueList.replace(/[\s,]+$|^[\s,]+/g, ''); // remove leading and trailing runs consisting only of commas and whitespace
514	if (valueList.length === 0)
515		return '';
516	var uniqueValuesArrayOrigCase = [];
517	var uniqueValuesArrLowerCase = [];
518	var joinStr = valueList.match(/[\r\n]/) ? ',\n' : ','; // if there ar any CRs or LFs left, put a newline after every comma
519	var valueListArray = valueList.split(/[,\r\n]+/);
520	for (var i = 0; i < valueListArray.length; i++)
521	{
522		var compareValue = valueListArray[i];
523		if (doTrim === 1) // currently 1 always
524			compareValue = compareValue.trim();
525		var compareValueLC = compareValue.toLowerCase();
526		if (uniqueValuesArrLowerCase.indexOf(compareValueLC) === -1)
527		{
528			uniqueValuesArrLowerCase.push(compareValueLC);
529			uniqueValuesArrayOrigCase.push(compareValue);
530		}
531	}
532	return uniqueValuesArrayOrigCase.join(joinStr);
533}
534
535function resizeTextarea(textareaID, action, increment, minRows, maxRows)
536{
537	increment = increment || 4;
538	if (action === 'smaller')
539		increment = -increment;
540	minRows = minRows || 4;
541	maxRows = maxRows || 40;
542	var ta = document.getElementById(textareaID);
543	ta.rows = Math.max(Math.min(ta.rows + increment, maxRows), minRows);
544	checkFrameSize();
545}

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.