/* -*- C -*- */

/* --------------------------------------------------------------------
 * Shine: The Become Interactive Client Application Framework
 * @(#) $Id: com.uk.become.shine.core.js,v 1.1 2010/10/28 06:18:02 ultrasis\xiongjiping Exp $
 * --------------------------------------------------------------------
 * Copyright (c) 2006 Become Interactive
 * http://www.becomeinteractive.co.uk
 * All rights reserved.
 * --------------------------------------------------------------------
 * This software is the confidential and proprietary information of
 * Become Interactive ("Confidential Information").
 *
 * You shall not disclose such Confidential Information and shall use
 * it only in accordance with the terms of the license agreement you
 * with the terms of the license agreement you entered into with
 * Become Interactive.
 * --------------------------------------------------------------------
 */

var Shine;

if(typeof com == "undefined") var com = new Object();
if(typeof com.uk == "undefined") com.uk = new Object();
if(typeof com.uk.become == "undefined") com.uk.become = new Object();
if(typeof com.uk.become.shine == "undefined") com.uk.become.shine = new Object();

/**
 * com.uk.become.shine.Browser
 *
 * Provides information about the host browser.
 */

com.uk.become.shine.Browser = function()
{
	var ua;
	
	ua = navigator.userAgent.toLowerCase();	
	this.userAgent = navigator.userAgent;
	this.isOpera = ((ua.indexOf("opera") != -1) || window.opera);
	this.isWebTV = (ua.indexOf("webtv") != -1);
	this.isIE = (ua.indexOf("msie") != -1) && !com.uk.become.shine.Browser.isOpera && !com.uk.become.shine.Browser.isWebTV;
	this.isWebKit = (ua.indexOf('applewebkit') != -1);
	this.ieVersion = false;
	if(document.createElementNS)
		{
			this.isDOM = true;
		}
	else
		{
			this.isDOM = false;
		}
	if(this.ieIE)
		{
			this.ieVersion = navigator.appVersion.match(/MSIE (\d.\d)/)[1];
		}
}

/**
 * com.uk.become.shine.Core
 *
 * A layer of cross-browser glue for event handling, class-triggered behaviours,
 * and other support functions. 
 */

com.uk.become.shine.Core = function(window, document)
{
	this.version = '$Id: com.uk.become.shine.core.js,v 1.1 2010/10/28 06:18:02 ultrasis\xiongjiping Exp $';
	this.basePath = '/';
	this.rootPath = '/';
	this.tplPath = '/';
	this._abort = false;
	this._window = window;
	this._document = document;
	this._loaded = false;
	this._loadHandlers = new Array();
	this._validating = false;
	this._fieldValidators = new Array();
	this._forms = new Array();
	this._validateInterval = false;
	this._popupCount = 0;
	this._formDirty = 0;
	this._requiredModules = new Object();
	this._requiredModules['com.uk.become.shine.core'] = true;
	this.body = false;	
	this.browser = new com.uk.become.shine.Browser();
	if(this.browser.isIE && (this.browser.isVersion < 5 || this.browser.isVersion >= 7))
	{
		this._abort = true;
		return false;
	}
	this.debug('Shine:', this.version);
/*	if (this.browser.isDOM)	
		{
			this.addEventHandler(document, 'DOMContentLoaded', { host: this, handler: this.loaded });
		} */
	return this;
}
com.uk.become.shine.Core.prototype.debug = function()
{
	var args, a;
			
	args = new Array();
	d = args.length;	
	for(c = 0; c < arguments.length; c++)
		{
			args[d] = arguments[c];
			d++;
		}
	args = args.join(' ');	
	if(!arguments.length)
		{
			return false;
		}
	if(this.browser.isWebKit || window.console)
		{
			if(window.console && this.browser.isWebKit)
				{
					window.console.log(args);
				}
			else if(window.console)
				{
					window.console.log("%s", args);
				}	   
		}
	else if(this.browser.isOpera && window.opera.postError)
		{
			window.opera.postError(args);
		}
	else if(document.createEvent && window.dispatchEvent)
		{
			printfire = new Object();
			printfire.args = new Array(args);
			var ev = document.createEvent('Events');
			ev.initEvent('printfire', false, true);
			try
				{
					dispatchEvent(ev);
				}
			catch(e)
				{
				}
		}
	return true;
}
com.uk.become.shine.Core.prototype.createHTMLElement = function(tagName)
{
	if(this.browser.isDOM)
	{
		return document.createElementNS('http://www.w3.org/1999/xhtml', tagName);
	}
	return document.createElement(tagName);
}
com.uk.become.shine.Core.prototype.createRequest = function(method, uri)
{
	return new com.uk.become.shine.Request(method, uri);
}
com.uk.become.shine.Core.prototype._loadScript = function(path)
{
	var sel, heads;
	
	this.debug('Shine:', 'Loading script from ' + path);
	if(this.browser.isDOM)
	{
		heads = document.getElementsByTagName('head');
		if(heads && heads.length)
		{
			heads = heads[0];
		}
		else
		{
			return false;
		}
		sel = this.createHTMLElement('script');
		this.setAttribute(sel, 'type', 'text/javascript');
		this.setAttribute(sel, 'src', path);
		heads.appendChild(sel);
	}
	else
	{
		document.write('<' + 'script type="text/javascript" src="' + path + '"></script>');
	}
}
com.uk.become.shine.Core.prototype.importStylesheet = function(path, media)
{
	var sel, heads;
	
	this.debug('Shine:', 'Loading stylesheet from ' + path);
	if(this.browser.isDOM)
	{
		heads = document.getElementsByTagName('head');
		if(heads && heads.length)
		{
			heads = heads[0];
		}
		else
		{
			return false;
		}
		sel = this.createHTMLElement('link');
		this.setAttribute(sel, 'type', 'text/css');
		this.setAttribute(sel, 'media', media);
		this.setAttribute(sel, 'href', path);
		this.setAttribute(sel, 'rel', 'stylesheet');
		heads.appendChild(sel);
	}
	else
	{
		document.write('<' + 'link rel="stylesheet" type="text/css" href="' + path + '" media="screen,projection" />');
	}
}
com.uk.become.shine.Core.prototype.require = function(path, base, id)
{
	var req;

	if(typeof path == 'undefined')
		{
			Shine.debug('Attempt to require undefined path');
			return false;
		}
	if(typeof this._requiredModules[id] != 'undefined')
	{
		return true;
	}
	this._requiredModules[id] = this.basePath + path;
	if(base == 1)
		{
			path = this.basePath + path;
		}
	else if(base == 2)
		{
			path = this.rootPath + path;
		}
	return this._loadScript(path);
}
com.uk.become.shine.Core.prototype.setAttribute = function(element, name, value)
{
	if(this.browser.isDOM)
		{
			element.setAttribute(name, value);
		}
	else
		{
			if(name == 'class')
				{
					name = 'className';
				}
			eval('element.' + name + '= value');
		}
}
com.uk.become.shine.Core.prototype.addEventHandler = function(element, eventName, handler)
{
	var force, _Shine = this;
	
	force = false;
	if(typeof element == 'string')
		{
			element = document.getElementById(element);
		}
	if(!element)
		{
			return false;
		}
	if(!handler || !handler.handler)
		{
			Shine.debug('Shine:', 'Invalid handler passed for event on' + eventName);
			return false;
		}
	if(!element.shineEventHandlers)
	{
		element.shineEventHandlers = new Array();
	}
	if(!element.shineEventHandlers[eventName])
	{
		element.shineEventHandlers[eventName] = new Array();
		if(this.browser.isWebKit && eventName == 'click')
		{
			force = true;
		}
		if(this.browser.isDOM && element.addEventListener && !force)
		{
			element.addEventListener(eventName, 
								 	function(ev) { 
										return _Shine._eventHost(eventName, element, ev);
								 		}, false);
		}
		else if(element.attachEvent && element.attachEvent && !force)
		{
			element.attachEvent('on' + eventName, function(ev) { return Shine._eventHost(eventName, element, (ev ? ev : window.event)); });
		}
		else
		{
			eval('element.on' + eventName + ' = function(ev) { return Shine._eventHost(eventName, element, (ev ? ev : window.event)); }');
		}
	}
	element.shineEventHandlers[eventName][element.shineEventHandlers[eventName].length] = handler;
}
com.uk.become.shine.Core.prototype._eventHost = function(evtype, sender, ev)
{
	var handlers;
	
	if(!sender.shineEventHandlers || !sender.shineEventHandlers[evtype])
	{
		return true;
	}
	for(c in sender.shineEventHandlers[evtype])
	{
		if(!this.callEventHandler(sender, ev, sender.shineEventHandlers[evtype][c]))
		{
			if(ev.stopPropagation)
			{
				ev.stopPropagation();
			}
			if(ev.preventDefault)
			{
				ev.preventDefault();
			}
			ev.cancelBubble = true;
			return false;
		}
	}
	return true;
}
com.uk.become.shine.Core.prototype.callEventHandler = function(sender, event, handler)
{
	if(!handler.host)
		{
			handler.host = window;
		}
	handler.host._shineHandler = handler.handler;
	return handler.host._shineHandler(this, sender, event, handler.data);
}
com.uk.become.shine.Core.prototype.getAttribute = function(element, name)
{
	if(this.browser.isDOM)
		{
			return element.getAttribute(name);
		}
	if(name == 'class')
		{
			name = 'className';
		}
	return eval('element.' + name);
}
com.uk.become.shine.Core.prototype.getElementClass = function(element, forceDirect)
{
	var cn;

	if(element.shineStyleTarget && !forceDirect)
		{
			element = element.shineStyleTarget;
		}
	cn = this.getAttribute(element, 'class');
	if(typeof cn != 'string')
		{
			return '';
		}
	return cn;
}
com.uk.become.shine.Core.prototype._initStyles = function(element)
{
	if(element.shineStyleTarget)
	{
		element = element.shineStyleTarget;
	}
	if(typeof element.shineOriginalClass != 'string')
	{
		element.shineOriginalClass = this.getElementClass(element);
	}
	if(typeof element.shineClasses == 'undefined')
	{
		element.shineClasses = new Array();
	}
	return element;
}
com.uk.become.shine.Core.prototype._updateElementClass = function(element)
{
	var cn, cn2;
	
	cn = this.getAttribute(element, 'class');
	cn2 = element.shineOriginalClass + ' ' + element.shineClasses.join(' ');
	if(cn != cn2)
		{
			this.setAttribute(element,  'class', cn2);
		}
	return true;
}
com.uk.become.shine.Core.prototype.beginUpdate = function(element)
{
	element = this._initStyles(element);
	element._shineUpdating = true;
	return true;
}
com.uk.become.shine.Core.prototype.endUpdate = function(element)
{
	element = this._initStyles(element);
	element._shineUpdating = false;
	return this._updateElementClass(element);
}
com.uk.become.shine.Core.prototype.resetElementClass = function(element)
{
	element = this._initStyles(element);
	element.shineClasses = new Array();
	if(element._shineUpdating)
		{
			return true;
		}
	return this._updateElementClass(element);
}
com.uk.become.shine.Core.prototype.addElementClass = function(element, classname)
{
	var c;
		
	element = this._initStyles(element);
	for(c in element.shineClasses)
	{
		if(element.shineClasses[c] == classname)
		{
			return false;
		}
	}
	element.shineClasses[element.shineClasses.length] = classname;
	if(element._shineUpdating)
		{
			return true;
		}
	return this._updateElementClass(element);
}
com.uk.become.shine.Core.prototype.removeElementClass = function(element, classname)
{
	var c;
	
	element = this._initStyles(element);
	for(c in element.shineClasses)
	{
		if(element.shineClasses[c] == classname)
		{
			element.shineClasses.splice(c, 1);
		}
	}
	if(element._shineUpdating)
		{
			return true;
		}	
	return this._updateElementClass(element);
}
com.uk.become.shine.Core.prototype.hasElementClass = function(element, classname, forceDirect)
{
	var cn;

	if(!forceDirect)
		{
			forceDirect = false;
		}
	cn = ' ' + this.getElementClass(element, forceDirect) + ' ';
	if(cn.indexOf(' ' + classname + ' ') != -1)
		{
			return true;
		}
	return false;
}													
com.uk.become.shine.Core.prototype._inputHandler = function(shine, sender, event)
{
	var valid, empty, focussed, s;
	
	valid = true;
	s = false;
	prevalidated = false;
	if(typeof sender.defaultValue != 'undefined')
		{
			if(sender.value == sender.defaultValue && sender.acErrorField)
				{
					valid = false;
					prevalidated = true;
				}
		}
	empty = (sender.value ? false : true);	
	focussed = (sender.focussed ? true: false);
	if(!prevalidated && !empty && sender.shineValidator)
		{
			if(sender.shineValidatedValue && sender.shineValidatedValue == sender.value)
			{
				return true;
			}
			ev = new Object();
			ev.value = sender.value;
			ev.target = sender;
			ev.empty = empty;
			ev.focussed = focussed;
			valid = this.callEventHandler(sender, ev, sender.shineValidator);
			sender.shineValidatedValue = sender.value;
		}
	if(typeof sender.shinePrevValue == 'undefined' ||
	   sender.value != sender.shinePrevValue)
		{			
			this._formDirty++;
			sender.shinePrevValue = sender.value;
		}
	this.beginUpdate(sender);
	this.addElementClass(sender, 'shine-input');
	if(sender.shineSubField)
	{
		this.addElementClass(sender, 'shine-subfield');
	}
	this.removeElementClass(sender, 'shine-input-progress');
	this.removeElementClass(sender, 'shine-input-ok');
	this.removeElementClass(sender, 'shine-input-bad');
	this.removeElementClass(sender, 'shine-input-empty');	
	this.removeElementClass(sender, 'shine-input-focus');	
	if(sender.shineValidateInProgress)
	{
		this.addElementClass(sender, 'shine-input-progress');
		sender.shineValidated = false;
		sender.shineIncomplete = false;		
	}
	else if(empty)
	{
		this.addElementClass(sender, 'shine-input-empty');
		sender.shineValidated = false;
		sender.shineIncomplete = true;
	}
	else if(valid)
	{
		this.addElementClass(sender, 'shine-input-ok');
		sender.shineValidated = true;
		sender.shineIncomplete = false;
	}
	else
	{
		this.addElementClass(sender, 'shine-input-bad');
		sender.shineValidated = false;
		sender.shineIncomplete = false;
	}
	if(focussed)
	{
		this.addElementClass(sender, 'shine-input-focus');
	}
	this.endUpdate(sender);
	return true;
}
com.uk.become.shine.Core.prototype.validateField = function(sender, event)
{
	return this._inputHandler(this, sender, event);
}
com.uk.become.shine.Core.prototype._inputFocus = function(shine, sender, event)
{
	if(sender.focussed) return true;
	sender.focussed = true;
	this._inputHandler(shine, sender, event);
	return true;
}
com.uk.become.shine.Core.prototype._inputBlur = function(shine, sender, event)
{
	if(!sender.focussed) return true;
	sender.focussed = false;
	this._inputHandler(shine, sender, event);
	return true;
}
com.uk.become.shine.Core.prototype.addInputHandlers = function(elements, validator, data)
{
	var c;
	
	for(c = 0; c < elements.length; c++)
		{
			this.addInputHandler(elements[c], validator, data);
		}
}
com.uk.become.shine.Core.prototype.addLinkHandlers = function(elements, handler)
{
	var c;
	
	for(c = 0; c < elements.length; c++)
		{
			this.addLinkHandler(elements[c], handler);
		}
}
com.uk.become.shine.Core.prototype.addSubmitReplacements = function(elements)
{
	var c;
	
	for(c = 0; c < elements.length; c++)
		{
			this.addSubmitReplacement(elements[c]);
		}
}
com.uk.become.shine.Core.prototype.addSubmitReplacement = function(element)
{
	var link, span, tn;
	
	link = this.createHTMLElement('a');
	span = this.createHTMLElement('span');
	link._shineForm = element.form;
	this.setAttribute(link, 'href', 'javascript:void(0);');
	this.setAttribute(span, 'class', 'shine-replaced-button');
	id = this.getAttribute(element, 'id');
	if(id)
	{
		this.setAttribute(span, 'id', 'sr-' + id);
	}
	this.addEventHandler(link, 'click', { host: this, handler: this._submitHandler });
	span.appendChild(link);
	tn = document.createTextNode(this.getAttribute(element, 'value'));
	link.appendChild(tn);
	element.parentNode.replaceChild(span, element);
}
com.uk.become.shine.Core.prototype._submitHandler = function(Shine, sender, ev, data)
{
	if(sender._shineForm)
	{
		sender._shineForm.submit();
	}
	return false;
}
com.uk.become.shine.Core.prototype.addLinkHandler = function(element, handler)
{
	element.shineLinkRef = this.getAttribute(element, 'href');
	return this.addEventHandler(element, 'click', handler);
}
com.uk.become.shine.Core.prototype._createStyleWrapper = function(element)
{
	var newel;
	
	/* Create a wrapper element around an element, and set the child's
	 * .shineStyleTarget property to point to the new element. Useful for
	 * elements which can't really be styled themselves (e.g., list/drop-down
	 * boxes)
	 */
	if(element.parentNode && element.parentNode.shineStyleSource)
		{
			element.shineStyleTarget = element.parentNode;
			return element.parentNode;
		}
	newel = this.createHTMLElement('span');
	element.parentNode.replaceChild(newel, element);
	newel.appendChild(element);
	newel.shineStyleSource = true;
	element.shineStyleTarget = newel;
	return newel;
}
com.uk.become.shine.Core.prototype.addInputHandler = function(element, handler)
{
	if(typeof element == 'string')
		{
			element = document.getElementById(element);
		}
	if(!element)
		{
			return false;
		}
	this._createStyleWrapper(element);
	if(element.form)
		{
			if(!element.form.shineFields)
				{
					element.form.shineFields = new Array();
				}
			element.form.shineFields[element.form.shineFields.length] = element;
			if(!element.form.shineForm)
				{
					element.form.shineForm = true;
					this._forms[this._forms.length] = element.form;
				}
		}
	this.addElementClass(element, 'shine-input');
	if(this.hasElementClass(element, 'subfield', true))
	{
		element.shineSubField = true;
		this.addElementClass(element, 'shine-subfield');
	}
	else
	{
		element.shineSubField = false;
	}
	element.shineValidator = handler;
	element.shineValidatorData = handler.data;
	element.shineValidated = false;
	element.shineIncomplete = true;
	element.shineValidateInProgress = false;
	this._fieldValidators[this._fieldValidators.length] = element;
	this.addEventHandler(element, 'focus', { host: this, handler: this._inputFocus });
	this.addEventHandler(element, 'blur', { host: this, handler: this._inputBlur });
	return element;
}
com.uk.become.shine.Core.prototype._validateFields = function()
{
	var e, complete, valid;
	
	if(this._validating)
		{
			return true;
		}
	if(!this._formDirty)
		{
			return true;
		}
	this._validating = true;
	for(e in this._fieldValidators)
		{
			this._inputHandler(this, this._fieldValidators[e], false);
		}
	for(f in this._forms)
		{
			complete = true;
			valid = true;			
			for(e in this._forms[f].shineFields)
				{
					if(this._forms[f].shineFields[e].shineIncomplete)
						{
							complete = false;
						}
					if(!this._forms[f].shineFields[e].shineValidated)
						{
							valid = false;
						}
				}
			s = '';
			this.beginUpdate(this._forms[f]);
			this.removeElementClass(this._forms[f], 'form-complete');
			this.removeElementClass(this._forms[f], 'form-incomplete');
			this.removeElementClass(this._forms[f], 'form-valid');
			this.removeElementClass(this._forms[f], 'form-invalid');			
			this.removeElementClass(this._forms[f], 'form-valid-complete');
			this.removeElementClass(this._forms[f], 'form-not-valid-complete');						
			if(complete)
				{
					this.addElementClass(this._forms[f], 'form-complete');
				}
			else
				{
					this.addElementClass(this._forms[f], 'form-incomplete');
				}
			if(valid)
				{
					this.addElementClass(this._forms[f], 'form-valid');
				}
			else
				{
					this.addElementClass(this._forms[f], 'form-invalid');
				}
			if(complete && valid)
				{
					this.addElementClass(this._forms[f], 'form-valid-complete');
				}
			else
				{
					this.addElementClass(this._forms[f], 'form-not-valid-complete');					
				}
			this.endUpdate(this._forms[f]);
		}
	this._validating = false;
	if(this.formDirty > 0)
		{
			this._formDirty--;
		}
}
com.uk.become.shine.Core.prototype.getElementsByClass = function(root, el, classname)
{
	var c, nl, nlc, nodes, node;
	
	nodes = root.getElementsByTagName(el);
	nl = new Array();
	nlc = 0;
	for(c = 0; c < nodes.length; c++)
		{
			node = nodes[c];
			if(this.hasElementClass(node, classname, true))
				{					
					nl[nlc] = node;
					nlc++;
				}
		}
	return nl;
}
com.uk.become.shine.Core.prototype.insertAfter = function(parent, newChild, refChild) 
{ 
	if(refChild.nextSibling) 
	{ 
		return parent.insertBefore(newChild, refChild.nextSibling); 
	} 
	return parent.appendChild(newChild); 
}
com.uk.become.shine.Core.prototype.removeElement = function(element) 
{ 
	if(element.parentNode) 
	{ 
		return element.parentNode.removeChild(element); 
	} 

	return false; 
}
com.uk.become.shine.Core.prototype.addLoadHandler = function(obj)
{
	var ev;
	
	if(this._loaded)
	{
		ev = new Object();
		if(typeof obj.ondocumentloaded == 'undefined')
		{
			Shine.debug('Shine', "Warning: Load handler doesn't implement ondocumentloaded");
		}
		else
		{
			obj.ondocumentloaded(Shine, Shine, ev)
		}
	}
	else
	{
		this._loadHandlers[this._loadHandlers.length] = obj;
	}
}
com.uk.become.shine.Core.prototype.createPopup = function(url, w, h, name)
{
	var win, x, y, settings;
	
	x = (screen.width - w) / 2;
	y = (screen.height - h) / 2;
	settings = 'height=' + h +',';
	settings += 'width=' + w + ',';
	settings += 'top=' + y + ',';
	settings += 'left=' + x + ',';
	settings += 'scrollbars=yes,';
	settings += 'resizable=yes,';
	settings += 'status=no,';
	settings += 'titlebar=no,';
	settings += 'toolbar=no,';
	if(typeof name == undefined || !name)
		{
			name = 'win' + this._popupCount;
		}
	this._popupCount++;
	win = window.open(url, name, settings);
	if(win)
		{
			try
				{
					if(win.focus) win.focus();
				}
			catch(e)
				{
				}
			return false;
		}
	return true;
}
com.uk.become.shine.Core.prototype.popupLinkHandler = function(Shine, sender, ev, data)
{
	if (ev.shiftKey || ev.altKey || ev.ctrlKey || ev.metaKey)
		{
			return true;
		}
	return Shine.createPopup(sender.shineLinkRef, 400, 500);
}
com.uk.become.shine.Core.prototype.largePopupLinkHandler = function(Shine, sender, ev, data)
{
	if (ev.shiftKey || ev.altKey || ev.ctrlKey || ev.metaKey)
		{
			return true;
		}	
	return Shine.createPopup(sender.shineLinkRef, 600, 600);
}
com.uk.become.shine.Core.prototype.contentPopupLinkHandler = function(Shine, sender, ev, data)
{
	if (ev.shiftKey || ev.altKey || ev.ctrlKey || ev.metaKey)
		{
			return true;
		}	
	return Shine.createPopup(sender.shineLinkRef, 800, 600);
}	
com.uk.become.shine.Core.prototype.debugPopupLinkHandler = function(Shine, sender, ev, data)
{
	if (ev.shiftKey || ev.altKey || ev.ctrlKey || ev.metaKey)
		{
			return true;
		}	
	return Shine.createPopup(sender.shineLinkRef, 800, 600);
}
com.uk.become.shine.Core.prototype.externalLinkHandler = function(Shine, sender, ev, data)
{
	var win;
	if (ev.shiftKey || ev.altKey || ev.ctrlKey || ev.metaKey)
		{
			return true;
		}	
	win = window.open(sender.shineLinkRef, '_blank');
	if(win && win.window && win.window.focus) win.window.focus();
	return (win ? false : true);
}
com.uk.become.shine.Core.prototype._createHandlers = function()
{
	nodes = this.getElementsByClass(document, 'a', 'shine-popup-link');
	this.addLinkHandlers(nodes, { host: Shine, handler: Shine.popupLinkHandler });
	nodes = this.getElementsByClass(document, 'a', 'shine-largepopup-link');
	this.addLinkHandlers(nodes, { host: Shine, handler: Shine.largePopupLinkHandler });
	nodes = this.getElementsByClass(document, 'a', 'shine-contentpopup-link');
	this.addLinkHandlers(nodes, { host: Shine, handler: Shine.largePopupLinkHandler });
	nodes = this.getElementsByClass(document, 'a', 'shine-debugpopup-link');
	this.addLinkHandlers(nodes, { host: Shine, handler: Shine.debugPopupLinkHandler });
	nodes = this.getElementsByClass(document, 'a', 'shine-external-link');
	this.addLinkHandlers(nodes, { host: Shine, handler: Shine.externalLinkHandler });
	nodes = this.getElementsByClass(document, 'a', 'shine-nonhtml-link');
	this.addLinkHandlers(nodes, { host: Shine, handler: Shine.externalLinkHandler });
	nodes = this.getElementsByClass(document, 'input', 'shine-submit-button');
	this.addSubmitReplacements(nodes);
	/* Set up form field validation */
	Shine._validatorInterval = window.setInterval(function() {  Shine._validateFields(); }, 250);
	this._validateFields();	
}
com.uk.become.shine.Core.prototype.loaded = function(Shine, sender, ev, data)
{
	var nodes;

	if(this._loaded)
		{
			return true;
		}
	else if(this._abort)
		{
			return false;
		}
	this.body = document.getElementsByTagName('body').item(0);
	this._loaded = true;
	this._createHandlers();
	for(h in this._loadHandlers)
		{
			this._loadHandlers[h].ondocumentloaded(Shine, sender, ev, data);
		}
	return true;
}

Shine = new com.uk.become.shine.Core(window, document);

