// wForms - a javascript extension to web forms.
// v2.0 beta - March.16th 2006
// This software is licensed under the CC-GNU LGPL <http://creativecommons.org/licenses/LGPL/2.1/>


// wForms Helper Functions 
// v2.1 beta - Feb.14th 2006
// This software is licensed under the CC-GNU LGPL <http://creativecommons.org/licenses/LGPL/2.1/>

function wHELPERS() {};
	
	// addEvent adapated from http://ejohn.org/projects/flexible-javascript-events/
	// and  Andy Smith's (http://weblogs.asp.net/asmith/archive/2003/10/06/30744.aspx)
	wHELPERS.prototype.addEvent = function(obj, type, fn) {
		if(!obj) { return; }
		
		if (obj.attachEvent) {
			obj['e'+type+fn] = fn;
			obj[type+fn] = function(){obj['e'+type+fn]( window.event );}
			obj.attachEvent( 'on'+type, obj[type+fn] );
		} else if(obj.addEventListener) {			
			obj.addEventListener( type,fn, false );
		} else {
			var originalHandler = obj["on" + type]; 
			if (originalHandler) { 
			  obj["on" + type] = function(e){originalHandler(e);fn(e);}; 
			} else { 
			  obj["on" + type] = fn; 
			} 
		}
	}
	
	wHELPERS.prototype.removeEvent = function(obj, type, fn) {
		if (obj.detachEvent) {
			if(obj[type+fn]) {
				obj.detachEvent( 'on'+type, obj[type+fn] );
				obj[type+fn] = null;
			}
		} else if(obj.removeEventListener)
			obj.removeEventListener( type, fn, false );
		else {
			obj["on" + type] = null;
		}
	}
	
	
	
	
	
	// Returns the event's source element 
	wHELPERS.prototype.getSourceElement = function(e) {	
		if(!e) e = window.event;	
		if(e.target)
			var srcE = e.target;
		else
			var srcE = e.srcElement;
		if(!srcE) return null;
		if(srcE.nodeType == 3) srcE = srcE.parentNode; // safari weirdness		
		if(srcE.tagName.toUpperCase()=='LABEL' && e.type=='click') { 
			// when clicking a label, firefox fires the input onclick event
			// but the label remains the source of the event. In Opera and IE 
			// the source of the event is the input element. Which is the 
			// expected behavior, I suppose.		
			if(srcE.getAttribute('for')) {
				srcE = document.getElementById(srcE.getAttribute('for'));
			}
		}
		return srcE;
	}
	
	// Cancel the default execution of an event.
	wHELPERS.prototype.preventEvent = function(e) {
		if (!e) e = window.event;
		if (e.preventDefault) e.preventDefault();
		else e.returnValue = false;
		return false;
	}
	
	// Cancel the propagation of the event
	wHELPERS.prototype.stopPropagation = function(e) {
		if (!e) var e = window.event;
		e.cancelBubble = true;
		if (e.stopPropagation) e.stopPropagation();
	}
	
	// Generates a random ID
	wHELPERS.prototype.randomId = function () {
		var seed = (new Date()).getTime();
		seed = seed.toString().substr(6);
		for (var i=0; i<6;i++)
			seed += String.fromCharCode(48 + Math.floor((Math.random()*10)));
		return "id" + seed;
	}
	
	// Activating an Alternate Stylesheet (thx to: http://www.howtocreate.co.uk/tutorials/index.php?tut=0&part=27)
	// Use this to activate a CSS Stylesheet that shouldn't be used if javascript is turned off.
	// The stylesheet rel attribute should be 'alternate stylesheet'. The title attribute MUST be set.
	wHELPERS.prototype.activateStylesheet = function(sheetref) {
		if(document.getElementsByTagName) {
			var ss=document.getElementsByTagName('link');
		} else if (document.styleSheets) {
			var ss = document.styleSheets;
		}
		for(var i=0;ss[i];i++ ) {
			if(ss[i].href.indexOf(sheetref) != -1) {
				ss[i].disabled = true;
				ss[i].disabled = false;			
			}
		}
	}
	
	// hasClass
	wHELPERS.prototype.hasClass = function(element,className) {
		if(element && element.className) {
			if((' ' + element.className + ' ').indexOf(' ' + className +' ') != -1) {
				return true;
			}
		}
		return false;
	}
	wHELPERS.prototype.hasClassPrefix = function(element,className) {
		if(element && element.className) {
			if((' ' + element.className).indexOf(' ' + className) != -1) {
				return true;
			}
		}
		return false;
	}
	
	
	
	// getTop / getLeft  
	// Returns pixel coordinates from the top-left window corner.
	wHELPERS.prototype.getTop = function(obj) {
		var cur = 0;
		if(obj.offsetParent) {		
			while(obj.offsetParent) {
				if((new wHELPERS()).getComputedStyle(obj,'position') == 'relative' ) {
					// relatively postioned element
					return cur;
				}
				cur+=obj.offsetTop;
				obj = obj.offsetParent;
			}
		}
		return cur;
	}
	wHELPERS.prototype.getLeft = function(obj) {
		var cur = 0;
		if(obj.offsetParent) {		
			while(obj.offsetParent) {
				if((new wHELPERS()).getComputedStyle(obj,'position') == 'relative' ) {
					// relatively postioned element
					return cur;
				}
				cur+=obj.offsetLeft;
				obj = obj.offsetParent;
			}
		}
		return cur;
	}
 	
	wHELPERS.prototype.getComputedStyle = function(element, styleName) {
		if(window.getComputedStyle) {
			return window.getComputedStyle(element,"").getPropertyValue(styleName);
		} else if(element.currentStyle) {	
			return element.currentStyle[styleName];
		}
		return false;
	}
	// backward compatibility
	var wHelpers = wHELPERS;   


   /* 
	* MISC FUNCTIONS 
   /* ------------------------------------------------------------------------------------------ */
	
	// Push implementation for IE5/mac
	if (!Array.prototype.push) { 
		Array.prototype.push = function() { 
			for (var i = 0; i < arguments.length; ++i) { 
				this[this.length] = arguments[i]; 
			} 
			return this.length; 
		}; 
	}
	
	// @name      The Fade Anything Technique
	// @namespace http://www.axentric.com/aside/fat/
	// @version   1.0-RC1
	// @author    Adam Michela
	var Fat = {
		make_hex : function (r,g,b) 
		{
			r = r.toString(16); if (r.length == 1) r = '0' + r;
			g = g.toString(16); if (g.length == 1) g = '0' + g;
			b = b.toString(16); if (b.length == 1) b = '0' + b;
			return "#" + r + g + b;
		},
		fade_element : function (id, fps, duration, from, to) 
		{
			if (!fps) fps = 30;
			if (!duration) duration = 3000;
			if (!from || from=="#") from = "#FFFF33";
			if (!to) to = this.get_bgcolor(id);
			
			var frames = Math.round(fps * (duration / 1000));
			var interval = duration / frames;
			var delay = interval;
			var frame = 0;
			
			if (from.length < 7) from += from.substr(1,3);
			if (to.length < 7) to += to.substr(1,3);
			
			var rf = parseInt(from.substr(1,2),16);
			var gf = parseInt(from.substr(3,2),16);
			var bf = parseInt(from.substr(5,2),16);
			var rt = parseInt(to.substr(1,2),16);
			var gt = parseInt(to.substr(3,2),16);
			var bt = parseInt(to.substr(5,2),16);
			
			var r,g,b,h;
			while (frame < frames)
			{
				r = Math.floor(rf * ((frames-frame)/frames) + rt * (frame/frames));
				g = Math.floor(gf * ((frames-frame)/frames) + gt * (frame/frames));
				b = Math.floor(bf * ((frames-frame)/frames) + bt * (frame/frames));
				h = this.make_hex(r,g,b);
			
				setTimeout("Fat.set_bgcolor('"+id+"','"+h+"')", delay);
	
				frame++;
				delay = interval * frame; 
			}
			setTimeout("Fat.set_bgcolor('"+id+"','')", delay);
		},
		set_bgcolor : function (id, c)
		{
			var o = document.getElementById(id);
			if(o)
				o.style.backgroundColor = c;
		},
		get_bgcolor : function (id)
		{
			var o = document.getElementById(id);
			while(o)
			{
				var c;
				if (window.getComputedStyle) c = window.getComputedStyle(o,null).getPropertyValue("background-color");
				if (o.currentStyle) c = o.currentStyle.backgroundColor;
				if ((c != "" && c != "transparent") || o.tagName == "BODY") { break; }
				o = o.parentNode;
			}
			if (c == undefined || c == "" || c == "transparent") c = "#FFFFFF";
			var rgb = c.match(/rgb\s*\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)/);
			if (rgb) c = this.make_hex(parseInt(rgb[1]),parseInt(rgb[2]),parseInt(rgb[3]));
			return c;
		}
	}
	
		

// wForms - a javascript extension to web forms.
// v2.0 beta - Feb.14th 2006
// This software is licensed under the CC-GNU LGPL <http://creativecommons.org/licenses/LGPL/2.1/>
    
  if(wHELPERS) {
	  var wFORMS = { 
	  
		  debugLevel     : 0, /* 0: Inactive, 1+: Debug Level */
		  
		  helpers        : new wHELPERS(),     
		  behaviors      : {},
		  onLoadComplete : new Array(),  /* stack of functions to call once all behaviors have been applied */
		  processedForm  : null,
		  
		  onLoadHandler  : function() {
			  for(var behaviorName in  wFORMS.behaviors) {
				   wFORMS.debug('wForms/loaded behavior: ' + behaviorName);
			  }
  			 
			  for (var i=0;i<document.forms.length;i++) {
			  	wFORMS.debug('wForms/initialize: '+ (document.forms[i].name || document.forms[i].id) );				 
			  	wFORMS.processedForm = document.forms[i];
			  	wFORMS.addBehaviors(document.forms[i]);
			  }
		  },
		  
		  addBehaviors : function (node) {			
			
			if(!node.nodeType) {
				 // argument is not a node. probably an id string. 
				 // (typeof not used for IE5/mac compatibility)
				 node = document.getElementById(node);
			}
			if(!node || node.nodeType!=1) return;
			
			deep=(arguments.length>1)?arguments[1]:true;	
				    	    	
			wFORMS._addBehaviors(node, deep);					
		  },
		  
		  _addBehaviors : function (node, deep) {
			  if(node.getAttribute('rel')=='no-behavior') {
			  	return false;
			  }
			  
			  for(var behaviorName in wFORMS.behaviors) {		  	 
			  	wFORMS.behaviors[behaviorName].evaluate(node);					  
			  }
			 
			  if(deep) {
				  for (var i=node.childNodes.length-1, cn=node.childNodes; i>=0; i--) {
				  	 if(cn[i].nodeType==1)
					 	wFORMS._addBehaviors(cn[i], deep);
			      }
			  }
			  
			  if(node.tagName.toUpperCase() == 'FORM') {
				  // wFORMS.debug('wForms/processed: ' + node.id);
				  // run the init stack
				  for (var i=0;i<wFORMS.onLoadComplete.length;i++) {					 
					  wFORMS.onLoadComplete[i]();
				  }
			  	  // empty the stack					  
				  if(wFORMS.onLoadComplete.length > 0) {
					  wFORMS.onLoadComplete = new Array();
				  }
			  }
		  },
		  
		  hasBehavior: function(behaviorName) {
			  if(wFORMS.behaviors[behaviorName]) return true;
			  return false;
		  },
		  
		  /* 
		   * DEBUG FUNCTIONS 
		   * ------------------------------------------------------------------------------------------ */
		  debug : function(txt) { 
			msgLevel = arguments[1] || 10; 	// 1 = least importance, X = most important
			
			if(wFORMS.debugLevel > 0 && msgLevel >= wFORMS.debugLevel) {
				if(!wFORMS.debugOutput)
					wFORMS.initDebug();
				if(wFORMS.debugOutput)
					wFORMS.debugOutput.innerHTML += "<br />" + txt;
			}
		  },
		  clearDebug: function() {
		  	if(wFORMS.debugOutput)
				wFORMS.debugOutput.innerHTML = "";
		  },
		  initDebug : function() {
			var output = document.getElementById('debugOutput');
			if(!output) {
				output = document.createElement('div');
				output.id = 'debugOutput';
				output.style.position   = 'absolute';
				output.style.right      = '10px';
				output.style.top        = '10px';
				output.style.zIndex     = '300';
				output.style.fontSize   = 'x-small';
				output.style.fontFamily = 'courier';
				output.style.backgroundColor = '#DDD';
				output.style.padding    = '5px';
				if(document.body) // if page fully loaded
					wFORMS.debugOutput = document.body.appendChild(output);
			}
			if(wFORMS.debugOutput)
				wFORMS.debugOutput.ondblclick = function() { this.innerHTML = '' };
		}
	  };
	 
	  // For backward compatibility
	  wFORMS.utilities = wFORMS.helpers;
	  var wf           = wFORMS; 
	  wf.utilities.getSrcElement				= wFORMS.helpers.getSourceElement;
	  wf.utilities.XBrowserPreventEventDefault	= wFORMS.helpers.preventEvent;
	  
	  // Initializations:
	  
	  // Attach JS only stylesheet.
	  wFORMS.helpers.activateStylesheet('wforms-jsonly.css');
	  // Parse document and apply wForms behavior
	  wFORMS.helpers.addEvent(window,'load',wFORMS.onLoadHandler);
  } 
  else {
	  // wHELPERS not loaded.
	  alert('Sorry, whelpers.js is not correctly loaded. The wFORMS Extension is not active.');
  }
  
  
  
  
// wForms - a javascript extension to web forms.
// Field Hint / Tooltip Component
// v2.0 beta - Feb.14th 2006
// This software is licensed under the CC-GNU LGPL <http://creativecommons.org/licenses/LGPL/2.1/>


 if(wFORMS) {

       // Component properties 
       wFORMS.idSuffix_fieldHint           = "-H";                     // a hint id is the associated field id (or name) plus this suffix
       wFORMS.className_inactiveFieldHint  = "field-hint-inactive";    // visual effect depends on CSS stylesheet
       wFORMS.className_activeFieldHint    = "field-hint";             // visual effect depends on CSS stylesheet
       
       
       wFORMS.behaviors['hint'] = {
           name: 'hint', 
                      
		   // evaluate: check if the behavior applies to the given node. Adds event handlers if appropriate
           evaluate: function(node) {
               if(node.id) {
               	   if(node.id.indexOf(wFORMS.idSuffix_fieldHint)>0) {               	   
               	     // this looks like a field-hint. See if we have a matching field.               	    
               	     // try first with the id, then with the name attribute.
               	     var id     = node.id.replace(wFORMS.idSuffix_fieldHint, '');               	     
               	     var hinted = document.getElementById(id) || wFORMS.processedForm[id];
               	   } 
                   if(hinted) {
					   // wFORMS.debug('hint/evaluate: '+ (node.id || node.name));
					   switch(hinted.tagName.toUpperCase()) {
						   case 'SELECT': 
						   case 'TEXTAREA':						   
						   case 'INPUT':
		                       	wFORMS.helpers.addEvent(hinted,'focus',wFORMS.behaviors['hint'].run);
    		                   	wFORMS.helpers.addEvent(hinted,'blur' ,wFORMS.behaviors['hint'].remove);
							   	break;
						   default:
						  	 	wFORMS.helpers.addEvent(hinted,'mouseover',wFORMS.behaviors['hint'].run);
								wFORMS.helpers.addEvent(hinted,'mouseout' ,wFORMS.behaviors['hint'].remove);
						  		break;
					   }
                   } 
               }
           },
		   
           // run: executed when the behavior is activated
           run: function(e) {
               var element   = wFORMS.helpers.getSourceElement(e);
               var fieldHint = document.getElementById(element.id   + wFORMS.idSuffix_fieldHint);
               if(!fieldHint) // try again with the element's name attribute
                   fieldHint = document.getElementById(element.name + wFORMS.idSuffix_fieldHint);
               if(fieldHint) {
                   fieldHint.className = fieldHint.className.replace(wFORMS.className_inactiveFieldHint,
                                                                     wFORMS.className_activeFieldHint);
				   // Field Hint Absolute Positionning
				   fieldHint.style.top  =  (wFORMS.helpers.getTop(element)+ element.offsetHeight).toString() + "px";
				   if(element.tagName.toUpperCase() == 'SELECT') 
					   fieldHint.style.left =  (wFORMS.helpers.getLeft(element) + (element.offsetWidth- 8)).toString() + "px";
				   else 
					   fieldHint.style.left =  (wFORMS.helpers.getLeft(element)).toString() + "px"; /* + element.offsetWidth */
//				   wFORMS.debug('hint/run: ' + (element.id || element.name) , 5);				   
			   }
           },
		   
           // remove: executed if the behavior should not be applied anymore
           remove: function(e) {
               var element   = wFORMS.helpers.getSourceElement(e);
               var fieldHint = document.getElementById(element.id   + wFORMS.idSuffix_fieldHint);
               if(!fieldHint) // try again with the element's name attribute
                   fieldHint = document.getElementById(element.name + wFORMS.idSuffix_fieldHint);
               if(fieldHint)
                   fieldHint.className = fieldHint.className.replace(wFORMS.className_activeFieldHint,
                                                                     wFORMS.className_inactiveFieldHint);
//			   wFORMS.debug('hint/remove: ' + (element.id || element.name) , 5);				   
           }
       }
   }
   
   
// wForms - a javascript extension to web forms.
// Switch Component
// v2.0 beta - Feb.14th 2006
// This software is licensed under the CC-GNU LGPL <http://creativecommons.org/licenses/LGPL/2.1/>


 if(wFORMS) {

		// Component properties 
		wFORMS.classNamePrefix_switch 		= "switch";
		wFORMS.className_switchIsOn         = "swtchIsOn";    // used to keep track of the switch state on buttons and links (where the checked attribute is not available)
		wFORMS.className_switchIsOff        = "swtchIsOff";
		wFORMS.classNamePrefix_offState		= "offstate";
		wFORMS.classNamePrefix_onState		= "onstate";
		wFORMS.switchScopeRootTag           = "";         	  // deprecated.	
		
		wFORMS.switchTriggers               = {};			  // associative multi-dimensional array (switchname->element Ids)
		wFORMS.switchTargets                = {};			  // associative multi-dimensional array (switchname->element Ids)
		
	
		wFORMS.behaviors['switch'] = {
		   
		   // ------------------------------------------------------------------------------------------
		   // evaluate: check if the behavior applies to the given node. Adds event handlers if appropriate
		   // ------------------------------------------------------------------------------------------
		   evaluate: function(node) {
               
			    // Handle Switch Triggers
				// add event handles and populate the wFORMS.switchTriggers 
				// associative array (switchname->element Ids)
				// ------------------------------------------------------------------------------------------				
				if (wFORMS.helpers.hasClassPrefix(node, wFORMS.classNamePrefix_switch)) {

					if(!node.id) node.id = wFORMS.helpers.randomId();
					
					//wFORMS.debug('switch/evaluate: '+ node.className + ' ' + node.tagName);
					
					// Go through each class (one element can have more than one switch trigger).
					var switchNames = wFORMS.behaviors['switch'].getSwitchNames(node);
					for(var i=0; i < switchNames.length; i++) {
						if(!wFORMS.switchTriggers[switchNames[i]]) 
							wFORMS.switchTriggers[switchNames[i]] = new Array();
						if(!wFORMS.switchTriggers[switchNames[i]][node.id])
							wFORMS.switchTriggers[switchNames[i]].push(node.id);
						//wFORMS.debug('switch/evaluate: [trigger] '+ switchNames[i] + ' ' + node.id,3);
					}

					switch(node.tagName.toUpperCase()) {
							
						case "OPTION":
							// get the SELECT element
							var selectNode = node.parentNode;
							while(selectNode && selectNode.tagName.toUpperCase() != 'SELECT') {
								var selectNode = selectNode.parentNode;
							}
							if(!selectNode) { alert('Error: invalid markup in SELECT field ?'); return false;  } // invalid markup
							if(!selectNode.id) selectNode.id = wFORMS.helpers.randomId();

							// Make sure we have only one event handler for the select.
							if(!selectNode.getAttribute('rel') || selectNode.getAttribute('rel').indexOf('wfHandled')==-1) {
								//wFORMS.debug('switch/add event: '+ selectNode.className + ' ' + selectNode.tagName);
								selectNode.setAttribute('rel', (selectNode.getAttribute('rel')||"") + ' wfHandled');
								wFORMS.helpers.addEvent(selectNode, 'change', wFORMS.behaviors['switch'].run);
							}							
							break;

						case "INPUT":							
							if(node.type && node.type.toLowerCase() == 'radio') {
								// Add the onclick event on radio inputs of the same group
								var formElement = node.form;	
								for (var j=0; j<formElement[node.name].length; j++) {
									var radioNode = formElement[node.name][j];
									// prevents conflicts with elements with an id = name of radio group
									if(radioNode.type.toLowerCase() == 'radio') {
										// Make sure we have only one event handler for this radio input.
										if(!radioNode.getAttribute('rel') || radioNode.getAttribute('rel').indexOf('wfHandled')==-1) {								
											wFORMS.helpers.addEvent(radioNode, 'click', wFORMS.behaviors['switch'].run);
											// flag the node 
											radioNode.setAttribute('rel', (radioNode.getAttribute('rel')||"") + ' wfHandled');
										} 
									}
								}
							} else {
								wFORMS.helpers.addEvent(node, 'click', wFORMS.behaviors['switch'].run);
							}
							break;
						
						default:		
							wFORMS.helpers.addEvent(node, 'click', wFORMS.behaviors['switch'].run);
							break;
					}
				}
				
				// Push targets in the wFORMS.switchTargets array 
				// (associative array with switchname -> element ids)
				// ------------------------------------------------------------------------------------------
				if (wFORMS.helpers.hasClassPrefix(node, wFORMS.classNamePrefix_offState) ||
				    wFORMS.helpers.hasClassPrefix(node, wFORMS.classNamePrefix_onState)) {
					
					if(!node.id) node.id = wFORMS.helpers.randomId();
					
					// Go through each class (one element can be the target of more than one switch).
					var switchNames = wFORMS.behaviors['switch'].getSwitchNames(node);
					
					for(var i=0; i < switchNames.length; i++) {
						if(!wFORMS.switchTargets[switchNames[i]]) 
							wFORMS.switchTargets[switchNames[i]] = new Array();
						if(!wFORMS.switchTargets[switchNames[i]][node.id]) 
							wFORMS.switchTargets[switchNames[i]].push(node.id);
						//wFORMS.debug('switch/evaluate: [target] '+ switchNames[i],3);
					}										
				}
				
				if(node.tagName && node.tagName.toUpperCase()=='FORM') {
					// function to be called when all behaviors for this form have been applied
					wFORMS.onLoadComplete.push(wFORMS.behaviors['switch'].init); 
					// wFORMS.debug('switch/push init' + wFORMS.onLoadComplete.length);					
				}
           },
		   
		   // ------------------------------------------------------------------------------------------
           // init: executed once evaluate has been applied to all elements
		   // ------------------------------------------------------------------------------------------	   
		   init: function() {
			   // go through all switch triggers and activate those who are already ON
			   wFORMS.debug('switch/init: ');
			   for(var switchName in wFORMS.switchTriggers) {
					// go through all triggers for the current switch
					for(var i=0; i< wFORMS.switchTriggers[switchName].length; i++) {		   
					   	var element = document.getElementById(wFORMS.switchTriggers[switchName][i]);
						// wFORMS.debug('switch/init: ' + element + ' ' + switchName , 5);	
					   	if(wFORMS.behaviors['switch'].isTriggerOn(element,switchName)) {
							// if it's a select option, get the select element
							if(element.tagName.toUpperCase()=='OPTION') {
								var element = element.parentNode;
								while(element && element.tagName.toUpperCase() != 'SELECT') {
									var element = element.parentNode;
								}
							}
							// run the trigger
							wFORMS.behaviors['switch'].run(element);
						}
				   }
			   }
		   },
		   
		   // ------------------------------------------------------------------------------------------
           // run: executed when the behavior is activated
		   // ------------------------------------------------------------------------------------------	   
           run: function(e) {
                var element   = wFORMS.helpers.getSourceElement(e);
				if(!element) element = e;
			    //wFORMS.debug('switch/run: ' + element.id , 5);	

				var switches_ON  = new Array();
				var switches_OFF = new Array();
				
				// Get list of triggered switches (some ON, some OFF)
				switch(element.tagName.toUpperCase()) {
					case 'SELECT':
						for(var i=0;i<element.options.length;i++) {
							if(i==element.selectedIndex) {	
								switches_ON  = switches_ON.concat(wFORMS.behaviors['switch'].getSwitchNames(element.options[i]));
							} else {
								switches_OFF = switches_OFF.concat(wFORMS.behaviors['switch'].getSwitchNames(element.options[i]));
							}
						}

						break;
					case 'INPUT':
						if(element.type.toLowerCase() == 'radio') {
							// Go through the radio group.
							
							for(var i=0;i <element.form[element.name].length;i++) { 
								var radioElement = element.form[element.name][i];
								if(radioElement.checked) {
									switches_ON  = switches_ON.concat(wFORMS.behaviors['switch'].getSwitchNames(radioElement));
								} else {
									//wFORMS.debug(wFORMS.behaviors['switch'].getSwitchNames(radioElement).length,1);
									switches_OFF = switches_OFF.concat(wFORMS.behaviors['switch'].getSwitchNames(radioElement));
								}
							}
						} else {
							if(element.checked || wFORMS.helpers.hasClass(element, wFORMS.className_switchIsOn)) {
								switches_ON  = switches_ON.concat(wFORMS.behaviors['switch'].getSwitchNames(element));
							} else {
								switches_OFF = switches_OFF.concat(wFORMS.behaviors['switch'].getSwitchNames(element));
							}							
						}
						break;
					default:
						break;
				}
				
				// Turn off switches first
				for(var i=0; i < switches_OFF.length; i++) {
					// Go through all targets of the switch 
					var elements = wFORMS.behaviors['switch'].getElementsBySwitchName(switches_OFF[i]);
					for(var j=0;j<elements.length;j++) {
																									
						// only turn off a target if all its triggers are off
						var triggers = wFORMS.switchTriggers[switches_OFF[i]];												
						var doSwitch = true;
							
						for (var k=0; k < triggers.length; k++) {
							var trigger = document.getElementById(triggers[k]);
							if(wFORMS.behaviors['switch'].isTriggerOn(trigger, switches_OFF[i])) {
								// An element with the REPEAT behavior limits the scope of switches 
								// targets outside of the scope of the switch are not affected. 
								if(wFORMS.behaviors['switch'].isWithinSwitchScope(trigger, elements[j])) {
									// one of the trigger is still ON. no switch off
									doSwitch = false;
								}
							}							
						}
						if(doSwitch) {
							wFORMS.behaviors['switch'].switchState(elements[j], wFORMS.classNamePrefix_onState, wFORMS.classNamePrefix_offState);
						}
					}
				}
				// Turn on
				for(var i=0; i < switches_ON.length; i++) {
					var elements = wFORMS.behaviors['switch'].getElementsBySwitchName(switches_ON[i]);
					for(var j=0;j<elements.length;j++) {
						// An element with the REPEAT behavior limits the scope of switches 
						// targets outside of the scope of the switch are not affected. 
						if(wFORMS.behaviors['switch'].isWithinSwitchScope(element, elements[j])) {

							wFORMS.behaviors['switch'].switchState(elements[j], wFORMS.classNamePrefix_offState, wFORMS.classNamePrefix_onState);
							//wFORMS.debug('switch/run: [turn on ' + switches_ON[i] + '] ' + elements[j].id , 3);	
						}
					}
				}
           },

		   // ------------------------------------------------------------------------------------------
           // clear: executed if the behavior should not be applied anymore
		   // ------------------------------------------------------------------------------------------
		   clear: function(e) {
             	// @TODO: go through wFORMS.switchTriggers to remove events.
             	wFORMS.switchTriggers = {};		
             	wFORMS.switchTargets = {};
             	
           },
		   
		   
		   // ------------------------------------------------------------------------------------------
		   // Get the list of switches 
		   // Note: potential conflict if an element is both a switch and a target.
		   getSwitchNames: function(element) {
				var switchNames = new Array();
				var classNames  = element.className.split(' ');
				for(var i=0; i < classNames.length; i++) {
					// Note: Might be worth keeping a prefix on switchName to prevent collision with reserved names						
					if(classNames[i].indexOf(wFORMS.classNamePrefix_switch) == 0) {
						switchNames.push(classNames[i].substr(wFORMS.classNamePrefix_switch.length+1));
					}
					if(classNames[i].indexOf(wFORMS.classNamePrefix_onState) == 0) {
						switchNames.push(classNames[i].substr(wFORMS.classNamePrefix_onState.length+1));
					}
					else if(classNames[i].indexOf(wFORMS.classNamePrefix_offState) == 0) {
						switchNames.push(classNames[i].substr(wFORMS.classNamePrefix_offState.length+1));
					}
				}
				return switchNames;
			},
			
		   // ------------------------------------------------------------------------------------------
			switchState: function(element, oldStateClass, newStateClass) {		
				if(!element || element.nodeType != 1) return;
				if(element.className) {  		
					element.className = element.className.replace(oldStateClass, newStateClass);
				}		
				// For  elements that don't have a native state variable (like checked, or selectedIndex)
				if(wFORMS.helpers.hasClass(element, wFORMS.className_switchIsOff)) {
					element.className = element.className.replace(wFORMS.className_switchIsOff, wFORMS.className_switchIsOn);
				} else if(wFORMS.helpers.hasClass(element, wFORMS.className_switchIsOn)) {
					element.className = element.className.replace(wFORMS.className_switchIsOn, wFORMS.className_switchIsOff);
				}
			},
			
			// ------------------------------------------------------------------------------------------
			getElementsBySwitchName: function(switchName) {
				var elements = new Array();
				if(wFORMS.switchTargets[switchName]) {
					for (var i=0; i<wFORMS.switchTargets[switchName].length; i++) {
						var element = document.getElementById(wFORMS.switchTargets[switchName][i]);
						if(element)
							elements.push(element);
					}
				}
				return elements;
			},
			
			// ------------------------------------------------------------------------------------------
			isTriggerOn: function(element, triggerName) {
				if(!element) return false;
				if(element.tagName.toUpperCase()=='OPTION') {
					var selectElement = element.parentNode;
					while(selectElement && selectElement.tagName.toUpperCase() != 'SELECT') {
						var selectElement = selectElement.parentNode;
					}
					if(!selectElement) return false; // invalid markup					
					if(selectElement.selectedIndex==-1) return false; // nothing selected
					// TODO: handle multiple-select
					if(wFORMS.helpers.hasClass(selectElement.options[selectElement.selectedIndex],
											   wFORMS.classNamePrefix_switch + '-' + triggerName)) {
						return true;
					}
				} else {
					if(element.checked || wFORMS.helpers.hasClass(element, wFORMS.className_switchIsOn)) 
						return true;
				}
				return false;
			},
			
			// isWithinSwitchScope: An element with the REPEAT behavior limits the scope of switches 
			// targets outside of the scope of the switch are not affected. 
			// ------------------------------------------------------------------------------------------			
			isWithinSwitchScope: function(trigger, target) {
				
				if(wFORMS.hasBehavior('repeat') && wFORMS.limitSwitchScope == true) { 
					// check if the trigger is in a repeatable/removeable element
					var scope = trigger;
				
					while(scope && scope.tagName && scope.tagName.toUpperCase() != 'FORM' && 
						  !wFORMS.helpers.hasClass(scope, wFORMS.className_repeat) &&
					      !wFORMS.helpers.hasClass(scope, wFORMS.className_delete) ) {
						scope = scope.parentNode;
					}
					if(wFORMS.helpers.hasClass(scope, wFORMS.className_repeat) || 
					   wFORMS.helpers.hasClass(scope, wFORMS.className_delete)) {
						// yes, the trigger is nested in a repeat/remove element
						
						// check if the target is in the same element.
						var scope2 = target;
						while(scope2 && scope2.tagName && scope2.tagName.toUpperCase() != 'FORM' && 
							  !wFORMS.helpers.hasClass(scope2, wFORMS.className_repeat) &&
							  !wFORMS.helpers.hasClass(scope2, wFORMS.className_delete) ) {
							scope2 = scope2.parentNode;
						}
						if(scope == scope2) {
							return true;  // target & trigger are in the same repeat/remove element		
						} else {
							return false; // target not in the same repeat/remove element,					
						}
					} else {
						return true;	  // trigger is not nested in a repeat/remove element, scope unaffected
					}
				} else 
					return true;
			}
       } // END wFORMS.behaviors['switch'] object

  	   
   }
   
   
// wForms - a javascript extension to web forms.
// Form Validation Component
// v2.0 beta - Feb.14th 2006
// This software is licensed under the CC-GNU LGPL <http://creativecommons.org/licenses/LGPL/2.1/>
    
    
   if(wFORMS) {
		// Component properties 
		// wFORMS.functionName_formValidation  is defined at the bottom of this file
       	wFORMS.preventSubmissionOnEnter   		= false; 			// prevents submission when pressing the 'enter' key. Set to true if pagination behavior is used.
	   	wFORMS.showAlertOnError 			  	= true; 			// sets to false to not show the alert when a validation error occurs.
		wFORMS.className_required 			 	= "required";
		wFORMS.className_validationError_msg 	= "errMsg";		 
		wFORMS.className_validationError_fld	= "errFld";  
		wFORMS.classNamePrefix_validation 		= "validate";	
		wFORMS.idSuffix_fieldError				= "-E";
		
		// Error messages. This array may be overwritten in a separate js file for localization or customization purposes.
		wFORMS.arrErrorMsg = new Array(); 
		wFORMS.arrErrorMsg[0] = "This field is required. "; // required
		wFORMS.arrErrorMsg[1] = "The text must use alphabetic characters only (a-z, A-Z). Numbers are not allowed. "; 	// validate_alpha
		wFORMS.arrErrorMsg[2] = "This does not appear to be a valid email address.";									// validate_email
		wFORMS.arrErrorMsg[3] = "Please enter an integer.";															// validate_integer
		wFORMS.arrErrorMsg[4] = "Please enter a float (ex. 1.9).";
		wFORMS.arrErrorMsg[5] = "Unsafe password. Your password should be between 4 and 12 characters long and use a combinaison of upper-case and lower-case letters.";
		wFORMS.arrErrorMsg[6] = "Please use alpha-numeric characters only [a-z 0-9].";
		wFORMS.arrErrorMsg[7] = "This does not appear to be a valid date.";
		wFORMS.arrErrorMsg[8] = "%% error(s) detected. Your form has not been submitted yet.\nPlease check the information you provided."; // %% will be replaced by the actual number of errors.

		wFORMS.behaviors['validation'] = {

		   // ------------------------------------------------------------------------------------------
		   // evaluate: check if the behavior applies to the given node. Adds event handlers if appropriate
		   // ------------------------------------------------------------------------------------------
			evaluate: function(node) {
               if(node.tagName.toUpperCase()=="FORM") {
				   // functionName_formValidation can be a reference to a function, or a string with the name of the function.
				   // avoid using typeof
				   if(wFORMS.functionName_formValidation.toString()==wFORMS.functionName_formValidation) {
					   // this is a string, not a function
					   wFORMS.functionName_formValidation = eval(wFORMS.functionName_formValidation);
				   }
                   wFORMS.helpers.addEvent(node,'submit',wFORMS.functionName_formValidation);
				   //wFORMS.debug('validation/evaluate: FORM '+ node.id,3);
               }
           },
		   // ------------------------------------------------------------------------------------------
           // init: executed once evaluate has been applied to all elements
		   // ------------------------------------------------------------------------------------------	   
		   init: function() {
		   },
		   
		   // ------------------------------------------------------------------------------------------
           // run: executed when the behavior is activated
		   // ------------------------------------------------------------------------------------------	   		   
           run: function(e) {
				var element  = wFORMS.helpers.getSourceElement(e);
				if(!element) element = e;
				//wFORMS.debug('validation/run: ' + element.id , 5);	
				
				// on multi-page forms we need to prevent the submission when the 'enter' key is pressed
				// (doesn't work in Opera. Further tests needed in IE and Safari)
				if(wFORMS.preventSubmissionOnEnter) { 
					if(element.type && element.type.toLowerCase()=='text') 
						// source element is a text field, the form was submitted with the 'enter' key.
						return wFORMS.preventEvent(e); 
				}
				// make sure we have the form element
				while (element && element.tagName.toUpperCase() != 'FORM') {
					element = element.parentNode;
				}		
				
				var nbErrors = wFORMS.behaviors['validation'].validateElement(element, true);
				
				if (nbErrors > 0) {
					if(wFORMS.showAlertOnError){ wFORMS.behaviors['validation'].showAlert(nbErrors); }
					return wFORMS.helpers.preventEvent(e); 
				}
				return true;
			},
		   
			// ------------------------------------------------------------------------------------------
			// remove: executed if the behavior should not be applied anymore
			// ------------------------------------------------------------------------------------------
			remove: function() {
			},
		   
		   
			// ------------------------------------------------------------------------------------------
			// validation functions
			// ------------------------------------------------------------------------------------------
			validateElement: function(element /*, deep */) {
				
				var wBehavior = wFORMS.behaviors['validation'];		// shortcut
				
				// do not validate elements that are in a OFF-Switch
				// Note: what happens if an element is the target of 2+ switches, some ON and some OFF ?
				if(wFORMS.hasBehavior('switch') && wFORMS.helpers.hasClassPrefix(element,wFORMS.classNamePrefix_offState)) {
					return 0;
				}
				// do not validate elements that are not in the current page (Paging Behavior)
				if(wFORMS.hasBehavior('paging') &&  wFORMS.helpers.hasClass(element,wFORMS.className_paging)
											    && !wFORMS.helpers.hasClass(element,wFORMS.className_pagingCurrent) ) {
					return 0;
				}
				
				var nbErrors = 0;
				
				// check if required
				if(!wBehavior.checkRequired(element)) {
					wBehavior.showError(element,wFORMS.arrErrorMsg[0]);
					nbErrors++;
					//wFORMS.debug('validation/error: [required]' + element.id + '('+nbErrors+')' , 5);
				} else {
				
					// input format validation
					if (wFORMS.helpers.hasClassPrefix(element,wFORMS.classNamePrefix_validation)) {
		
						var arrClasses = element.className.split(" ");
						for (j=0;j<arrClasses.length;j++) {
							switch(arrClasses[j]) {
								case "validate-alpha":
									if(!wBehavior.isAlpha(element.value)) {
										wBehavior.showError(element,wFORMS.arrErrorMsg[1]);
										nbErrors++;
										//wFORMS.debug('validation/error: [alpha]' + element.id , 5);
									}
									break;
								case "validate-alphanum":
									if(!wBehavior.isAlphaNum(element.value)) {
										wBehavior.showError(element,wFORMS.arrErrorMsg[6]);
										nbErrors++;
										//wFORMS.debug('validation/error: [alphanum]' + element.id , 5);
									}
									break;
								case "validate-date":
									if(!wBehavior.isDate(element.value)) {
										wBehavior.showError(element,wFORMS.arrErrorMsg[7]);
										nbErrors++;
										//wFORMS.debug('validation/error: [date]' + element.id , 5);
									}
									break;
								case "validate-time":
									/* NOT IMPLEMENTED */
									break;
								case "validate-email":
									if(!wBehavior.isEmail(element.value)) {
										wBehavior.showError(element,wFORMS.arrErrorMsg[2]);
										nbErrors++;
										//wFORMS.debug('validation/error: [email]' + element.id , 5);
									}
									break;
								case "validate-integer":
									if(!wBehavior.isInteger(element.value)) {
										wBehavior.showError(element,wFORMS.arrErrorMsg[3]);
										nbErrors++;
										//wFORMS.debug('validation/error: [integer]' + element.id , 5);
									}					
									break;
								case "validate-float":
									if(!wBehavior.isFloat(element.value)) {
										wBehavior.showError(element,wFORMS.arrErrorMsg[4]);
										nbErrors++;
										//wFORMS.debug('validation/error: [float]' + element.id , 5);
									}
									break;
								case "validate-strongpassword": // NOT IMPLEMENTED
									if(!wBehavior.isPassword(element.value)) {
										wBehavior.showError(element,wFORMS.arrErrorMsg[5]);
										nbErrors++;
										//wFORMS.debug('validation/error: [password]' + element.id , 5);
									}
									break;
							} // end switch
						} // end for
					}
				} // end validation check
				
				// remove previous error flags if any.
				if(nbErrors==0) {
					var rErrClass     = new RegExp(wFORMS.className_validationError_fld,"gi");
					element.className = element.className.replace(rErrClass,"");
					var errorMessage  = document.getElementById(element.id + wFORMS.idSuffix_fieldError);
					if(errorMessage)  errorMessage.parentNode.removeChild(errorMessage);
				} 
					
				// recursive loop	
				var deep = arguments[1] ? arguments[1] : true;
				if(deep) {
					for(var i=0; i < element.childNodes.length; i++) {
						if(element.childNodes[i].nodeType==1) { // Element Nodes only
							nbErrors += wBehavior.validateElement(element.childNodes[i], deep);
						}
					}
				}
				
				return nbErrors;
			},
			
			// ------------------------------------------------------------------------------------------
			checkRequired: function(element) {
										
				if(wFORMS.helpers.hasClass(element,wFORMS.className_required)) {

					var wBehavior = wFORMS.behaviors['validation'];		// shortcut

					switch(element.tagName.toUpperCase()) {
						case "INPUT":
							switch(element.getAttribute("type").toLowerCase()) {
								case "checkbox":
									return element.checked; 
									break;
								case "radio":
									return element.checked; 
									break;
								default:
									return !wBehavior.isEmpty(element.value);
							}
							break;
						case "SELECT":
							return !wBehavior.isEmpty(element.options[element.selectedIndex].value);
							break;
						case "TEXTAREA":
							return !wBehavior.isEmpty(element.value);
							break;
						default:
							return wBehavior.checkOneRequired(element);
							break;
					} 	
				} 
				return true;
			},
			checkOneRequired: function(element) {	

				var value = false;
				if(element.nodeType != 1) return false;
				if(element.tagName.toUpperCase() == "INPUT") {
					switch(element.type.toLowerCase()) {
						case "checkbox":
							value = element.checked; 
							break;
						case "radio":
							value = element.checked; 
							break;
						default:
							value = element.value;
					}
				} else value = element.value;
				if(value && !wFORMS.behaviors['validation'].isEmpty(value)) {
					return true;
				}
				for(var i=0; i<element.childNodes.length;i++) {
					if(wFORMS.behaviors['validation'].checkOneRequired(element.childNodes[i])) return true;
				}
				return false;
			},
				
			// ------------------------------------------------------------------------------------------
			isEmpty: function(s) {
				var regexpWhitespace = /^\s+$/;
				return  ((s == null) || (s.length == 0) || regexpWhitespace.test(s));
			},
			isAlpha: function(s) {
				var regexpAlphabetic = /^[a-zA-Z]+$/; // Add ' and - ?
				return wFORMS.behaviors['validation'].isEmpty(s) || regexpAlphabetic.test(s);
			},
			isAlphaNum: function(s) {
				var illegalChars = /\W/;
				return wFORMS.behaviors['validation'].isEmpty(s) || !illegalChars.test(s);
			},
			isDate: function(s) {
				var testDate = new Date(s);
				return wFORMS.behaviors['validation'].isEmpty(s) || !isNaN(testDate);
			},
			isEmail: function(s) {
				var regexpEmail = /\w{1,}[@][\w\-]{1,}([.]([\w\-]{1,})){1,3}$/;
				return wFORMS.behaviors['validation'].isEmpty(s) || regexpEmail.test(s);
			},
			isInteger: function(s) {
				var regexp = /^[+]?\d+$/;
				return wFORMS.behaviors['validation'].isEmpty(s) || regexp.test(s);
			},
			isFloat: function(s) {		
				return wFORMS.behaviors['validation'].isEmpty(s) || !isNaN(parseFloat(s));
			},
			// NOT IMPLEMENTED
			isPassword: function(s) {
			// Matches strong password : at least 1 upper case latter, one lower case letter. 4 characters minimum. 12 max.
			//var regexp = /^(?=.*[a-z])(?=.*[A-Z])(?!.*\s).{4,12}$/;  // <= breaks in IE5/Mac
				return wFORMS.behaviors['validation'].isEmpty(s);
			},
			
			// ------------------------------------------------------------------------------------------		
			// Error Alert Functions
			// ------------------------------------------------------------------------------------------		
			showError: function (element,errorMsg) {		
				if(element.className.indexOf(wFORMS.className_validationError_fld)!= -1) {
					return;
				}
				if (!element.id) element.id = wFORMS.helpers.randomId(); // we'll need an id here.		
				// Add error flag to the field
				element.className += " " + wFORMS.className_validationError_fld;
				// Prepare error message
				var msgNode = document.createTextNode(" " + errorMsg);
				// Find error message placeholder.
				var fe = document.getElementById(element.id +  wFORMS.idSuffix_fieldError);
				if(!fe) { // create placeholder.
					fe = document.createElement("div"); 
					fe.setAttribute('id', element.id +  wFORMS.idSuffix_fieldError);
						
					// attach the error message after the field label if possible
					var fl = document.getElementById(element.id +  wFORMS.idSuffix_fieldLabel);
					if(fl)
						fl.parentNode.insertBefore(fe,fl.nextSibling);
					else
						// otherwise, attach it after the field tag.
						element.parentNode.insertBefore(fe,element.nextSibling);
				}
				// Finish the error message.
				fe.appendChild(msgNode);  	
				fe.className += " " + wFORMS.className_validationError_msg;
			},
			showAlert: function (nbTotalErrors) {
			   alert(wFORMS.arrErrorMsg[8].replace('%%',nbTotalErrors));
			}			
       } // End wFORMS.behaviors['validation']
	   
		wFORMS.functionName_formValidation = wFORMS.behaviors['validation'].run;
		// backward compatibility
		wFORMS.formValidation  			   = wFORMS.behaviors['validation'].run;
   }
   
   
   
   
   
// wForms - a javascript extension to web forms.
// Form Paging Component
// v2.0 beta - Feb.14th 2006
// This software is licensed under the CC-GNU LGPL <http://creativecommons.org/licenses/LGPL/2.1/>
    
    
   if(wFORMS) {
		// Component properties 
		wFORMS.className_paging				= "wfPage";
		wFORMS.className_pagingCurrent		= "wfCurrentPage";
		wFORMS.className_pagingButtons		= "wfPageButton";
		wFORMS.className_hideSubmit			= "wfHideSubmit";
		wFORMS.idPrefix_pageIndex			= "wfPgIndex-";
		wFORMS.runValidationOnPageNext   	= true;
		
		if(!wFORMS.arrMsg) wFORMS.arrMsg 	= new Array();
		wFORMS.arrMsg[4] 					= "Next Page";
		wFORMS.arrMsg[5] 					= "Previous Page";	


		wFORMS.behaviors['paging'] = {

			// ------------------------------------------------------------------------------------------
			// evaluate: check if the behavior applies to the given node. Adds event handlers if appropriate
			// ------------------------------------------------------------------------------------------
			evaluate: function(node) {
				if (wFORMS.helpers.hasClass(node,wFORMS.className_paging)) {
					
					var currentPageIndex = parseInt(node.id.replace(/[\D]*/,""));
					if(currentPageIndex > 1) {
						// add previous page button			
						var actionNode = document.createElement("input"); 
						actionNode.setAttribute('value',wFORMS.arrMsg[5]);	
						actionNode.setAttribute('type',"button");	
						actionNode.className = wFORMS.className_pagingButtons;
						node.appendChild(actionNode);
						// Add event handler			
						wFORMS.helpers.addEvent(actionNode,'click',wFORMS.behaviors['paging'].pagingPrevious);			
					} else {
						// set current page class
						node.className += ' ' + wFORMS.className_pagingCurrent;
						
						// get the corresponding form element
						var form = node.parentNode;
						while(form && form.tagName.toUpperCase() != "FORM")
							form = form.parentNode;
							
						// hide submit button until the last page of the form is reached
						var buttons = form.getElementsByTagName('input');
						for (var i=0;i<buttons.length;i++) {
							if(buttons[i].type && buttons[i].type.toLowerCase() == 'submit') {
								buttons[i].className += ' ' + wFORMS.className_hideSubmit; 
							}
						}
												
						// prevent submission of form with enter key.
						wFORMS.helpers.addEvent(form,'submit', function(e) { var element = wFORMS.helpers.getSourceElement(e);
																			 if(element.type && element.type.toLowerCase()=='text') 
																				return wFORMS.preventEvent(e); } );
						wFORMS.preventSubmissionOnEnter = true; // for input validation behavior
						
					}
					if(document.getElementById(wFORMS.idPrefix_pageIndex+(currentPageIndex+1).toString())) {
						// add next page button			
						var actionNode = document.createElement("input"); 
						actionNode.setAttribute('value',wFORMS.arrMsg[4]);	
						actionNode.setAttribute('type',"button");	
						actionNode.className = wFORMS.className_pagingButtons;
						node.appendChild(actionNode);
						// Add event handler			
						wFORMS.helpers.addEvent(actionNode,'click',wFORMS.behaviors['paging'].pagingNext);			
					}
				}
			  
			},

			// ------------------------------------------------------------------------------------------
			// pagingNext
			// ------------------------------------------------------------------------------------------
			pagingNext: function(e) {
				var element  = wFORMS.helpers.getSourceElement(e);
				if(!element) element = e
				
				var pageElement     = element.parentNode;
				var pageIndex       = parseInt(pageElement.id.replace(/[\D]*/,"")) + 1;
				var nextPageElement = document.getElementById(wFORMS.idPrefix_pageIndex+pageIndex.toString());
				if(nextPageElement) {
					if(!wFORMS.hasBehavior('validation') ||
					   (wFORMS.hasBehavior('validation') && !wFORMS.runValidationOnPageNext) || 
					   (wFORMS.hasBehavior('validation') &&  wFORMS.runValidationOnPageNext && wFORMS.functionName_formValidation(e))) {
						 						  
						pageElement.className      = pageElement.className.replace(wFORMS.className_pagingCurrent,"");
						nextPageElement.className += ' ' + wFORMS.className_pagingCurrent;
						// show submit button if the last page of the form is reached
						pageIndex++;
						nextPageElement = document.getElementById(wFORMS.idPrefix_pageIndex+pageIndex.toString());			
						if(!nextPageElement) {		
							// get the corresponding form element
							var form = pageElement.parentNode;
							while(form && form.tagName.toUpperCase() != "FORM")
								form = form.parentNode;
						
							var buttons = form.getElementsByTagName('input');
							for (var i=0;i<buttons.length;i++) {
								if(buttons[i].type && buttons[i].type.toLowerCase() == 'submit') {
									buttons[i].className = buttons[i].className.replace(wFORMS.className_hideSubmit,"");
									wFORMS.debug('submit class ' + buttons[i].className);
								}
							}
						}
					}
				}
			},
			
			// ------------------------------------------------------------------------------------------
			// pagingPrevious
			// ------------------------------------------------------------------------------------------				
			pagingPrevious: function(e) {
				var element  = wFORMS.helpers.getSourceElement(e);
				if(!element) element = e
 
				var pageElement         = element.parentNode;
				var pageIndex           = parseInt(pageElement.id.replace(/[\D]*/,"")) - 1;
				var previousPageElement = document.getElementById(wFORMS.idPrefix_pageIndex+pageIndex.toString());
				if(previousPageElement) {
					pageElement.className          = pageElement.className.replace(wFORMS.className_pagingCurrent,"");
					previousPageElement.className += ' ' + wFORMS.className_pagingCurrent;										
					// get the corresponding form element
					var form = pageElement.parentNode;
					while(form && form.tagName.toUpperCase() != "FORM")
						form = form.parentNode;
					// hide submit button if necessary
					var buttons = form.getElementsByTagName('input');
					for (var i=0;i<buttons.length;i++) {
						if(buttons[i].type && buttons[i].type.toLowerCase() == 'submit' && !wFORMS.helpers.hasClass(buttons[i],wFORMS.className_hideSubmit)) {
							buttons[i].className += ' ' + wFORMS.className_hideSubmit; 
						}
					}
				}
			}
			
       } // End wFORMS.behaviors
	   
   }
   
   
   

// wForms - a javascript extension to web forms.
// Repeat Behavior
// v2.0 beta - Feb.14th 2006
// This software is licensed under the CC-GNU LGPL <http://creativecommons.org/licenses/LGPL/2.1/>
    
    
   if(wFORMS) {
		// Component properties 
		wFORMS.className_repeat 			= "repeat";
		wFORMS.className_delete 			= "removeable";
		wFORMS.className_duplicateLink 		= "duplicateLink";
		wFORMS.className_removeLink 		= "removeLink";
		wFORMS.className_preserveRadioName  = "preserveRadioName";		
		wFORMS.idSuffix_repeatCounter		= "-RC";
		wFORMS.idSuffix_duplicateLink		= "-wfDL";									 
		wFORMS.preserveRadioName			= false;									 // if true, Repeat behavior will preserve name attributes for radio input. 
		wFORMS.limitSwitchScope				= true;									 	 // if true, Repeat behavior will limit the scope of nested switches.
		
		if(!wFORMS.arrMsg) wFORMS.arrMsg 	= new Array();
		wFORMS.arrMsg[0] 					= "Add another response"; 					 // repeat link
		wFORMS.arrMsg[1] 					= "Will duplicate this question or section." // title attribute on the repeat link 
		wFORMS.arrMsg[2] 					= "Remove"; 								 // remove link
		wFORMS.arrMsg[3] 					= "Will remove this question or section." 	 // title attribute on the remove link
		
		wFORMS.behaviors['repeat'] = {

		   	// ------------------------------------------------------------------------------------------
		   	// evaluate: check if the behavior applies to the given node. Adds event handlers if appropriate
		   	// ------------------------------------------------------------------------------------------
			evaluate: function(node) {
				
				// Repeatable element
				if(wFORMS.helpers.hasClass(node, wFORMS.className_repeat)) {
					//wFORMS.debug('evaluate/repeat: '+ node.id,3);
				   
					// Check if we have a 'repeat' link
					var repeatLink;
					if(node.id) 
						repeatLink = document.getElementById(node.id + wFORMS.idSuffix_duplicateLink);
					if(!repeatLink) {				
						// create the repeat link
						repeatLink   = document.createElement("a"); 
						var spanNode = document.createElement("span");  // could be used for CSS image replacement 
						var textNode = document.createTextNode(wFORMS.arrMsg[0]);
						repeatLink.setAttribute('href',"#");	
						repeatLink.className = wFORMS.className_duplicateLink;			
						repeatLink.setAttribute('title', wFORMS.arrMsg[1]);	
						// find where to insert the link
						if(node.tagName.toUpperCase()=="TR") {
							// find the last TD
							var n = node.lastChild;	
							while(n && n.nodeType != 1)  
								n = n.previousSibling;
							if(n && n.nodeType == 1) 
								n.appendChild(repeatLink);
							// Else Couldn't find the TD. Table row malformed ?
						} else
							node.appendChild(repeatLink);
							
						spanNode.appendChild(textNode); 
						repeatLink.appendChild(spanNode); 
					}
					// Add hidden counter field if necessary
					var counterField = document.getElementById(node.id + wFORMS.idSuffix_repeatCounter);
					if(!counterField) {
						// IE Specific :-(
						if(document.all && !window.opera) { 
							// see http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/name_2.asp
							var counterFieldId = node.id + wFORMS.idSuffix_repeatCounter;
							if(navigator.appVersion.indexOf("MSIE") != -1 && navigator.appVersion.indexOf("Windows") == -1) // IE5 Mac
								counterField   = document.createElement("INPUT NAME=\"" + counterFieldId + "\"");
							else
								counterField   = document.createElement("<INPUT NAME=\"" + counterFieldId + "\"></INPUT>"); 					
							counterField.type  ='hidden';
							counterField.id    = counterFieldId; 
							counterField.value = "1";
						}
						else {
							counterField = document.createElement("INPUT"); 
							counterField.setAttribute('type','hidden'); // hidden
							counterField.setAttribute('value','1');
							counterField.setAttribute('name', node.id + wFORMS.idSuffix_repeatCounter);
							counterField.setAttribute('id', node.id + wFORMS.idSuffix_repeatCounter); 
						}
						
						// get the form element						
						var form = node.parentNode;
						while(form && form.tagName.toUpperCase() != "FORM")
							form = form.parentNode;
						
						form.appendChild(counterField);
					}
					
					// Add event handler			
					wFORMS.helpers.addEvent(repeatLink,'click',wFORMS.behaviors['repeat'].duplicateFieldGroup);			
				}	
		 	  	// ------------------------------------------------------------------------------------------
				// Removeable element
				if(wFORMS.helpers.hasClass(node, wFORMS.className_delete)) {
					var removeLink = document.createElement("a");
					var spanNode   = document.createElement("span");  // could be used for CSS image replacement 
					var textNode   = document.createTextNode(wFORMS.arrMsg[2]);
					removeLink.setAttribute('href',"#");	
					removeLink.className = wFORMS.className_removeLink;
					removeLink.setAttribute('title',wFORMS.arrMsg[3]);	
					// find where to insert the link
					if(node.tagName.toUpperCase()=="TR") {
						// find the last TD
						var n = node.lastChild;	
						while(n && n.nodeType != 1)  
							n = n.previousSibling;
						if(n && n.nodeType == 1) 
							n.appendChild(removeLink);
						// Else Couldn't find the TD. Table row malformed ?
					} else
						node.appendChild(removeLink);
					spanNode.appendChild(textNode); 
					removeLink.appendChild(spanNode); 	
					wFORMS.helpers.addEvent(removeLink,'click',wFORMS.behaviors['repeat'].removeFieldGroup);			
				}	

           	},

		   	duplicateFieldGroup: function(e) {
				var element  = wFORMS.helpers.getSourceElement(e);
				if(!element) element = e
				
				// override of the wFORMS.preserveRadioName property using a class on the repeat link.
				var preserveRadioName = wFORMS.helpers.hasClass(element,wFORMS.className_preserveRadioName) ? true : wFORMS.preserveRadioName;
				//wFORMS.debug('preserveRadioName='+preserveRadioName);
				
				// Get Element to duplicate.
				var element = element.parentNode;
				while (element && !wFORMS.helpers.hasClass(element,wFORMS.className_repeat)) {
					element = element.parentNode;
				}	
				if (element) {
					// Extract row counter information
					counterField = document.getElementById(element.id + wFORMS.idSuffix_repeatCounter);
					if(!counterField) return; // should not happen.
					var rowCount = parseInt(counterField.value) + 1;
					// Prepare id suffix
					var suffix = "-" + rowCount.toString()
					// duplicate node tree 
					var dupTree = wFORMS.behaviors['repeat'].replicateTree(element, null, suffix, preserveRadioName);  //  sourceNode.cloneNode(true); 
					// find insert point in DOM tree (after existing repeated element)
					var insertNode = element.nextSibling;
					
					while(insertNode && 
						 (insertNode.nodeType==3 ||       // skip text-node that can be generated server-side when populating a previously repeated group 
						  wFORMS.helpers.hasClass(insertNode,wFORMS.className_delete))) {						
						insertNode = insertNode.nextSibling;
					}
					element.parentNode.insertBefore(dupTree,insertNode);	 // Buggy rendering in IE5/Mac
					// if(navigator.appVersion.indexOf("MSIE") != -1 && navigator.appVersion.indexOf("Windows") == -1)			
					//
					
					// the copy is not duplicable, it's removeable
					dupTree.className = element.className.replace(wFORMS.className_repeat,wFORMS.className_delete);
					// Save new row count 			
					document.getElementById(element.id + wFORMS.idSuffix_repeatCounter).value = rowCount;
					// re-add wFORMS behaviors
					wFORMS.addBehaviors(dupTree);
				}
				return wFORMS.helpers.preventEvent(e);
			},
			
		   	removeFieldGroup: function(e) { 
				var element  = wFORMS.helpers.getSourceElement(e);
				if(!element) element = e
				// Get Element to remove.
				var element = element.parentNode;
				while (element && !wFORMS.helpers.hasClass(element,wFORMS.className_delete)) {
					element = element.parentNode;
				}	
				element.parentNode.removeChild(element);
				return wFORMS.helpers.preventEvent(e);
			},	
			
			removeRepeatCountSuffix: function(str) {
				return str.replace(/-\d$/,'');
			},
	
			replicateTree: function(element,parentElement, idSuffix, preserveRadioName) {
				
				// Duplicating TEXT-NODE (do not copy value of textareas)
				if(element.nodeType==3) { 
					if(element.parentNode.tagName.toUpperCase() != 'TEXTAREA')
						var newElement = document.createTextNode(element.data); 
				} 
				// Duplicating ELEMENT-NODE
				else if(element.nodeType==1) { 
					
					// Do not copy repeat/remove links
					if(wFORMS.helpers.hasClass(element,wFORMS.className_duplicateLink) ||
					   wFORMS.helpers.hasClass(element,wFORMS.className_removeLink)) 							
						return null; 
					// Exclude duplicated elements of a nested repeat group
					if(wFORMS.helpers.hasClass(element,wFORMS.className_delete)) 
						return null; 
					// Adjust row suffix id if we find a nested repeat group 
					if(wFORMS.helpers.hasClass(element,wFORMS.className_repeat) && parentElement!=null)
						idSuffix = idSuffix.replace('-','__');
					
					if(!document.all || window.opera) { 
						// Common Branch
						var newElement = document.createElement(element.tagName); 
					} else {
						// IE Branch 
						// see http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/name_2.asp						
						var tagHtml = element.tagName;
						
						if(element.name) 					
							if (element.tagName.toUpperCase() == "INPUT" && 
								element.type.toLowerCase()    == "radio" && preserveRadioName)
								tagHtml += " NAME='" + element.name + "' ";
							else
								tagHtml += " NAME='" + wFORMS.behaviors['repeat'].removeRepeatCountSuffix(element.name) + idSuffix + "' ";
						if(element.type) {
							tagHtml += " TYPE='" + element.type + "' ";
						}
						if(element.selected) 
							tagHtml += " SELECTED='SELECTED' ";
						if(element.checked)
							tagHtml += " CHECKED='CHECKED' ";
	
						if(navigator.appVersion.indexOf("MSIE") != -1 && navigator.appVersion.indexOf("Windows") == -1) // IE5 Mac
							var newElement = document.createElement(tagHtml);
						else
							var newElement = document.createElement("<" + tagHtml + "></"+ element.tagName + ">"); 
						try { newElement.type = element.type; } catch(e) {}; // nail it down for IE5 ?, breaks in IE6
						
					}
				 
					// duplicate attributes										
					for(var i=0; i< element.attributes.length; i++) {
						var attribute = element.attributes[i];
						
						// Get attribute value. 
						if(	attribute.specified || // in IE, the attributes array contains all attributes in the DTD
							attribute.nodeName.toLowerCase() == 'value' ) { // attr.specified buggy in IE?  
							// Add the row suffix if necessary.
							if(	attribute.nodeName.toLowerCase() == "id" || 
								attribute.nodeName.toLowerCase() == "name" ||
								attribute.nodeName.toLowerCase() == "for") {
															
								if(wFORMS.hasBehavior('hint') && 
								   attribute.nodeValue.indexOf(wFORMS.idSuffix_fieldHint) != -1)  {
									//leave the field hint suffix at the end of the id.
									var value = attribute.nodeValue;
									value= wFORMS.behaviors['repeat'].removeRepeatCountSuffix(value.substr(0,value.indexOf(wFORMS.idSuffix_fieldHint))) + idSuffix + wFORMS.idSuffix_fieldHint;
								}
								else {
									if(element.tagName.toUpperCase()=="INPUT" && 
									   element.getAttribute('type',false).toLowerCase()=="radio" &&
									   attribute.nodeName.toLowerCase() == "name" && 
									   preserveRadioName) {
										var value = attribute.nodeValue;						
									}
									else {
										// var value = wFORMS.behaviors['repeat'].removeRepeatCountSuffix(attribute.nodeValue) + idSuffix;
										var value = attribute.nodeValue + idSuffix;
									}
								}
							} else {
								// Do not copy the value attribute for text/password/file input
								if(attribute.nodeName.toLowerCase() == "value" &&
								   element.tagName.toUpperCase()=='INPUT'      &&  
								  (element.type.toLowerCase() == 'text'     || 
								   element.type.toLowerCase() == 'password' || 
								   element.type.toLowerCase() == 'file')) 
									var value='';   
								// Do not copy the switch behavior's 'event handled' flag, stored in the rel attribute
								else if(attribute.nodeName.toLowerCase() == "rel" && 
										attribute.nodeValue.indexOf('wfHandled') != -1) {
									var value = attribute.nodeValue.replace('wfHandled','');
								} else 
									var value = attribute.nodeValue;
							}
							// Create attribute and assign value
							switch(attribute.nodeName.toLowerCase()) {
								case "class":
									newElement.className = value; 
									break;
								case "style": // inline style attribute (fix for IE)
									if(element.style && element.style.cssText) 
										newElement.style.cssText = element.style.cssText; 
									break;								
								case "onclick": // inline event handler (fix for IE)
									newElement.onclick     = element.onclick;							
									break;							
								case "onchange":							
									newElement.onchange    = element.onchange;							
									break;							
								case "onsubmit":
									newElement.onsubmit    = element.onsubmit;							
									break;							
								case "onmouseover":							
									newElement.onmouseover = element.onmouseover;							
									break;							
								case "onmouseout":							
									newElement.onmouseout  = element.onmouseout;							
									break;							
								case "onmousedown":
									newElement.onmousedown = element.onmousedown;							
									break;							
								case "onmouseup":
									newElement.onmouseup   = element.onmouseup;							
									break;							
								case "ondblclick":
									newElement.ondblclick  = element.ondblclick;							
									break;							
								case "onkeydown":
									newElement.onkeydown   = element.onkeydown;							
									break;							
								case "onkeyup":
									newElement.onkeyup     = element.onkeyup;							
									break;							
								case "onblur": 
									newElement.onblur      = element.onblur;							
									break;							
								case "onfocus":
									newElement.onfocus     = element.onfocus;							
									break;
								default:
									newElement.setAttribute(attribute.name, value, 0);
							}
						}
					}				
				}
				if(parentElement && newElement) 
					parentElement.appendChild(newElement);
				for(var i=0; i<element.childNodes.length;i++) {
					wFORMS.behaviors['repeat'].replicateTree(element.childNodes[i],newElement,idSuffix, preserveRadioName);
				}
				return newElement;
			}
       } // End wFORMS.behaviors['repeat']
	   

   }
