// This file contains some of the common functions used for this site.
// To use these functions you must make reference to this page in the
// HTML pages. 

// Unless otherwise stated all the following code is copyright of netXdesign

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Even up columns
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

function evenCol(){
	//return;

	var lh = getObjectHeight("sidebar1");
	var rh = getObjectHeight("mainContent");

	var nh = Math.max(lh, rh); 
	document.getElementById("sidebar1").style.height = nh + "px";
	document.getElementById("mainContent").style.height = nh + "px";

}

function getLastpath(){
	var fso;
//fso = new ActiveXObject("Scripting.FileSystemObject");

	//alert(fso.GetParentFolderName(window.location.pathname));
	//return (GetParentFolderName(window.location.pathname));
}


/////////////////////////////////////////////////////////////////////////////////
// Confirmation form submit
/////////////////////////////////////////////////////////////////////////////////

function submitFormCheck(form, msg){
	if (confirm(msg)){
		document.forms[form].submit();
		return;
	}
	else
		return false;	
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Flash content placer
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


function getFlash(id, file,title, w, h, wmode){

var idC = document.getElementById(id);
var cont;

cont = "<object classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000' codebase="+
"'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0' "+
"width='"+w+"' height='"+h+"' title='"+title+"' id='"+file+"SWF'>"+
"<param name='movie' value='"+ file +"' />"+
"<param name='allowScriptAccess' value='sameDomain' />"+
"<param name='quality' value='high' />"+ 
"<param name='wmode' value='"+wmode+"' />"+


"<embed src='"+ file +"' quality='high' pluginspage='http://www.macromedia.com/go/getflashplayer'"+
"type='application/x-shockwave-flash' width='"+w+"' height='"+h+"' allowScriptAccess='sameDomain' name='headerSWF' swLiveConnect='true' wmode='"+wmode+"' />"+
"</object>";

idC.innerHTML = cont;
	
}



/////////////////////////////////////////////////////////////////////////////////
// Change background on focus 
/////////////////////////////////////////////////////////////////////////////////

function changeBg(form,field, requiredFields, fieldNames)
{
var	c,i,z,r;
r=0,empty=false;
	
	//setBGColor(field, 'f6fbfe');
	//field.style.borderColor = '6699ff';
	
	// Find form field pos.
	//alert (form.length);
	for (i=0;i<form.length;i++)
	{
		
	if (field.name == form[i].name)
		{
			break;
		}
	}
	msg = "";
	
	c = 0;
	for (t=0;t<i;t++)
	{
		
		if ((form[t].value == "") || (form[t].value == null))
			{
				
			for (z=0;z<requiredFields.length;z++)
				{
					//alert (form.elements.length);
					if (form[t].name == requiredFields[z])
					{
						
						msg += "'" + fieldNames[z] + ":'\n";
						c++;
						if (empty == false){
							empty = true;
							r = t;
						}
					}
				}
			
			}
		
	}
	if (c == 1){
		alert ("Please complete the required field:\n\n" + msg);
		restoreBg(field);
		form.elements[r].focus();
	}
	else if (c > 1){
		alert ("Please complete the required fields:\n\n" + msg);
		restoreBg(field);
		form.elements[r].focus();
	}
}

function restoreBg(obj)
{
	//obj.style.backgroundColor = 'white';
	//obj.style.borderColor = '999999';
}




////////////////////////////////////////////////////////////////////////////////
// Test for empty/null data
function isEmpty(data){
if ((data == null) ||
(data == "") ||
(data.length < 1))
return (true);
else return (false);
}


////////////////////////////////////////////////////////////////////////////////
// Returns the date in long hand format
function date1 ()
{
  var d, s = "";
  var month = ["January", "February", "March", "April", "May" , "June",
  "July", "August", "September", "October", "November", "December"];
  
  var day = ["Sunday", "Monday", "Tuesday",
  "Wenesday", "Thursday", "Friday", "Saturday"];
  
  d = new Date();
  //s += day[d.getDay()] + " ";
  s += d.getDate() + " ";
  s += month[(d.getMonth())] + " ";
  s += d.getFullYear();
  return (s)
   
}
////////////////////////////////////////////////////////////////////////////////
function year ()
{
  var d, s = "";
  
  d = new Date();
  s += d.getFullYear();
  return (s)
   
}

////////////////////////////////////////////////////////////////////////////////
// Check email validity
/* 1.1.4: Fixed a bug where upper ASCII characters (i.e. accented letters
international characters) were allowed.

1.1.3: Added the restriction to only accept addresses ending in two
letters (interpreted to be a country code) or one of the known
TLDs (com, net, org, edu, int, mil, gov, arpa), including the
new ones (biz, aero, name, coop, info, pro, museum).  One can
easily update the list (if ICANN adds even more TLDs in the
future) by updating the knownDomsPat variable near the
top of the function.  Also, I added a variable at the top
of the function that determines whether or not TLDs should be
checked at all.  This is good if you are using this function
internally (i.e. intranet site) where hostnames don't have to 
conform to W3C standards and thus internal organization e-mail
addresses don't have to either.
Changed some of the logic so that the function will work properly
with Netscape 6.

1.1.2: Fixed a bug where trailing . in e-mail address was passing
(the bug is actually in the weak regexp engine of the browser; I
simplified the regexps to make it work).

1.1.1: Removed restriction that countries must be preceded by a domain,
so abc@host.uk is now legal.  However, there's still the 
restriction that an address must end in a two or three letter
word.

1.1: Rewrote most of the function to conform more closely to RFC 822.

1.0: Original  */
// -->

<!-- Begin
function emailCheck (emailStr) {

/* The following variable tells the rest of the function whether or not
to verify that the address ends in a two-letter country or well-known
TLD.  1 means check it, 0 means don't. */

var checkTLD=1;

/* The following is the list of known TLDs that an e-mail address must end with. */

var knownDomsPat=/^(com|net|org|edu|int|mil|gov|arpa|biz|aero|name|coop|info|pro|museum)$/;

/* The following pattern is used to check if the entered e-mail address
fits the user@domain format.  It also is used to separate the username
from the domain. */

var emailPat=/^(.+)@(.+)$/;

/* The following string represents the pattern for matching all special
characters.  We don't want to allow special characters in the address. 
These characters include ( ) < > @ , ; : \ " . [ ] */

var specialChars="\\(\\)><@,;:\\\\\\\"\\.\\[\\]";

/* The following string represents the range of characters allowed in a 
username or domainname.  It really states which chars aren't allowed.*/

var validChars="\[^\\s" + specialChars + "\]";

/* The following pattern applies if the "user" is a quoted string (in
which case, there are no rules about which characters are allowed
and which aren't; anything goes).  E.g. "jiminy cricket"@disney.com
is a legal e-mail address. */

var quotedUser="(\"[^\"]*\")";

/* The following pattern applies for domains that are IP addresses,
rather than symbolic names.  E.g. joe@[123.124.233.4] is a legal
e-mail address. NOTE: The square brackets are required. */

var ipDomainPat=/^\[(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\]$/;

/* The following string represents an atom (basically a series of non-special characters.) */

var atom=validChars + '+';

/* The following string represents one word in the typical username.
For example, in john.doe@somewhere.com, john and doe are words.
Basically, a word is either an atom or quoted string. */

var word="(" + atom + "|" + quotedUser + ")";

// The following pattern describes the structure of the user

var userPat=new RegExp("^" + word + "(\\." + word + ")*$");

/* The following pattern describes the structure of a normal symbolic
domain, as opposed to ipDomainPat, shown above. */

var domainPat=new RegExp("^" + atom + "(\\." + atom +")*$");

/* Finally, let's start trying to figure out if the supplied address is valid. */

/* Begin with the coarse pattern to simply break up user@domain into
different pieces that are easy to analyze. */

var matchArray=emailStr.match(emailPat);

if (matchArray==null) {

/* Too many/few @'s or something; basically, this address doesn't
even fit the general mould of a valid e-mail address. */

alert("Email address seems incorrect (check @ and .'s)");
return false;
}
var user=matchArray[1];
var domain=matchArray[2];

// Start by checking that only basic ASCII characters are in the strings (0-127).

for (i=0; i<user.length; i++) {
if (user.charCodeAt(i)>127) {
alert("Email username contains invalid characters.");
return false;
   }
}
for (i=0; i<domain.length; i++) {
if (domain.charCodeAt(i)>127) {
alert("Email domain name contains invalid characters.");
return false;
   }
}

// See if "user" is valid 

if (user.match(userPat)==null) {

// user is not valid

alert("Email username doesn't seem to be valid.");
return false;
}

/* if the e-mail address is at an IP address (as opposed to a symbolic
host name) make sure the IP address is valid. */

var IPArray=domain.match(ipDomainPat);
if (IPArray!=null) {

// this is an IP address

for (var i=1;i<=4;i++) {
if (IPArray[i]>255) {
alert("Email destination IP address is invalid!");
return false;
   }
}
return true;
}

// Domain is symbolic name.  Check if it's valid.
 
var atomPat=new RegExp("^" + atom + "$");
var domArr=domain.split(".");
var len=domArr.length;
for (i=0;i<len;i++) {
if (domArr[i].search(atomPat)==-1) {
alert("Email domain name does not seem to be valid.");
return false;
   }
}

/* domain name seems valid, but now make sure that it ends in a
known top-level domain (like com, edu, gov) or a two-letter word,
representing country (uk, nl), and that there's a hostname preceding 
the domain or country. */

if (checkTLD && domArr[domArr.length-1].length!=2 && 
domArr[domArr.length-1].search(knownDomsPat)==-1) {
alert("The email address must end in a well-known domain or two letter " + "country.");
return false;
}

// Make sure there's a host name preceding the domain.

if (len<2) {
alert("The email address is missing a hostname!");
return false;
}

// If we've gotten this far, everything's valid!
return true;
}


////////////////////////////////////////////////////////////////////////////////
// Form Validation
// Arrays for the required fields and discriptions are passed to this function
// from the form. If there is an 'emailaddress' field then this is tested for
// correct syntax.

function formCheck(formobj, fieldRequired, fieldDescription){

	var alertMsg = "Please complete the following field(s):\n";
	
	var l_Msg = alertMsg.length;
	var groupChecked = false;
	for (var i = 0; i < fieldRequired.length; i++){
		var obj = formobj.elements[fieldRequired[i]];
		if (obj){
			switch(obj.type){
			case "checkbox": // Not likely to be used
			
				if (obj.checked == false){
					
						alertMsg += " - " + fieldDescription[i] + "\n";
				}
				
				
				break;
			case "select-one":
				if (obj.selectedIndex == -1 || obj.options[obj.selectedIndex].text == ""){
					alertMsg += " - " + fieldDescription[i] + "\n";
				}
				break;
			case "select-multiple":
				if (obj.selectedIndex == -1){
					alertMsg += " - " + fieldDescription[i] + "\n";
				}
				break;
			case "text":
			case "textarea":
				if (obj.value == "" || obj.value == null){
					alertMsg += " - " + fieldDescription[i] + "\n";
					}
			else	if (fieldRequired[i] == "email"){
		 			 if (!emailCheck (formobj.email.value))	
						return false;
					 }
					 
				//}
				break;
			default:
				if (obj.value == "" || obj.value == null){
					alertMsg += " - " + fieldDescription[i] + "\n";
				}
			}
		}
	}

	if (alertMsg.length == l_Msg){
		return true;

	}
	else{
		alert(alertMsg);
		return false;
	}
}


//////////////////////////////////////////////////////////////////////////////////////////////

// DHTMLapi.js custom API for cross-platform
// object positioning by Danny Goodman (http://www.dannyg.com).
// Release 2.0. Supports NN4, IE, and W3C DOMs.

// Global variables
var isCSS, isW3C, isIE4, isNN4, isIE6CSS;
// Initialize upon load to let all browsers establish content objects
function initDHTMLAPI() {
	
    if (document.images) {
        isCSS = (document.body && document.body.style) ? true : false;
        isW3C = (isCSS && document.getElementById) ? true : false;
        isIE4 = (isCSS && document.all) ? true : false;
        isNN4 = (document.layers) ? true : false;
        isIE6CSS = (document.compatMode && document.compatMode.indexOf("CSS1") >= 0) ? true : false;
    }
}
// Set event handler to initialize API
//window.onload = initDHTMLAPI;

// Seek nested NN4 layer from string name
function seekLayer(doc, name) {
    var theObj;
    for (var i = 0; i < doc.layers.length; i++) {
        if (doc.layers[i].name == name) {
            theObj = doc.layers[i];
            break;
        }
        // dive into nested layers if necessary
        if (doc.layers[i].document.layers.length > 0) {
            theObj = seekLayer(document.layers[i].document, name);
        }
    }
    return theObj;
}

// Convert object name string or object reference
// into a valid element object reference
function getRawObject(obj) {
    var theObj;
    if (typeof obj == "string") {
        if (isW3C) {
            theObj = document.getElementById(obj);
        } else if (isIE4) {
            theObj = document.all(obj);
        } else if (isNN4) {
            theObj = seekLayer(document, obj);
        }
    } else {
        // pass through object reference
        theObj = obj;
    }
    return theObj;
}

// Convert object name string or object reference
// into a valid style (or NN4 layer) reference
function getObject(obj) {
    var theObj = getRawObject(obj);
    if (theObj && isCSS) {
        theObj = theObj.style;
    }
    return theObj;
}

// Position an object at a specific pixel coordinate
function shiftTo(obj, x, y) {
    var theObj = getObject(obj);
    if (theObj) {
        if (isCSS) {
            // equalize incorrect numeric value type
            var units = (typeof theObj.left == "string") ? "px" : 0 
            theObj.left = x + units;
            theObj.top = y + units;
        } else if (isNN4) {
            theObj.moveTo(x,y)
        }
    }
}

// Move an object by x and/or y pixels
function shiftBy(obj, deltaX, deltaY) {
    var theObj = getObject(obj);
    if (theObj) {
        if (isCSS) {
            // equalize incorrect numeric value type
            var units = (typeof theObj.left == "string") ? "px" : 0 
            theObj.left = getObjectLeft(obj) + deltaX + units;
            theObj.top = getObjectTop(obj) + deltaY + units;
        } else if (isNN4) {
            theObj.moveBy(deltaX, deltaY);
        }
    }
}

// Set the z-order of an object
function setZIndex(obj, zOrder) {
    var theObj = getObject(obj);
    if (theObj) {
        theObj.zIndex = zOrder;
    }
}

// Set the background color of an object
function setBGColor(obj, color) {
    var theObj = getObject(obj);
    if (theObj) {
        if (isNN4) {
            theObj.bgColor = color;
        } else if (isCSS) {
            theObj.backgroundColor = color;
        }
    }
}

// Set the visibility of an object to visible
function show(obj) {
    var theObj = getObject(obj);
    if (theObj) {
        theObj.visibility = "visible";
    }
}

// Set the visibility of an object to hidden
function hide(obj) {
    var theObj = getObject(obj);
    if (theObj) {
        theObj.visibility = "hidden";
    }
}

// Retrieve the x coordinate of a positionable object
function getObjectLeft(obj)  {
    var elem = getRawObject(obj);
    var result = 0;
    if (document.defaultView) {
        var style = document.defaultView;
        var cssDecl = style.getComputedStyle(elem, "");
        result = cssDecl.getPropertyValue("left");
    } else if (elem.currentStyle) {
        result = elem.currentStyle.left;
    } else if (elem.style) {
        result = elem.style.left;
    } else if (isNN4) {
        result = elem.left;
    }
    return parseInt(result);
}

// Retrieve the y coordinate of a positionable object
function getObjectTop(obj)  {
    var elem = getRawObject(obj);
    var result = 0;
    if (document.defaultView) {
        var style = document.defaultView;
        var cssDecl = style.getComputedStyle(elem, "");
        result = cssDecl.getPropertyValue("top");
    } else if (elem.currentStyle) {
        result = elem.currentStyle.top;
    } else if (elem.style) {
        result = elem.style.top;
    } else if (isNN4) {
        result = elem.top;
    }
    return parseInt(result);
}

// Retrieve the rendered width of an element
function getObjectWidth(obj)  {
    var elem = getRawObject(obj);
    var result = 0;
    if (elem.offsetWidth) {
        result = elem.offsetWidth;
    } else if (elem.clip && elem.clip.width) {
        result = elem.clip.width;
    } else if (elem.style && elem.style.pixelWidth) {
        result = elem.style.pixelWidth;
    }
    return parseInt(result);
}

// Retrieve the rendered height of an element
function getObjectHeight(obj)  {
    var elem = getRawObject(obj);
    var result = 0;
    if (elem.offsetHeight) {
        result = elem.offsetHeight;
    } else if (elem.clip && elem.clip.height) {
        result = elem.clip.height;
    } else if (elem.style && elem.style.pixelHeight) {
        result = elem.style.pixelHeight;
    }
    return parseInt(result);
}

// Return the available content width space in browser window
function getInsideWindowWidth() {
    if (window.innerWidth) {
        return window.innerWidth;
    } else if (isIE6CSS) {
        // measure the html element's clientWidth
        return document.body.parentElement.clientWidth
    } else if (document.body && document.body.clientWidth) {
        return document.body.clientWidth;
    }
    return 0;
}

// Return the available content height space in browser window
function getInsideWindowHeight() {
    if (window.innerHeight) {
        return window.innerHeight;
    } else if (isIE6CSS) {
        // measure the html element's clientHeight
        return document.body.parentElement.clientHeight
    } else if (document.body && document.body.clientHeight) {
        return document.body.clientHeight;
    }
    return 0;
}

/////////////////////////////////////////////////////////////////////////////////
// Open new simulated window using a DIV for the Info Box
/////////////////////////////////////////////////////////////////////////////////

ids = new Array();
//function showInfoBox(img, title,description,prodImg,price,stockCode,inStock,brand,prodCount,formID,cols){
function showInfoBox(formID,prodCount,cols){
	
//alert (info.innerHTML);	
	var id, i, c=0,t=0;
	
	// Make sure all product form elements are visible
	//var forms = document.body.getElementsByTagName("div");

	for (i=0;i<prodCount;i++){
		id = 'f'+i;
		document.getElementById(id).style.visibility='visible';
		// Create an array of the ids for the forms located to the left
		if (c >= cols){
			c=0;t=i;
		}
		c++;
		id = 'f'+t;
		ids.push(id);
	}
	// Now hide the form elements that could show through the Info Box
	
	document.getElementById(ids[formID]).style.visibility='hidden';
	if (formID >= cols)
		document.getElementById(ids[formID - cols]).style.visibility='hidden';
	
	if ((formID <= prodCount - cols) && (prodCount != cols))
		document.getElementById(ids[formID + cols]).style.visibility='hidden';

	var title = document.getElementById("title"+formID).innerHTML;
	var description = document.getElementById("description"+formID).innerHTML;
	var price = document.getElementById("price"+formID).innerHTML;	
	var stockCode = document.getElementById("partNo"+formID).innerHTML;	
	var inStock = document.getElementById("stockTxt"+formID).innerHTML;
	var form = document.getElementById("f"+formID).innerHTML;			
	var image = document.getElementById("image"+formID).innerHTML;
	prodImg = "../images/prods/" + image;
	
	// Header
	newContent = "<table width='100%' cellspacing='0' cellpadding='0'>";
	newContent += "<tr>";
	//newContent += "<td class='boxTl'>&nbsp;</td>";
	newContent += "<td class='boxTm'>"+title+"</td>";
	//newContent += "<td class='boxTr'>&nbsp;</td>";
	newContent += "</tr>";
	newContent += "</table>";
	
	// Body
	newContent += "<table width='99%' cellspacing='2' cellpadding='2' align='center' class='boxInner'>";
 	newContent += "<tr>";
    newContent += "<td  valign='top' colspan='2'><img src='"+prodImg+"' style='float:left' hspace='4' vspace='2' alt='"+title+"' title='"+title+"' />";
    newContent += description+"</td>";
	newContent += "</tr>";
	newContent += "<tr>";
	newContent += "<td class='infoPrice' colspan='2' align='right'>"+price+"<br />";
	//newContent += stockCode+" - <em>"+inStock+"</em><br /></td>";
	newContent += "Ref: "+stockCode+"<br />";
	newContent += form+"</td></tr>";

	newContent += "<tr><td colspan='2' align='right'><img src='../images/prodBox/butt_close.jpg' alt='Close Information Box' class='boxButton' onclick='closeInfoBox("+prodCount+");' /></td>";
	newContent += "</tr>";
	newContent += "</table>";

	// Footer
	newContent += "<table width='100%' cellspacing='0' cellpadding='0'>";
	newContent += "<tr>";
	//newContent += "<td class='boxBl'>&nbsp;</td>";
	newContent += "<td class='boxBm'>&nbsp;</td>";
	//newContent += "<td class='boxBr'></td>";
	newContent += "</tr>";
	newContent += "</table>";	

	var popUp = document.getElementById("prodInfo");
	popUp.style.visibility = 'visible';
	popUp.innerHTML = newContent;


	centerOnWindow("prodInfo",false); //true for centre, false for top left

}

function closeInfoBox(prodCount){
	var id = "";
	// Make sure all product forms are visible
	for (var i=0;i<prodCount;i++){
		id = 'f'+i;
		document.getElementById(id).style.visibility='visible';
	}
	var popUp = document.getElementById("prodInfo");
	popUp.style.visibility = 'hidden';
	

}

/////////////////////////////////////////////////////////////////////////////////
// Center a positionable element whose name is passed as 
// a parameter in the current window/frame, and show it
/////////////////////////////////////////////////////////////////////////////////

function centerOnWindow(elemID, center) {
    // 'obj' is the positionable object
	// center = true to cettre obj, false for top left
	
    var obj = getRawObject(elemID);
    // window scroll factors
    var scrollX = 0, scrollY = 0;
    if (document.body && typeof document.body.scrollTop != "undefined") {
        scrollX += document.body.scrollLeft;
        scrollY += document.body.scrollTop;
        if (document.body.parentNode && 
            typeof document.body.parentNode.scrollTop != "undefined") {
            scrollX += document.body.parentNode.scrollLeft;
            scrollY += document.body.parentNode.scrollTop;
        }
    } else if (typeof window.pageXOffset != "undefined") {
        scrollX += window.pageXOffset;
        scrollY += window.pageYOffset;
    }
    if (!center){ // top left
		
		shiftTo(obj, scrollX, scrollY);
		return;
	}
	else {
    	var x = Math.round((getInsideWindowWidth()/2) - 
        	(getObjectWidth(obj)/2)) + scrollX;
    	var y = Math.round((getInsideWindowHeight()/2) - 
        	(getObjectHeight(obj)/2)) + scrollY;
    	shiftTo(obj, x, y*2);
    	show(obj);
		}
}


// Return the available content height space in browser window
function getInsideWindowHeight() {
    if (window.innerHeight) {
        return window.innerHeight;
    } else if (isIE6CSS) {
        // measure the html element's clientHeight
        return document.body.parentElement.clientHeight;
    } else if (document.body && document.body.clientHeight) {
        return document.body.clientHeight;
    }
    return 0;
}

//----------

// Special handling for CSS-P redraw bug in Navigator 4
function handleResize() {
    if (isNN4) {
        // causes extra redraw, but must do it to get banner object color drawn
        location.reload();
    } else {
        centerOnWindow("banner");
    }
}
// Keep centered during scroll
function handleScroll() {
    centerOnWindow("banner");
}

window.onresize = handleResize;
window.onscroll = handleScroll;


//////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////


function pageSelect(pageForm){
	// get current sort selection
for (var i=0; i < document.sortProducts.sortRadio.length; i++)
   {
   if (document.sortProducts.sortRadio[i].checked)
      {
      pageForm.sort.value = document.sortProducts.sortRadio[i].value;
	  
      }
   }

	pageForm.submit();	
	return (false);
	
}


function pageSort(){
	
	// get current sort selection
for (var i=0; i < document.sortProducts.sortRadio.length; i++)
   {
   if (document.sortProducts.sortRadio[i].checked)
      {
      document.sortProducts.sort.value = document.sortProducts.sortRadio[i].value;
      }
   }

	document.sortProducts.submit();	
	//return (false);
}




/**
 * Convert a single file-input element into a 'multiple' input list
 *
 * Usage:
 *
 *   1. Create a file input element (no name)
 *      eg. <input type="file" id="first_file_element">
 *
 *   2. Create a DIV for the output to be written to
 *      eg. <div id="files_list"></div>
 *
 *   3. Instantiate a MultiSelector object, passing in the DIV and an (optional) maximum number of files
 *      eg. var multi_selector = new MultiSelector( document.getElementById( 'files_list' ), 3 );
 *
 *   4. Add the first element
 *      eg. multi_selector.addElement( document.getElementById( 'first_file_element' ) );
 *
 *   5. That's it.
 *
 *   You might (will) want to play around with the addListRow() method to make the output prettier.
 *
 *   You might also want to change the line 
 *       element.name = 'file_' + this.count;
 *   ...to a naming convention that makes more sense to you.
 * 
 * Licence:
 *   Use this however/wherever you like, just don't blame me if it breaks anything.
 *
 * Credit:
 *   If you're nice, you'll leave this bit:
 *  
 *   Class by Stickman -- http://www.the-stickman.com
 *      with thanks to:
 *      [for Safari fixes]
 *         Luis Torrefranca -- http://www.law.pitt.edu
 *         and
 *         Shawn Parker & John Pennypacker -- http://www.fuzzycoconut.com
 *      [for duplicate name bug]
 *         'neal'
 */
function MultiSelector( list_target, max ){

	// Where to write the list
	this.list_target = list_target;
	// How many elements?
	this.count = 0;
	// How many elements?
	this.id = 0;
	// Is there a maximum?
	if( max ){
		this.max = max;
	} else {
		this.max = -1;
	};
	
	/**
	 * Add a new file input element
	 */
	this.addElement = function( element ){

		// Make sure it's a file input element
		if( element.tagName == 'INPUT' && element.type == 'file' ){

			// Element name -- what number am I?
			element.name = 'file_' + this.id++;
			//element.name = 'Filedata';


			// Add reference to this object
			element.multi_selector = this;

			// What to do when a file is selected
			element.onchange = function(){

				// New file input
				var new_element = document.createElement( 'input' );
				new_element.type = 'file';

				// Add new element
				this.parentNode.insertBefore( new_element, this );

				// Apply 'update' to element
				this.multi_selector.addElement( new_element );

				// Update list
				this.multi_selector.addListRow( this );

				// Hide this: we can't use display:none because Safari doesn't like it
				this.style.position = 'absolute';
				this.style.left = '-1000px';

			};
			// If we've reached maximum number, disable input element
			if( this.max != -1 && this.count >= this.max ){
				element.disabled = true;
			};

			// File element counter
			this.count++;
			// Most recent element
			this.current_element = element;
			
		} else {
			// This can only be applied to file input elements!
			alert( 'Error: not a file input element' );
		};

	};

	/**
	 * Add a new row to the list of files
	 */
	this.addListRow = function( element ){

		// Row div
		var new_row = document.createElement( 'div' );

		// Delete button
		var new_row_button = document.createElement( 'input' );
		new_row_button.type = 'button';
		new_row_button.value = 'Delete';

		// References
		new_row.element = element;

		// Delete function
		new_row_button.onclick= function(){

			// Remove element from form
			this.parentNode.element.parentNode.removeChild( this.parentNode.element );

			// Remove this row from the list
			this.parentNode.parentNode.removeChild( this.parentNode );

			// Decrement counter
			this.parentNode.element.multi_selector.count--;

			// Re-enable input element (if it's disabled)
			this.parentNode.element.multi_selector.current_element.disabled = false;

			// Appease Safari
			//    without it Safari wants to reload the browser window
			//    which nixes your already queued uploads
			return false;
		};

		// Set row value
		new_row.innerHTML = element.value;

		// Add button
		new_row.appendChild( new_row_button );

		// Add it to the list
		this.list_target.appendChild( new_row );
		
	};

};


//======================================================================================================================================