PageSourceSearch

https://agentagitateur.com/cymassets/js/mootools/07081279416980e0b204e4da0de66ca67b968e93formcheck.js

js agentagitateur.com collected 2026-10-02 22:59:29 UTC 38,311 bytes, 1,047 lines download raw bytes

1/*
2	Class: FormCheck
3		Performs different tests on forms and indicates errors.
4		
5	Usage:
6		Works with these types of fields :
7		- input (text, radio, checkbox)
8		- textarea
9		- select
10		
11		You just need to add a specific class to each fields you want to check. 
12		For example, if you add the class
13			(code)
14			validate['required','length[4, -1]','differs[email]','digit']
15			(end code)
16		the value's field must be set (required) with a minimum length of four chars (4, -1), 
17		must differs of the input named email (differs[email]), and must be digit. 
18		
19		You can perform check during the datas entry or on the submit action, shows errors as tips or in a div before or after the field, 
20		show errors one by one or all together, show a list of all errors at the top of the form, localize error messages, add new regex check, ...
21		
22		The layout is design only with css. Now I added a hack to use transparent png with IE6, so you can use png images in formcheck.css (works only for theme, so the file must be named formcheck.css). It can also works with multiple forms on a single html page.
23		The class supports now internationalization. To use it, simply specify a new <script> element in your html head, like this : <script type="text/javascript" src="formcheck/lang/fr.js"></script>.
24
25		If you add the class
26			(code)
27			validate['submit']
28			(end code)
29		to an element like an anchor (or anything else), this element will act as a submit button.
30		
31		N.B. : you must load the language script before the formcheck and this method overpass the old way. You can create new languages following existing ones. You can otherwise still specifiy the alerts' strings when you initialize the Class, with options.
32		If you don't use a language script, the alert will be displayed in english.
33	
34	Test type:
35		You can perform various test on fields by addind them to the validate class. Be careful to *not use space chars*. Here is the list of them.
36			
37		required 					- The field becomes required. This is a regex, you can change it with class options.
38		alpha 						- The value is restricted to alphabetic chars. This is a regex, you can change it with class options.
39		alphanum 					- The value is restricted to alphanumeric characters only. This is a regex, you can change it with class options.
40		nodigit 					- The field doesn't accept digit chars. This is a regex, you can change it with class options.
41		digit 						- The value is restricted to digit (no floating point number) chars, you can pass two arguments (f.e. digit[21,65]) to limit the number between them. Use -1 as second argument to not set a maximum.
42		number 						- The value is restricted to number, including floating point number. This is a regex, you can change it with class options.
43		email 						- The value is restricted to valid email. This is a regex, you can change it with class options.
44		phone 						- The value is restricted to phone chars. This is a regex, you can change it with class options.
45		url: 						- The value is restricted to url. This is a regex, you can change it with class options.
46		confirm 					- The value has to be the same as the one passed in argument. f.e. confirm[password].
47		differs 					- The value has to be diferent as the one passed in argument. f.e. differs[user].
48		length 						- The value length is restricted by argument (f.e. length[6,10]). Use -1 as second argument to not set a maximum.
49		
50		You can also use a custom function to check a field. For example, if you have a field with class
51			(code)
52			validate['required','%customCheck']
53			(end code)
54		the function customCheck(el) will be called to validate the field. '%customcheck' works with other validate(s) together, and '~customcheck' works if the element pass the other validate(s). 
55		Here is an example of what customCheck could look : 
56			(code)
57			function customCheck(el){
58				if (!el.value.test(/^[A-Z]/)) {
59					el.errors.push("Username should begin with an uppercase letter"); 
60					return false;
61				} else {
62					return true;
63				}
64			}
65			(end code)
66		
67		It is now possible to register new fields after a new FormCheck call by using <FormCheck::register> (see <FormCheck::dispose> too).
68		
69	Parameters:
70		When you initialize the class with addEvent, you can set some options. If you want to modify regex, you must do it in a hash, like for display or alert. You can also add new regex check method by adding the regex and an alert with the same name.
71		
72		Required:
73			
74			form_id - The id of the formular. This is required.
75			
76		Optional:
77			
78			submitByAjax 			- you can set this to true if you want to submit your form with ajax. You should use provided events to handle the ajax request (see below). By default it is false.
79			ajaxResponseDiv 		- id of element to inject ajax response into (can also use onAjaxSuccess). By default it is false.
80			ajaxEvalScripts 		- use evalScripts in the Request response. Can be true or false, by default it is false.
81			onAjaxRequest 			- Function to fire when the Request event starts.
82			onAjaxSuccess 			- Function to fire when the Request receives .  Args: response [the request response] - see Mootools docs for Request.onSuccess.
83			onAjaxFailure 			- Function to fire if the Request fails.
84			
85			tipsClass 				- The class to apply to tipboxes' errors. By default it is 'fc-tbx'.
86			errorClass 				- The class to apply to alertbox (not tips). By default it is 'fc-error'.
87			fieldErrorClass 		- The class to apply to fields with errors, except for radios. You should also turn on  options.addClassErrorToField. By default it is 'fc-field-error'
88			
89			trimValue				- If set to true, strip whitespace (or other characters) from the beginning and end of values. By default it is false.
90			validateDisabled		- If set to true, disabled input will be validated too, otherwise not.
91
92		Display:
93			This is a hash of display settings. in here you can modify.
94			
95			showErrors 				- 0 : onSubmit, 1 : onSubmit & onBlur, by default it is 1.
96			titlesInsteadNames		- 0 : When you do a check using differs or confirm, it takes the field name for the alert. If it's set to 1, it will use the title instead of the name.
97			errorsLocation 			- 1 : tips, 2 : before, 3 : after, by default it is 1.
98			indicateErrors 			- 0 : none, 1 : one by one, 2 : all, by default it is 1.
99			indicateErrorsInit		- 0 : determine if the form must be checked on initialize. Could be usefull to force the user to update fields that don't validate.
100			keepFocusOnError 		- 0 : normal behaviour, 1 : the current field keep the focus as it remain errors. By default it is 0.
101			checkValueIfEmpty 		- 0 : When you leave a field and you have set the showErrors option to 1, the value is tested only if a value has been set. 1 : The value is tested  in any case.  By default it is 1.
102			addClassErrorToField 	- 0 : no class is added to the field, 1 : the options.fieldErrorClass is added to the field with an error (except for radio). By default it is 0.
103
104			fixPngForIe 			- 0 : do nothing, 1 : fix png alpha for IE6 in formcheck.css. By default it is 1.
105			replaceTipsEffect 		- 0 : No effect on tips replace when we resize the broswer, 1: tween transition on browser resize;
106			closeTipsButton 		- 0 : the close button of the tipbox is hidden, 1 : the close button of the tipbox is visible. By default it is 1.
107			flashTips 				- 0 : normal behaviour, 1 : the tipbox "flash" (disappear and reappear) if errors remain when the form is submitted. By default it is 0.
108			tipsPosition 			- 'right' : the tips box is placed on the right part of the field, 'left' to place it on the left part. By default it is 'right'.
109			tipsOffsetX 			- Horizontal position of the tips box (margin-left), , by default it is 100 (px).
110			tipsOffsetY				- Vertical position of the tips box (margin-bottom), , by default it is -10 (px).
111			
112			listErrorsAtTop 		- List all errors at the top of the form, , by default it is false.
113			scrollToFirst 			- Smooth scroll the page to first error and focus on it, by default it is true.
114			fadeDuration 			- Transition duration (in ms), by default it is 300.
115		
116		Alerts:
117			This is a hash of alerts settings. in here you can modify strings to localize or wathever else. %0 and %1 represent the argument.
118			
119			required 				- "This field is required."
120			alpha 					- "This field accepts alphabetic characters only."
121			alphanum 				- "This field accepts alphanumeric characters only."
122			nodigit 				- "No digits are accepted."
123			digit 					- "Please enter a valid integer."
124			digitmin 				- "The number must be at least %0"
125			digitltd 				- "The value must be between %0 and %1"
126			number 					- "Please enter a valid number."
127			email 					- "Please enter a valid email: <br /><span>E.g. [email protected]</span>"
128			phone 					- "Please enter a valid phone."
129			url 					- "Please enter a valid url: <br /><span>E.g. http://www.domain.com</span>"
130			confirm 				- "This field is different from %0"
131			differs 				- "This value must be different of %0"
132			length_str 				- "The length is incorrect, it must be between %0 and %1"
133			length_fix 				- "The length is incorrect, it must be exactly %0 characters"
134			lengthmax 				- "The length is incorrect, it must be at max %0"
135			lengthmin 				- "The length is incorrect, it must be at least %0"
136			checkbox 				- "Please check the box"
137			radios 					- "Please select a radio"
138			select 					- "Please choose a value"
139		
140	Example:
141		You can initialize a formcheck (no scroll, custom classes and alert) by adding for example this in your html head this code :
142		
143		(code)
144		<script type="text/javascript">
145			window.addEvent('domready', function() {
146				var myCheck = new FormCheck('form_id', {
147					tipsClass : 'tips_box',
148					display : {
149						scrollToFirst : false
150					},
151					alerts : {
152						required : 'This field is ablolutely required! Please enter a value'
153					}
154				})
155			});
156		</script>
157		(end code)
158	
159	About:
160		formcheck.js v.1.4.2 for mootools v1.2 - 12 / 2008
161		
162		by Floor SA (http://www.floor.ch) MIT-style license
163		
164		Created by Luca Pillonel, last modified by Luca Pillonel
165		
166	Credits:
167		This class was inspired by fValidator by Fabio Zendhi Nagao (http://zend.lojcomm.com.br)
168		
169		Thanks to oneZ, Blots, huughelmink, chdeliens, and everyone who contribute to this project...
170*/
171
172var FormCheck = new Class({
173	
174	Implements: [Options, Events],
175
176	options : {
177		
178		tipsClass: 'fc-tbx',				//tips error class
179		errorClass: 'fc-error',				//div error class
180		fieldErrorClass: 'formlineinputerror',	//error class for elements
181		divErrorClass: 'formlineerror',	//error class for div container elements
182		
183		trimValue : false,					//trim (remove whitespaces before and after) the value
184		validateDisabled : false,			//skip validation on disabled input if set to false.
185		
186		submitByAjax : false,				//false : standard submit way, true : submit by ajax
187		customSubmit : false,				//false : standard submit way, true : submit by onFormIsValid event
188		ajaxResponseDiv : false,			//element to inject ajax response into (can also use onAjaxSuccess) [cronix] 
189		ajaxEvalScripts : false,			//use evalScripts in the Request response [cronix] 
190		onAjaxRequest : $empty,				//Function to fire when the Request event starts 
191		onAjaxSuccess : $empty,				//Function to fire when the Request receives .  Args: response [the request response] - see Mootools docs for Request.onSuccess 
192		onAjaxFailure : $empty,				//Function to fire if the Request fails 
193		onFormIsValid : $empty,				//Function to fire when form is valid
194
195		display : {
196			showErrors : 0,
197			titlesInsteadNames : 0,
198			errorsLocation : 1,
199			indicateErrors : 1,
200			indicateErrorsInit : 0,
201			keepFocusOnError : 0,
202			checkValueIfEmpty : 1,
203			addClassErrorToField : 0,
204			fixPngForIe : 1,
205			replaceTipsEffect : 1,
206			flashTips : 0,
207			closeTipsButton : 1,
208			tipsPosition : "right",
209			tipsOffsetX : -75,
210			tipsOffsetY : 10,
211			listErrorsAtTop : false,
212			scrollToFirst : true,
213			fadeDuration : 300
214		},
215		
216		alerts : {
217			required: "Champs requis",
218			alpha: "This field accepts alphabetic characters only.",
219			alphanum: "Ce champs n'accepte que des charactères alphanumérique",
220			nodigit: "No digits are accepted.",
221			digit: "Please enter a valid integer.",
222			digitltd: "The value must be between %0 and %1",
223			number: "Please enter a valid number.",
224			email: "Adresse email invalide.",
225			phone: "Please enter a valid phone.",
226			url: "Please enter a valid url.",
227			
228			confirm: "Champs de confirmation incorrect",
229			differs: "This value must be different of %0",
230			length_str: "The length is incorrect, it must be between %0 and %1",
231			length_fix: "The length is incorrect, it must be exactly %0 characters",
232			lengthmax: "The length is incorrect, it must be at max %0",
233			lengthmin: "Nb de caractères minimum : %0",
234			checkbox: "Please check the box",
235			radios: "Champs requis",
236			select: "Champs requis"
237		},
238		
239		regexp : {
240			required : /[^.*]/,
241			alpha : /^[a-z ._-]+$/i,
242			alphanum : /^[a-z0-9 ._-]+$/i,
243			digit : /^[-+]?[0-9]+$/,
244			nodigit : /^[^0-9]+$/,
245			number : /^[-+]?\d*\.?\d+$/,
246			email : /^[a-z0-9._%-]+@[a-z0-9.-]+\.[a-z]{2,4}$/i,
247			phone : /^[\d\s ().-]+$/,
248			url : /^(http|https|ftp)\:\/\/[a-z0-9\-\.]+\.[a-z]{2,3}(:[a-z0-9]*)?\/?([a-z0-9\-\._\?\,\'\/\\\+&amp;%\$#\=~])*$/i
249		}
250	},
251	
252	/*
253	Constructor: initialize
254		Constructor
255	
256		Add event on formular and perform some stuff, you now, like settings, ...
257	*/
258	initialize : function(form, options) {
259		if (this.form = $(form)) {
260			
261			this.form.isValid = true;
262			this.regex = ['length'];
263			this.setOptions(options);
264			
265			//internalization
266			if (typeof(formcheckLanguage) != 'undefined') this.options.alerts = $merge(this.options.alerts, formcheckLanguage);
267			
268			this.validations = [];
269			this.alreadyIndicated = false;
270			this.firstError = false;
271			
272			var regex = new Hash(this.options.regexp);
273			regex.each(function(el, key) {
274				this.regex.push(key);
275			}, this);
276
277			this.form.getElements("*[class*=validate]").each(function(el) {
278				this.register(el);
279			}, this);
280			
281			this.form.addEvents({
282				"submit": this.onSubmit.bind(this)
283			});
284			
285			if(this.options.display.fixPngForIe) this.fixIeStuffs();
286			document.addEvent('mousewheel', function(){
287				this.isScrolling = false;
288			}.bind(this));
289		}
290	},
291	
292	/*
293	Function: register
294		Allows you to declare afterward new fields to the formcheck, to check dynamically loaded fields for example.
295	
296	Example:
297		(code)
298		<script type="text/javascript">
299			window.addEvent('domready', function() {
300				formcheck = new FormCheck('form_id');
301			});
302			
303			// ...some code...
304			
305			var newField = new Element('input', {
306				class	: "validate['required']",
307				name	: "new-field"
308			}).inject('form_id');
309			formcheck.register(newField);
310			
311			new Element('input', {
312				class	: "validate['required']",
313				name	: "another-field",
314				id		: "another-field"
315			}).inject('form_id');
316			formcheck.register($('another-field'));
317		</script>
318		(end code)
319	
320	See also:
321		<FormCheck::dispose>
322	*/
323	register : function(el) {
324		el.validation = [];
325		el.getProperty("class").split(' ').each(function(classX) {
326			if(classX.match(/^validate(\[.+\])$/)) {
327				var validators = eval(classX.match(/^validate(\[.+\])$/)[1]);
328				for(var i = 0; i < validators.length; i++) {
329					el.validation.push(validators[i]);
330					if (validators[i].match(/^confirm\[/)) {
331						var field = eval(validators[i].match(/^.+(\[.+\])$/)[1].replace(/([A-Z0-9\._-]+)/i, "'$1'"));
332						if (this.form[field].validation.contains('required')){
333							el.validation.push('required');
334						}
335							
336					}
337				}
338				this.addListener(el);
339			}
340		}, this);
341	},
342	
343	/*
344	Function: dispose
345		Allows you to remove a declared field from formCheck
346	
347	Example:
348		(code)
349		<script type="text/javascript">
350			window.addEvent('domready', function() {
351				formcheck = new FormCheck('form_id');
352			});
353			
354			// ...some code...
355			
356			formcheck.dispose($('obsolete-field'));
357		</script>
358		(end code)
359	
360	See also:
361		<FormCheck::register>
362	*/
363	dispose : function(element) {
364		this.validations.erase(element);
365	},
366	
367	/*
368	Function: addListener
369		Private method
370		
371		Add listener on fields
372	*/
373	addListener : function(el) {
374		this.validations.push(el);
375		el.errors = [];
376		
377		if (this.options.display.indicateErrorsInit) {
378			this.validations.each(function(el) {
379				if(!this.manageError(el,'submit')) this.form.isValid = false;
380			}, this);
381			return true;
382		} 
383	
384		if (el.validation[0] == 'submit') {
385			el.addEvent('click', function(e){
386				this.onSubmit(e);
387			}.bind(this));
388			return true;
389		}
390
391		if (this.isChildType(el) == false) el.addEvent('blur', function() {
392			(function(){
393				if(!this.fxRunning && (el.element || this.options.display.showErrors == 1) && (this.options.display.checkValueIfEmpty || el.value))
394				this.manageError(el, 'blur')
395			}.bind(this)).delay(100);
396		}.bind(this))
397		//We manage errors on radio
398		else if (this.isChildType(el) == true) {
399			//We get all radio from the same group and add a blur option
400			var nlButtonGroup = this.form.getElements('input[name="'+ el.getProperty("name") +'"]');
401			nlButtonGroup.each(function(radio){
402				radio.addEvent('blur', function(){
403					(function(){
404						if((el.element || this.options.display.showErrors == 1) && (this.options.display.checkValueIfEmpty || el.value)) this.manageError(el, 'click');
405					}.bind(this)).delay(100);
406				}.bind(this))
407			},this);
408		}
409	},
410	
411	/*
412	Function: validate
413		Private method
414		
415		Dispatch check to other methods
416	*/
417	validate : function(el) {
418		el.errors = [];
419		el.isOk = true;
420		
421		//skip validation and trim if specified
422		if (el.getParent('div.formline') && el.getParent('div.formline').getStyle('display') == 'none') return true;
423		if (!this.options.validateDisabled && el.get('disabled')) return true;
424		if (this.options.trimValue && el.value) el.value = el.value.trim();
425		
426		el.validation.each(function(rule) {
427			if(this.isChildType(el)) {
428				if (this.validateGroup(el) == false) {
429					el.isOk = false;
430				}
431			} else {
432				var ruleArgs = [];
433				
434				if(rule.match(/^.+\[/)) {
435					var ruleMethod = rule.split('[')[0];
436					ruleArgs = eval(rule.match(/^.+(\[.+\])$/)[1].replace(/([A-Z0-9\._-]+)/i, "'$1'"));
437				} else var ruleMethod = rule;
438				//console.log(ruleMethod);
439				//console.log(ruleArgs);
440				if (this.regex.contains(ruleMethod) && el.get('tag') != "select") {
441					//console.log('----');
442					if (this.validateRegex(el, ruleMethod, ruleArgs) == false) {
443						el.isOk = false;
444					}
445				}
446				
447				if (ruleMethod == 'confirm') {
448					if (this.validateConfirm(el, ruleArgs) == false) {
449						el.isOk = false;
450					}
451				}
452				if (ruleMethod == 'differs') {
453					if (this.validateDiffers(el, ruleArgs) == false) {
454						el.isOk = false;
455					}
456				}
457				if (el.get('tag') == "select" || (el.type == "checkbox" && ruleMethod == 'required')) {
458					if (this.simpleValidate(el) == false) {
459						el.isOk = false;
460					}
461				}
462				if(rule.match(/%[A-Z0-9\._-]+$/i) || (el.isOk && rule.match(/~[A-Z0-9\._-]+$/i))) {
463					if(eval(rule.slice(1)+'(el)') == false) {
464						el.isOk = false;
465					}
466				}
467			}
468		}, this);
469		
470		if (el.isOk) return true;
471		else return false;
472	},
473	
474	/*
475	Function: simpleValidate
476		Private method
477		
478		Perform simple check for select fields and checkboxes
479	*/
480	simpleValidate : function(el) {
481		if (el.get('tag') == 'select' && el.selectedIndex <= 0) {
482			el.errors.push([this.options.alerts.select,1]);
483			return false;
484		} else if (el.type == "checkbox" && el.checked == false) {
485			el.errors.push([this.options.alerts.checkbox,1]);
486			return false;
487		}
488		return true;
489	},
490	
491	/*
492	Function: validateRegex
493		Private method
494		
495		Perform regex validations
496	*/
497	validateRegex : function(el, ruleMethod, ruleArgs) {
498		var msg = "";
499		if (ruleArgs[1] && ruleMethod == 'length') {
500			if (ruleArgs[1] == -1) {
501				this.options.regexp.length = new RegExp("^[\\s\\S]{"+ ruleArgs[0] +",}$");
502				msg = this.options.alerts.lengthmin.replace("%0",ruleArgs[0]);
503			} else if(ruleArgs[0] == ruleArgs[1]) {
504				this.options.regexp.length = new RegExp("^[\\s\\S]{"+ ruleArgs[0] +"}$");
505				msg = this.options.alerts.length_fix.replace("%0",ruleArgs[0]);
506			} else {
507				this.options.regexp.length = new RegExp("^[\\s\\S]{"+ ruleArgs[0] +","+ ruleArgs[1] +"}$");
508				msg = this.options.alerts.length_str.replace("%0",ruleArgs[0]).replace("%1",ruleArgs[1]);
509			}
510		} else if (ruleArgs[0] && ruleMethod == 'length') {
511			this.options.regexp.length = new RegExp("^.{0,"+ ruleArgs[0] +"}$");
512			msg = this.options.alerts.lengthmax.replace("%0",ruleArgs[0]);
513		} else {
514			msg = this.options.alerts[ruleMethod];
515		}
516		if (ruleArgs[1] && ruleMethod == 'digit') {
517			var regres = true;
518			if (!this.options.regexp.digit.test(el.value)) {
519				el.errors.push([this.options.alerts[ruleMethod],1]);
520				regres = false;
521			}
522			if (ruleArgs[1] == -1) {
523				if (el.value >= ruleArgs[0]) var valueres = true; else var valueres = false;
524				msg = this.options.alerts.digitmin.replace("%0",ruleArgs[0]);
525			} else {
526				if (el.value >= ruleArgs[0] && el.value <= ruleArgs[1]) var valueres = true; else var valueres = false;
527				msg = this.options.alerts.digitltd.replace("%0",ruleArgs[0]).replace("%1",ruleArgs[1]);
528			}
529			if (regres == false || valueres == false) {
530				el.errors.push([msg,1]);
531				return false;
532			}
533		} else if (this.options.regexp[ruleMethod].test(el.value) == false)  {
534			var priority = (ruleMethod == 'required') ? 2 : 1;
535			el.errors.push([msg,priority]);
536			return false;
537		}
538		return true;
539	},
540
541	/*
542	Function: validateConfirm
543		Private method
544		
545		Perform confirm validations
546	*/
547	validateConfirm: function(el,ruleArgs) {
548		
549		var confirm = ruleArgs[0];
550		if(el.value != this.form[confirm].value){
551			if (this.options.display.titlesInsteadNames)
552				var msg = this.options.alerts.confirm.replace("%0",this.form[confirm].getProperty('title'));
553			else
554				var msg = this.options.alerts.confirm.replace("%0",confirm);
555			el.errors.push([msg,1]);
556			return false;
557		}
558		return true;
559	},
560	
561	/*
562	Function: validateDiffers
563		Private method
564		
565		Perform differs validations
566	*/
567	validateDiffers: function(el,ruleArgs) {
568		var differs = ruleArgs[0];
569		if(el.value == this.form[differs].value){
570			if (this.options.display.titlesInsteadNames)
571				var msg = this.options.alerts.differs.replace("%0",this.form[differs].getProperty('title'));
572			else
573				var msg = this.options.alerts.differs.replace("%0",differs);
574			el.errors.push([msg,1]);
575			return false;
576		}
577		return true;
578	},
579	
580	/*
581	Function: isChildType
582		Private method
583		
584		Determine if the field is a group of radio or not.
585	*/
586	isChildType: function(el) {
587		return ($defined(el.type) && el.type == 'radio') ? true : false;
588	},
589	
590	/*
591	Function: validateGroup
592		Private method
593		
594		Perform radios validations
595	*/
596	validateGroup : function(el) {
597		el.errors = [];
598		var nlButtonGroup = this.form[el.getProperty("name")];
599		el.group = nlButtonGroup;
600		var cbCheckeds = false;
601		
602		for(var i = 0; i < nlButtonGroup.length; i++) {
603			if(nlButtonGroup[i].checked) {
604				cbCheckeds = true;
605			}
606		}
607		if(cbCheckeds == false) {
608			el.errors.push([this.options.alerts.radios,1]);
609			return false;
610		} else {
611			return true;	
612		}
613	},
614	
615	/*
616	Function: listErrorsAtTop
617		Private method
618		
619		Display errors
620	*/
621	listErrorsAtTop : function(obj) {
622		if(!this.form.element) {
623			 this.form.element = new Element('div', {'id' : 'errorlist', 'class' : this.options.errorClass}).injectTop(this.form);
624		}
625		if ($type(obj) == 'collection') {
626			new Element('p').set('html',"<span>" + obj[0].name + " : </span>" + obj[0].errors[0]).injectInside(this.form.element);
627		} else {
628			if ((obj.validation.contains('required') && obj.errors.length > 0) || (obj.errors.length >
628 0 && obj.value && obj.validation.contains('required') == false)) {
629				obj.errors.each(function(error) {
630					new Element('p').set('html',"<span>" + obj.name + " : </span>" + error[0]).injectInside(this.form.element);
631				}, this);
632			}
633		}
634	},
635	
636	/*
637	Function: manageError
638		Private method
639		
640		Manage display of errors boxes
641	*/
642	manageError : function(el, method) {
643		var isValid = this.validate(el);
644		if ((!isValid && el.validation.flatten()[0].contains('confirm[')) || (!isValid && el.validation.contains('required')) || (!el.validation.contains('required') && el.value && !isValid)) {
645			if(this.options.display.listErrorsAtTop == true && method == 'submit')
646				this.listErrorsAtTop(el, method);
647			if (this.options.display.indicateErrors == 2 ||this.alreadyIndicated == false || el.name == this.alreadyIndicated.name)
648			{
649				if(!this.firstError) this.firstError = el;
650				
651				this.alreadyIndicated = el;
652				
653				if (this.options.display.keepFocusOnError && el.name == this.firstError.name) (function(){el.focus()}).delay(20);
654				this.addError(el);
655				return false;
656			}
657		} else if ((isValid || (!el.validation.contains('required') && !el.value)) && el.element) {
658			this.removeError(el);
659			return true;
660		}
661		return true;
662	},
663	
664	/*
665	Function: addError
666		Private method
667		
668		Add error message
669	*/
670	addError : function(obj) {
671		if(!obj.element && this.options.display.indicateErrors != 0) {
672			if (this.options.display.errorsLocation == 1) {
673				var pos = (this.options.display.tipsPosition == 'left') ? obj.getCoordinates().left : obj.getCoordinates().right;
674				pos += this.options.display.tipsOffsetX;
675				if ( this.isChildType(obj) && this.options.display.tipsPosition == 'right'){
676					pos = obj.getParent('div.inputform').getLast('span').getCoordinates().right - 40;
677				}
678				if ( obj.hasClass('unikcb') ){
679					pos -= this.options.display.tipsOffsetX;
680					pos -= 45;
681				}
682				var options = {
683					'opacity' : 0,
684					'position' : 'absolute',
685					'float' : 'left',
686					'left' : pos
687				}
688				obj.element = new Element('div', {'class' : this.options.tipsClass, 'styles' : options}).injectInside(document.body);
689				this.addPositionEvent(obj);
690			} else if (this.options.display.errorsLocation == 2){
691				obj.element = new Element('div', {'class' : this.options.errorClass, 'styles' : {'opacity' : 0}}).injectBefore(obj);
692			} else if (this.options.display.errorsLocation == 3){
693				obj.element = new Element('div', {'class' : this.options.errorClass, 'styles' : {'opacity' : 0}});
694				if ($type(obj.group) == 'object' || $type(obj.group) == 'collection')
695					obj.element.injectAfter(obj.group[obj.group.length-1]);
696				else
697					obj.element.injectAfter(obj);
698			}
699		}					
700		if (obj.element && obj.element != true) {
701			obj.element.empty();
702			if (this.options.display.errorsLocation == 1) {
703				var errors = [];
704				var priority_max = -1;
705				obj.errors.each(function(error) {
706					if ( error[1] > priority_max) priority_max = error[1];
707				});
708				obj.errors.each(function(error) {
709					if ( error[1] == priority_max)
710						errors.push(new Element('p').set('html', error[0]));
711				});
712				var alt_err = obj.get('rel');
713				if ( alt_err && alt_err.length > 0 )
714					errors = [new Element('p').set('html', alt_err)];
715				// si obj a un attribut spécial d'erreur remplacer les erreurs par celle ci
716				var tips = this.makeTips(errors).injectInside(obj.element);
717				if(this.options.display.closeTipsButton) {
718					tips.getElements('a.close').addEvent('mouseup', function(){
719						this.removeError(obj);
720					}.bind(this));
721				}
722				var pos = obj.getCoordinates().top - tips.getCoordinates().height + this.options.display.tipsOffsetY;
723				if ( this.isChildType(obj) && this.options.display.tipsPosition == 'right'){
724					//pos -= this.options.display.tipsOffsetY;
725				}
726				if ( obj.hasClass('unikcb') ){
727					pos -= 5;
728				}
729				obj.element.setStyle('top', pos);
730			} else {
731				obj.errors.each(function(error) {
732					new Element('p').set('html',error[0]).injectInside(obj.element);
733				});
734			}
735			
736			if (!this.options.display.fadeDuration || Browser.Engine.trident && Browser.Engine.version == 5 && this.options.display.errorsLocation < 2) {
737				obj.element.setStyle('opacity', 1);
738			} else {
739				obj.fx = new Fx.Tween(obj.element, {
740					'duration' : this.options.display.fadeDuration,
741					'ignore' : true,
742					'onStart' : function(){
743						this.fxRunning = true;
744					}.bind(this),
745					'onComplete' : function() {
746						this.fxRunning = false;
747						if (obj.element && obj.element.getStyle('opacity').toInt() == 0) {
748							obj.element.destroy();
749							obj.element = false;
750						}
751					}.bind(this)
752				})
753				if(obj.element.getStyle('opacity').toInt() != 1) obj.fx.start('opacity', 1);
754			}
755		}
756		if (this.options.display.addClassErrorToField){
757			if ( obj.getParent('div.formline') ) 
758				obj.getParent('div.formline').addClass(this.options.divErrorClass);
759			if ( !this.isChildType(obj) ){
760				obj.addClass(this.options.fieldErrorClass);
761				obj.element = obj.element || true;
762			}
763		}
764			
765	},
766	
767	/*
768	Function: addPositionEvent
769		
770		Update tips position after a browser resize
771	*/
772	addPositionEvent : function(obj) {
773		if(this.options.display.replaceTipsEffect) {
774			obj.event = function(){
775				new Fx.Morph(obj.element, {
776					'duration' : this.options.display.fadeDuration
777				}).start({ 
778					'left':[obj.element.getStyle('left'), obj.getCoordinates().right + this.options.display.tipsOffsetX],
779					'top':[obj.element.getStyle('top'), obj.getCoordinates().top - obj.element.getCoordinates().height + this.options.display.tipsOffsetY]
780				});
781			}.bind(this);
782			
783		} else {
784			obj.event = function(){
785				obj.element.setStyles({ 
786					'left':obj.getCoordinates().right + this.options.display.tipsOffsetX,
787					'top':obj.getCoordinates().top - obj.element.getCoordinates().height + this.options.display.tipsOffsetY
788				});
789			}.bind(this)
790		}
791		window.addEvent('resize', obj.event);
792	},
793	
794	/*
795	Function: removeError
796		Private method
797		
798		Remove the error display
799	*/
800	removeError : function(obj) {
801		this.alreadyIndicated = false;
802		obj.errors = [];
803		obj.isOK = true;
804		window.removeEvent('resize', obj.event);
805		if (this.options.display.errorsLocation >= 2 && obj.element) {
806			new Fx.Tween(obj.element, {
807				'duration': this.options.display.fadeDuration
808			}).start('height', 0);
809		}
810		if (!this.options.display.fadeDuration || Browser.Engine.trident && Browser.Engine.version == 5 && this.options.display.errorsLocation == 1 && obj.element) {
811			this.fxRunning = true;
812			obj.element.destroy();
813			obj.element = false;
814			(function(){this.fxRunning = false}.bind(this)).delay(200);
815		} else if (obj.element && obj.element != true) {
816			obj.fx.start('opacity', 0);
817		}
818		
819		if (this.options.display.addClassErrorToField){
820			if ( obj.getParent('div.formline') ) 
821				obj.getParent('div.formline').removeClass(this.options.divErrorClass);
822			if ( !this.isChildType(obj) )
823				obj.removeClass(this.options.fieldErrorClass);
824		}
825	},
826	
827	/*
828	Function: focusOnError
829		Private method
830		
831		Create set the focus to the first field with an error if needed
832	*/
833	focusOnError : function (obj) {
834		if (this.options.display.scrollToFirst && !this.alreadyFocused && !this.isScrolling) {
835			if (!this.options.display.indicateErrors || !this.options.display.errorsLocation) {
836				var dest = obj.getCoordinates().top-30;
837			} else if (this.alreadyIndicated.element) {
838				switch (this.options.display.errorsLocation){
839					case 1 : 
840						var dest = obj.element.getCoordinates().top;
841						break;
842					case 2 :
843						var dest = obj.element.getCoordinates().top-30;
844						break;
845					case 3 :
846						var dest = obj.getCoordinates().top-30;
847						break;
848				}
849				this.isScrolling = true;
850			}
851			var winh = window.getSize().y;
852			//if (window.getScroll().y != dest) {
853			if (dest < window.getScroll().y || dest > (winh + window.getScroll().y)) {
854				new Fx.Scroll(window, {
855					onComplete : function() {
856						this.isScrolling = false;
857						obj.focus();
858					}.bind(this)
859				}).start(0,dest);
860			} else {
861				this.isScrolling = false;
862				obj.focus();
863			}
864			this.alreadyFocused = true;
865		}
866	},
867	
868	/*
869	Function: fixIeStuffs
870		Private method
871		
872		Fix png for IE6
873	*/
874	fixIeStuffs : function () {
875		if (Browser.Engine.trident4) {
876			//We fix png stuffs
877			var rpng = new RegExp('url\\(([\.a-zA-Z0-9_/:-]+\.png)\\)');
878			var search = new RegExp('(.+)formcheck\.css');
879			for (var i = 0; i < document.styleSheets.length; i++){
880				if (document.styleSheets[i].href.match(/formcheck\.css$/)) {
881					var root = document.styleSheets[i].href.replace(search, '$1');
882					var count = document.styleSheets[i].rules.length;
883					for (var j = 0; j < count; j++){
884						var cssstyle = document.styleSheets[i].rules[j].style;
885						var bgimage = root + cssstyle.backgroundImage.replace(rpng, '$1');
886						if (bgimage && bgimage.match(/\.png/i)){
887							var scale = (cssstyle.backgroundRepeat == 'no-repeat') ? 'crop' : 'scale';
888							cssstyle.filter =  'progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, src=\'' + bgimage + '\', sizingMethod=\''+ scale +'\')';
889							cssstyle.backgroundImage = "none";
890						}
891					}
892				}
893			}
894		}
895	},
896	
897	/*
898	Function: makeTips
899		Private method
900		
901		Create tips boxes
902	*/
903	makeTips : function(txt) {
904		var table = new Element('table');
905			table.cellPadding ='0';
906			table.cellSpacing ='0';
907			table.border ='0';
908			
909			var tbody = new Element('tbody').injectInside(table);
910				var tr1 = new Element('tr').injectInside(tbody);
911					new Element('td', {'class' : 'tl'}).injectInside(tr1);
912					new Element('td', {'class' : 't'}).injectInside(tr1);
913					new Element('td', {'class' : 'tr'}).injectInside(tr1);
914				var tr2 = new Element('tr').injectInside(tbody);
915					new Element('td', {'class' : 'l'}).injectInside(tr2);
916					var cont = new Element('td', {'class' : 'c'}).injectInside(tr2);
917						var errors = new Element('div', {'class' : 'err'}).injectInside(cont);
918						txt.each(function(error) {
919							error.injectInside(errors);
920						});
921						if (this.options.display.closeTipsButton) new Element('a',{'class' : 'close'}).injectInside(cont);
922					new Element('td', {'class' : 'r'}).injectInside(tr2);
923				var tr3 = new Element('tr').injectInside(tbody);
924					new Element('td', {'class' : 'bl'}).injectInside(tr3);
925					new Element('td', {'class' : 'b'}).injectInside(tr3);
926					new Element('td', {'class' : 'br'}).injectInside(tr3);			
927		return table;
928	},
929	
930	/*
931	Function: reinitialize
932		Private method		
933		
934		Reinitialize form before submit check
935	*/
936	reinitialize: function() {
937		this.validations.each(function(el) {
938			if (el.element) {
939				el.errors = [];
940				el.isOK = true;
941				if(this.options.display.flashTips == 1) {
942					el.element.destroy();
943					el.element = false;
944				}
945			}
946		}, this);
947		if (this.form.element) this.form.element.empty();
948		this.alreadyFocused = false;
949		this.firstError = false;
950		this.elementToRemove = this.alreadyIndicated;
951		this.alreadyIndicated = false;
952		this.form.isValid = true;
953	},
954	
955	/*
956	Function: submitByAjax
957		Private method		
958		
959		Send the form by ajax, and replace the form with response
960	*/
961	
962	submitByAjax: function() {
963		var url = this.form.getProperty('action');
964		this.fireEvent('ajaxRequest');
965		new Request({
966			url: url,
967			method: this.form.getProperty('method'),
968			data : this.form.toQueryString(),
969			evalScripts: this.options.ajaxEvalScripts,
970			onFailure: function(instance){
971				this.fireEvent('ajaxFailure', instance);
972			}.bind(this),
973			onSuccess: function(result){
974				this.fireEvent('ajaxSuccess', result);
975				if(this.options.ajaxResponseDiv) $(this.options.ajaxResponseDiv).set('html',result);
976			}.bind(this)
977		}).send();
978	},
979	
980	/*
981	Function: onSubmit
982		Private method		
983		
984		Perform check on submit action
985	*/
986	onSubmit: function(event) {
987		this.reinitialize();
988	
989		this.validations.each(function(el) {
990			var validation = this.manageError(el,'submit');
991			if(!validation) this.form.isValid = false;
992		}, this);
993	    
994		if (this.form.isValid) {
995			if (this.options.submitByAjax) {
996				new Event(event).stop();
997				this.submitByAjax();
998			}
999			
1000			if (this.options.customSubmit) {
1001				new Event(event).stop();
1002				//this.fireEvent('formIsValid');
1003				this.options.customSubmit.call();
1004			}
1005		} else {
1006			new Event(event).stop();
1007			if (this.elementToRemove && this.elementToRemove != this.firstError && this.options.display.indicateErrors == 1) {
1008				this.removeError(this.elementToRemove);
1009			}
1010			this.focusOnError(this.firstError)
1011		}
1012	}
1013});
1014
1015
1016var formcheck_forms = [];
1017window.addEvent('domready', function(){
1018	$$('form.formcheck').each(function(d){
1019		formcheck_forms[d.id] = new FormCheck(d, {
1020			display : {
1021				errorsLocation : 1,
1022				indicateErrors : 2,
1023				showErrors : 1,
1024				addClassErrorToField : 1
1025			}
1026		});
1027	});
1028	if ( $('nlform') && formcheck_forms['nlform'] ){
1029		formcheck_forms['nlform'].options.customSubmit = function(){
1030			$('nlsubmit').setStyle('cursor','wait');
1031			$('nlform').animate({'opacity':0.3},500,function(){
1032				new Element('input', {'type':'hidden','name':'nllang','value':SITE_LANG}).inject($('nlform'));
1033				new Request({url:SITE_ROOT+'ajax/?page=nlinscform', onComplete: function(txt, xml){
1034					if ( txt.trim() == '1' ){ // success
1035						$('nlform').animate({'opacity':'0'}, 500, function(){
1036							$('nlform').setStyle('display','none');
1037							$('nlformsuccess').setStyle('opacity','0');
1038							$('nlformsuccess').setStyle('display','block');
1039							$('nlformsuccess').animate({'opacity':'1'},500);
1040						});
1041					}
1042				}}).post($('nlform'));
1043			});
1044			return false;
1045		};
1046	}
1047});

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.