PageSourceSearch

https://letscolour.hu/assets/fb12b37a/yii.activeForm.js?v=1649323544

js letscolour.hu collected 2026-10-07 19:28:44 UTC 29,766 bytes, 711 lines download raw bytes

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
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    };
129
130    // NOTE: If you change any of these defaults, make sure you update yii\widgets\ActiveField::getClientOptions() as well
131    var attributeDefaults = {
132        // a unique ID identifying an attribute (e.g. "loginform-username") in a form
133        id: undefined,
134        // attribute name or expression (e.g. "[0]content" for tabular input)
135        name: undefined,
136        // the jQuery selector of the container of the input field
137        container: undefined,
138        // the jQuery selector of the input field under the context of the form
139        input: undefined,
140        // the jQuery selector of the error tag under the context of the container
141        error: '.help-block',
142        // whether to encode the error
143        encodeError: true,
144        // whether to perform validation when a change is detected on the input
145        validateOnChange: true,
146        // whether to perform validation when the input loses focus
147        validateOnBlur: true,
148        // whether to perform validation when the user is typing.
149        validateOnType: false,
150        // number of milliseconds that the validation should be delayed when a user is typing in the input field.
151        validationDelay: 500,
152        // whether to enable AJAX-based validation.
153        enableAjaxValidation: false,
154        // function (attribute, value, messages, deferred, $form), the client-side validation function.
155        validate: undefined,
156        // status of the input field, 0: empty, not entered before, 1: validated, 2: pending validation, 3: validating
157        status: 0,
158        // whether the validation is cancelled by beforeValidateAttribute event handler
159        cancelled: false,
160        // the value of the input
161        value: undefined
162    };
163
164
165    var submitDefer;
166
167    var setSubmitFinalizeDefer = function($form) {
168        submitDefer = $.Deferred();
169        $form.data('yiiSubmitFinalizePromise', submitDefer.promise());
170    };
171
172    // finalize yii.js $form.submit
173    var submitFinalize = function($form) {
174        if(submitDefer) {
175            submitDefer.resolve();
176            submitDefer = undefined;
177            $form.removeData('yiiSubmitFinalizePromise');
178        }
179    };
180
181
182    var methods = {
183        init: function (attributes, options) {
184            return this.each(function () {
185                var $form = $(this);
186                if ($form.data('yiiActiveForm')) {
187                    return;
188                }
189
190                var settings = $.extend({}, defaults, options || {});
191                if (settings.validationUrl === undefined) {
192                    settings.validationUrl = $form.attr('action');
193                }
194
195                $.each(attributes, function (i) {
196                    attributes[i] = $.extend({value: getValue($form, this)}, attributeDefaults, this);
197                    watchAttribute($form, attributes[i]);
198                });
199
200                $form.data('yiiActiveForm', {
201                    settings: settings,
202                    attributes: attributes,
203                    submitting: false,
204                    validated: false,
205                    target: $form.attr('target')
206                });
207
208                /**
209                 * Clean up error status when the form is reset.
210                 * Note that $form.on('reset', ...) does work because the "reset" event does not bubble on IE.
211                 */
212                $form.bind('reset.yiiActiveForm', methods.resetForm);
213
214                if (settings.validateOnSubmit) {
215                    $form.on('mouseup.yiiActiveForm keyup.yiiActiveForm', ':submit', function () {
216                        $form.data('yiiActiveForm').submitObject = $(this);
217                    });
218                    $form.on('submit.yiiActiveForm', methods.submitForm);
219                }
220            });
221        },
222
223        // add a new attribute to the form dynamically.
224        // please refer to attributeDefaults for the structure of attribute
225        add: function (attribute) {
226            var $form = $(this);
227            attribute = $.extend({value: getValue($form, attribute)}, attributeDefaults, attribute);
228            $form.data('yiiActiveForm').attributes.push(attribute);
229            watchAttribute($form, attribute);
230        },
231
232        // remove the attribute with the specified ID from the form
233        remove: function (id) {
234            var $form = $(this),
235                attributes = $form.data('yiiActiveForm').attributes,
236                index = -1,
237                attribute = undefined;
238            $.each(attributes, function (i) {
239                if (attributes[i]['id'] == id) {
240                    index = i;
241                    attribute = attributes[i];
242                    return false;
243                }
244            });
245            if (index >= 0) {
246                attributes.splice(index, 1);
247                unwatchAttribute($form, attribute);
248            }
249            return attribute;
250        },
251
252        // manually trigger the validation of the attribute with the specified ID
253        validateAttribute: function (id) {
254            var attribute = methods.find.call(this, id);
255            if (attribute != undefined) {
256                validateAttribute($(this), attribute, true);
257            }
258        },
259
260        // find an attribute config based on the specified attribute ID
261        find: function (id) {
262            var attributes = $(this).data('yiiActiveForm').attributes,
263                result = undefined;
264            $.each(attributes, function (i) {
265                if (attributes[i]['id'] == id) {
266                    result = attributes[i];
267                    return false;
268                }
269            });
270            return result;
271        },
272
273        destroy: function () {
274            return this.each(function () {
275                $(this).unbind('.yiiActiveForm');
276                $(this).removeData('yiiActiveForm');
277            });
278        },
279
280        data: function () {
281            return this.data('yiiActiveForm');
282        },
283
284        // validate all applicable inputs in the form
285        validate: function () {
286            var $form = $(this),
287                data = $form.data('yiiActiveForm'),
288                needAjaxValidation = false,
289                messages = {},
290                deferreds = deferredArray(),
291                submitting = data.submitting;
292
293            if (submitting) {
294                var event = $.Event(events.beforeValidate);
295                $form.trigger(event, [messages, deferreds]);
296                if (event.result === false) {
297                    data.submitting = false;
298                    submitFinalize($form);
299                    return;
300                }
301            }
302
303            // client-side validation
304            $.each(data.attributes, function () {
305                if (!$(this.input).is(":disabled")) {
306                    this.cancelled = false;
307                    // perform validation only if the form is being submitted or if an attribute is pending validation
308                    if (data.submitting || this.status === 2 || this.status === 3) {
309                        var msg = messages[this.id];
310                        if (msg === undefined) {
311                            msg = [];
312                            messages[this.id] = msg;
313                        }
314                        var event = $.Event(events.beforeValidateAttribute);
315                        $form.trigger(event, [this, msg, deferreds]);
316                        if (event.result !== false) {
317                            if (this.validate) {
318                                this.validate(this, getValue($form, this), msg, deferreds, $form);
319                            }
320                            if (this.enableAjaxValidation) {
321                                needAjaxValidation = true;
322                            }
323                        } else {
324                            this.cancelled = true;
325                        }
326                    }
327                }
328            });
329
330            // ajax validation
331            $.when.apply(this, deferreds).always(function() {
332                // Remove empty message arrays
333                for (var i in messages) {
334                    if (0 === messages[i].length) {
335                        delete messages[i];
336                    }
337                }
338                if ($.isEmptyObject(messages) && needAjaxValidation) {
339                    var $button = data.submitObject,
340                        extData = '&' + data.settings.ajaxParam + '=' + $form.attr('id');
341                    if ($button && $button.length && $button.attr('name')) {
342                        extData += '&' + $button.attr('name') + '=' + $button.attr('value');
343                    }
344                    $.ajax({
345                        url: data.settings.validationUrl,
346                        type: $form.attr('method'),
347                        data: $form.serialize() + extData,
348                        dataType: data.settings.ajaxDataType,
349                        complete: function (jqXHR, textStatus) {
350                            $form.trigger(events.ajaxComplete, [jqXHR, textStatus]);
351                        },
352                        beforeSend: function (jqXHR, settings) {
353                            $form.trigger(events.ajaxBeforeSend, [jqXHR, settings]);
354                        },
355                        success: function (msgs) {
356                            if (msgs !== null && typeof msgs === 'object') {
357                                $.each(data.attributes, function () {
358                                    if (!this.enableAjaxValidation || this.cancelled) {
359                                        delete msgs[this.id];
360                                    }
361                                });
362                                updateInputs($form, $.extend(messages, msgs), submitting);
363                            } else {
364                                updateInputs($form, messages, submitting);
365                            }
366                        },
367                        error: function () {
368                            data.submitting = false;
369                            submitFinalize($form);
370                        }
371                    });
372                } else if (data.submitting) {
373                    // delay callback so that the form can be submitted without problem
374                    setTimeout(function () {
375                        updateInputs($form, messages, submitting);
376                    }, 200);
377                } else {
378                    updateInputs($form, messages, submitting);
379                }
380            });
381        },
382
383        submitForm: function () {
384            var $form = $(this),
385                data = $form.data('yiiActiveForm');
386
387            if (data.validated) {
388                // Second submit's call (from validate/updateInputs)
389                data.submitting = false;
390                var event = $.Event(events.beforeSubmit);
391                $form.trigger(event);
392                if (event.result === false) {
393                    data.validated = false;
394                    submitFinalize($form);
395                    return false;
396                }
397                updateHiddenButton($form);
398                return true;   // continue submitting the form since validation passes
399            } else {
400                // First submit's call (from yii.js/handleAction) - execute validating
401                setSubmitFinalizeDefer($form);
402
403                if (data.settings.timer !== undefined) {
404                    clearTimeout(data.settings.timer);
405                }
406                data.submitting = true;
407                methods.validate.call($form);
408                return false;
409            }
410        },
411
412        resetForm: function () {
413            var $form = $(this);
414            var data = $form.data('yiiActiveForm');
415            // Because we bind directly to a form reset event instead of a reset button (that may not exist),
416            // when this function is executed form input values have not been reset yet.
417            // Therefore we do the actual reset work through setTimeout.
418            setTimeout(function () {
419                $.each(data.attributes, function () {
420                    // Without setTimeout() we would get the input values that are not reset yet.
421                    this.value = getValue($form, this);
422                    this.status = 0;
423                    var $container = $form.find(this.container);
424                    $container.removeClass(
425                        data.settings.validatingCssClass + ' ' +
426                            data.settings.errorCssClass + ' ' +
427                            data.settings.successCssClass
428                    );
429                    $container.find(this.error).html('');
430                });
431                $form.find(data.settings.errorSummary).hide().find('ul').html('');
432            }, 1);
433        },
434
435        /**
436         * Updates error messages, input containers, and optionally summary as well.
437         * If an attribute is missing from messages, it is considered valid.
438         * @param messages array the validation error messages, indexed by attribute IDs
439         * @param summary whether to update summary as well.
440         */
441        updateMessages: function (messages, summary) {
442            var $form = $(this);
443            var data = $form.data('yiiActiveForm');
444            $.each(data.attributes, function () {
445                updateInput($form, this, messages);
446            });
447            if (summary) {
448                updateSummary($form, messages);
449            }
450        },
451
452        /**
453         * Updates error messages and input container of a single attribute.
454         * If messages is empty, the attribute is considered valid.
455         * @param id attribute ID
456         * @param messages array with error messages
457         */
458        updateAttribute: function(id, messages) {
459            var attribute = methods.find.call(this, id);
460            if (attribute != undefined) {
461                var msg = {};
462                msg[id] = messages;
463                updateInput($(this), attribute, msg);
464            }
465        }
466
467    };
468
469    var watchAttribute = function ($form, attribute) {
470        var $input = findInput($form, attribute);
471        if (attribute.validateOnChange) {
472            $input.on('change.yiiActiveForm', function () {
473                validateAttribute($form, attribute, false);
474            });
475        }
476        if (attribute.validateOnBlur) {
477            $input.on('blur.yiiActiveForm', function () {
478                if (attribute.status == 0 || attribute.status == 1) {
479                    validateAttribute($form, attribute, true);
480                }
481            });
482        }
483        if (attribute.validateOnType) {
484            $input.on('keyup.yiiActiveForm', function (e) {
485                if ($.inArray(e.which, [16, 17, 18, 37, 38, 39, 40]) !== -1 ) {
486                    return;
487                }
488                if (attribute.value !== getValue($form, attribute)) {
489                    validateAttribute($form, attribute, false, attribute.validationDelay);
490                }
491            });
492        }
493    };
494
495    var unwatchAttribute = function ($form, attribute) {
496        findInput($form, attribute).off('.yiiActiveForm');
497    };
498
499    var validateAttribute = function ($form, attribute, forceValidate, validationDelay) {
500        var data = $form.data('yiiActiveForm');
501
502        if (forceValidate) {
503            attribute.status = 2;
504        }
505        $.each(data.attributes, function () {
506            if (this.value !== getValue($form, this)) {
507                this.status = 2;
508                forceValidate = true;
509            }
510        });
511        if (!forceValidate) {
512            return;
513        }
514
515        if (data.settings.timer !== undefined) {
516            clearTimeout(data.settings.timer);
517        }
518        data.settings.timer = setTimeout(function () {
519            if (data.submitting || $form.is(':hidden')) {
520                return;
521            }
522            $.each(data.attributes, function () {
523                if (this.status === 2) {
524                    this.status = 3;
525                    $form.find(this.container).addClass(data.settings.validatingCssClass);
526                }
527            });
528            methods.validate.call($form);
529        }, validationDelay ? validationDelay : 200);
530    };
531
532    /**
533     * Returns an array prototype with a shortcut method for adding a new deferred.
534     * The context of the callback will be the deferred object so it can be resolved like ```this.resolve()```
535     * @returns Array
536     */
537    var deferredArray = function () {
538        var array = [];
539        array.add = function(callback) {
540            this.push(new $.Deferred(callback));
541        };
542        return array;
543    };
544
545    /**
546     * Updates the error messages and the input containers for all applicable attributes
547     * @param $form the form jQuery object
548     * @param messages array the validation error messages
549     * @param submitting whether this method is called after validation triggered by form submission
550     */
551    var updateInputs = function ($form, messages, submitting) {
552        var data = $form.data('yiiActiveForm');
553
554        if (submitting) {
555            var errorAttributes = [];
556            $.each(data.attributes, function () {
557                if (!$(this.input).is(":disabled") && !this.cancelled && updateInput($form, this, messages)) {
558                    errorAttributes.push(this);
559                }
560            });
561
562            $form.trigger(events.afterValidate, [messages, errorAttributes]);
563
564            updateSummary($form, messages);
565
566            if (errorAttributes.length) {
567                if (data.settings.scrollToError) {
568                    var top = $form.find($.map(errorAttributes, function(attribute) {
569                        return attribute.input;
570                    }).join(',')).first().closest(':visible').offset().top;
571                    var wtop = $(window).scrollTop();
572                    if (top < wtop || top > wtop + $(window).height()) {
573                        $(window).scrollTop(top);
574                    }
575                }
576                data.submitting = false;
577            } else {
578                data.validated = true;
579                var buttonTarget = data.submitObject ? data.submitObject.attr('formtarget') : null;
580                if (buttonTarget) {
581                    // set target attribute to form tag before submit
582                    $form.attr('target', buttonTarget);
583                }
584                $form.submit();
585                // restore original target attribute value
586                $form.attr('target', data.target);
587            }
588        } else {
589            $.each(data.attributes, function () {
590                if (!this.cancelled && (this.status === 2 || this.status === 3)) {
591                    updateInput($form, this, messages);
592                }
593            });
594        }
595        submitFinalize($form);
596    };
597
598    /**
599     * Updates hidden field that represents clicked submit button.
600     * @param $form the form jQuery object.
601     */
602    var updateHiddenButton = function ($form) {
603        var data = $form.data('yiiActiveForm');
604        var $button = data.submitObject || $form.find(':submit:first');
605        // TODO: if the submission is caused by "change" event, it will not work
606        if ($button.length && $button.attr('type') == 'submit' && $button.attr('name')) {
607            // simulate button input value
608            var $hiddenButton = $('input[type="hidden"][name="' + $button.attr('name') + '"]', $form);
609            if (!$hiddenButton.length) {
610                $('<input>').attr({
611                    type: 'hidden',
612                    name: $button.attr('name'),
613                    value: $button.attr('value')
614                }).appendTo($form);
615            } else {
616                $hiddenButton.attr('value', $button.attr('value'));
617            }
618        }
619    };
620
621    /**
622     * Updates the error message and the input container for a particular attribute.
623     * @param $form the form jQuery object
624     * @param attribute object the configuration for a particular attribute.
625     * @param messages array the validation error messages
626     * @return boolean whether there is a validation error for the specified attribute
627     */
628    var updateInput = function ($form, attribute, messages) {
629        var data = $form.data('yiiActiveForm'),
630            $input = findInput($form, attribute),
631            hasError = false;
632
633        if (!$.isArray(messages[attribute.id])) {
634            messages[attribute.id] = [];
635        }
636        $form.trigger(events.afterValidateAttribute, [attribute, messages[attribute.id]]);
637
638        attribute.status = 1;
639        if ($input.length) {
640            hasError = messages[attribute.id].length > 0;
641            var $container = $form.find(attribute.container);
642            var $error = $container.find(attribute.error);
643            if (hasError) {
644                if (attribute.encodeError) {
645                    $error.text(messages[attribute.id][0]);
646                } else {
647                    $error.html(messages[attribute.id][0]);
648                }
649                $container.removeClass(data.settings.validatingCssClass + ' ' + data.settings.successCssClass)
650                    .addClass(data.settings.errorCssClass);
651            } else {
652                $error.empty();
653                $container.removeClass(data.settings.validatingCssClass + ' ' + data.settings.errorCssClass + ' ')
654                    .addClass(data.settings.successCssClass);
655            }
656            attribute.value = getValue($form, attribute);
657        }
658        return hasError;
659    };
660
661    /**
662     * Updates the error summary.
663     * @param $form the form jQuery object
664     * @param messages array the validation error messages
665     */
666    var updateSummary = function ($form, messages) {
667        var data = $form.data('yiiActiveForm'),
668            $summary = $form.find(data.settings.errorSummary),
669            $ul = $summary.find('ul').empty();
670
671        if ($summary.length && messages) {
672            $.each(data.attributes, function () {
673                if ($.isArray(messages[this.id]) && messages[this.id].length) {
674                    var error = $('<li/>');
675                    if (data.settings.encodeErrorSummary) {
676                        error.text(messages[this.id][0]);
677                    } else {
678                        error.html(messages[this.id][0]);
679                    }
680                    $ul.append(error);
681                }
682            });
683            $summary.toggle($ul.find('li').length > 0);
684        }
685    };
686
687    var getValue = function ($form, attribute) {
688        var $input = findInput($form, attribute);
689        var type = $input.attr('type');
690        if (type === 'checkbox' || type === 'radio') {
691            var $realInput = $input.filter(':checked');
692            if (!$realInput.length) {
693                $realInput = $form.find('input[type=hidden][name="' + $input.attr('name') + '"]');
694            }
695            return $realInput.val();
696        } else {
697            return $input.val();
698        }
699    };
700
701    var findInput = function ($form, attribute) {
702        var $input = $form.find(attribute.input);
703        if ($input.length && $input[0].tagName.toLowerCase() === 'div') {
704            // checkbox list or radio list
705            return $input.find('input');
706        } else {
707            return $input;
708        }
709    };
710
711})(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.