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.