PageSourceSearch

https://neyshabur.ac.ir/assets/8ae58b54/yii.activeForm.js?v=1790149130

js neyshabur.ac.ir collected 2026-09-25 08:14:56 UTC 36,629 bytes, 922 lines download raw bytes

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