1(function($) { 2 $.fxbConditions = function(el, options) { 3 this.el = el; 4 this.$el = $(el); 5 this.options = $.extend({}, $.fxbConditions.defaultOptions, options); 6 }, 7 $.fxbConditions.parse = function (formId) { 8 var $form = $(formId); 9 $form.init_formConditions(); 10 }, 11 12 $.extend($.fxbConditions, 13 { 14 defaultOptions: { 15 fieldConditions: [], 16 animate: true 17 }, 18 19 helpers: { 20 normalize: function(value, preserveCase) { 21 if (value == null) { 22 return ""; 23 } 24 25 return preserveCase ? String(value) : String(value).toLowerCase(); 26 }, 27 28 toNumber: function(value) { 29 value = Number(value); 30 return isNaN(value) ? undefined : value; 31 }, 32 33 indexOf: function(str, value, startIndex, preserveCase) { 34 str = this.normalize(str, preserveCase); 35 value = this.normalize(value, preserveCase); 36 37 return str.indexOf(value, startIndex); 38 }, 39 40 endsWith: function(str, value, preserveCase) { 41 str = this.normalize(str, preserveCase); 42 value = this.normalize(value, preserveCase); 43 44 var lengthDiff = str.length - value.length; 45 return lengthDiff >= 0 && str.substring(lengthDiff) === value; 46 } 47 }, 48 49 actions: { 50 show: function($target) { 51 if (this.loaded && this.options.animate) { 52 if ($target.is(":hidden")) { 53 var $self = this; 54 $target.slideDown(function () { 55 $self.setRequired($target); 56 }); 57 58 return; 59 } 60 } else { 61 $target.show(); 62 } 63 64 this.setRequired($target); 65 }, 66 67 hide: function($target) { 68 if (this.loaded && this.options.animate) { 69 if ($target.is(":visible")) { 70 var $self = this; 71 $target.slideUp(function() { 72 $self.setRequired($target); 73 }); 74 75 return; 76 } 77 } else { 78 $target.hide(); 79 } 80 81 this.setRequired($target); 82 }, 83 84 enable: function($target) { 85 if ($target.is("input,select,textarea,button")) { 86 $target.prop("disabled", false); 87 this.setRequired($target); 88 $('[data-valmsg-for="' + $target.prop("name") + '"]').show(); 89 } 90 }, 91 92 disable: function($target) { 93 if ($target.is("input,select,textarea,button")) { 94 $target.prop("disabled", true); 95 this.setRequired($target); 96 $('[data-valmsg-for="' + $target.prop("name") + '"]').hide(); 97 } 98 }, 99 100 "go to page": function($target, action, conditionsResult) { 101 $target.each(function(idx, target) { 102 if (target.name && 103 target.name.length && 104 $(target).is("input[type='submit'], button[type='submit']")) { 105 var $nextPageEl = this.$el.find("[name=\"" + target.name + "\"][data-sc-next-page]"); 106 if (!$nextPageEl.length) { 107 if (conditionsResult && action.value) { 108 var $currentEl = this.$el.find("[name=\"" + target.name + "\"]"); 109 $('<input>').attr({ 110 type: 'hidden', 111 name: target.name, 112 value: action.value, 113 'data-sc-next-page': "" 114 }).insertAfter($currentEl.last()); 115 } 116 117 return; 118 } 119 120 var value = action.value; 121 if (!conditionsResult) { 122 value = $nextPageEl.data("sc-next-page"); 123 124 for (var i = (this.executedActions.length - 1); i >= 0; i--) { 125 var prevAction = this.executedActions[i]; 126 if (prevAction.fieldId === action.fieldId && 127 prevAction.conditionsResult && 128 prevAction.actionType.toLowerCase() === "go to page") { 129 value = prevAction.value; 130 break; 131 } 132 } 133 } 134 135 $nextPageEl.val(value); 136 $nextPageEl.prop("disabled", !value); 137 } 138 }.bind(this)); 139 }, 140 141 // action pairs used for finding the opposite action to execute when conditions are not satisfied 142 actionLinks: { 143 show: "hide", 144 enable: "disable", 145 "go to page": "go to page" 146 }, 147 148 addAction: function(actionName, actionFn, oppositeActionName, oppositeActionFn) { 149 if (actionName && actionName.length) { 150 actionName = actionName.toLowerCase(); 151 152 this[actionName] = actionFn; 153 154 if (arguments.length === 2) { 155 return; 156 } 157 158 if (oppositeActionName && oppositeActionName.length) { 159 oppositeActionName = oppositeActionName.toLowerCase(); 160 161 this.actionLinks[actionName] = oppositeActionName; 162 if (arguments.length > 3) { 163 this[oppositeActionName] = oppositeActionFn; 164 } 165 } else { 166 delete this.actionLinks[actionName]; 167 } 168 } 169 }, 170 171 getAction: function(actionName, conditionsResult) { 172 if (actionName && actionName.length) { 173 actionName = actionName.toLowerCase(); 174 175 if (conditionsResult) { 176 return this[actionName]; 177 } 178 179 if (this.actionLinks.hasOwnProperty(actionName)) { 180 var oppositeActionName = this.actionLinks[actionName]; 181 return this[oppositeActionName]; 182 } else { 183 for (var property in this.actionLinks) { 184 if (this.actionLinks.hasOwnProperty(property) && 185 this.actionLinks[property] === actionName) { 186 return this[property]; 187 } 188 } 189 } 190 } 191 192 return this[actionName]; 193 } 194 }, 195 196 operators: { 197 "contains": function(conditionValue, fieldValue) { 198 return $.fxbConditions.helpers.indexOf(fieldValue, conditionValue) >= 0; 199 }, 200 201 "does not contain": function(conditionValue, fieldValue) { 202 return $.fxbConditions.helpers.indexOf(fieldValue, conditionValue) === -1; 203 }, 204 205 "starts with": function(conditionValue, fieldValue) { 206 return $.fxbConditions.helpers.indexOf(fieldValue, conditionValue) === 0; 207 }, 208 209 "does not start with": function(conditionValue, fieldValue) { 210 return $.fxbConditions.helpers.indexOf(fieldValue, conditionValue) !== 0; 211 }, 212 213 "ends with": function(conditionValue, fieldValue) { 214 return $.fxbConditions.helpers.endsWith(fieldValue, conditionValue); 215 }, 216 217 "does not end with": function(conditionValue, fieldValue) { 218 return !$.fxbConditions.helpers.endsWith(fieldValue, conditionValue); 219 }, 220 221 "is equal to": function(conditionValue, fieldValue) { 222 conditionValue = $.fxbConditions.helpers.normalize(conditionValue); 223 fieldValue = $.fxbConditions.helpers.normalize(fieldValue); 224 if (fieldValue === conditionValue) { 225 return true; 226 } 227 228 if (conditionValue.length) { 229 var left = $.fxbConditions.helpers.toNumber(conditionValue); 230 if (typeof left === "number") { 231 var right = $.fxbConditions.helpers.toNumber(fieldValue); 232 return typeof right === "number" && left === right; 233 } 234 } 235 236 return false; 237 }, 238 239 "is not equal to": function(conditionValue, fieldValue) { 240 conditionValue = $.fxbConditions.helpers.normalize(conditionValue); 241 fieldValue = $.fxbConditions.helpers.normalize(fieldValue); 242 if (fieldValue === conditionValue) { 243 return false; 244 } 245 246 if (conditionValue.length) { 247 var left = $.fxbConditions.helpers.toNumber(conditionValue); 248 if (typeof left === "number") { 249 var right = $.fxbConditions.helpers.toNumber(fieldValue);
250 return typeof right !== "number" || left !== right; 251 } 252 } 253 254 return true; 255 }, 256 257 "is greater than": function(conditionValue, fieldValue) { 258 conditionValue = $.fxbConditions.helpers.normalize(conditionValue); 259 fieldValue = $.fxbConditions.helpers.normalize(fieldValue); 260 261 if (conditionValue.length) { 262 var left = $.fxbConditions.helpers.toNumber(conditionValue); 263 if (typeof left === "number") { 264 var right = $.fxbConditions.helpers.toNumber(fieldValue); 265 return typeof right === "number" && right > left; 266 } 267 } 268 269 return fieldValue > conditionValue; 270 }, 271 272 "is greater than or equal to": function(conditionValue, fieldValue) { 273 conditionValue = $.fxbConditions.helpers.normalize(conditionValue); 274 fieldValue = $.fxbConditions.helpers.normalize(fieldValue); 275 276 if (fieldValue === conditionValue) { 277 return true; 278 } 279 280 if (conditionValue.length) { 281 var left = $.fxbConditions.helpers.toNumber(conditionValue); 282 if (typeof left === "number") { 283 var right = $.fxbConditions.helpers.toNumber(fieldValue); 284 return typeof right === "number" && right >= left; 285 } 286 } 287 288 return fieldValue >= conditionValue; 289 }, 290 291 "is less than": function(conditionValue, fieldValue) { 292 conditionValue = $.fxbConditions.helpers.normalize(conditionValue); 293 fieldValue = $.fxbConditions.helpers.normalize(fieldValue); 294 295 if (conditionValue.length) { 296 var left = $.fxbConditions.helpers.toNumber(conditionValue); 297 if (typeof left === "number") { 298 var right = $.fxbConditions.helpers.toNumber(fieldValue); 299 return typeof right === "number" && right < left; 300 } 301 } 302 303 return fieldValue < conditionValue; 304 }, 305 306 "is less than or equal to": function(conditionValue, fieldValue) { 307 conditionValue = $.fxbConditions.helpers.normalize(conditionValue); 308 fieldValue = $.fxbConditions.helpers.normalize(fieldValue); 309 310 if (fieldValue === conditionValue) { 311 return true; 312 } 313 314 if (conditionValue.length) { 315 var left = $.fxbConditions.helpers.toNumber(conditionValue); 316 if (typeof left === "number") { 317 var right = $.fxbConditions.helpers.toNumber(fieldValue); 318 return typeof right === "number" && right <= left; 319 } 320 } 321 322 return fieldValue <= conditionValue; 323 }, 324 325 addOperator: function(operatorName, operatorFn) { 326 if (operatorName && operatorName.length) { 327 this[operatorName.toLowerCase()] = operatorFn; 328 } 329 }, 330 331 getOperator: function(operatorName) { 332 return operatorName && operatorName.length ? this[operatorName.toLowerCase()] : null; 333 } 334 }, 335 336 prototype: { 337 initConditions: function(options) { 338 this.options = $.extend(true, this.options || {}, options); 339 340 if (!this.options.fieldConditions) { 341 return; 342 } 343 344 var sourceFields = []; 345 this.options.fieldConditions.forEach(function(fieldCondition) { 346 if (!fieldCondition || !fieldCondition.conditions) { 347 return; 348 } 349 350 fieldCondition.conditions.forEach(function(condition) { 351 if (condition.fieldId && sourceFields.indexOf(condition.fieldId) === -1) { 352 sourceFields.push(condition.fieldId); 353 var $source = this.$el.find("[data-sc-field-key=\"" + condition.fieldId + "\"]") 354 .filter(function() { 355 return $.fxbConditions.helpers.endsWith(this.name, "value"); 356 }); 357 if ($source.length) { 358 $source.on("change", this.applyConditions.bind(this)); 359 } 360 } 361 }.bind(this)); 362 }.bind(this)); 363 364 this.applyConditions(); 365 this.loaded = true; 366 }, 367 368 applyConditions: function() { 369 if (!this.options.fieldConditions) { 370 return; 371 } 372 373 this.executedActions = []; 374 this.fieldActions = {}; 375 376 this.options.fieldConditions.forEach(function(fieldCondition) { 377 if (fieldCondition && fieldCondition.actions && fieldCondition.actions.length) { 378 var conditionsResult = this.evaluateConditions(fieldCondition); 379 fieldCondition.actions.forEach(function(action) { 380 this.gatherFieldActions(action, conditionsResult); 381 }.bind(this)); 382 } 383 }.bind(this)); 384 385 for (var fieldId in this.fieldActions) { 386 if (!this.fieldActions.hasOwnProperty(fieldId)) continue; 387 for (var actionType in this.fieldActions[fieldId]) { 388 if (!this.fieldActions[fieldId].hasOwnProperty(actionType)) continue; 389 var action = this.fieldActions[fieldId][actionType].action; 390 var conditionsResult = this.fieldActions[fieldId][actionType].conditionsResult; 391 this.executeAction(action, conditionsResult); 392 } 393 } 394 }, 395 396 setRequired: function($targets) { 397 $targets.each(function(idx, target) { 398 var $target = $(target);
399 if ($target.is("input:not([type='submit']), select, textarea")) { 400 var name = target.name; 401 if (!$.fxbConditions.helpers.endsWith(name, "value") && !$.fxbConditions.helpers.endsWith(name, "Files") ) 402 return; 403 404 name = name.slice(0, -(name.length - name.lastIndexOf(".") - 1)) + "Required"; 405 var $requiredEl = this.$el.find("[name=\"" + name + "\"][data-sc-conditions-required]"), 406 isNotAccessible = $target.is(":hidden") || 407 $target.css("visibility") === "hidden" || 408 target.disabled; 409 410 if (!$requiredEl.length) { 411 if (isNotAccessible) { 412 var $currentEl = this.$el.find("[name=\"" + target.name + "\"]"); 413 $('<input>').attr({ 414 type: 'hidden', 415 name: name, 416 value: false, 417 "data-sc-conditions-required": "" 418 }).insertAfter($currentEl.last()); 419 } 420 421 return; 422 } 423 424 $requiredEl.val(false); 425 $requiredEl.prop("disabled", !isNotAccessible); 426 } else { 427 this.setRequired($target.find("input:not([type='submit']), select, textarea")); 428 } 429 }.bind(this)); 430 }, 431 432 executeAction: function(action, conditionsResult) { 433 if (action && action.fieldId && action.actionType) { 434 var $target = this.$el.find("[data-sc-field-key=\"" + action.fieldId + "\"]"); 435 if ($target.length) { 436 var actionFn = $.fxbConditions.actions.getAction(action.actionType, conditionsResult); 437 if (actionFn && typeof actionFn === "function") { 438 actionFn.call(this, $target, action, conditionsResult); 439 var executedAction = $.extend(true, 440 action, 441 { 442 conditionsResult: conditionsResult 443 }); 444 this.executedActions.push(executedAction); 445 } 446 } 447 } 448 }, 449 450 evaluateConditions: function(fieldCondition) { 451 if (!fieldCondition || !fieldCondition.conditions) return true; 452 453 var matchType = (fieldCondition.matchType || "").toLowerCase(); 454 switch (matchType) { 455 case "all": 456 return fieldCondition.conditions.every(this.isConditionSatisfied.bind(this)); 457 case "any": 458 default: 459 return fieldCondition.conditions.some(this.isConditionSatisfied.bind(this)); 460 } 461 }, 462 463 gatherFieldActions: function(action, conditionsResult) { 464 if (action && action.fieldId && action.actionType) { 465 if (typeof this.fieldActions[action.fieldId] === "undefined") { 466 this.fieldActions[action.fieldId] = {}; 467 } 468 469 if (typeof this.fieldActions[action.fieldId][action.actionType] === "undefined") { 470 this.fieldActions[action.fieldId][action.actionType] = { 471 action: action, 472 conditionsResult: conditionsResult 473 }; 474 } 475 // if a true conditionsResult finally appears for this particular fieldId and actionType, set it to true. 476 // from now on, it can never be set back to fal
476se again. 477 // (existing is deleted first to ensure this latest action appears at the bottom of the queue) 478 else if (!this.fieldActions[action.fieldId][action.actionType].conditionsResult && conditionsResult) { 479 delete this.fieldActions[action.fieldId][action.actionType]; 480 this.fieldActions[action.fieldId][action.actionType] = { 481 action: action, 482 conditionsResult: true 483 }; 484 } 485 } 486 }, 487 488 getValueList: function(fieldId) { 489 var $fieldEl = this.$el.find("[data-sc-field-key=\"" + fieldId + "\"]").filter(function() { 490 return $.fxbConditions.helpers.endsWith(this.name, "value"); 491 }); 492 493 var $listElements = $fieldEl.filter(function(idx, element) { 494 return element.type === "checkbox" || element.type === "radio"; 495 }); 496 497 if (!$listElements.length && $fieldEl.prop("multiple")) { 498 $listElements = $fieldEl.find("option"); 499 } 500 501 var value; 502 if ($listElements.length) { 503 if ($listElements.length > 1) { 504 value = $listElements.filter(":checked").map(function() { 505 return $(this).val(); 506 }).get(); 507 if (!value.length) { 508 value.push(""); 509 } 510 } else { 511 value = [$listElements[0].checked ? "true" : "false"]; 512 } 513 } else { 514 value = [$fieldEl.val()]; 515 } 516 517 return value; 518 }, 519 520 isConditionSatisfied: function(condition) { 521 if (condition && condition.operator) { 522 var operatorFn = $.fxbConditions.operators.getOperator(condition.operator); 523 if (operatorFn && typeof operatorFn === "function") { 524 525 var valueList = this.getValueList(condition.fieldId); 526 var result = condition.operator === "is not equal to" 527 ? valueList.every(operatorFn.bind(this, condition.value)) 528 : valueList.some(operatorFn.bind(this, condition.value)); 529 return result; 530 }; 531 } 532 533 return false; 534 } 535 } 536 }); 537 538 $.fn.init_fxbConditions = function(options) { 539 return this.each(function() { 540 var conditions = $.data(this, "fxbForms.conditions"); 541 if (conditions) { 542 conditions.initConditions(options); 543 } else { 544 conditions = new $.fxbConditions(this, options); 545 $.data(this, "fxbForms.conditions", conditions); 546 conditions.initConditions(); 547 } 548 }); 549 }; 550 551 $.fn.init_formConditions = function() { 552 var input = this.find('input[data-sc-fxb-condition]'); 553 if (input) { 554 var conditions = JSON.parse(input.attr('value')); 555 if (conditions) { 556 if (typeof this.init_fxbConditions === 'function') { 557 this.init_fxbConditions(conditions); 558 } 559 } 560 } 561 }; 562 563 var forms = $("form[data-sc-fxb]"); 564 if (forms.length) { 565 forms.each(function () { 566 var formEl = $(this); 567 formEl.init_formConditions(); 568 }).parent().on("submit", "form[data-sc-fxb]", function () { 569 var $submitBtns = $(this).find("input[type='submit'], button[type='submit']"); 570 if ($submitBtns.length) { 571 $('html, body').animate({ 572 scrollTop: $(this).offset().top 573 }, 500); 574 $submitBtns.on("click", function () { 575 return false; 576 }); 577 } 578 }); 579 } 580})(jQuery);
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.