Return to Snippet

Revision: 43135
at March 17, 2011 08:41 by AndyG


Initial Code
//This prototype is provided by the Mozilla foundation and is distributed under the MIT license.
if (!Array.prototype.every) {			//http://www.ibiblio.org/pub/Linux/LICENSES/mit.license
  Array.prototype.every = function(fun /*, thisp*/) {
    var len = this.length;			// required if browser doesn't support 'every()' - IE!!
    if (typeof fun !== "function")
    	throw new TypeError();
    var thisp = arguments[1];
    for (var i = 0; i < len; i++) {
      if (i in this && !fun.call(thisp, this[i], i, this))
        return false;
    }
    return true;
  };
}
if (!Array.prototype.some) {	// required if browser doesn't support the 'some()' method							
	Array.prototype.some = function(fun /*, thisp */) {		// this code must remain 'as is'
		"use strict";
		if (this === void 0 || this === null)
			throw new TypeError();
		var t = Object(this);
		var len = t.length >>> 0;
		if (typeof fun !== "function")
			throw new TypeError();
		var thisp = arguments[1];
		for (var i = 0; i < len; i++) {
			if (i in t && fun.call(thisp, t[i], i, t))
			return true;
		}
		return false;
	};
}
if (!Array.prototype.indexOf) {
	Array.prototype.indexOf = function(elt /*, from*/) {
		var len = this.length;
		var from = Number(arguments[1]) || 0;
		from = (from < 0) ? Math.ceil(from) : Math.floor(from);
		if (from < 0)
			from += len;
		for (; from < len; from++) {
			if (from in this && this[from] === elt)
				return from;
		}
		return -1;
	};
}

// Create an empty namespace:
var AndyG_ns = AndyG_ns || {};
AndyG_ns._construct = function () {
	function ADG_Utils () {					// my Class
		var MonthNames = ["January","February","March","April","May","June","July",
			"August","September","October","November","December"];
		var DayNames = [ "Sunday","Monday","Tueday","Wednesday","Thursday","Friday","Saturday" ];
		var ShortMths = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"];
		var ShortDays = ["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"];
		
		var Left = function (str,n) {		// returns characters from the left of a string
			if ( n <= 0 ) return "";
			return ( (n > String(str).length) ? str : String(str).substring(0,n) );
		}
		var Right = function (str, n) {	// returns characters from the right of a string
			if (n <= 0) return "";
			else if (n > String(str).length) 
				return str;
			else 
			   return String(str).substring(String(str).length-n, n);
		}
		var TrimLR = function (text) {			// would trim leading and trailiing spaces v.fast (Steven Levithan)
			text = text.replace(/^\s+/, "");
			for (var i = text.length - 1; i >= 0; i--) {
				if (/\S/.test(text.charAt(i))) {
					text = text.substring(0, i + 1);
					break;
				}
			}
			return text;
		}
		var $ = function () {									// Example: var els = $('obj1name',obj2,'obj2name');			
			var elements = {}, doc, argLen, i, element;	// Saves having to write 'document.getElementById' repeatedly,
			doc = document;								// but could also be useful for grouping elements.
			argLen = arguments.length;
			for (i = 0, element; i < argLen; i++) {
				element = arguments[i];
				if (typeof element === 'string')
					element = doc.getElementById(element);
				if (argLen === 1)
					return element;
				elements.push(element);
			}
			return elements;
		}
		var DeleteEl = function (el) {
			var elem = $(el);
			elem.parentNode.removeChild(elem);
		}
		var DisplayMsg = function (oMsg,sMsg,colour) {		// uses a hidden span to display any message (for 2 secs)
			var msgObj = $(oMsg);						// clicking a message will cancel future messages
			if ( (msgObj.firstChild.nodeValue !== 'messages cancelled') && sMsg ) {
				msgObj.style.color = colour || 'green';		// the default text colour is green
				msgObj.firstChild.nodeValue = sMsg;
				msgObj.style.display = 'inline';
				window.setTimeout(function () { msgObj.style.display = 'none'; } ,2000);
			}
		}
		var MoveElDown = function (container,elem) {
			// Moves elem to the bottom of the container. For example, moves a paragraph to the end of
			// it's containing DIV. If the element is already the last one, moves it to the top.
			var firstElem;
			if (elem.nextSibling)				// move element to end of container
				container.appendChild(elem);
			else {																// element is already the last one..
				firstElem = container.getElementsByTagName(elem.nodeName)[0];	// get the 1st element in the container
				container.insertBefore(elem,firstElem);						// insert the current paragraph before it
			}
		}
		var MoveElDownwards = function (container,elem) {
			// Moves an element one place further down within it's container.
			// If the element is already at the bottom, moves it to the top.
			var nextElem, firstElem;
			if (elem.nextSibling) {
				nextElem = elem.nextSibling;
				if (nextElem.nextSibling)
					container.insertBefore(elem,nextElem.nextSibling);
				else
					container.appendChild(elem);
			} else {
				firstElem = container.getElementsByTagName(elem.nodeName)[0];
				container.insertBefore(elem,firstElem);
			}
		}
		var MoveElUp = function (container,elem) {
			var firstElem;
			if (elem.previousSibling) {
				firstElem = container.getElementsByTagName(elem.nodeName)[0];
				container.insertBefore(elem,firstElem);
			} else {
				container.appendChild(elem);
			}
		}
		var MoveElUpwards = function (container, elem) {
			if (elem.previousSibling)
				container.insertBefore(elem,elem.previousSibling);
			else
				container.appendChild(elem);	// must be at the top
		}
		var RemoveToolTips = function (mins) {
			if ( document.getElementsByTagName('button') ) {		// if there are any buttons
				window.setInterval(function () { 		// hide tooltips after 5 mins, by removing the
														// 'title' attribute from all buttons				
					var btns = document.getElementsByTagName('button');
					var i = btns.length;
					while ( i-- ) btns[i].removeAttribute('title');
				}, mins * 60 * 1000);
			}
		}
		/*
			Developed by Robert Nyman, http://www.robertnyman.com
			Code/licensing: http://code.google.com/p/getelementsbyclassname/
		*/
		var getElementsByClassName = function (className, tag, elm) {
			if (document.getElementsByClassName) {		// use built-in method
				getElementsByClassName = function (className, tag, elm) {
					elm = elm || document;
					var elements = elm.getElementsByClassName(className),
						nodeName = (tag) ? new RegExp("\\b" + tag + "\\b", "i") : null,
						returnElements = [], current;
					for(var i=0, il=elements.length; i < il; i++){
						current = elements[i];
						if(!nodeName || nodeName.test(current.nodeName)) {
							returnElements.push(current);
						}
					}
					return returnElements;
				};
			}
			else if (document.evaluate) {		// using XPath
				getElementsByClassName = function (className, tag, elm) {
					tag = tag || "*";
					elm = elm || document;
					var classes = className.split(" "), classesToCheck = "",
						xhtmlNamespace = "http://www.w3.org/1999/xhtml",
						namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace)? xhtmlNamespace : null,
						returnElements = [], elements, node;
					for(var j=0, jl=classes.length; j < jl; j++) {
						classesToCheck += "[contains(concat(' ', @class, ' '), ' " + classes[j] + " ')]";
					}
					try	{
						elements = document.evaluate(".//" + tag + classesToCheck, elm, namespaceResolver, 0, null);
					}
					catch (e) {
						elements = document.evaluate(".//" + tag + classesToCheck, elm, null, 0, null);
					}
					while ((node = elements.iterateNext())) {
						returnElements.push(node);
					}
					return returnElements;
				};
			} else {
				getElementsByClassName = function (className, tag, elm) {
					tag = tag || "*";
					elm = elm || document;
					var classes = className.split(" "), classesToCheck = [],
						elements = (tag === "*" && elm.all)? elm.all : elm.getElementsByTagName(tag),
						current, returnElements = [], match;
					for(var k=0, kl=classes.length; k < kl; k++) {
						classesToCheck.push(new RegExp("(^|\\s)" + classes[k] + "(\\s|$)"));
					}
					for(var l=0, ll=elements.length; l < ll; l++) {
						current = elements[l];
						match = false;
						for(var m=0, ml=classesToCheck.length; m < ml; m++) {
							match = classesToCheck[m].test(current.className);
							if (!match) {
								break;
							}
						}
						if (match) {
							returnElements.push(current);
						}
					}
					return returnElements;
				};
			}
			return getElementsByClassName(className, tag, elm);
		}
		var ResetAll = function (aFrm) {		// clears all text and checkboxes within a form
			var allInputs, i, inp, frm = $(aFrm);
			if ( !confirm('Clear text-boxes and untick check-boxes?') ) return false;
			allInputs = frm.getElementsByTagName('input');
			i = allInputs.length;
			while ( i-- ) {
				inp = allInputs[i];
				if ( inp.type === 'text' ) inp.value = '';
				else if ( inp.type === 'checkbox' ) inp.checked = false;
			}
			return true;
		}
		var SetCookie = function ( name, value, expires, path, domain, secure ) {
				// the caller should Trim the name/value pair
				// sets the name/value pair (encoded) - 'expires' is the number of days
			var expires_date;
			if (expires) {
				expires_date = new Date();
				expires_date.setDate(expires_date.getDate() + expires);
			}
			document.cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value) +
				( ( expires ) ? ";expires=" + expires_date.toUTCString() : "" ) +
				( ( path ) ? ";path=" + path : "" ) +
				( ( domain ) ? ";domain=" + domain : "" ) +
				( ( secure ) ? ";secure" : "" );
		}
		var DeleteCookie = function ( name, path, domain ) {					// the caller should Trim the name/value pair
			document.cookie = encodeURIComponent(name) + "=" +			// encodes the name before deleting
				( ( path ) ? ";path=" + path : "") + ( ( domain ) ? ";domain=" + domain : "" ) +
					";expires=Fri, 01-Jan-2010 00:00:01 UTC";
		}
		var DelAllCookies = function () {
			var currDate = new Date(), i;
			var theCookie = document.cookie.split(";");
			currDate = currDate.toUTCString();
			i = theCookie.length;
			while ( i-- ) {
				document.cookie = theCookie[i] + "; expires =" + currDate;
			}
		}
		// The following four functions do not Trim the name or value before use - the calling fns should do this.
		var Name_Exists = function ( cookie_name ) {					// case-insensitive
			var testName, myReg;
			if (document.cookie.length == 0) return false;
			testName = cookie_name.EscapeR();
			myReg = new RegExp('(^|;) ?' + testName + '=([^;]*)(;|$)','i');
			return myReg.test(decodeURIComponent(document.cookie));
		}
		var Value_Exists = function ( cookie_value )	{				// case insensitive
			var testName, myReg;
			if (document.cookie.length == 0) return false; 
			testName = cookie_value.EscapeR();
			myReg = new RegExp('(=)' + testName + '(;|$)','i');
			return myReg.test(decodeURIComponent(document.cookie));
		}
		var Get_Name = function ( cookie_value ) { 			// (case-insensitive)
			var testName, myReg, results;
			if (document.cookie.length == 0) return '';
			testName = cookie_value.EscapeR();
			myReg = new RegExp('(^|;) ?([^=]*)=' + testName + '(;|$)','i');
			results = decodeURIComponent(document.cookie).match(myReg);
			return ( results ) ? results[2] : '';
		}
		var Get_Value = function ( cookie_name ) {			// (case-insensitive)
			var testName, myReg, results;
			if (document.cookie.length == 0) return '';
			testName = cookie_name.EscapeR();
			myReg = new RegExp('(^|;) ?' + testName + '=([^;]*)(;|$)','i');
			results = decodeURIComponent(document.cookie).match(myReg);
			return ( results ) ? results[2] : '';
		}
		var GetCookieStr = function () {	// returns a string which could be placed in a textarea (for example)
			return decodeURIComponent(document.cookie).replace(/([^=;]+)=([^;]*)[;\s]*/g,'$1 ($2)\n') || '';
		}
		var Asc = function (a, b) {		// used by sort() method (case insensitive)
			var x = a.toLowerCase();
			var y = b.toLowerCase();
			return ((x < y) ? -1 : ((x > y) ? 1 : 0));
		}
		var Desc = function (a, b) {		// used by sort() method (case insensitive)
			var x = a.toLowerCase();
			var y = b.toLowerCase();
			return ((x > y) ? -1 : ((x < y) ? 1 : 0));
		}
		var SortNum = function(a, b) {
			return a-b;
		}
		var IsAscending = function (element, index, array) {		// used by every() method
			return ( index == 0 || element.toLowerCase() >= array[index-1].toLowerCase() );
		}
		var IsDescending = function (element, index, array) {		// used by every() method
			return ( index == 0 || element.toLowerCase() <= array[index-1].toLowerCase() );
		}
		var SortElements = function (parentEl, childTag, colTag, colIndex) {	// example use: SortElements('table1','tr','td',2)
			var i, j, cTags = {};										// or SortElements('list1','li')
			var parent, childLen, aChild, elem;							// or SortElements('divName','p','span',3)
			var origKey, origKeys={}, sortedKeys=[], keyNo='', sortedLen, sorted, frag;
			
			parent = $(parentEl);
			cTags = parent.getElementsByTagName(childTag);
			for ( i = 0, childLen = cTags.length; i < childLen; i++ )	{		// go forward examining each child
				aChild = cTags[i];
				elem = (colTag) ? aChild.getElementsByTagName(colTag)[colIndex] : aChild;
				if ( elem ) {
					origKey = elem.getAttribute('sort') || elem.firstChild.nodeValue;
					// you can supply 'sort' attributes to enable correct sorting of numbers or dates.
					// For example, <td sort='2011/02/12'> for a date.
					keyNo = origKey + (10000 + i);		// need to ensure unique keys - means we can only sort 9999 items!
					origKeys[keyNo] = aChild;			// (browsers can't cope with anything like this no of rows.)
					sortedKeys[sortedKeys.length] = keyNo;
				}
			}
			sorted = sortedKeys.every(IsAscending);
			sortedKeys.sort(Asc);
			if ( sorted ) {				// if they were already in Asc order..
				sortedKeys.reverse();
			}
			frag = document.createDocumentFragment();
			for (i = 0, sortedLen = sortedKeys.length; i < sortedLen; i++) {
				frag.appendChild(origKeys[sortedKeys[i]]);
			}
			parent.appendChild(frag);
			sortedKeys = null;	// probably not necessary as the array goes out of scope
			return sorted;		// t/f was the list already in ascending order?
		}
		var ApplyFilter = function (txt,tbl,col) {		// filters a table by a specified column index
			var theTable = $(tbl), i, theRow, cellText;
			
			txt = txt.toLowerCase();
			i = theTable.rows.length;
			while ( --i ) {		// ignore the first (header) row
				theRow = theTable.rows[i];
				cellText = theRow.cells[col].firstChild.nodeValue.toLowerCase();
				theRow.style.display = ( cellText.indexOf(txt)+1 ) ? '' : 'none';
			}
		}
		var AlignTables = function (tbl, cols, direction) {	// cols is an array identifying which
			var i, j, r, colLen, rLen;				// column nos. to align. Direction should be 'left', 'center'
			var dirs = ['left','center','right'];	// or 'right'. Use this to amend an existing table.
													// Ignores the first row (assumes it's a header row). 
			if ( dirs.indexOf(direction) < 0 ) {
				return false;		// direction should be left, center or right
			}
			tbl = $(tbl);
			for ( i = 1, rLen =  tbl.rows.length; i < rLen; i++) {
				r = tbl.rows[i];
				for ( j = 0, colLen = cols.length; j < colLen; j++)
					r.cells[cols[j]].style.textAlign = direction;
			}
			return true;
		}
		var AddSortToTables = function () {					// if table attribute 'sortIt="yes"'
			var tables, i, j, tblLen, tbl, hdrs, aHdr, hdrsLen;
			function PreserveSortScope(a,b,c,d) {	// used when table attribute sortIt = "yes"
				return function() {				// assigns the SortElements fn. to a table header
					SortElements(a,b,c,d);
				}
			}
			tables = document.getElementsByTagName('table');			// add sorting to table headers,
			for ( i = 0, tblLen = tables.length; i < tblLen; i++ ) {	// if they have attribute sortIt="yes"
				tbl = tables[i];
				if ( tbl.getAttribute('sortIt') && tbl.getAttribute('sortIt') == 'yes' ) {
					hdrs = tbl.getElementsByTagName('th');
					if ( hdrs ) {
						for ( j = 0, hdrsLen=hdrs.length; j < hdrsLen; j++ ) {
							aHdr = hdrs[j];
							AddEvent(aHdr,'click',PreserveSortScope(tbl,'tr','td',j));
						}
					}
				}
			}
		}
		var AddSortByDate = function (tbl,col,dateMask) {
			// Input: the table name (or object), a column index, and a date mask e.g. 'dd-mmm-yy'
			// Adds a sort attribute to every cell to enable sorting correctly by date.
			// (ignores the first row, assuming it is a header row.)
			var i, rLen, cell;
			tbl = $(tbl);
			for ( i = 1, rLen =  tbl.rows.length; i < rLen; i++) {
				cell = tbl.rows[i].cells[col];
				cell.setAttribute('sort',StringToDate(cell.firstChild.nodeValue,dateMask));
			}
			return true;
		}
		var AddSortByNumber = function (tbl, col) {
			// (ignores the first row, assuming it is a header row.)
			var i, rLen, cell, tempNum;
			tbl = $(tbl);
			for ( i = 1, rLen =  tbl.rows.length; i < rLen; i++) {
				cell = tbl.rows[i].cells[col];
				tempNum = cell.firstChild.nodeValue;
				tempNum = tempNum.replace(/[^0-9.]/g,'');
				tempNum = 10000000000000 + parseFloat(tempNum);
				cell.setAttribute('sort',tempNum);
			}
			return true;
		}
		var HighlightRows = function (tbl,colour,withIndex) {
			// Supply the table name (or object) and the colour you want for the highlight
			// E.g. HighlightRows('table1','yellow')
			// Any row background colour will be re-instated on mouseout; if a cell already
			// has a background colour this will remain.
			// If withIndex (optional) is true, pointing at a row will show a tooltip 'Row 24'.
			var OnMouseOver = function (e) {
				var evt = e || window.event;
				var elem = evt.target || evt.srcElement;
				if ( elem.nodeName == 'TD' ) {
					elem.prevColour = elem.parentNode.style.backgroundColor;
					elem.parentNode.style.backgroundColor = colour;
					if (withIndex == true) elem.setAttribute('title','Row ' + elem.parentNode.rowIndex);
				}
			};
			var OnMouseOut = function (e) {
				var evt = e || window.event;
				var elem = evt.target || evt.srcElement;
				if ( elem.nodeName == 'TD' ) {
					elem.parentNode.style.backgroundColor = elem.prevColour;
				}
			};				
			tbl = $(tbl);
			AddEvent(tbl,'mouseover',OnMouseOver);
			AddEvent(tbl,'mouseout',OnMouseOut);
		}
		var GetToday = function (sFormat)	{		// returns a string with today's date
			var currDT = new Date();
			var D = currDT.getDate();
			var DDDD = DayNames[currDT.getDay()];
			var DDD = DDDD.substr(0,3);
			var M = currDT.getMonth()+1;
			var MMMM = MonthNames[currDT.getMonth()];
			var MMM = MMMM.substr(0,3);
			var YYYY = currDT.getFullYear();
			var YY = ('' + YYYY).substr(2,2);
			var H = currDT.getHours();
			var N = currDT.getMinutes();
			var S = currDT.getSeconds();
			var DD = ( D < 10 ? "0" : "" ) + D;			// Pad with leading zeros, if required
			var MM = ( M < 10 ? "0" : "" ) + M;
			var HH = ( H < 10 ? "0" : "" ) + H;
			var NN = ( N < 10 ? "0" : "" ) + N;
			var SS = ( S < 10 ? "0" : "" ) + S;
			
			sFormat = ( sFormat ) ? sFormat.toUpperCase() : 'DD/MM/YYYY';
			var sParsed = sFormat.replace(/D{1,4}|M{1,4}|Y{2,4}|H{1,2}|N{1,2}|S{1,2}/g,function (m) {
				try {
					return eval(m);
				} catch (e) {
					return '';
				}
			});
			return sParsed;
		}
		var FormatDate = function (sFormat, aDate)	{
			// Example use: FormatDate('ddd, dd mmm YYYY hh:nn'); - use 'nn' for mins
			// If aDate is not supplied the current date is assumed.
            var currDT = aDate || new Date();
			
 			sFormat = sFormat.toUpperCase();
            function ReplaceDTChars(match) {
				switch (match) {
                	case 'D': return currDT.getDate();
                	case 'DD': 
						var currDate = currDT.getDate();
	                    return ( currDate < 10 ? "0" : "" ) + currDate;
					case 'DDD': return DayNames[currDT.getDay()].substring(0,3);
                	case 'DDDD': return DayNames[currDT.getDay()];
                	case 'M': return currDT.getMonth()+1;
                	case 'MM':
						var currMonth = currDT.getMonth()+1;
	                    return ( currMonth < 10 ? "0" : "" ) + currMonth;
	                case 'MMM': return MonthNames[currDT.getMonth()].substring(0,3);
					case 'MMMM': return MonthNames[currDT.getMonth()];
					case 'Y': 
					case 'YY': return ('' + currDT.getFullYear()).substring(2);
                	case 'YYY': 
					case 'YYYY': return '' + currDT.getFullYear();
                	case 'H': return currDT.getHours();
                	case 'HH': 
						var currHr = currDT.getHours();
	                    return ( currHr < 10 ? "0" : "" ) + currHr;
                	case 'N': return currDT.getMinutes();
                	case 'NN': 
						var currMin = currDT.getMinutes();
	                    return ( currMin < 10 ? "0" : "" ) + currMin;
	                case 'S': return currDT.getSeconds();
                	case 'SS': 
						var currSecs = currDT.getSeconds();
	                    return ( currSecs < 10 ? "0" : "" ) + currSecs;
					default: return match;
                }
            }
            return sFormat.replace(/D{1,4}|M{1,4}|Y{1,4}|H{1,2}|N{1,2}|S{1,2}/g,function(m){return ReplaceDTChars(m)});
		}
        function StringToDate(sDate, sFormat, cutOff) {
			// Input: a date value as a string, it's format as a string e.g. 'dd-mmm-yy'
			// Optional: a cutoff (integer) for 2 digit years.
			// If no 'd' appears in the format string then the 1st of the month is assumed.
			// If the year is 20 and the cut-off is 30 then the value will be converted to 2020;
			// if the year is 40 then this will be converted to 1940.
			// If no cut-off is supplied then '20' will be pre-pended to the year (YY).
			// Output: a string in the format 'YYYY/MM/DD' or ''
			// Will not attempt to convert certain combinations e.g. DMM, MDD, DDM, YYYYD
			var sParsed, fndSingle; 			// sParsed will be constructed in the format 'YYYY/MM/DD'
			sDate = sDate.toString().toUpperCase();
			sFormat = sFormat.toUpperCase();
			
			if (sFormat.search(/MMMM|MMM/) + 1) {		// replace Mar/March with 03, etc.
				sDate = sDate.replace(new RegExp('(' + ShortMths.join('|') + ')[A-Z]*', 'g'), function(m){
					var i = ShortMths.indexOf(m.substr(0, 3)) + 1;
					return ((i < 10) ? "0" + i : "" + i).toString();
				});
				sFormat = sFormat.replace(/MMMM|MMM/g, 'MM');
			}
			if (sFormat.search(/DDDD|DDD/) + 1) {		// replace Tue/Tuesday, etc. with ''
				sDate = sDate.replace(new RegExp('(' + ShortDays.join('|') + ')[A-Z]*', 'g'), '');
				sFormat = sFormat.replace(/DDDD|DDD/g, '');
			}
			sDate = sDate.replace(/(^|\D)(\d)(?=\D|$)/g, function($0, $1, $2){	// single digits 2 with 02
				return $1 + '0' + $2;
			});
			sFormat = sFormat.replace(/(^|[^DMY])(D|M)(?=[^DMY]|$)/g, function($0, $1, $2){
				return $1 + $2 + $2;		// replace D or M with DD and MM
			});
			fndSingle = sFormat.search(/(^|[^D])D([^D]|$)|(^|[^M])M([^M]|$)/)+1;	// are there still single Ds or Ms?
			if ( fndSingle ) return '';		// do not attempt to parse, for example, 'DMM'
			sFormat = sFormat.replace(/(^|[^Y])(YY)(?=[^Y]|$)/g, function($0, $1, $2, index){
				var tempDate = sDate.substr(0, index + 1);
				tempDate += (cutOff) ? ((parseInt(sDate.substr(index + 1, 2)) > cutOff) ? '19' : '20') : '20';
				tempDate += sDate.substr(index + 1);
				sDate = tempDate;
				return $1 + $2 + $2;
			});
			sParsed = ('YYYY/MM/DD').replace(/YYYY|MM|DD/g, function(m){
				return (sFormat.indexOf(m) + 1) ? sDate.substr(sFormat.indexOf(m), m.length) : '';
			});
			if (sParsed.charAt(0) == '/') { 	// if no year specified, assume the current year
				sParsed = (new Date().getFullYear()) + sParsed;
			}
			if (sParsed.charAt(sParsed.length - 1) == '/') { // if no date, assume the 1st of the month
				sParsed += '01';
			}
			return ( sParsed.length == 10 ) ? sParsed : '';	// should end up with 10 characters..
		}
		var StartClock = function (clockID, sFormat) {		// supply the id of the clock or an object
			var theClock = $(clockID);
			sFormat = sFormat || 'hh:nn';
			if ( theClock ) {						// if there is a clock
				theClock.firstChild.nodeValue = GetToday(sFormat);		// start the clock
				( function () { setInterval( function () {		// this is called a 'closure'
					this.clock = theClock.firstChild;
					clock.nodeValue = GetToday(sFormat); },3000); }
				) ();			// updates the clock every three seconds
			}
		}
		var GetParam = function (name) {  						// get named parameter from url
		  var regexS = "[\\?&]"+name+"=([^&#]*)";
		  var regex = new RegExp( regexS,'i' );			// case insensitive
		  var results = regex.exec( window.location.href );
		  return (results == null) ? "" : decodeURIComponent(results[1]);
		}
		var Delay = function (mills) {		// cause an 'artificial' delay of mills (milliseconds)
			var date = new Date();
			var curDate = null;
			do { curDate = new Date(); }
			while (curDate-date < mills);
		}
		var AddEvent = function (elem, eventType, func) {
			if ( elem.addEventListener )
				elem.addEventListener(eventType, func, false);
			else if ( elem.attachEvent )
				elem.attachEvent('on' + eventType, func);
			else
				elem['on' + eventType] = func;
		}
		var RemoveEvent = function (elem, eventType, func) {
			if ( elem.removeEventListener )
				elem.removeEventListener(eventType, func, false);
			else if ( elem.detachEvent )
				elem.detachEvent('on' + eventType, func);
			else
				elem['on' + eventType] = null;
		}
		// Expose class methods:
		// String functions/ methods ***********************************************
		this.Left = Left;
		this.Right = Right;
		this.TrimLR = TrimLR;
		// DOM functions ***********************************************************
		this.$ = $;
		this.DeleteEl = DeleteEl;
		this.DisplayMsg = DisplayMsg;
		this.MoveElDown = MoveElDown;
		this.MoveElDownwards = MoveElDownwards;
		this.MoveElUp = MoveElUp;
		this.MoveElUpwards = MoveElUpwards;
		this.RemoveToolTips = RemoveToolTips;
		this.getElementsByClassName = getElementsByClassName;
		// Form functions **********************************************************
		this.ResetAll = ResetAll;
		// Cookie functions ********************************************************
		this.SetCookie = SetCookie;
		this.DeleteCookie = DeleteCookie;
		this.DelAllCookies = DelAllCookies;
		this.Name_Exists = Name_Exists;
		this.Value_Exists = Value_Exists;
		this.Get_Name = Get_Name;
		this.Get_Value = Get_Value;
		this.GetCookieStr = GetCookieStr;
		// Sort functions **********************************************************
		this.Asc = Asc;
		this.Desc = Desc;
		this.SortNum = SortNum;
		this.IsAscending = IsAscending;
		this.IsDescending = IsDescending;
		this.SortElements = SortElements;
		// Table functions *********************************************************
		this.ApplyFilter = ApplyFilter;
		this.AlignTables = AlignTables;
		this.AddSortToTables = AddSortToTables;	// uses the Sort functions
		this.AddSortByDate = AddSortByDate;
		this.AddSortByNumber = AddSortByNumber;
		this.HighlightRows = HighlightRows;
		// Date/Time functions *****************************************************
		this.GetToday = GetToday;
		this.FormatDate = FormatDate;
		this.StringToDate = StringToDate;
		this.StartClock = StartClock;
		// Miscellaneous ***********************************************************
		this.GetParam = GetParam;
		this.Delay = Delay;
		this.AddEvent = AddEvent;
		this.RemoveEvent = RemoveEvent;
	}
	function ADG_Drag() { 				// Class : allow draggable elements
		this._startX; this._startY;			// mouse starting positions 
		this._offsetX; this._offsetY;		// current element offsets
		this._dragElement;		// needs to be passed from OnMouseDown to OnMouseMove 
        this._oldZIndex;		// we temporarily increase the z-index during drag 
        
        var InitDragDrop = function () { 
			_startX = 0; _startY = 0; 
			_offsetX = 0; _offsetY = 0;
	        _oldZIndex = 0; 
			document.onmousedown = OnMouseDown; 
			document.onmouseup = OnMouseUp; 
		};
        var OnMouseDown = function (e) { 
            if (e == null) e = window.event;    // IE is retarded and doesn't pass the event object 
            var target = e.target != null ? e.target : e.srcElement;    // IE uses srcElement, others use target
            // for IE, left click == 1; for Firefox, left click == 0 
            if ((e.button == 1 && window.event != null || e.button == 0) && target.className == 'dragIt') {   // grab the mouse position 
                _startX = e.clientX; _startY = e.clientY;       // grab the clicked element's position 
                _offsetX = ExtractNumber(target.style.left); 
                _offsetY = ExtractNumber(target.style.top); // bring the clicked element to the front while it is being dragged 
                _oldZIndex = target.style.zIndex; target.style.zIndex = 100; // we need to access the element in OnMouseMove 
                _dragElement = target; // tell our code to start moving the element with the mouse 
                document.onmousemove = OnMouseMove; // cancel out any text selections 
                document.body.focus(); // prevent text selection in IE 
                document.onselectstart = function () { return false; }; // prevent IE from trying to drag an image 
                target.ondragstart = function() { return false; }; // prevent text selection (except IE) 
                return false; 
            } 
        };
        var OnMouseMove = function (e) { 
            if (e == null) var e = window.event; // this is the actual "drag code" 
            _dragElement.style.left = (_offsetX + e.clientX - _startX) + 'px'; 
            _dragElement.style.top = (_offsetY + e.clientY - _startY) + 'px'; 
        };
        var OnMouseUp = function (e) {	    // When the mouse is released, we remove the event handlers and reset _dragElement:
            if (_dragElement != null) { 
                _dragElement.style.zIndex = _oldZIndex; // we're done with these events until the next OnMouseDown 
                document.onmousemove = null; 
                document.onselectstart = null; 
                _dragElement.ondragstart = null; // this is how we know we're not dragging 
                _dragElement = null; 
            } 
        };
        var ExtractNumber = function (value) { 
            var n = parseInt(value); 
            return n == null || isNaN(n) ? 0 : n; 
        };
		this.InitDragDrop = InitDragDrop;	// only need to expose this method
	}
	
	this.ADG_Utils = ADG_Utils;		// expose the classes
	this.ADG_Drag = ADG_Drag;
}

AndyG_ns._construct();

Initial URL


Initial Description
This is my own (compact) JS library which contains a variety of methods - cookies, (fast) sorting of tables,paragraphs, etc., highlighting rows, moving elements up or down, converting strings to dates, updating a clock etc.. Include the library and add a JS line such as 'var adg = new AndyG_ns.ADG_Utils();' to access the methods.
The ADG_Drag class is not mine - if anyone knows the author please advise me and I will acknowledge. Andy.

Initial Title
A compact, versatile library

Initial Tags
javascript

Initial Language
JavaScript