/* * DEK JavaScript Library * Copyright(c) 2008-2010, DEK International * * Version 1.0.12 */  /* ############################## DOM ############################## *//** * Utility class for working with DOM * @class Core.Dom * @singleton */Core.Dom = {	/**	 * <p>Creates an html element.  The details parameter is an object used to define the 	 * new element.  With the exception of three special propeties, each property in the 	 * details object will be created an attribute of the new element.  The three special	 * properties do the following:<p>	 * <p><ul>	 * <li><b>tag</b> is used as the element type.</li>	 * <li><b>klass</b> is used as the css class of the element.  You can not use "class" as 	 * this is a reserved word in javascript.</li>	 * <li><b>html</b> is used as the innerHTML for the element.</li>	 * </ul></p>      * <p>If no tag property is defined, a text node is cerated instead.</p>      * <h5>Example</h5><p>This code:</p><pre><code>Core.Dom.create({  tag: "input",  type: "text",  name: "descritption",  klass: "extraWide"});</code></pre>	 * <p>is the equivalent of</p><pre><code>&lt;input type="text" name="description" class="extraWide"/&gt;</code></pre>	 * @method create	 * @static	 * @param Object details The element Details	 * @param Object doc (Optional) The document the new node should be created on, this will defualt to the top level document.	 * @return HTMLElement Return a reference to the new HTML element.	 */	create: function(details, doc) {		doc = doc?doc:document;				if(typeof(details)=="object") {			if(details.tag) {				var element;				if(details.name && Core.isIE) {					element = doc.createElement("<"+details.tag+" name=\""+details.name+"\">");				} else {					element = doc.createElement(details.tag);				}				for(var property in details) {					if(property!="tag" && (property!="name" || !Core.isIE)) {						if(property=="html") {							element.innerHTML = details[property];						} else if(property=="klass") {							element.className = details[property];						} else {							element.setAttribute(property, details[property]);									}					}				}					     	return element;			} else if(details.html) {				return doc.createTextNode(details.html);			}		} else {			return null;		}	}};/* ############################## Form ############################## *//** * A wrapper for a HTML Form.  It contains all the methods to get and set form inputs, validate the form and serialize it. * @class Core.Form */Core.Form = Core.create({	/**	 * Creates a new Core.Element object for the DOM element passed	 * @method init	 * @constructor	 * @param {String}/HTMLForm/{Core.Element} form Either the id of a form, the form element or Core.Element for a form element.	 * @param Boolean createSpecialFields (Optional) If true the createSpecialFields method is called.  Defaults to false.	 */	init: function(form, createSpecialFields) {		if(form instanceof Core.Element) {			this.formElement = form;			this.form = form.getDom();		} else {			this.formElement = Core.get(form);			this.form = form;		}		this.validation = new Array();		this.hideWhens = new Array();				if(createSpecialFields) {			this.createSpecialFields();		}	},	getFormElement: function() {		return this.formElement;	},	/**	 * <p>Converts inputs of certain  types to the special UI versions.</p>	 * <p><ul>	 * <li>Inputs with the css class "expand" are converted in to a {Core.Ui.EpandingTextArea}</li>	 * <li>Inputs with the css class "datePicker" are converted in to a {Core.Ui.DatePickerField}</li>	 * </ul></p>	 * @method createSpecialFields	 */	createSpecialFields: function() {		for(var index=0; index<this.form.elements.length; index++) {			var element = Core.get(this.form.elements[index]);			if(element) {				if(element.hasClass("expand")) {					new Core.Ui.ExpandingTextArea(element);				} else if(element.hasClass("datePicker")) {					new Core.Ui.DatePickerField(this, element);				}			}		}	},		/**	 * Resets the form, returning all fields to the values they where when the page loaded.	 * @method reset	 */	reset : function() {		this.form.reset();	},	/**	 * Submits the form.	 * @method submit	 */	submit : function() {		this.form.submit();	},	/**	 * Gets the first input in the form with the specified name.	 * @method getInput	 * @param {String}/HTMLInput/{Core.Element} field Either the name of an input, the input element or Core.Element for an input element.	 * @return HTMLInput The HTMLInput element or null if it is not present.	 */	getInput : function(field) {		if(typeof(field)!="undefined") {			if(typeof(field)=="string") {				if(typeof(this.form[field])!="undefined") {					var input = this.form[field];					if(typeof(input.name)=="undefined" && typeof(input.length)=="number") {						input = input[0];					}					return input;				} else {					return null;				}			} else if(field instanceof Core.Element) {				return field.getDom();			} else {				return field;			}		} else {			return null;		}	},	/**	 * Checks to see if an input exists in this form	 * @method hasInput	 * @param {String} field The input name to lookup.	 * @return Boolean True if the input exists	 */	hasInput : function(field) {		return typeof(this.form[field])!="undefined";	},	/**	 * Gets the first input in the form with the specified name as a {Core.Element}.	 * @method getElement	 * @param {String}/HTMLInput/{Core.Element} field Either the name of an input, the input element or Core.Element for an input element.	 * @return {Core.Element} The element or null if it is not present.	 */	getElement : function(field) {		if(typeof(field)!="undefined") {			if(typeof(field)=="string") {				input = this.getInput(field);				if(input!=null) {					return Core.get(input);				} 			} else if(field instanceof Core.Element) {				return field;			}		} 		return null;	},	/**	 * Gets an input's value	 * @method getValue	 * @param {String}/HTMLInput/{Core.Element} field Either the name of an input, the input element or Core.Element for an input element.	 * @return {String}/{Array} The inputs value or array of values for check boxes where there is more than one option	 */	getValue : function(input) {		input = this.getInput(input);				var value = "";		if(input!=null) {			switch(input.type) {				case "hidden":				case "file":				case "password":				case "text":				case "textarea":					value = input.value;					break;				case "select-one":					if(input.selectedIndex>=0) {						value = input.options[input.selectedIndex].value;						if(value=="") {							value = input.options[input.selectedIndex].text;						}					}					break;				case "radio":					var options = this.form[input.name];					if(typeof(options.name)=="undefined" && typeof(options.length)=="number") {						var found=false;						for(var index=0; index<options.length && !found; index++) {							if(options[index].checked) {								value = options[index].value;								found=true;							}						}					} else {						if(input.checked) {							value = input.value;						}						}										break;				case "checkbox":					var options = this.form[input.name];					if(typeof(options.name)=="undefined" && typeof(options.length)=="number") {						var values = new Array();						for(var index=0; index<options.length; index++) {							if(options[index].checked) {								values[values.length] = options[index].value;							}						}						value = values;					} else {						if(input.checked) {							value = input.value;						}						}					break;				/*default:					alert("DEBUG: unsupported type.  "+input.name+" is type "+input.type);					break;*/			}		}		return value;	},		/**	 * Sets an input's value	 * @method setValue	 * @param {String}/HTMLInput/{Core.Element} field Either the name of an input, the input element or Core.Element for an input element.	 * @param {String} value The value to set the string	 * @pppparam Boolean bubble (Optional) When true and if the input has a onSetValue property, the function specified in onSetValue will be called.  Default to true.	 */	setValue : function(input, value, bubble) {		input = this.getInput(input);		if(typeof(bubble)=="undefined") {			bubble = true;		}				if(input!=null) {			switch(input.type) {				case "hidden":				case "file":				case "password":				case "text":				case "textarea":					input.value=value;					if(input.onSetValue && bubble) {						input.onSetValue();					}					break;				case "select-one":					var found=false;					for(var index=0; index<input.options.length && !found; index++) {						if(value==input.options[index].value || value==input.options[index].text) {							input.selectedIndex = index;							found=true;						}					}					break;				case "radio":					var options = this.form[input.name];					if(typeof(options.name)=="undefined" && typeof(options.length)=="number") {						for(var index=0; index<options.length; index++) {							options[index].checked=(value==options[index].value);												}					} else {						input.checked=(value==input.value);					}										break;				case "checkbox":					var values;					if(typeof(value.name)=="undefined" && typeof(value.length)=="number") {						values = value;					} else {						values = [value];					} 										var options = this.form[input.name];					if(typeof(options.name)=="undefined" && typeof(options.length)=="number") {						for(var index=0; index<options.length; index++) {							options[index].checked=(values.indexOf(options[index].value)>=0);						}					} else {						input.checked=(values.indexOf(input.value)>=0);					}										break;			}			}	},		/**	 * Add's a value to the inputs values, this only works on check boxes.	 * @method addValue	 * @param {String}/HTMLInput/{Core.Element} field Either the name of an input, the input element or Core.Element for an input element.	 * @param {String} value The value to add.	 */	addValue : function(input, value) {		input = this.getInput(input);				if(input!=null) {			switch(input.type) {				case "checkbox":					var options = this.form[input.name];					if(typeof(options.name)=="undefined" && typeof(options.length)=="number") {						for(var index=0; index<options.length; index++) {							if(options[index].value==value) {								options[index].checked = true;							}						}					} else {						if(input.value==value) {							input.checked = true;						}					}										break;			}		}	},	/**	 * Remove a value from the inputs values, this only works on check boxes.	 * @method removeValue	 * @param {String}/HTMLInput/{Core.Element} field Either the name of an input, the input element or Core.Element for an input element.	 * @param {String} value The value to remove.	 */	removeValue : function(input, value) {		input = this.getInput(input);				if(input!=null) {			switch(input.type) {				case "checkbox":					var options = this.form[input.name];					if(typeof(options.name)=="undefined" && typeof(options.length)=="number") {						for(var index=0; index<options.length; index++) {							if(options[index].value==value) {								options[index].checked = false;							}						}					} else {						if(input.value==value) {							input.checked = false;						}					}										break;			}		}	},		/**	 * Serializes the content of the form in to a series of key value pairs.  The format is that same as that which would be posted if the form is submitted.	 * @method serialize	 * @return {String} The serialized version of the form	 */	serialize : function() {		var text ="";		var element;		var inputsDone = new Array();						for(var index=0; index<this.form.elements.length; index++) {			element = this.form.elements[index];			if(inputsDone.indexOf(element.name)<0) {				text += "&" + element.name + "=" + escape(this.getValue(element));				inputsDone.push(element.name);			}		}		if(text.length>0) {			text = text.substr(1);		}		return text;	},	serialise : function() {		return this.serialize();	},	/**	 * Adds a listener to the specified input.  This is most useful for radio and checkboxes as the listener is added to all the inputs of the specified name.	 * @method addListener	 * @param {String}/HTMLInput/{Core.Element} field Either the name of an input, the input element or Core.Element for an input element.	 * @param {String} action The name of the event which will trigger the event, for example "click" for onClick events.	 * @param {Function} listener The function to be called when the event fires.	 */	addListener: function(input, action, listener) {		input = typeof(input)=="string" ? this.getInput(input) : input;				if(input!=null) {			switch(input.type) {				case "radio":				case "checkbox":					var options = this.form[input.name];					if(typeof(options.name)=="undefined" && typeof(options.length)=="number") {						for(var index=0; index<options.length; index++) {							Core.EventManager.addListener(options[index], action, listener);						}					} else {						Core.EventManager.addListener(input, action, listener);					}										break;				default:					Core.EventManager.addListener(input, action, listener);					break;			}		}	},		/**	 * Adds a validation object to the form to be used when validate is called.	 * @method addValidation	 * @param {InputValidation} validation The validation object to add.	 * @param {Function} when (Optional) A function that returns a boolean which determins if the validation should take place.  If unspecified validation will always take place.	 */	addValidation : function(validation, when) {		if(typeof(when)!="function") {			when = this.alwaysValidate;		}		this.validation.push(new Array(validation, when));	},	/* private function that always returns true used to make validation always happen */	alwaysValidate: function() {		return true;	},	/**	 * Validates the form based on the validation objects than have been added	 * @method validate	 * @param Boolean displayErrors (Optional) When true validate will show a dialog with a list of errors.  Defaults to true	 * @param {Function} errorCallback (Optional) A function to be called if there are errors, an array of {Core.Form.ValidationError} will be passed as the first argument.	 * @return Boolean When there are no errors this will return true, if there are errors false.	 */	validate : function(displayErrors, errorCallback) {		displayErrors = typeof(displayErrors)=="undefined" ? true : displayErrors;		errorCallback = typeof(errorCallback)!="function" ? null : errorCallback;		var valid = true;		var errors = new Array();				for(var index=0; index<this.validation.length; index++) {			var validation = this.validation[index][0];			var when = this.validation[index][1];			if(when()) {				var error = validation.test(this);				if(error!=null) {					valid = false;					errors.push(error);				}			}		}				if(!valid) {			if(displayErrors) {				var message="";				for(var index=0; index<errors.length; index++) {					message+="<li>"+errors[index].getFormattedMessage()+"</li>";				}				if(errorCallback!=null) {					Core.Ui.msgbox("Validation Errors", "<ul>"+message+"</ul>", ["OK"], errorCallback.bind([errors]));				} else {					Core.Ui.msgbox("Validation Errors", "<ul>"+message+"</ul>", ["OK"]);								}			} else if(errorCallback!=null) {				errorCallback(errors);			}		}					return valid;	},	/**	 * Creates and returns a text represntaion of this Form object.	 * @method toString	 * @return {String} The form seralized.	 */	toString : function() {		return "[Core.Form "+this.serialize()+"]";	}});/** * <p>A class that holds information about a validation error on a Form.</p> * <p>These should not be created directly by via the {Core.Form.InputValidation#createError} method.</p> * @class Core.Form.ValidationError */Core.Form.ValidationError = Core.create({	init: function(form, inputName, label, message) {		this.form = form;		this.inputName = inputName;		this.label = label;		this.message = message;	},	/**	 * Creates a formated version of the error message so it can be added to HTML.	 * The text is formatted as follows "<em>label</em> error message".	 * @method getFormattedMessage	 * @return {String} The formatted message.	 */	getFormattedMessage : function() {		return "<em>" + this.label + "</em> " + this.message;	},	/*	 * Creates and returns a text represntaion of this validatiion error.	 * @method toString	 * @return {String}	 */	toString : function() {		return "[Core.Form.ValidationError "+this.label+": "+this.message+"]";	}});/** * The base class for input validation, this contains all the basic properties and methods handling  * validation however the test method will always return no errors.  It is intended that InputValidation * is extended for specific validation needs where a custom test method would be implemented. * @class Core.Form.InputValidation */Core.Form.InputValidation = Core.create({	/**	 * Creates a new input validation.	 * @method init	 * @constructor	 * @param {String} inputName The name of the input to validate.	 * @param {String} label A human readable label for the input to validate.	 */	init: function(inputName, label) {		this.inputName = inputName;		this.label = label;	},	/**	 * This method performs the validation for the input.  It should not be called directly but from {Core.Form#validate}.	 * By default this always returns no errors and it should be overriden in sub class.	 * @method test	 * @param {Core.Form} form The form where the inputs exsit.	 * @return {Core.Form.ValidationError} If an error is found an instance of {Core.Form.ValidationError} is returned with details of the error.  If there are no errors it reurns null.  	 */	test : function(form) {		return null;	},	/**	 * Creates an instance of {Core.Form.ValidationError} to be returned by the test method.	 * @method createError	 * @param {Core.Form} form The form where the inputs exsit.	 * @param {String} message The error message.	 * @return {Core.Form.ValidationError} The validation error.	 */	createError : function(form, message) {		return new Core.Form.ValidationError(form, this.inputName, this.label, message);	},	/*	 * Creates and returns a text represntaion of this InputValidation object.	 * @method toString	 * @return {String}	 */	toString : function() {		return "[Core.Form.Validation "+this.label+"]";	}});/** * Implements text based validation for inputs. * @class Core.Form.TextValidation * @extends Core.Form.InputValidation */Core.Form.TextValidation = Core.create(Core.Form.InputValidation, {	/**	 * Creates a new text based input validation.	 * @method init	 * @constructor	 * @param {String} inputName The name of the input to validate.	 * @param {String} label A human readable label for the input to validate.	 * @param Boolean required (Optional) When true the input can not be left blank.  Defaults to false.	 * @param {Number} min (Optional) The minimum length of the string.  Defaults to 0.	 * @param {Number} max (Optional) The maximum length of the string. 0 means no limit.  Defaults to 0.	 */	init: function(inputName, label, required, min, max) {		Core.Form.InputValidation.prototype.init.call(this, inputName, label);				this.required = typeof(required)=="undefined" ? false : required;		this.min = typeof(min)=="undefined" ? 0 : min;		this.max = typeof(max)=="undefined" ? 0 : max;	},	/**	 * This method performs the validation for the input. It should not be called directly but from {Core.Form#validate}.	 * @method test	 * @param {Core.Form} form The form where the inputs exsit.	 * @return {Core.Form.ValidationError} If an error is found an instance of {Core.Form.ValidationError} is returned with details of the error.  If there are no errors it reurns null.  	 */	test : function(form) {		var text = form.getValue(this.inputName).trim();		if(text=="") {			if(this.required) {				return this.createError(form, "is a required field.");			}		} else {			if(this.max>0 && text.length>this.max) {				return this.createError(form, "can be a maximum of "+max+" characters.");			}			if(this.min>0 && text.length<this.min) {				return this.createError(form, "can be a minimum of "+min+" characters.");			}		}		return null;	},	/*	 * Creates and returns a text represntaion of this TextValidation object.	 * @method toString	 * @return {String}	 */	toString : function() {		return "[Core.Form.TextValidation "+this.label+"]";	}});/** * Implements number based validation for inputs. * @class Core.Form.NumberValidation * @extends Core.Form.InputValidation */Core.Form.NumberValidation = Core.create(Core.Form.InputValidation, {	/**	 * Creates a new number based input validation.	 * @method init	 * @constructor	 * @param {String} inputName The name of the input to validate.	 * @param {String} label A human readable label for the input to validate.	 * @param Boolean required (Optional) When true the input can not be left blank.  Default to false.	 * @param {Number} min (Optional) The minimum value.  null measn no limit.  Defaults to null.	 * @param {Number} max (Optional) The maximum value. null measn no limit.  Defaults to null.	 */	init: function(inputName, label, required, min, max) {		Core.Form.InputValidation.prototype.init.call(this, inputName, label);				this.required = typeof(required)=="undefined" ? false : required;		this.min = typeof(min)=="undefined" ? null : min;		this.max = typeof(max)=="undefined" ? null : max;	},	/**	 * This method performs the validation for the input. It should not be called directly but from {Core.Form#validate}.	 * @method test	 * @param {Core.Form} form The form where the inputs exsit.	 * @return {Core.Form.ValidationError} If an error is found an instance of {Core.Form.ValidationError} is returned with details of the error.  If there are no errors it reurns null.  	 */	test : function(form) {		var text = form.getValue(this.inputName).trim().replace(/(,| )*/g, "");		if(text=="") {			if(this.required) {				return this.createError(form, "is a required field.");			}		} else {			var value = parseFloat(text);			if(isNaN(value)) {				return this.createError(form, "should be a number.");			} else {				//form.setValue(this.elementName, value);				if(this.max!=null && value>this.max) {					return this.createError(form, "can be a maximum of "+this.max+".");				}				if(this.min!=null && value<this.min) {					return this.createError(form, "can be a minimum of "+this.min+".");				}			}		}		return null;	},	/*	 * Creates and returns a text represntaion of this NumberValidation object.	 * @method toString	 * @return {String}	 */	toString : function() {		return "[Core.Form.NumberValidation "+this.label+"]";	}});/** * Implements validation for selection inputs (combo boxes). * @class Core.Form.SelectionValidation * @extends Core.Form.InputValidation */Core.Form.SelectionValidation = Core.create(Core.Form.InputValidation, {	/**	 * Creates a new validation for selection inputs.	 * @method init	 * @constructor	 * @param {String} inputName The name of the input to validate.	 * @param {String} label A human readable label for the input to validate.	 * @param {Number} firstValidSelection (Optional) The first valid selction in the list, the first element is 0.  This is useful if your first element is something like "-Please Select-". Defaults to 0.	 */	init: function(inputName, label, firstValidSelection) {		Core.Form.InputValidation.prototype.init.call(this, inputName, label);				this.firstValidSelection = typeof(firstValidSelection)=="undefined" ? 0 : firstValidSelection;	},	/**	 * This method performs the validation for the input. It should not be called directly but from {Core.Form#validate}.	 * @method test	 * @param {Core.Form} form The form where the inputs exsit.	 * @return {Core.Form.ValidationError} If an error is found an instance of {Core.Form.ValidationError} is returned with details of the error.  If there are no errors it reurns null.  	 */	test : function(form) {		var element = form.getElement(this.inputName);		if(element.getDom().selectedIndex<this.firstValidSelection) {			return this.createError(form, "is a required field.");		}		return null;	},	/*	 * Creates and returns a text represntaion of this SelectionValidation object.	 * @method toString	 * @return {String}	 */	toString : function() {		return "[Core.Form.SelectionValidation "+this.label+"]";	}});/** * Implements validation for radio inputs * @class Core.Form.RadioValidation * @extends Core.Form.InputValidation */Core.Form.RadioValidation = Core.create(Core.Form.InputValidation, {	/**	 * This method performs the validation for the input. It should not be called directly but from {Core.Form#validate}.	 * @method test	 * @param {Core.Form} form The form where the inputs exsit.	 * @return {Core.Form.ValidationError} If an error is found an instance of {Core.Form.ValidationError} is returned with details of the error.  If there are no errors it reurns null.  	 */	test : function(form) {		if(form.getValue(this.inputName)=="") {			return this.createError(form, "is a required field.");		}		return null;	},	/*	 * Creates and returns a text represntaion of this RadioValidation object.	 * @method toString	 * @return {String}	 */	toString : function() {		return "[Core.Form.RadioValidation "+this.label+"]";	}});/** * Implements validation for date fields * @class Core.Form.DateValidation * @extends Core.Form.InputValidation */Core.Form.DateValidation = Core.create(Core.Form.InputValidation, {	/**	 * Creates a new validation for date inputs.	 * @method init	 * @constructor	 * @param {String} inputName The name of the input to validate.	 * @param {String} label A human readable label for the input to validate.	 * @param {String} format (Optional) A format string to define how the date would be stored in the field.  Defaults to "dd mmmm yyyy".	 * @param Boolean required (Optional) When true the input can not be left blank.  Defaults to false.	 */	init: function(inputName, label, format, required) {		Core.Form.InputValidation.prototype.init.call(this, inputName, label);				this.format = format ? format : "dd mmmm yyyy";		this.required = typeof(required)=="undefined" ? false : required;	},	/**	 * This method performs the validation for the input. It should not be called directly but from {Core.Form#validate}.	 * @method test	 * @param {Core.Form} form The form where the inputs exsit.	 * @return {Core.Form.ValidationError} If an error is found an instance of {Core.Form.ValidationError} is returned with details of the error.  If there are no errors it reurns null.  	 */	test : function(form) {		var value = form.getValue(this.inputName).trim();		if(value!=="") {			var date = value.parseDate();			if(date==null) {				date = value.parseDate(this.format);			}					if(date==null) {				return this.createError(form, "is an invalid date.");			}		} else {			if(this.required) {				return this.createError(form, "is a required field.");			}		}		return null;	},	/*	 * Creates and returns a text represntaion of this TextValidation object.	 * @method toString	 * @return {String}	 */	toString : function() {		return "[Core.Form.DateValidation "+this.label+"]";	}});/* ############################## Element ############################## *//** * A wrapper for a HTML element.  It contains all the methods nessasery to manipulate an element. * You should not create a Core.Element directly but instead use a the static method get or the get method * in the {Core} object to return one. * @class Core.Element */Core.Element = Core.create({	/**	 * Creates a new Core.Element object for the DOM element passed	 * @method init	 * @constructor	 * @param HTMLElement dom The dom element.	 */	init: function(dom) {		this.dom = dom;		this.useVisibility=false;	},		/**	 * Returns the DOM element assoisiated with this Core.Element	 * @method getDom	 * @return HTMLElement The DOM element	 */	getDom: function() {		return this.dom;	},	/**	 * Adds a listener to this element.	 * @method addListener	 * @param {String} action The name of the event which will trigger the event, for example "click" for onClick events	 * @param {Function} listener The function to be called when the event fires.	 */	addListener: function(action, listener) {		Core.EventManager.addListener(this.dom, action, listener);	},	/**	 * Removes a listener from this element.	 * @param {String} action The name of the event which triggers the event, for example "click" for onClick events	 * @param {Function} listener The function to be removed.	 */	removeListener: function(action, listener) {		Core.EventManager.removeListener(this.dom, action, listener);	},	/**	 * Prevents text selection in this element.	 * @method preventTextSelection	 */	preventTextSelection: function() {		var target = this.getDom();		target.onselectstart=Core.returnFalse; // ie		target.style.MozUserSelect="none"; // firefox		target.onmousedown=Core.returnFalse; // all	},	/**	 * Removes all content from this element.	 * @method clear	 */	clear: function() {		while(this.dom.firstChild) {      		this.dom.removeChild(this.dom.firstChild);		}	},	/**	 * @method getHtml	 * @retrun {String} The innerHTML for this element.	 */	getHtml: function() {		return this.dom.innerHTML;	},	/**	 * Sets the innerHTML for this element.	 * @method setHtml	 * @param {String} text The text/html to set the innerHTML to.	 */	setHtml: function(text) {		this.dom.innerHTML = text;	},	/**	 * Creates an html element and adds it as a child to this element.  It uses 	 * <code>Core.DOM.create</code> to create the new element.	 * @method createChild	 * @param Object details A object with the details of the element to create.	 * @param {Core.Element}/HTMLElement insert (Optional) An element to insert the new element before, if not specified the element is appended.	 * @param Boolean insertAfter (Optional) If ture the new element is inserted after the element specified.	 * @see Core.DOM	 */	createChild: function(details, insert, insertAfter) {		var child = Core.Dom.create(details, this.dom.ownerDocument);		if(insert) {			if(insert instanceof Core.Element) {				insert = insert.getDom();			}		}		if(insert && insert.nodeType && insertAfter) {			insert = insert.nextSibling;		}		if(insert && insert.nodeType) {			this.getDom().insertBefore(child, insert);		} else {			this.getDom().appendChild(child);		}		return new Core.Element(child);	},	/**	 * Creates an html element and adds it as a sibling to this element. It uses 	 * <code>Core.DOM.create</code> to create the new element.	 * @method createSibling	 * @param Object details A object with the details of the element to create.	 * @param Boolean insertAfter (Optional) If ture the new element is inserted after this element instead of before. Defaults to false. 	 * @see Core.DOM	 */	createSibling: function(details, insertAfter) {		var child = Core.Dom.create(details, this.dom.ownerDocument);		var insert = this.getDom();		var parent = this.getDom().parentNode;		if(insertAfter) {			insert = insert.nextSibling;		}		if(insert && insert.nodeType) {			parent.insertBefore(child, insert);		} else {			parent.appendChild(child);		}		return new Core.Element(child);	},	/**	 * Removes the element from the document.	 * @method remove	 */	remove: function() {		if(this.getDom() && this.getDom().parentNode) {			this.getDom().parentNode.removeChild(this.getDom());		}	},	/**	 * Replaces the HTML element with a new HTML element.	 * @method replace	 * @param HTMLElment node The new element.	 */	replace: function(node) {		this.getDom().parentNode.replaceChild(node, this.getDom());		this.dom = node;	},		/**	 * This will find this elements first child.	 * @method findFirstChild	 * @param {String} nodeName (Optional) When specified this will look for the first child with that node name.	 * @param {String} className (Optional) When specified this will look for the first child using this css class.	 * @return {Core.Element} The first child, if there are no children or no children of the specified type, this will return null.	 */	findFirstChild: function(nodeName, className) {		return this.findChild(this.getDom().firstChild, nodeName, className);	},	/**	 * This will find the next sibling of the child specified.	 * @method findNextChild	 * @param {Core.Element}/HTMLElement child The node whos siblings your are looking for.	 * @param {String} nodeName (Optional) When specified this will look for the first sibling with that node name.	 * @param {String} className (Optional) When specified this will look for the first child using this css class.	 * @return {Core.Element} The first sibling, if there are no more siblings or no more siblings of the specified type, this will return null.	 */	findNextChild: function(child, nodeName, className) {		if(child instanceof Core.Element) {			child = child.getDom();		}		return this.findChild(child.nextSibling, nodeName, className);	},	/* private */	findChild: function(child, nodeName, className) {		while(child && child.nodeType) {			if(child.nodeType==1) {				if(!nodeName || child.nodeName.toUpperCase()==nodeName.toUpperCase()) {					if(!className || child.className.split(" ").indexOf(className)>=0) {						return Core.Element.get(child);					}				}			}			child = child.nextSibling;		}		return null;	},	/**	 * This will return the parent element for this current element.	 * @method getParent	 * @return {Core.Element} The parent element.	 */	getParent: function() {		return Core.Element.get(this.getDom().parentNode);	},		/**	 * Attempts to read the style attribute for this element	 * @method readStyle	 * @param {String} property The name of the property to try and read.	 */	readStyle : function(property) {		var rv = "";		if(document.defaultView && document.defaultView.getComputedStyle){			rv = document.defaultView.getComputedStyle(this.getDom(), "").getPropertyValue(property);		} else if(this.getDom().currentStyle){			property = property.replace(/\-(\w)/g, function (strMatch, p1){				return p1.toUpperCase();			});			rv = this.getDom().currentStyle[property];		}		return rv;	},		/**	 * @method getClass	 * @return {String} The complete CSS class for this element.	 */	getClass : function() {		return this.getDom().className;	},	/**	 * Replaces the all the CSS classes for this element, in most circumstance it is advisable to use 	 * <code>addClass</code>, <code>removeClass</code> or <code>changeClass</code> instead.	 * @method setClass	 * @param <String> className The new CSS class for this element.	 */	setClass : function(className) {		this.getDom().className = className;	},	/**	 * Adds a CSS class to this element.	 * @method addClass	 * @param <String> className The CSS class to add.	 */	addClass : function(className) {		var classNames = this.getClass().split(" ");		className=className.trim();						if(!this.hasClass(className)) {			this.setClass(this.getClass().trim() + " " + className);		}		},	/**	 * Removes CSS class from this element.	 * @method removeClass	 * @param <String> className The CSS class to remove.	 */	removeClass : function(className) {		var classNames = this.getClass().split(" ");		var newClass="";		var found=false;		className=className.trim();				for(var index=0; index<classNames.length; index++) {			if(classNames[index].trim() == className) {				found=true;			} else {				newClass=newClass+" " + classNames[index].trim()			}		}		if(found) {			this.setClass(newClass.substring(1));		}		},	/**	 * Changes a CSS class in this element.  This is short hand for calling <code>removeClass</code>	 * followed by<code>addClass</code>.	 * @method changeClass	 * @param <String> oldClassName The CSS class to remove.	 * @param <String> newClassName The CSS class to add.	 */	changeClass : function(oldClassName, newClassName) {		this.removeClass(oldClassName);		this.addClass(newClassName);	},	/**	 * Checks to see if a CSS class is used by this element.	 * @method hasClass	 * @param <String> className The CSS class to look for.	 * @return Boolean True if the class is in use.	 */	hasClass : function(className) {		return this.getClass().split(" ").indexOf(className)>=0;	},	/**	 * Changes the way the show and hide methods work.	 * @method setUseVisibility	 * @param Boolean useVisibility When true show and hide will change the visibility style property, when false (default) they will change the display type.	 */	setUseVisibility: function(useVisibility) {		this.useVisibility = useVisibility;	},	/**	 * Makes the element visible.  By default elements are hidden by setting 	 * <code>style.display</code> to "none" and shown by setting <code>style.display</code>	 * to the default value.  To use the <code>style.visibility</code> property use 	 * <code>setUseVisibility</code> to change the setting.	 * @method show	 * @param {String} how (Optional) When using <code>style.display</code> this can be used to overide what <code>style.display</code> should be set to.	 */	show: function(how) {		if(this.useVisibility) {			this.dom.style.visibility="visible";		} else {			if(!how) {				how = "";			}			this.dom.style.display=how;		}	},	/**	 * Makes the element hidden.  By default elements are hidden by setting 	 * <code>style.display</code> to "none" and shown by setting <code>style.display</code>	 * to the default value.  To use the <code>style.visibility</code> property use 	 * <code>setUseVisibility</code> to change the setting.	 * @method hide	 */	hide: function() {		if(this.useVisibility) {			this.dom.style.visibility="hidden";		} else {			this.dom.style.display="none";		}	},	/**	 * Checks to see if this element has been shown or hidden using the show/hide functions.	 * @method isVisible	 * @return boolean True if the element is visible.	 */	isVisible: function() {		if(this.useVisibility) {			return this.dom.style.visibility=="visible";		} else {			return this.dom.style.display!="none";		}	},		/**	 * Caculates the elements position within it's imediate container.  For the elements position within the document use <code>getTotalOffset</code>.	 * @method getOffset	 * @return {Core.Point} The elements position.	 */	getOffset : function() {		return new Core.Point(this.dom.offsetLeft, this.dom.offsetTop); 	},	/**	 * Sets the elements position within it's container.  This will only work elements that are position absolutely.	 * @method setOffset	 * @param {Core.Point} point The elements position.	 */	setOffset : function(point) {		this.dom.style.top = point.y + "px";		this.dom.style.left = point.x + "px";	},	/**	 * Sets the elements horizontal position within it's container.  This will only work elements that are position absolutely.	 * @method setXOffset	 * @param {Core.Point} point The elements position.	 */	setXOffset : function(point) {		this.dom.style.left = point.x + "px";			},	/**	 * Sets the elements vertical position within it's container.  This will only work elements that are position absolutely.	 * @method setYOffset	 * @param {Core.Point} point The elements position.	 */	setYOffset : function(point) {		this.dom.style.top = point.y + "px";			},	/**	 * Caculates the elements position within the document.  For the elements position within it's imediate container use <code>getOffset</code>.	 * @method getTotalOffset	 * @return {Core.Point} The elements position.	 */	getTotalOffset : function() {		var offset = new Core.Point(this.dom.offsetLeft, this.dom.offsetTop); 		var parent = this.dom.offsetParent;		while (parent) {			if(parent!=document.body) {				offset.minus(new Core.Point(parent.scrollLeft, parent.scrollTop));			}			offset.add(new Core.Point(parent.offsetLeft, parent.offsetTop));			parent = parent.offsetParent;		}		return offset;	},	/**	 * Caculates the elements position within a specified container.	 * @method getOffsetWithin	 * @return {Core.Point} The elements position.	 * @param {Core.Element}/HTMLNode within The offset will be calculated based on this container.	 */	getOffsetWithin : function(within) {		within = Core.get(within).getDom();		var offset = new Core.Point(this.dom.offsetLeft, this.dom.offsetTop); 		var parent = this.dom.parentNode;		var offsetParent = this.dom.offsetParent;		while (parent && parent!=within) {			if(parent==offsetParent) {				offset.minus(new Core.Point(parent.scrollLeft, parent.scrollTop));				offset.add(new Core.Point(parent.offsetLeft, parent.offsetTop));				parent = parent.parentNode;				offsetParent = parent.offsetParent;			} else {				parent = parent.parentNode;			}		}		return offset;	},	/**	 * Caculates the elements size.	 * @method getSize	 * @return {Core.Point} The elements size.	 */	getSize: function() {		return new Core.Point(this.dom.offsetWidth, this.dom.offsetHeight);	},	/**	 * Set the elements size. This will only work with block elements.	 * @method getSize	 * @param {Core.Point} size The elements size.	 */	setSize: function(point) {		this.getDom().style.width = point.x;		this.getDom().style.height = point.y;	},	/**	 * Gets the elements z index.	 * @method getZIndex	 * @retrun {Number} The elements z index.	 */	getZIndex: function() {		return this.getDom().style.zIndex;	},	/**	 * Set the elements z index.	 * @method setZIndex	 * @param {Number} index The elements z index.	 */	setZIndex: function(index) {		this.getDom().style.zIndex=index;	},			/*	 * Creates and returns a text represntaion of this Element object.	 * @method toString	 * @return {String}	 */	toString : function() {		return "[Core.Element "+"]";	}});Core.copy(Core.Element, {	/**	 * Returns a Core.Element object for the requested HTML element.  If an element has been collected 	 * previously it will return the original Core.Element object however it will update the link DOM element	 * incase it has been replaced since the last call.	 * @todo implement the cache	 * @method get	 * @static	 * @param {String}/HTMLElement/{Core.Element} request The id of a HTMLElement, the DOM node or an Element	 * @return {Core.Element} The requested element or null if it is not found.	 */	get: function(request) {		if(request) {			if(request instanceof Core.Element) {				return request;			} else if(typeof(request)=="object" && request.nodeType) {				return new Core.Element(request);			} else if(typeof(request)=="string") {				var dom = document.getElementById(request);				if(dom) {					return new Core.Element(dom)				}			}		}		return null;				},		/**	 * <p>This is used to highlight elements, it basicly adds or removes a CSS class from an element when an event occurs.</p>	 * <h5>example</h5><p>The following example uses the method to highlight a row element when a mouse moves over it.</p><pre><code>rowElement.addListener("mouseover", Core.Element.highlight.bind(["highlight", true]));rowElement.addListener("mouseout", Core.Element.highlight.bind(["highlight", false]));</pre><code>	 * @method highlight	 * @static	 * @param Object event An event information object, normally a system generated one.  It needs to have a target property that references the source of the event.	 * @param {String} className The class to add or remove from the element.	 * @param Boolean add When true the class is added to the element, when false it is removed.	 * @param {String} nodeName (Optional) When specified the code will move up from the element where the element occured until it finds an element of this name.	 * @param {String} nodeClass (Optional) When specified the code will move up from the element where the element occured until it finds an element of the nodeName and nodeClass.	 */	 highlight: function(event, className, add, nodeName, nodeClass) {		if(event && event.target) {			var element = Core.Element.get(event.target);			if(nodeName && nodeClass) {				while(element!=null && (element.getDom().nodeName!=nodeName.toUpperCase() || !element.hasClass(nodeClass))) {					element = element.getParent();				}			} else if(nodeName) {				while(element!=null && element.getDom().nodeName!=nodeName.toUpperCase()) {					element = element.getParent();				}			}			if(element!=null) {				if(add) {					element.addClass(className);				} else {					element.removeClass(className);				}			}		}	}});/** * Returns a {Core.Element} object for the requested HTML element.  If an element has been collected  * previously it will return the original {Core.Element} object however it will update the link DOM element * incase it has been replaced since the last call.  Shorthand for {Core.Element#get} * @method get * @static * @member Core * @param {String}/HTMLElement/{Core.Element} request The id of a HTMLElement, the DOM node or an Element * @return {Core.Element} The requested element or null if it is not found. */Core.get = Core.Element.get;/** * Returns a {Core.Element} object for HTML Body element.  Shorthand for  * <code>Core.Element.get(document.body);</code> * @method getBody * @static * @member Core * @return {Core.Element} The body element. */Core.copy(Core, {	getBody : function() {		return Core.Element.get(document.body);	}});
