1/** 2 * Yii form widget. 3 * 4 * This is the JavaScript widget used by the yii\widgets\ActiveForm widget. 5 * 6 * @link http://www.yiiframework.com/ 7 * @copyright Copyright (c) 2008 Yii Software LLC 8 * @license http://www.yiiframework.com/license/ 9 * @author Qiang Xue <[email protected]> 10 * @since 2.0 11 */ 12(function ($) { 13 14 $.fn.yiiActiveForm = function (method) { 15 if (methods[method]) { 16 return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); 17 } else if (typeof method === 'object' || !method) { 18 return methods.init.apply(this, arguments); 19 } else { 20 $.error('Method ' + method + ' does not exist on jQuery.yiiActiveForm'); 21 return false; 22 } 23 }; 24 25 var events = { 26 /** 27 * beforeValidate event is triggered before validating the whole form. 28 * The signature of the event handler should be: 29 * function (event, messages, deferreds) 30 * where 31 * - event: an Event object. 32 * - messages: an associative array with keys being attribute IDs and values being error message arrays 33 * for the corresponding attributes. 34 * - deferreds: an array of Deferred objects. You can use deferreds.add(callback) to add a new deferred validation. 35 * 36 * If the handler returns a boolean false, it will stop further form validation after this event. And as 37 * a result, afterValidate event will not be triggered. 38 */ 39 beforeValidate: 'beforeValidate', 40 /** 41 * afterValidate event is triggered after validating the whole form. 42 * The signature of the event handler should be: 43 * function (event, messages, errorAttributes) 44 * where 45 * - event: an Event object. 46 * - messages: an associative array with keys being attribute IDs and values being error message arrays 47 * for the corresponding attributes. 48 * - errorAttributes: an array of attributes that have validation errors. Please refer to attributeDefaults for the structure of this parameter. 49 */ 50 afterValidate: 'afterValidate', 51 /** 52 * beforeValidateAttribute event is triggered before validating an attribute. 53 * The signature of the event handler should be: 54 * function (event, attribute, messages, deferreds) 55 * where 56 * - event: an Event object. 57 * - attribute: the attribute to be validated. Please refer to attributeDefaults for the structure of this parameter. 58 * - messages: an array to which you can add validation error messages for the specified attribute. 59 * - deferreds: an array of Deferred objects. You can use deferreds.add(callback) to add a new deferred validation. 60 * 61 * If the handler returns a boolean false, it will stop further validation of the specified attribute. 62 * And as a result, afterValidateAttribute event will not be triggered. 63 */ 64 beforeValidateAttribute: 'beforeValidateAttribute', 65 /** 66 * afterValidateAttribute event is triggered after validating the whole form and each attribute. 67 * The signature of the event handler should be: 68 * function (event, attribute, messages) 69 * where 70 * - event: an Event object. 71 * - attribute: the attribute being validated. Please refer to attributeDefaults for the structure of this parameter. 72 * - messages: an array to which you can add additional validation error messages for the specified attribute. 73 */ 74 afterValidateAttribute: 'afterValidateAttribute', 75 /** 76 * beforeSubmit event is triggered before submitting the form after all validations have passed. 77 * The signature of the event handler should be: 78 * function (event) 79 * where event is an Event object. 80 * 81 * If the handler returns a boolean false, it will stop form submission. 82 */ 83 beforeSubmit: 'beforeSubmit', 84 /** 85 * ajaxBeforeSend event is triggered before sending an AJAX request for AJAX-based validation. 86 * The signature of the event handler should be: 87 * function (event, jqXHR, settings) 88 * where 89 * - event: an Event object. 90 * - jqXHR: a jqXHR object 91 * - settings: the settings for the AJAX request 92 */ 93 ajaxBeforeSend: 'ajaxBeforeSend', 94 /** 95 * ajaxComplete event is triggered after completing an AJAX request for AJAX-based validation. 96 * The signature of the event handler should be: 97 * function (event, jqXHR, textStatus) 98 * where 99 * - event: an Event object. 100 * - jqXHR: a jqXHR object 101 * - textStatus: the status of the request ("success", "notmodified", "error", "timeout", "abort", or "parsererror"). 102 */ 103 ajaxComplete: 'ajaxComplete', 104 /** 105 * afterInit event is triggered after yii activeForm init. 106 * The signature of the event handler should be: 107 * function (event) 108 * where 109 * - event: an Event object. 110 */ 111 afterInit: 'afterInit' 112 }; 113 114 // NOTE: If you change any of these defaults, make sure you update yii\widgets\ActiveForm::getClientOptions() as well 115 var defaults = { 116 // whether to encode the error summary 117 encodeErrorSummary: true, 118 // the jQuery selector for the error summary 119 errorSummary: '.error-summary', 120 // whether to perform validation before submitting the form. 121 validateOnSubmit: true, 122 // the container CSS class representing the corresponding attribute has validation error 123 errorCssClass: 'has-error', 124 // the container CSS class representing the corresponding attribute passes validation 125 successCssClass: 'has-success', 126 // the container CSS class representing the corresponding attribute is being validated 127 validatingCssClass: 'validating', 128 // the GET parameter name indicating an AJAX-based validation 129 ajaxParam: 'ajax', 130 // the type of data that you're expecting back from the server 131 ajaxDataType: 'json', 132 // the URL for performing AJAX-based validation. If not set, it will use the the form's action 133 validationUrl: undefined, 134 // whether to scroll to first visible error after validation. 135 scrollToError: true, 136 // offset in pixels that should be added when scrolling to the first error. 137 scrollToErrorOffset: 0 138 }; 139 140 // NOTE: If you change any of these defaults, make sure you update yii\widgets\ActiveField::getClientOptions() as well 141 var attributeDefaults = { 142 // a unique ID identifying an attribute (e.g. "loginform-username") in a form 143 id: undefined, 144 // attribute name or expression (e.g. "[0]content" for tabular input) 145 name: undefined, 146 // the jQuery selector of the container of the input field 147 container: undefined, 148 // the jQuery selector of the input field under the context of the form 149 input: undefined, 150 // the jQuery selector of the error tag under the context of the container 151 error: '.help-block', 152 // whether to encode the error 153 encodeError: true, 154 // whether to perform validation when a change is detected on the input 155 validateOnChange: true, 156 // whether to perform validation when the input loses focus 157 validateOnBlur: true, 158 // whether to perform validation when the user is typing. 159 validateOnType: false, 160 // number of milliseconds that the validation should be delayed when a user is typing in the input field. 161 validationDelay: 500, 162 // whether to enable AJAX-based validation. 163 enableAjaxValidation: false, 164 // function (attribute, value, messages, deferred, $form), the client-side validation function. 165 validate: undefined, 166 // status of the input field, 0: empty, not entered before, 1: validated, 2: pending validation, 3: validating 167 status: 0, 168 // whether the validation is cancelled by beforeValidateAttribute event handler 169 cancelled: false, 170 // the value of the input 171 value: undefined, 172 // whether to update aria-invalid attribute after validation 173 updateAriaInvalid: true 174 }; 175 176 177 var submitDefer; 178 179 var setSubmitFinalizeDefer = function($form) { 180 submitDefer = $.Deferred(); 181 $form.data('yiiSubmitFinalizePromise', submitDefer.promise()); 182 }; 183 184 // finalize yii.js $form.submit 185 var submitFinalize = function($form) { 186 if(submitDefer) { 187 submitDefer.resolve(); 188 submitDefer = undefined; 189 $form.removeData('yiiSubmitFinalizePromise'); 190 } 191 }; 192 193 194 var methods = { 195 init: function (attributes, options) { 196 return this.each(function () { 197 var $form = $(this); 198 if ($form.data('yiiActiveForm')) { 199 return; 200 } 201 202 var settings = $.extend({}, defaults, options || {});
203 if (settings.validationUrl === undefined) { 204 settings.validationUrl = $form.attr('action'); 205 } 206 207 $.each(attributes, function (i) { 208 attributes[i] = $.extend({value: getValue($form, this)}, attributeDefaults, this); 209 watchAttribute($form, attributes[i]); 210 }); 211 212 $form.data('yiiActiveForm', { 213 settings: settings, 214 attributes: attributes, 215 submitting: false, 216 validated: false, 217 options: getFormOptions($form) 218 }); 219 220 /** 221 * Clean up error status when the form is reset. 222 * Note that $form.on('reset', ...) does work because the "reset" event does not bubble on IE. 223 */ 224 $form.bind('reset.yiiActiveForm', methods.resetForm); 225 226 if (settings.validateOnSubmit) { 227 $form.on('mouseup.yiiActiveForm keyup.yiiActiveForm', ':submit', function () { 228 $form.data('yiiActiveForm').submitObject = $(this); 229 }); 230 $form.on('submit.yiiActiveForm', methods.submitForm); 231 } 232 var event = $.Event(events.afterInit); 233 $form.trigger(event); 234 }); 235 }, 236 237 // add a new attribute to the form dynamically. 238 // please refer to attributeDefaults for the structure of attribute 239 add: function (attribute) { 240 var $form = $(this); 241 attribute = $.extend({value: getValue($form, attribute)}, attributeDefaults, attribute); 242 $form.data('yiiActiveForm').attributes.push(attribute); 243 watchAttribute($form, attribute); 244 }, 245 246 // remove the attribute with the specified ID from the form 247 remove: function (id) { 248 var $form = $(this), 249 attributes = $form.data('yiiActiveForm').attributes, 250 index = -1, 251 attribute = undefined; 252 $.each(attributes, function (i) { 253 if (attributes[i]['id'] == id) { 254 index = i; 255 attribute = attributes[i]; 256 return false; 257 } 258 }); 259 if (index >= 0) { 260 attributes.splice(index, 1); 261 unwatchAttribute($form, attribute); 262 } 263 return attribute; 264 }, 265 266 // manually trigger the validation of the attribute with the specified ID 267 validateAttribute: function (id) { 268 var attribute = methods.find.call(this, id); 269 if (attribute != undefined) { 270 validateAttribute($(this), attribute, true); 271 } 272 }, 273 274 // find an attribute config based on the specified attribute ID 275 find: function (id) { 276 var attributes = $(this).data('yiiActiveForm').attributes, 277 result = undefined; 278 $.each(attributes, function (i) { 279 if (attributes[i]['id'] == id) { 280 result = attributes[i]; 281 return false; 282 } 283 }); 284 return result; 285 }, 286 287 destroy: function () { 288 return this.each(function () { 289 $(this).unbind('.yiiActiveForm'); 290 $(this).removeData('yiiActiveForm'); 291 }); 292 }, 293 294 data: function () { 295 return this.data('yiiActiveForm'); 296 }, 297 298 // validate all applicable inputs in the form 299 validate: function (forceValidate) { 300 if (forceValidate) { 301 $(this).data('yiiActiveForm').submitting = true; 302 } 303 304 var $form = $(this), 305 data = $form.data('yiiActiveForm'), 306 needAjaxValidation = false, 307 messages = {}, 308 deferreds = deferredArray(), 309 submitting = data.submitting && !forceValidate; 310 311 if (data.submitting) { 312 var event = $.Event(events.beforeValidate); 313 $form.trigger(event, [messages, deferreds]); 314 315 if (event.result === false) { 316 data.submitting = false;
317 submitFinalize($form); 318 return; 319 } 320 } 321 322 // client-side validation 323 $.each(data.attributes, function () { 324 this.$form = $form; 325 if (!$(this.input).is(":disabled")) { 326 this.cancelled = false; 327 // perform validation only if the form is being submitted or if an attribute is pending validation 328 if (data.submitting || this.status === 2 || this.status === 3) { 329 var msg = messages[this.id]; 330 if (msg === undefined) { 331 msg = []; 332 messages[this.id] = msg; 333 } 334 var event = $.Event(events.beforeValidateAttribute); 335 $form.trigger(event, [this, msg, deferreds]); 336 if (event.result !== false) { 337 if (this.validate) { 338 this.validate(this, getValue($form, this), msg, deferreds, $form); 339 } 340 if (this.enableAjaxValidation) { 341 needAjaxValidation = true; 342 } 343 } else { 344 this.cancelled = true; 345 } 346 } 347 } 348 }); 349 350 // ajax validation 351 $.when.apply(this, deferreds).always(function() { 352 // Remove empty message arrays 353 for (var i in messages) { 354 if (0 === messages[i].length) { 355 delete messages[i]; 356 } 357 } 358 if (needAjaxValidation && ($.isEmptyObject(messages) || data.submitting)) { 359 var $button = data.submitObject, 360 extData = '&' + data.settings.ajaxParam + '=' + $form.attr('id'); 361 if ($button && $button.length && $button.attr('name')) { 362 extData += '&' + $button.attr('name') + '=' + $button.attr('value'); 363 } 364 $.ajax({ 365 url: data.settings.validationUrl, 366 type: $form.attr('method'), 367 data: $form.serialize() + extData, 368 dataType: data.settings.ajaxDataType, 369 complete: function (jqXHR, textStatus) { 370 $form.trigger(events.ajaxComplete, [jqXHR, textStatus]); 371 }, 372 beforeSend: function (jqXHR, settings) { 373 $form.trigger(events.ajaxBeforeSend, [jqXHR, settings]); 374 }, 375 success: function (msgs) { 376 if (msgs !== null && typeof msgs === 'object') { 377 $.each(data.attributes, function () { 378 if (!this.enableAjaxValidation || this.cancelled) { 379 delete msgs[this.id]; 380 } 381 }); 382 updateInputs($form, $.extend(messages, msgs), submitting); 383 } else { 384 updateInputs($form, messages, submitting); 385 } 386 }, 387 error: function () { 388 data.submitting = false; 389 submitFinalize($form); 390 } 391 }); 392 } else if (data.submitting) { 393 // delay callback so that the form can be submitted without problem 394 setTimeout(function () { 395 updateInputs($form, messages, submitting); 396 }, 200); 397 } else { 398 updateInputs($form, messages, submitting); 399 } 400 }); 401 }, 402 403 submitForm: function () { 404 var $form = $(this), 405 data = $form.data('yiiActiveForm'); 406 407 if (data.validated) { 408 // Second submit's call (from validate/updateInputs) 409 data.submitting = false;
410 var event = $.Event(events.beforeSubmit); 411 $form.trigger(event); 412 if (event.result === false) { 413 data.validated = false; 414 submitFinalize($form); 415 return false; 416 } 417 updateHiddenButton($form); 418 return true; // continue submitting the form since validation passes 419 } else { 420 // First submit's call (from yii.js/handleAction) - execute validating 421 setSubmitFinalizeDefer($form); 422 423 if (data.settings.timer !== undefined) { 424 clearTimeout(data.settings.timer); 425 } 426 data.submitting = true; 427 methods.validate.call($form); 428 return false; 429 } 430 }, 431 432 resetForm: function () { 433 var $form = $(this); 434 var data = $form.data('yiiActiveForm'); 435 // Because we bind directly to a form reset event instead of a reset button (that may not exist), 436 // when this function is executed form input values have not been reset yet. 437 // Therefore we do the actual reset work through setTimeout. 438 setTimeout(function () { 439 $.each(data.attributes, function () {
440 // Without setTimeout() we would get the input values that are not reset yet. 441 this.value = getValue($form, this); 442 this.status = 0; 443 var $container = $form.find(this.container); 444 $container.removeClass( 445 data.settings.validatingCssClass + ' ' + 446 data.settings.errorCssClass + ' ' + 447 data.settings.successCssClass 448 ); 449 $container.find(this.error).html(''); 450 }); 451 $form.find(data.settings.errorSummary).hide().find('ul').html(''); 452 }, 1); 453 }, 454 455 /** 456 * Updates error messages, input containers, and optionally summary as well. 457 * If an attribute is missing from messages, it is considered valid. 458 * @param messages array the validation error messages, indexed by attribute IDs 459 * @param summary whether to update summary as well. 460 */ 461 updateMessages: function (messages, summary) { 462 var $form = $(this); 463 var data = $form.data('yiiActiveForm'); 464 $.each(data.attributes, function () { 465 updateInput($form, this, messages); 466 }); 467 if (summary) { 468 updateSummary($form, messages); 469 } 470 }, 471 472 /** 473 * Updates error messages and input container of a single attribute. 474 * If messages is empty, the attribute is considered valid. 475 * @param id attribute ID 476 * @param messages array with error messages 477 */ 478 updateAttribute: function(id, messages) { 479 var attribute = methods.find.call(this, id); 480 if (attribute != undefined) { 481 var msg = {}; 482 msg[id] = messages; 483 updateInput($(this), attribute, msg); 484 } 485 } 486 487 }; 488 489 var watchAttribute = function ($form, attribute) { 490 var $input = findInput($form, attribute); 491 if (attribute.validateOnChange) { 492 $input.on('change.yiiActiveForm', function () { 493 validateAttribute($form, attribute, false); 494 }); 495 } 496 if (attribute.validateOnBlur) { 497 $input.on('blur.yiiActiveForm', function () { 498 if (attribute.status == 0 || attribute.status == 1) { 499 validateAttribute($form, attribute, true); 500 } 501 }); 502 } 503 if (attribute.validateOnType) { 504 $input.on('keyup.yiiActiveForm', function (e) { 505 if ($.inArray(e.which, [16, 17, 18, 37, 38, 39, 40]) !== -1 ) { 506 return; 507 } 508 if (attribute.value !== getValue($form, attribute)) { 509 validateAttribute($form, attribute, false, attribute.validationDelay); 510 } 511 }); 512 } 513 }; 514 515 var unwatchAttribute = function ($form, attribute) { 516 findInput($form, attribute).off('.yiiActiveForm'); 517 }; 518 519 var validateAttribute = function ($form, attribute, forceValidate, validationDelay) { 520 var data = $form.data('yiiActiveForm'); 521 522 if (forceValidate) { 523 attribute.status = 2; 524 } 525 $.each(data.attributes, function () { 526 if (this.value !== getValue($form, this)) { 527 this.status = 2; 528 forceValidate = true; 529 } 530 }); 531 if (!forceValidate) { 532 return; 533 } 534 535 if (data.settings.timer !== undefined) { 536 clearTimeout(data.settings.timer); 537 } 538 data.settings.timer = setTimeout(function () { 539 if (data.submitting || $form.is(':hidden')) { 540 return; 541 } 542 $.each(data.attributes, function () { 543 if (this.status === 2) { 544 this.status = 3; 545 $form.find(this.container).addClass(data.settings.validatingCssClass); 546 } 547 }); 548 methods.validate.call($form); 549 }, validationDelay ? validationDelay : 200); 550 }; 551 552 /** 553 * Returns an array prototype with a shortcut method for adding a new deferred. 554 * The context of the callback will be the deferred object so it can be resolved like ```this.resolve()``` 555 * @returns Array 556 */ 557 var deferredArray = function () { 558 var array = []; 559 array.add = function(callback) { 560 this.push(new $.Deferred(callback)); 561 }; 562 return array; 563 }; 564 565 var buttonOptions = ['action', 'target', 'method', 'enctype']; 566 567 /** 568 * Returns current form options 569 * @param $form 570 * @returns object Object with button of form options 571 */ 572 var getFormOptions = function ($form) { 573 var attributes = {}; 574 for (var i = 0; i < buttonOptions.length; i++) { 575 attributes[buttonOptions[i]] = $form.attr(buttonOptions[i]); 576 } 577 return attributes; 578 }; 579 580 /** 581 * Applies temporary form options related to submit button 582 * @param $form the form jQuery object 583 * @param $button the button jQuery object 584 */ 585 var applyButtonOptions = function ($form, $button) { 586 for (var i = 0; i < buttonOptions.length; i++) { 587 var value = $button.attr('form' + buttonOptions[i]); 588 if (value) { 589 $form.attr(buttonOptions[i], value); 590 } 591 } 592 }; 593 594 /** 595 * Restores original form options 596 * @param $form the form jQuery object 597 */ 598 var restoreButtonOptions = function ($form) { 599 var data = $form.data('yiiActiveForm'); 600 601 for (var i = 0; i < buttonOptions.length; i++) { 602 $form.attr(buttonOptions[i], data.options[buttonOptions[i]] || null); 603 } 604 }; 605 606 /** 607 * Updates the error messages and the input containers for all applicable attributes 608 * @param $form the form jQuery object 609 * @param messages array the validation error messages 610 * @param submitting whether this method is called after validation triggered by form submission 611 */ 612 var updateInputs = function ($form, messages, submitting) { 613 var data = $form.data('yiiActiveForm'); 614 615 if (data === undefined) { 616 return false;
617 } 618 619 if (submitting) { 620 var errorAttributes = []; 621 $.each(data.attributes, function () { 622 if (!$(this.input).is(":disabled") && !this.cancelled && updateInput($form, this, messages)) { 623 errorAttributes.push(this); 624 } 625 }); 626 627 $form.trigger(events.afterValidate, [messages, errorAttributes]); 628 629 updateSummary($form, messages); 630 631 if (errorAttributes.length) { 632 if (data.settings.scrollToError) { 633 var top = $form.find($.map(errorAttributes, function(attribute) { 634 return attribute.input; 635 }).join(',')).first().closest(':visible').offset().top - data.settings.scrollToErrorOffset; 636 if (top < 0) { 637 top = 0; 638 } else if (top > $(document).height()) { 639 top = $(document).height(); 640 } 641 var wtop = $(window).scrollTop(); 642 if (top < wtop || top > wtop + $(window).height()) { 643 $(window).scrollTop(top); 644 } 645 } 646 data.submitting = false; 647 } else { 648 data.validated = true; 649 if (data.submitObject) { 650 applyButtonOptions($form, data.submitObject); 651 } 652 $form.submit(); 653 if (data.submitObject) { 654 restoreButtonOptions($form); 655 } 656 } 657 } else { 658 $.each(data.attributes, function () { 659 if (!this.cancelled && (this.status === 2 || this.status === 3)) { 660 updateInput($form, this, messages); 661 } 662 }); 663 } 664 submitFinalize($form); 665 }; 666 667 /** 668 * Updates hidden field that represents clicked submit button. 669 * @param $form the form jQuery object. 670 */ 671 var updateHiddenButton = function ($form) { 672 var data = $form.data('yiiActiveForm'); 673 var $button = data.submitObject || $form.find(':submit:first'); 674 // TODO: if the submission is caused by "change" event, it will not work 675 if ($button.length && $button.attr('type') == 'submit' && $button.attr('name')) { 676 // simulate button input value 677 var $hiddenButton = $('input[type="hidden"][name="' + $button.attr('name') + '"]', $form); 678 if (!$hiddenButton.length) { 679 $('<input>').attr({ 680 type: 'hidden', 681 name: $button.attr('name'), 682 value: $button.attr('value') 683 }).appendTo($form); 684 } else { 685 $hiddenButton.attr('value', $button.attr('value')); 686 } 687 } 688 }; 689 690 /** 691 * Updates the error message and the input container for a particular attribute. 692 * @param $form the form jQuery object 693 * @param attribute object the configuration for a particular attribute. 694 * @param messages array the validation error messages 695 * @return boolean whether there is a validation error for the specified attribute 696 */ 697 var updateInput = function ($form, attribute, messages) { 698 var data = $form.data('yiiActiveForm'), 699 $input = findInput($form, attribute), 700 hasError = false; 701 702 if (!$.isArray(messages[attribute.id])) { 703 messages[attribute.id] = []; 704 } 705 $form.trigger(events.afterValidateAttribute, [attribute, messages[attribute.id]]); 706 707 attribute.status = 1; 708 if ($input.length) { 709 hasError = messages[attribute.id].length > 0; 710 var $container = $form.find(attribute.container); 711 var $error = $container.find(attribute.error); 712 updateAriaInvalid($form, attribute, hasError); 713 if (hasError) { 714 if (attribute.encodeError) { 715 $error.text(messages[attribute.id][0]); 716 } else { 717 $error.html(messages[attribute.id][0]); 718 }
719 $container.removeClass(data.settings.validatingCssClass + ' ' + data.settings.successCssClass) 720 .addClass(data.settings.errorCssClass); 721 } else { 722 $error.empty(); 723 $container.removeClass(data.settings.validatingCssClass + ' ' + data.settings.errorCssClass + ' ') 724 .addClass(data.settings.successCssClass); 725 } 726 attribute.value = getValue($form, attribute); 727 } 728 return hasError; 729 }; 730 731 /** 732 * Updates the error summary. 733 * @param $form the form jQuery object 734 * @param messages array the validation error messages 735 */ 736 var updateSummary = function ($form, messages) { 737 var data = $form.data('yiiActiveForm'), 738 $summary = $form.find(data.settings.errorSummary), 739 $ul = $summary.find('ul').empty(); 740 741 if ($summary.length && messages) { 742 $.each(data.attributes, function () { 743 if ($.isArray(messages[this.id]) && messages[this.id].length) { 744 var error = $('<li/>'); 745 if (data.settings.encodeErrorSummary) { 746 error.text(messages[this.id][0]); 747 } else { 748 error.html(messages[this.id][0]); 749 } 750 $ul.append(error); 751 } 752 }); 753 $summary.toggle($ul.find('li').length > 0); 754 } 755 }; 756 757 var getValue = function ($form, attribute) { 758 var $input = findInput($form, attribute); 759 var type = $input.attr('type'); 760 if (type === 'checkbox' || type === 'radio') { 761 var $realInput = $input.filter(':checked'); 762 if (!$realInput.length) { 763 $realInput = $form.find('input[type=hidden][name="' + $input.attr('name') + '"]'); 764 } 765 return $realInput.val(); 766 } else { 767 return $input.val(); 768 } 769 }; 770 771 var findInput = function ($form, attribute) { 772 var $input = $form.find(attribute.input); 773 if ($input.length && $input[0].tagName.toLowerCase() === 'div') { 774 // checkbox list or radio list 775 return $input.find('input'); 776 } else { 777 return $input; 778 } 779 }; 780 781 var updateAriaInvalid = function ($form, attribute, hasError) { 782 if (attribute.updateAriaInvalid) { 783 $form.find(attribute.input).attr('aria-invalid', hasError ? 'true' : 'false'); 784 } 785 } 786})(window.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.