PageSourceSearch

https://www.outfy.com/assets/c1c4115b/jquery.yiiactiveform.js

js outfy.com collected 2026-09-24 09:05:59 UTC 14,713 bytes, 440 lines download raw bytes

1/**
2 * jQuery yiiactiveform plugin file.
3 *
4 * @author Qiang Xue <[email protected]>
5 * @link https://www.yiiframework.com/
6 * @copyright 2008-2010 Yii Software LLC
7 * @license https://www.yiiframework.com/license/
8 * @since 1.1.1
9 */
10
11(function ($) {
12	/*
13	 * returns the value of the CActiveForm input field
14	 * performs additional checks to get proper values for checkbox / radiobutton / checkBoxList / radioButtonList
15	 * @param o object the jQuery object of the input element
16	 */
17	var getAFValue = function (o) {
18		var type,
19			c = [];
20		if (!o.length) {
21			return undefined;
22		}
23		if (o[0].tagName.toLowerCase() === 'span') {
24			o.find(':checked').each(function () {
25				c.push(this.value);
26			});
27			return c.join(',');
28		}
29		type = o.attr('type');
30		if (type === 'checkbox' || type === 'radio') {
31			return o.filter(':checked').val();
32		} else {
33			return o.val();
34		}
35	};
36
37	/**
38	 * yiiactiveform set function.
39	 * @param options map settings for the active form plugin. Please see {@link CActiveForm::options} for available options.
40	 */
41	$.fn.yiiactiveform = function (options) {
42		return this.each(function () {
43			var settings = $.extend({}, $.fn.yiiactiveform.defaults, options || {}),
44				$form = $(this);
45
46			if (settings.validationUrl === undefined) {
47				settings.validationUrl = $form.attr('action');
48			}
49			$.each(settings.attributes, function (i) {
50				this.value = getAFValue($form.find('#' + this.inputID));
51				settings.attributes[i] = $.extend({}, {
52					validationDelay: settings.validationDelay,
53					validateOnChange: settings.validateOnChange,
54					validateOnType: settings.validateOnType,
55					hideErrorMessage: settings.hideErrorMessage,
56					inputContainer: settings.inputContainer,
57					errorCssClass: settings.errorCssClass,
58					successCssClass: settings.successCssClass,
59					beforeValidateAttribute: settings.beforeValidateAttribute,
60					afterValidateAttribute: settings.afterValidateAttribute,
61					validatingCssClass: settings.validatingCssClass,
62					errorCallback: settings.errorCallback
63				}, this);
64			});
65			$form.data('settings', settings);
66
67			settings.submitting = false;  // whether it is waiting for ajax submission result
68			var validate = function (attribute, forceValidate) {
69				if (forceValidate) {
70					attribute.status = 2;
71				}
72				$.each(settings.attributes, function () {
73					if (this.value !== getAFValue($form.find('#' + this.inputID))) {
74						this.status = 2;
75						forceValidate = true;
76					}
77				});
78				if (!forceValidate) {
79					return;
80				}
81
82				if (settings.timer !== undefined) {
83					clearTimeout(settings.timer);
84				}
85				settings.timer = setTimeout(function () {
86					if (settings.submitting || $form.is(':hidden')) {
87						return;
88					}
89					if (attribute.beforeValidateAttribute === undefined || attribute.beforeValidateAttribute($form, attribute)) {
90						$.each(settings.attributes, function () {
91							if (this.status === 2) {
92								this.status = 3;
93								$.fn.yiiactiveform.getInputContainer(this, $form).addClass(this.validatingCssClass);
94							}
95						});
96						$.fn.yiiactiveform.validate($form, function (data) {
97							var hasError = false;
98							$.each(settings.attributes, function () {
99								if (this.status === 2 || this.status === 3) {
100									hasError = $.fn.yiiactiveform.updateInput(this, data, $form) || hasError;
101								}
102							});
103							if (attribute.afterValidateAttribute !== undefined) {
104								attribute.afterValidateAttribute($form, attribute, data, hasError);
105							}
106						},settings.errorCallback);
107					}
108				}, attribute.validationDelay);
109			};
110
111			$.each(settings.attributes, function (i, attribute) {
112				if (this.validateOnChange) {
113					$form.find('#' + this.inputID).on('change', function () {
114						validate(attribute, false);
115					}).on('blur', function () {
116						if (attribute.status !== 2 && attribute.status !== 3) {
117							validate(attribute, !attribute.status);
118						}
119					});
120				}
121				if (this.validateOnType) {
122					$form.find('#' + this.inputID).keyup(function () {
123						if (attribute.value !== getAFValue($(this))) {
124							validate(attribute, false);
125						}
126					});
127				}
128			});
129
130			if (settings.validateOnSubmit) {
131				$form.on('mouseup keyup', ':submit', function () {
132					$form.data('submitObject', $(this));
133				});
134				var validated = false;
135				$form.on('submit', function () {
136					if (validated) {
137						validated = false;
138						return true;
139					}
140					if (settings.timer !== undefined) {
141						clearTimeout(settings.timer);
142					}
143					settings.submitting = true;
144					if (settings.beforeValidate === undefined || settings.beforeValidate($form)) {
145						$.fn.yiiactiveform.validate($form, function (data) {
146							var hasError = false;
147							$.each(settings.attributes, function () {
148								hasError = $.fn.yiiactiveform.updateInput(this, data, $form) || hasError;
149							});
150							$.fn.yiiactiveform.updateSummary($form, data);
151							if (settings.afterValidate === undefined || settings.afterValidate($form, data, hasError)) {
152								if (!hasError) {
153									validated = true;
154									var $button = $form.data('submitObject') || $form.find(':submit:first');
155									// TODO: if the submission is caused by "change" event, it will not work
156									if ($button.length) {
157										$button.trigger('click');
158									} else {  // no submit button in the form
159										$form.trigger('submit');
160									}
161									return;
162								}
163							}
164							settings.submitting = false;
165						},settings.errorCallback);
166					} else {
167						settings.submitting = false;
168					}
169					return false;
170				});
171			}
172
173			/*
174			 * In case of reseting the form we need to reset error messages
175			 * NOTE1: $form.reset - does not exist
176			 * NOTE2: $form.on('reset', ...) does not work
177			 */
178			$form.bind('reset', function () {
179				/*
180				 * because we bind directly to a form reset event, not to a reset button (that could or could not exist),
181				 * when this function is executed form elements values have not been reset yet,
182				 * because of that we use the setTimeout
183				 */
184				setTimeout(function () {
185					$.each(settings.attributes, function () {
186						this.status = 0;
187						var $error = $form.find('#' + this.errorID),
188							$container = $.fn.yiiactiveform.getInputContainer(this, $form);
189
190						$container.removeClass(
191							this.validatingCssClass + ' ' +
192							this.errorCssClass + ' ' +
193							this.successCssClass
194						);
195
196						$error.html('').hide();
197
198						/*
199						 * without the setTimeout() we would get here the current entered value before the reset instead of the reseted value
200						 */
201						this.value = getAFValue($form.find('#' + this.inputID));
202					});
203					/*
204					 * If the form is submited (non ajax) with errors, labels and input gets the class 'error'
205					 */
206					$form.find('label, :input').each(function () {
207						$(this).removeClass(settings.errorCss);
208					});
209					$('#' + settings.summaryID).hide().find('ul').html('');
210					//.. set to initial focus on reset
211					if (settings.focus !== undefined && !window.location.hash) {
212						$form.find(settings.focus).trigger('focus');
213					}
214				}, 1);
215			});
216
217			/*
218			 * set to initial focus
219			 */
220			if (settings.focus !== undefined && !window.location.hash) {
221				$form.find(settings.focus).trigger('focus');
222			}
223		});
224	};
225
226	/**
227	 * Returns the container element of the specified attribute.
228	 * @param attribute object the configuration for a particular attribute.
229	 * @param form the form jQuery object
230	 * @return jQuery the jQuery representation of the container
231	 */
232	$.fn.yiiactiveform.getInputContainer = function (attribute, form) {
233		if (attribute.inputContainer === undefined) {
234			return form.find('#' + attribute.inputID).closest('div');
235		} else {
236			return form.find(attribute.inputContainer).filter(':has("#' + attribute.inputID + '")');
237		}
238	};
239
240	/**
241	 * updates the error message and the input container for a particular attribute.
242	 * @param attribute object the configuration for a particular attribute.
243	 * @param messages array the json data obtained from the ajax validation request
244	 * @param form the form jQuery object
245	 * @return boolean whether there is a validation error for the specified attribute
246	 */
247	$.fn.yiiactiveform.updateInput = function (attribute, messages, form) {
248		attribute.status = 1;
249		var $error, $container,
250			hasError = false,
251			$el = form.find('#' + attribute.inputID),
252			errorCss = form.data('settings').errorCss;
253
254		if ($el.length) {
255			hasError = messages !== null && $.isArray(messages[attribute.id]) && messages[attribute.id].length > 0;
256			$error = form.find('#' + attribute.errorID);
257			$container = $.fn.yiiactiveform.getInputContainer(attribute, form);
258
259			$container.removeClass(
260				attribute.validatingCssClass + ' ' +
261				attribute.errorCssClass + ' ' +
262				attribute.successCssClass
263			);
264			$container.find('label, :input').each(function () {
265				$(this).removeClass(errorCss);
266			});
267
268			if (hasError) {
269				$error.html(messages[attribute.id][0]);
270				$container.addClass(attribute.errorCssClass);
271			} else if (attribute.enableAjaxValidation || attribute.clientValidation) {
272				$container.addClass(attribute.successCssClass);
273			}
274			if (!attribute.hideErrorMessage) {
275				$error.toggle(hasError);
276			}
277
278			attribute.value = getAFValue($el);
279		}
280		return hasError;
281	};
282
283	/**
284	 * updates the error summary, if any.
285	 * @param form jquery the jquery representation of the form
286	 * @param messages array the json data obtained from the ajax validation request
287	 */
288	$.fn.yiiactiveform.updateSummary = function (form, messages) {
289		var settings = $(form).data('settings'),
290			content = '';
291		if (settings.summaryID === undefined) {
292			return;
293		}
294		if (messages) {
295			var summaryAttributes = [];
296			for (var i in settings.attributes) {
297				if (settings.attributes[i].summary) {
298					summaryAttributes.push(settings.attributes[i].id);
299				}
300			}
301			$.each(settings.attributes, function () {
302				if ($.inArray(this.id, summaryAttributes) !== -1 && $.isArray(messages[this.id])) {
303					$.each(messages[this.id], function (j, message) {
304						content = content + '<li>' + message + '</li>';
305					});
306				}
307			});
308		}
309		$('#' + settings.summaryID).toggle(content !== '').find('ul').html(content);
310	};
311
312	/**
313	 * Performs the ajax validation request.
314	 * This method is invoked internally to trigger the ajax validation.
315	 * @param form jquery the jquery representation of the form
316	 * @param successCallback function the function to be invoked if the ajax request succeeds
317	 * @param errorCallback function the function to be invoked if the ajax request fails
318	 */
319	$.fn.yiiactiveform.validate = function (form, successCallback, errorCallback) {
320		var $form = $(form),
321			settings = $form.data('settings'),
322			needAjaxValidation = false,
323			messages = {};
324		$.each(settings.attributes, function () {
325			var value,
326				msg = [];
327			if (this.clientValidation !== undefined && (settings.submitting || this.status === 2 || this.status === 3)) {
328				value = getAFValue($form.find('#' + this.inputID));
329				this.clientValidation(value, msg, this);
330				if (msg.length) {
331					messages[this.id] = msg;
332				}
333			}
334			if (this.enableAjaxValidation && !msg.length && (settings.submitting || this.status === 2 || this.status === 3)) {
335				needAjaxValidation = true;
336			}
337		});
338
339		if (!needAjaxValidation || settings.submitting && !$.isEmptyObject(messages)) {
340			if (settings.submitting) {
341				// delay callback so that the form can be submitted without problem
342				setTimeout(function () {
343					successCallback(messages);
344				}, 200);
345			} else {
346				successCallback(messages);
347			}
348			return;
349		}
350
351		var $button = $form.data('submitObject'),
352			extData = '&' + settings.ajaxVar + '=' + $form.attr('id');
353		if ($button && $button.length) {
354			extData += '&' + $button.attr('name') + '=' + $button.attr('value');
355		}
356
357		$.ajax({
358			url: settings.validationUrl,
359			type: $form.attr('method'),
360			data: $form.serialize() + extData,
361			dataType: 'json',
362			success: function (data) {
363				if (data !== null && typeof data === 'object') {
364					$.each(settings.attributes, function () {
365						if (!this.enableAjaxValidation) {
366							delete data[this.id];
367						}
368					});
369					successCallback($.extend({}, messages, data));
370				} else {
371					successCallback(messages);
372				}
373			},
374			error: function () {
375				if (errorCallback !== undefined) {
376					errorCallback();
377				}
378			}
379		});
380	};
381
382	/**
383	 * Returns the configuration for the specified form.
384	 * The configuration contains all needed information to perform ajax-based validation.
385	 * @param form jquery the jquery representation of the form
386	 * @return object the configuration for the specified form.
387	 */
388	$.fn.yiiactiveform.getSettings = function (form) {
389		return $(form).data('settings');
390	};
391
392	$.fn.yiiactiveform.defaults = {
393		ajaxVar: 'ajax',
394		validationUrl: undefined,
395		validationDelay: 200,
396		validateOnSubmit: false,
397		validateOnChange: true,
398		validateOnType: false,
399		hideErrorMessage: false,
400		inputContainer: undefined,
401		errorCss: 'error',
402		errorCssClass: 'error',
403		successCssClass: 'success',
404		validatingCssClass: 'validating',
405		summaryID: undefined,
406		timer: undefined,
407		beforeValidateAttribute: undefined, // function (form, attribute) | boolean
408		afterValidateAttribute: undefined,  // function (form, attribute, data, hasError)
409		beforeValidate: undefined, // function (form) | boolean
410		afterValidate: undefined,  // function (form, data, hasError) | boolean
411		focus: undefined,  // jquery selector that indicates which element to receive input focus initially
412		/**
413		 * list of attributes to be validated. Each array element is of the following structure:
414		 * {
415		 *     id: 'ModelClass_attribute', // the unique attribute ID
416		 *     model: 'ModelClass', // the model class name
417		 *     name: 'name', // attribute name
418		 *     inputID: 'input-tag-id',
419		 *     errorID: 'error-tag-id',
420		 *     value: undefined,
421		 *     status: 0,  // 0: empty, not entered before,  1: validated, 2: pending validation, 3: validating
422		 *     validationDelay: 200,
423		 *     validateOnChange: true,
424		 *     validateOnType: false,
425		 *     hideErrorMessage: false,
426		 *     inputContainer: undefined,
427		 *     errorCssClass: 'error',
428		 *     successCssClass: 'success',
429		 *     validatingCssClass: 'validating',
430		 *     enableAjaxValidation: true,
431		 *     enableClientValidation: true,
432		 *     clientValidation: undefined, // function (value, messages, attribute) | client-side validation
433		 *     beforeValidateAttribute: undefined, // function (form, attribute) | boolean
434		 *     afterValidateAttribute: undefined,  // function (form, attribute, data, hasError)
435		 * }
436		 */
437		attributes: [],
438		errorCallback: undefined
439	};
440})(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.