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.on('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 264 return attribute; 265 }, 266 267 // manually trigger the validation of the attribute with the specified ID 268 validateAttribute: function (id) { 269 var attribute = methods.find.call(this, id); 270 if (attribute != undefined) { 271 validateAttribute($(this), attribute, true); 272 } 273 }, 274 275 // find an attribute config based on the specified attribute ID 276 find: function (id) { 277 var attributes = $(this).data('yiiActiveForm').attributes, 278 result = undefined; 279 $.each(attributes, function (i) { 280 if (attributes[i]['id'] == id) { 281 result = attributes[i]; 282 return false; 283 } 284 }); 285 return result; 286 }, 287 288 destroy: function () { 289 return this.each(function () { 290 $(this).off('.yiiActiveForm'); 291 $(this).removeData('yiiActiveForm'); 292 }); 293 }, 294 295 data: function () { 296 return this.data('yiiActiveForm'); 297 }, 298 299 // validate all applicable inputs in the form 300 validate: function (forceValidate) { 301 if (forceValidate) { 302 $(this).data('yiiActiveForm').submitting = true; 303 } 304 305 var $form = $(this), 306 data = $form.data('yiiActiveForm'), 307 needAjaxValidation = false, 308 messages = {}, 309 deferreds = deferredArray(), 310 submitting = data.submitting; 311 312 if (submitting) { 313 var event = $.Event(events.beforeValidate); 314 $form.trigger(event, [messages, deferreds]); 315 316 if (event.result === false) { 317 data.submitting = false;
318 submitFinalize($form); 319 return; 320 } 321 } 322 323 // client-side validation 324 $.each(data.attributes, function () { 325 this.$form = $form; 326 if (!$(this.input).is(":disabled")) { 327 this.cancelled = false; 328 // perform validation only if the form is being submitted or if an attribute is pending validation 329 if (data.submitting || this.status === 2 || this.status === 3) { 330 var msg = messages[this.id]; 331 if (msg === undefined) { 332 msg = []; 333 messages[this.id] = msg; 334 } 335 var event = $.Event(events.beforeValidateAttribute); 336 $form.trigger(event, [this, msg, deferreds]); 337 if (event.result !== false) { 338 if (this.validate) { 339 this.validate(this, getValue($form, this), msg, deferreds, $form); 340 } 341 if (this.enableAjaxValidation) { 342 needAjaxValidation = true; 343 } 344 } else { 345 this.cancelled = true; 346 } 347 } 348 } 349 }); 350 351 // ajax validation 352 $.when.apply(this, deferreds).always(function() { 353 // Remove empty message arrays 354 for (var i in messages) { 355 if (0 === messages[i].length) { 356 delete messages[i]; 357 } 358 } 359 if (needAjaxValidation && ($.isEmptyObject(messages) || data.submitting)) { 360 var $button = data.submitObject, 361 extData = '&' + data.settings.ajaxParam + '=' + $form.attr('id'); 362 if ($button && $button.length && $button.attr('name')) { 363 extData += '&' + $button.attr('name') + '=' + $button.attr('value'); 364 } 365 $.ajax({ 366 url: data.settings.validationUrl, 367 type: $form.attr('method'), 368 data: $form.serialize() + extData, 369 dataType: data.settings.ajaxDataType, 370 complete: function (jqXHR, textStatus) { 371 $form.trigger(events.ajaxComplete, [jqXHR, textStatus]); 372 }, 373 beforeSend: function (jqXHR, settings) { 374 $form.trigger(events.ajaxBeforeSend, [jqXHR, settings]); 375 }, 376 success: function (msgs) { 377 if (msgs !== null && typeof msgs === 'object') { 378 $.each(data.attributes, function () { 379 if (!this.enableAjaxValidation || this.cancelled) { 380 delete msgs[this.id]; 381 } 382 }); 383 updateInputs($form, $.extend(messages, msgs), submitting); 384 } else { 385 updateInputs($form, messages, submitting); 386 } 387 }, 388 error: function () { 389 data.submitting = false; 390 submitFinalize($form); 391 } 392 }); 393 } else if (data.submitting) { 394 // delay callback so that the form can be submitted without problem 395 window.setTimeout(function () { 396 updateInputs($form, messages, submitting); 397 }, 200); 398 } else { 399 updateInputs($form, messages, submitting); 400 } 401 }); 402 }, 403 404 submitForm: function () { 405 var $form = $(this), 406 data = $form.data('yiiActiveForm'); 407 408 if (data.validated) { 409 // Second submit's call (from validate/updateInputs) 410 data.submitting = false;
411 var event = $.Event(events.beforeSubmit); 412 $form.trigger(event); 413 if (event.result === false) { 414 data.validated = false; 415 submitFinalize($form); 416 return false; 417 } 418 updateHiddenButton($form); 419 return true; // continue submitting the form since validation passes 420 } else { 421 // First submit's call (from yii.js/handleAction) - execute validating 422 setSubmitFinalizeDefer($form); 423 424 if (data.settings.timer !== undefined) { 425 clearTimeout(data.settings.timer); 426 } 427 data.submitting = true; 428 methods.validate.call($form); 429 return false; 430 } 431 }, 432 433 resetForm: function () { 434 var $form = $(this); 435 var data = $form.data('yiiActiveForm'); 436 // Because we bind directly to a form reset event instead of a reset button (that may not exist), 437 // when this function is executed form input values have not been reset yet. 438 // Therefore we do the actual reset work through setTimeout. 439 window.setTimeout(function () { 440 $.each(data.attributes, function () {
441 // Without setTimeout() we would get the input values that are not reset yet. 442 this.value = getValue($form, this); 443 this.status = 0; 444 var $container = $form.find(this.container); 445 $container.removeClass( 446 data.settings.validatingCssClass + ' ' + 447 data.settings.errorCssClass + ' ' + 448 data.settings.successCssClass 449 ); 450 $container.find(this.error).html(''); 451 }); 452 $form.find(data.settings.errorSummary).hide().find('ul').html(''); 453 }, 1); 454 }, 455 456 /** 457 * Updates error messages, input containers, and optionally summary as well. 458 * If an attribute is missing from messages, it is considered valid. 459 * @param messages array the validation error messages, indexed by attribute IDs 460 * @param summary whether to update summary as well. 461 */ 462 updateMessages: function (messages, summary) { 463 var $form = $(this); 464 var data = $form.data('yiiActiveForm'); 465 $.each(data.attributes, function () { 466 updateInput($form, this, messages); 467 }); 468 if (summary) { 469 updateSummary($form, messages); 470 } 471 }, 472 473 /** 474 * Updates error messages and input container of a single attribute. 475 * If messages is empty, the attribute is considered valid. 476 * @param id attribute ID 477 * @param messages array with error messages 478 */ 479 updateAttribute: function(id, messages) { 480 var attribute = methods.find.call(this, id); 481 if (attribute != undefined) { 482 var msg = {}; 483 msg[id] = messages; 484 updateInput($(this), attribute, msg); 485 } 486 } 487 488 }; 489 490 var watchAttribute = function ($form, attribute) { 491 var $input = findInput($form, attribute); 492 if (attribute.validateOnChange) { 493 $input.on('change.yiiActiveForm', function () { 494 validateAttribute($form, attribute, false); 495 }); 496 } 497 if (attribute.validateOnBlur) { 498 $input.on('blur.yiiActiveForm', function () { 499 if (attribute.status == 0 || attribute.status == 1) { 500 validateAttribute($form, attribute, true); 501 } 502 }); 503 } 504 if (attribute.validateOnType) { 505 $input.on('keyup.yiiActiveForm', function (e) { 506 if ($.inArray(e.which, [16, 17, 18, 37, 38, 39, 40]) !== -1 ) { 507 return; 508 } 509 if (attribute.value !== getValue($form, attribute)) { 510 validateAttribute($form, attribute, false, attribute.validationDelay); 511 } 512 }); 513 } 514 }; 515 516 var unwatchAttribute = function ($form, attribute) { 517 findInput($form, attribute).off('.yiiActiveForm'); 518 }; 519 520 var validateAttribute = function ($form, attribute, forceValidate, validationDelay) { 521 var data = $form.data('yiiActiveForm'); 522 523 if (forceValidate) { 524 attribute.status = 2; 525 } 526 $.each(data.attributes, function () { 527 if (this.value !== getValue($form, this)) { 528 this.status = 2; 529 forceValidate = true; 530 } 531 }); 532 if (!forceValidate) { 533 return; 534 } 535 536 if (data.settings.timer !== undefined) { 537 clearTimeout(data.settings.timer); 538 } 539 data.settings.timer = window.setTimeout(function () { 540 if (data.submitting || $form.is(':hidden')) { 541 return; 542 } 543 $.each(data.attributes, function () { 544 if (this.status === 2) { 545 this.status = 3; 546 $form.find(this.container).addClass(data.settings.validatingCssClass); 547 } 548 }); 549 methods.validate.call($form); 550 }, validationDelay ? validationDelay : 200); 551 }; 552 553 /** 554 * Returns an array prototype with a shortcut method for adding a new deferred. 555 * The context of the callback will be the deferred object so it can be resolved like ```this.resolve()``` 556 * @returns Array 557 */ 558 var deferredArray = function () { 559 var array = []; 560 array.add = function(callback) { 561 this.push(new $.Deferred(callback)); 562 }; 563 return array; 564 }; 565 566 var buttonOptions = ['action', 'target', 'method', 'enctype']; 567 568 /** 569 * Returns current form options 570 * @param $form 571 * @returns object Object with button of form options 572 */ 573 var getFormOptions = function ($form) { 574 var attributes = {}; 575 for (var i = 0; i < buttonOptions.length; i++) { 576 attributes[buttonOptions[i]] = $form.attr(buttonOptions[i]); 577 } 578 579 return attributes; 580 }; 581 582 /** 583 * Applies temporary form options related to submit button 584 * @param $form the form jQuery object 585 * @param $button the button jQuery object 586 */ 587 var applyButtonOptions = function ($form, $button) { 588 for (var i = 0; i < buttonOptions.length; i++) { 589 var value = $button.attr('form' + buttonOptions[i]); 590 if (value) { 591 $form.attr(buttonOptions[i], value); 592 } 593 } 594 }; 595 596 /** 597 * Restores original form options 598 * @param $form the form jQuery object 599 */ 600 var restoreButtonOptions = function ($form) { 601 var data = $form.data('yiiActiveForm'); 602 603 for (var i = 0; i < buttonOptions.length; i++) { 604 $form.attr(buttonOptions[i], data.options[buttonOptions[i]] || null); 605 } 606 }; 607 608 /** 609 * Updates the error messages and the input containers for all applicable attributes 610 * @param $form the form jQuery object 611 * @param messages array the validation error messages 612 * @param submitting whether this method is called after validation triggered by form submission 613 */ 614 var updateInputs = function ($form, messages, submitting) { 615 var data = $form.data('yiiActiveForm'); 616 617 if (data === undefined) { 618 return false;
619 } 620 621 if (submitting) { 622 var errorAttributes = []; 623 $.each(data.attributes, function () { 624 if (!$(this.input).is(":disabled") && !this.cancelled && updateInput($form, this, messages)) { 625 errorAttributes.push(this); 626 } 627 }); 628 629 $form.trigger(events.afterValidate, [messages, errorAttributes]); 630 631 updateSummary($form, messages); 632 633 if (errorAttributes.length) { 634 if (data.settings.scrollToError) { 635 var top = $form.find($.map(errorAttributes, function(attribute) { 636 return attribute.input; 637 }).join(',')).first().closest(':visible').offset().top - data.settings.scrollToErrorOffset; 638 if (top < 0) { 639 top = 0; 640 } else if (top > $(document).height()) { 641 top = $(document).height(); 642 } 643 var wtop = $(window).scrollTop(); 644 if (top < wtop || top > wtop + $(window).height()) { 645 $(window).scrollTop(top); 646 } 647 } 648 data.submitting = false; 649 } else { 650 data.validated = true; 651 if (data.submitObject) { 652 applyButtonOptions($form, data.submitObject); 653 } 654 $form.submit(); 655 if (data.submitObject) { 656 restoreButtonOptions($form); 657 } 658 } 659 } else { 660 $.each(data.attributes, function () { 661 if (!this.cancelled && (this.status === 2 || this.status === 3)) { 662 updateInput($form, this, messages); 663 } 664 }); 665 } 666 submitFinalize($form); 667 }; 668 669 /** 670 * Updates hidden field that represents clicked submit button. 671 * @param $form the form jQuery object. 672 */ 673 var updateHiddenButton = function ($form) { 674 var data = $form.data('yiiActiveForm'); 675 var $button = data.submitObject || $form.find(':submit:first'); 676 // TODO: if the submission is caused by "change" event, it will not work 677 if ($button.length && $button.attr('type') == 'submit' && $button.attr('name')) { 678 // simulate button input value 679 var $hiddenButton = $('input[type="hidden"][name="' + $button.attr('name') + '"]', $form); 680 if (!$hiddenButton.length) { 681 $('<input>').attr({ 682 type: 'hidden', 683 name: $button.attr('name'), 684 value: $button.attr('value') 685 }).appendTo($form); 686 } else { 687 $hiddenButton.attr('value', $button.attr('value')); 688 } 689 } 690 }; 691 692 /** 693 * Updates the error message and the input container for a particular attribute. 694 * @param $form the form jQuery object 695 * @param attribute object the configuration for a particular attribute. 696 * @param messages array the validation error messages 697 * @return boolean whether there is a validation error for the specified attribute 698 */ 699 var updateInput = function ($form, attribute, messages) { 700 var data = $form.data('yiiActiveForm'), 701 $input = findInput($form, attribute), 702 hasError = false; 703 704 if (!$.isArray(messages[attribute.id])) { 705 messages[attribute.id] = []; 706 } 707 708 attribute.status = 1; 709 if ($input.length) { 710 hasError = messages[attribute.id].length > 0; 711 var $container = $form.find(attribute.container); 712 var $error = $container.find(attribute.error); 713 updateAriaInvalid($form, attribute, hasError); 714 if (hasError) { 715 if (attribute.encodeError) { 716 $error.text(messages[attribute.id][0]); 717 } else { 718 $error.html(messages[attribute.id][0]); 719 }
720 $container.removeClass(data.settings.validatingCssClass + ' ' + data.settings.successCssClass) 721 .addClass(data.settings.errorCssClass); 722 } else { 723 $error.empty(); 724 $container.removeClass(data.settings.validatingCssClass + ' ' + data.settings.errorCssClass + ' ') 725 .addClass(data.settings.successCssClass); 726 } 727 attribute.value = getValue($form, attribute); 728 } 729 730 $form.trigger(events.afterValidateAttribute, [attribute, messages[attribute.id]]); 731 732 return hasError; 733 }; 734 735 /** 736 * Updates the error summary. 737 * @param $form the form jQuery object 738 * @param messages array the validation error messages 739 */ 740 var updateSummary = function ($form, messages) { 741 var data = $form.data('yiiActiveForm'), 742 $summary = $form.find(data.settings.errorSummary), 743 $ul = $summary.find('ul').empty(); 744 745 if ($summary.length && messages) { 746 $.each(data.attributes, function () { 747 if ($.isArray(messages[this.id]) && messages[this.id].length) { 748 var error = $('<li/>'); 749 if (data.settings.encodeErrorSummary) { 750 error.text(messages[this.id][0]); 751 } else { 752 error.html(messages[this.id][0]); 753 } 754 $ul.append(error); 755 } 756 }); 757 $summary.toggle($ul.find('li').length > 0); 758 } 759 }; 760 761 var getValue = function ($form, attribute) { 762 var $input = findInput($form, attribute); 763 var type = $input.attr('type'); 764 if (type === 'checkbox' || type === 'radio') { 765 var $realInput = $input.filter(':checked'); 766 if (!$realInput.length) { 767 $realInput = $form.find('input[type=hidden][name="' + $input.attr('name') + '"]'); 768 } 769 770 return $realInput.val(); 771 } else { 772 return $input.val(); 773 } 774 }; 775 776 var findInput = function ($form, attribute) { 777 var $input = $form.find(attribute.input); 778 if ($input.length && $input[0].tagName.toLowerCase() === 'div') { 779 // checkbox list or radio list 780 return $input.find('input'); 781 } else { 782 return $input; 783 } 784 }; 785 786 var updateAriaInvalid = function ($form, attribute, hasError) { 787 if (attribute.updateAriaInvalid) { 788 $form.find(attribute.input).attr('aria-invalid', hasError ? 'true' : 'false'); 789 } 790 } 791})(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.