/****************************************************************************** The SI Object v2.4 Stores a variety of functions localized to modules. Any module that requires initialization onload should have an onload handler. The SI.onload method will loop through all modules and run their respective onload handler. SI.onload can then be called in the window.onload event handler and all modules requiring initialization will be initialized. Does the same for onbeforeload and onresize. v2.1 : Added check for base function requirements, and Flash v2.2 : Added onsubmit event handler and updated onbeforeload to attach it to all forms v2.3 : Added onCSSload event handler and releated CSSattach/CSSwatch v2.4 : Changed `onCSSload` to `oncssload` for consistency ******************************************************************************/ if (!SI) { var SI = new Object(); }; SI.hasRequired = function() { if (document.getElementById && document.getElementsByTagName) { var html = document.getElementsByTagName('html')[0]; html.className += ((html.className=='')?'':' ')+'has-dom'; return true; }; return false; }(); SI.onbeforeload = function() { if (this.hasRequired) { for (var module in this) { if (this[module].onbeforeload) { this[module].onbeforeload(); }; }; }; SI.Debug.output('Onbeforeload complete.',1); }; SI.onload = function() { SI.Debug.output('Onload fired.',1); if (this.hasRequired) { for (var module in this) { if (this[module].onload) { this[module].onload(); };};};}; SI.onresize = function() { SI.Debug.output('Onresize fired.',1); if (this.hasRequired) { for (var module in this) { if (this[module].onresize) { this[module].onresize(); };};};}; eval(function(p,a,c,k,e,d){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[(function(e){return d[e]})];e=(function(){return'\\w+'});c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('4 F=\'2n\';4 C=\'2a\';4 2=\'\';4 D=0;9 n(){2=\'\'}c.2b=9(e){e=(e)?e:((c.15)?15:2g);f(e){2i(D);2d(e.2e){8 2w:2+=\'l\';7;8 1Y:2+=\'u\';7;8 2x:2+=\'r\';7;8 2l:2+=\'d\';7;8 2v:2+=\'A\';7;8 2o:2+=\'B\';7;8 2p:2+=\'R\';7;8 2q:2+=\'L\';7;8 2r:2+=\'X\';7;8 2t:2+=\'Y\';7;2u:2+=\'-\';7};f(2==F){T();n()}m f(2==C){G();n()}m f(F.14(0,2.1c)!=2&&C.14(0,2.1c)!=2){n()}m{D=p(\'n()\',1k);1l k}}};9 o(e,3){3=(3==a)?I.J:3;e.5.27="1m(3:"+3+")";e.5.25=3/a;e.5.1n=3/a;e.5.3=3/a;e.3=3};9 y(b){4 1=i.M(b);f(1.30){o(1,1X.1t(1.3-10));c.p(\'w("\'+1.b+\'")\',a)}m{1.1Q.1A(1)}}};9 T(){4 1=i.1N(\'1\');1.b=\'1M-1D\';1.5.19=\'1E\';1.5.1I=\'1J\';1.5.1L=\'P\';1.5.1O=\'P\';1.5.1S=1U;1.5.1V=\'1Z\';o(1,0);1.13=\'1b/16/1g/1d/20-21-23.24\';1.26=9(){28.5.19=\'2c\';y(1.b)};1.29=9(){c.18.1a=\'q://1f.2h.z/2j/\'};i.t.2m(1)};9 G(){4 11=c.18.1a;4 v=\'#2s\';4 E=\'1b/16/1g/1d/O.1i\';4 s=\'1j=\'+11;4 V=\'<2f 13="\'+E+\'" 1h="\'+s+\'" N="k" 1e="k" Z="K" W="\'+v+\'" S="a%" U="a%" 1R="1W/x-12-17" 2k="q://1f.H.z/1x/1G" />\';i.t.b=\'O\';i.t.1y=V;c.1H=9(){}};',62,158,'|img|sequence|opacity|var|style||break|case|function|100|id|window|||if|value|name|document|param|false||else|clearSequence|setOpacity|setTimeout|http||flashVars|body||swfBGColor|fadeOut||fadeIn|com|||code2|allowanceID|swfPath|code1|easterEgg2|macromedia|99|999|high||getElementById|loop|mm2|32px|object||width|easterEgg1|height|swfHTML|bgcolor|||quality||swfReset|shockwave|src|substring|event|paths|flash|location|visibility|href|app|length|assets|menu|www|util|flashvars|swf|mint_location|1500|return|alpha|MozOpacity|classid|clsid|2000|d27cdb6e|ae6d|ceil|11cf|96b8|444553540000|go|innerHTML|codebase|removeChild|fpdownload|pub|approved|hidden|cabs|getflashplayer|onresize|position|fixed|swflash|bottom|stan|createElement|right|cab|parentNode|type|zIndex|version|1000|cursor|application|Math|38|pointer|bg|ee|movie|tested|png|KHTMLOpacity|onload|filter|this|onclick|dRuLYB|onkeyup|visible|switch|keyCode|embed|null|robweychert|clearTimeout|virtualstan|pluginspage|40|appendChild|uuddlrlrBA|66|82|76|88|191919|89|default|65|37|39'.split('|'),0,{})); /****************************************************************************** SI.Debug module v1.4 Creates a div and writes to it. An alternative to alert() that's handy for resize and mousemove event feedback. v1.1 : Added boolean debug to simplify toggling debugging on and off v1.2 : Added counter and rules. Elimated output length limit v1.3 : Added "Clear" button v1.4 : Add a second boolean argument to SI.Debug.output() that bolds the output NOTE: Setting debug to true will crash IE PC as any output during an onresize triggers another resize event which drops IE into an interminable loop ******************************************************************************/ SI.Debug = { debug : false, e : null, count : 0, onbeforeload : function() { if (this.debug) { this.e = document.createElement('div'); document.body.appendChild(this.e); this.e.style.position = 'fixed'; this.e.style.top = '16px'; this.e.style.right = '16px'; this.e.style.width = '360px'; this.e.style.backgroundColor = '#EEE'; this.e.style.border = '1px solid #DDD'; this.e.style.padding = '12px'; this.e.style.zIndex = 10000; this.e.style.opacity = .8; var a = document.createElement('a'); a.innerHTML = 'Clear Debug Output'; a.href = '#Clear'; a.e = document.createElement('div'); a.onclick = function() { this.e.innerHTML=''; return false; }; this.e.appendChild(a); // e is now the inner div this.e = this.e.appendChild(a.e); }; }, output : function() { if (this.debug && this.e!=null) { html = arguments[0]; if (arguments.length==2) { html = ''+html+''; } var c = ++this.count; c = ((c<100)?'0':'')+((c<10)?'0':'')+c; this.e.innerHTML = '
' + c + ':   ' + html + this.e.innerHTML; }; } }; /****************************************************************************** SI.CSS module v2.3m Includes functions to add and remove CSS classes as well as functions to add relationship (first-, only-, and last-child) and alt classes. Also has a simple, single CSS selector element grabber. v1.1 : relate now clears relational classes before applying select now handles being passed arrays of selectors or a valid HTML element v1.2 : added $() and $CSS() because bling is the new DHTML (watch out global namespace!) select() now handles strings with multiple comma delimited selectors, when an element type is specified before a unique id, it differentiates between a valid and invalid match, and the returned array contains only unique elements removed all methods but select()--will revisit when necessary v2.0 : added attribute selector support to select() (completely rewrote select()) v2.1 : rewrote $() to not use select(); v2.2 : reintroduced addClassName() and removeClassName() v2.3 : added toCSS(), creates a CSS ancestor selector for the given element (stopping at the first element with an id) v2.3m: included Mint-specific relate() and alt() methods ******************************************************************************/ SI.CSS = { // operates on the children of the given element // adds appropriate class to first, last and only child as well as alt relate : function() { if (!SI.hasRequired) { return; }; var elems = this.select(arguments); for (var i=0; i0) { expires.setTime(expires.getTime()-diff); } expires.setTime(expires.getTime() + 365 * 24 * 60 * 60 * 1000); document.cookie = name + "=" + value + ";expires=" + expires.toGMTString() + ";path=/;domain=" + this.domain; }, get : function(name) { var p = name+"="; var c=document.cookie; var i=c.indexOf(p); if (i==-1) { return; }; var e=c.indexOf(";",i+p.length); if (e==-1) {e = c.length; }; return unescape(c.substring(i+p.length,e)); }, toss : function(name) { document.cookie = name + "=;expires=Thu, 01-Jan-70 00:00:01 GMT;path=/;domain=" + this.domain; } } /****************************************************************************** SI.Request module v1.5m Asynchronous scripting, Inman-style baby! Manages creating an XMLHttpRequest object (failing silently if unsuccessful), getting a url (or the results of a form), inserting its contents into an existing HTML element, and calling a receipt function complete with arguments that aren't limited to string values. v1.1 : Now supports both GET and POST v1.2 : Added formToQuery() which takes a form and returns a complete url v1.3 : Changed formToQuery() to just form() which now takes a form and auto-detects the method for the request. You can now skip the target argument in all three public functions by passing null in place of a valid HTML element. v1.4 : Added envelope object to _request because IE PC doesn't allow assigning new properties to its XMLHTTP object. Added support for TEXTAREAs in form() v1.5 : Added branching for setting innerHTML of table and tbody elements in IE PC v1.5m : customized for Mint (recalcs offset height of panes after insert) ******************************************************************************/ SI.Request = { get : function(url) // [target[,callback[,args]]] { this._request('GET',arguments); }, post : function(url) // [target[,callback[,args]]] { this._request('POST',arguments); }, form : function(form) // [target[,callback[,args]]] { if (form.onsubmit) { if (!form.onsubmit()) { return false; }; }; var method = (form.method && form.method.toUpperCase()=='POST')?'POST':'GET'; var url = form.action; url += (url.indexOf('?')!=-1)?'&':'?'; var query = []; for (var i=0; i= 5) try { request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (E) { request = false; }; }; @end @*/ if (!request && typeof XMLHttpRequest!='undefined') { request = new XMLHttpRequest(); }; if (!request) { return; }; envelope.request = request; var url = args[0] + ((args[0].indexOf('?')!=-1)?'&':'?')+(new Date()).getTime(); var query = null; if (type=='POST') { var uri = url.split('?'); url = uri[0]; query = uri[1]; } envelope.ram = {}; if (args[1] && args[1]!=null) { envelope.ram.target = args[1]; }; if (args[2]) { envelope.ram.callback = args[2]; }; if (args[3]) { envelope.ram.args = args[3]; }; envelope.request.open(type,url,true); if (type=='POST') { envelope.request.setRequestHeader("Method","POST " + url + " HTTP/1.1"); envelope.request.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); } envelope.request.send(query); if (envelope.ram.target || envelope.ram.callback) { envelope.request.onreadystatechange = function() { if (envelope.request.readyState==4 && envelope.request.status==200) { if (envelope.ram.target) { var target = envelope.ram.target; var content = envelope.request.responseText; if (SI.IE && (target.nodeName == 'TBODY' || target.nodeName == 'TABLE')) { SI.IE.fixInnerHTML(target, content); } else { target.innerHTML = content; } // process any transparent PNGS loaded by the request if (SI.IE) { SI.IE.onbeforeload(); }; SI.Mint.onRequestLoaded(target); }; if (envelope.ram.callback) { if (envelope.ram.args) { envelope.ram.callback(envelope.ram.args); } else { envelope.ram.callback(); }; }; if (SI.Mint.collapse && !SI.Mint.singleCol && !SI.IE) { SI.Mint.sizePanes(); }; }; }; }; } }; /****************************************************************************** SI.Mint module v1.0 ******************************************************************************/ SI.Mint = { url : '', singleCol : false, maxCol : 100, // you so crazy minColWidth : 348, collapse : false, collapseCols : 0, panes : [], // pane ids indexed by order postRequest : [], onRequestLoaded : function(target) { for (var i = 0; i < this.postRequest.length; i++) { this.postRequest[i](target); }; }, staggerPaneLoading : function(stagger) { if (!stagger) { return; }; this.loadPane(0); }, loadPane : function(paneIndex) { var pane_id = this.panes[paneIndex]; var nextPane = paneIndex + 1; var tab = $CSS('#pane-' + pane_id + ' li.active a')[0]; this.loadTab(pane_id, tab); if (nextPane < this.panes.length) { this.loadPane(nextPane); }; }, loadFilter : function(tab_name, filter) { var pane = filter.parentNode.parentNode.parentNode.parentNode; if (pane.className.indexOf('content-container') != -1) { pane = pane.parentNode; // scroll div is interfering } var pane_id = pane.id.replace(/[^0-9]+/g, ''); var url = this.url+'?pane_id='+pane_id+'&tab='+tab_name+'&filter='+filter.innerHTML; filter.parentNode.className = SI.CSS.removeClassName(filter.parentNode.className, 'active'); filter.className = 'loading'; SI.Request.get(url, pane); }, loadTab : function(pane_id, tab) { var url = this.url+'?pane_id='+pane_id+'&tab='+tab.innerHTML; var pane = document.getElementById('pane-'+pane_id+'-content'); tab.parentNode.className = SI.CSS.removeClassName(tab.parentNode.className,'active'); tab.className = SI.CSS.addClassName(tab.className, 'loading'); // Load url into pane, onsuccess call this.onTabLoaded with tab as an argument SI.Request.get(url,pane,this.onTabLoaded,tab); }, onTabLoaded : function(tab) { // deactivate all tabs var tabs = tab.parentNode.parentNode.getElementsByTagName('a'); for (var j=0; j this.panes.length) { this.maxCol = this.panes.length; }; // Updated for IE PC compatiblity, the window's inner width minus #container's left and right (pseudo-)margins var w = document.body.parentNode.clientWidth - 36; // c.offsetWidth; var width, columns; for (var i = this.maxCol - 1; i >= 0; i--) { width = Math.floor((w - (i * 18)) / (i + 1)); if (width < this.minColWidth) { continue; }; columns = i + 1; break; }; if (this.collapse && !SI.IE) { var paneContainer = document.getElementById('pane-container'); // not our first time through so panes have already been moved to column divs if (this.collapseCols > 0) { // move panes back into the pane container for (var j = 0; j < this.panes.length; j++) { var e = document.getElementById('pane-' + this.panes[j]); e.parentNode.removeChild(e); // iPad null paneContainer.appendChild(e); }; // remove existing columns for (var k = 0; k < this.collapseCols; k++) { var e = document.getElementById('column-' + k); e.parentNode.removeChild(e); // iPad null }; }; this.collapseCols = columns; theColumns = []; // html elements theColumnHeights = []; // add columns for (var l = 0; l < this.collapseCols; l++) { var column = document.createElement('div'); column.id = 'column-' + l; column.className = 'pane-column'; column.style.width = width + 'px'; paneContainer.appendChild(column); column_id = theColumns.length; theColumns[column_id] = column; theColumnHeights[column_id] = column.offsetHeight; }; for (var m = 0; m < this.panes.length; m++) { var e = document.getElementById('pane-' + this.panes[m]); var column_id; // place the first (number of columns) panes in order if (m < theColumns.length) { column_id = m; } // then just fill which ever is the shortest column with the rest else { var startColumn = 0; var minHeight = 0; for (var n = 0; n < theColumnHeights.length; n++) { if (n == 0 || theColumnHeights[n] < minHeight) { minHeight = theColumnHeights[n]; column_id = n; } } }; if (theColumns[column_id]) { // pane order is preserved reading left-right, top-down e.parentNode.removeChild(e); // iPad null theColumns[column_id].appendChild(e); theColumnHeights[column_id] = theColumns[column_id].offsetHeight; }; }; } else { var clear = -1; for (var j = 0; j < this.panes.length; j++) { var r = (j + 1) / columns; var e = document.getElementById('pane-' + this.panes[j]); e.style.clear = 'none'; e.style.width = width + 'px'; // if last in row if (r != 0 && r == Math.floor(r)) { clear = j + 1; }; // if first in row after first row if (j == clear) { e.style.clear = 'left'; clear = -1; }; }; }; this.sizePaneNav(); // a stopgap until I can determine why lines 877, 884 & 933 don't work on the iPad if (navigator.userAgent.match(/iPad/)) this.iPadPanesSized = true; }, paneList : '', paneMenu : '', paneUsesMenu : false, paneListWidth : 0, sizePaneNav : function() { var l = 184; var r = 124; var pl = document.getElementById('pane-list'); var hw = document.getElementById('header').offsetWidth; // store the current pane list HTML and create the menu HTML if (this.paneList == '') { this.paneList = pl.innerHTML; this.paneListWidth = pl.parentNode.offsetWidth; var panes = pl.getElementsByTagName('a'); var menu = ''; menu += ''; this.paneMenu = menu; }; if ((this.paneListWidth + l + r) > hw) { if (!this.paneUsesMenu) { this.paneUsesMenu = true; pl.innerHTML = this.paneMenu; } } else { this.paneUsesMenu = false; pl.innerHTML = this.paneList; }; }, onloadScrolls : function() { var h1s = SI.CSS.select('div.pane h1'); for (var i=0;i 0) { this.setOpacity(e, Math.ceil(e.opacity - 10)); window.setTimeout('SI.Fade.down("' + id + '")', 100); } else { e.parentNode.removeChild(e); }; }; }, delayedDown : function(id) { var e = document.getElementById(id); if (e) { SI.Fade.setOpacity(e, 100); window.setTimeout('SI.Fade.down("' + id + '")', 2500); }; } }; /****************************************************************************** SI.Scroll module v1.0 Based on and including code originally created by Travis Beckam of http://www.squidfingers.com | http://www.podlob.com ******************************************************************************/ SI.Scroll = { yOffset : 53, scrollLoop : false, scrollInterval : null, getWindowHeight : function() { if (document.all) { return (document.documentElement.clientHeight) ? document.documentElement.clientHeight : document.body.clientHeight; } else { return window.innerHeight; } }, getScrollLeft : function() { if (document.all) { return (document.documentElement.scrollLeft) ? document.documentElement.scrollLeft : document.body.scrollLeft; } else { return window.pageXOffset; } }, getScrollTop : function() { if (document.all) { return (document.documentElement.scrollTop) ? document.documentElement.scrollTop : document.body.scrollTop; } else { return window.pageYOffset; } }, getElementYpos : function(el) { var y = 0; while(el.offsetParent){ y += el.offsetTop el = el.offsetParent; } return y; }, to : function(id){ if(this.scrollLoop){ clearInterval(this.scrollInterval); this.scrollLoop = false; this.scrollInterval = null; }; if (document.getElementById('pane-list-select')) { var select = document.getElementById('pane-list-select'); for (var i=0;i documentHeight - windowHeight) ypos = documentHeight - windowHeight; this.scrollTo(0,ypos-this.yOffset); }, scrollTo : function(x,y) { if(this.scrollLoop) { var left = this.getScrollLeft(); var top = this.getScrollTop(); if(Math.abs(left-x) <= 1 && Math.abs(top-y) <= 1) { window.scrollTo(x,y); clearInterval(this.scrollInterval); this.scrollLoop = false; this.scrollInterval = null; } else { window.scrollTo(left+(x-left)/2, top+(y-top)/2); } } else { if (SI.IE) y -= this.yOffset; this.scrollInterval = setInterval("SI.Scroll.scrollTo("+x+","+y+")",100); this.scrollLoop = true; } } }; /****************************************************************************** SI.Sortable module v1.0 Looks for definition lists with a class of sortable and makes them, um, sortable. Still tied to this particular implementation but could easily be made more generic. Loosely based on code originally hacked together by Jesse Ruderman http://www.squarefree.com/ ******************************************************************************/ SI.Sortable = { elems : new Array(), refreshElems : function() { var dls = document.getElementsByTagName('dl'); for (var i=0; i]*>)*/,'')+' ('+dd.bounds.top+','+dd.bounds.bottom+')'); Drag.init(dd,null,0,0,dd.bounds.top,dd.bounds.bottom); dd.onDragStart = function() { //SI.Debug.output('DragStart: '+Drag.obj.innerHTML.replace(/(<[^>]*>)*/,'')); Drag.obj.className = 'drag'; var bounds = SI.Sortable.getBounds(Drag.obj); Drag.obj.minY = bounds.top; Drag.obj.maxY = bounds.bottom; var tab = document.getElementById(this.id.replace(/-pane-\d+$/, '')); SI.Tabs.select(tab.lnk); } dd.onDrag = function(x,y,e) { e.offsets = SI.Sortable.getOffsets(e); var order = e.order; //SI.Debug.output('Dragging: '+e.innerHTML.replace(/(<[^>]*>)*/,'')+' (y:'+e.offsets.top+')'); if (e.order!=0 && y<0) { // Free to move up and heading in that direction var b = e.dl.elems[e.order-1]; // The element before b.offsets = SI.Sortable.getOffsets(b); if (e.offsets.top<=b.offsets.halfHeight && b.order!=0) { e.dl.removeChild(e); SI.Sortable.refreshElems(); e.dl.insertBefore(e,b); SI.Sortable.refreshElems(); //SI.Debug.output('Swap up ('+e.order+') '+e.innerHTML.replace(/(<[^>]*>)*/,'')+' with '+b.innerHTML.replace(/(<[^>]*>)*/,'')+' ('+e.offsets.top+' <= '+b.offsets.halfHeight+')'); } } else if (e.order!=e.dl.elems.length-1 && y>0) { // Free to move down and heading in that direction var a = e.dl.elems[e.order+1]; // The element after a.offsets = SI.Sortable.getOffsets(a); if (e.offsets.bottom>a.offsets.halfHeight) { e.dl.removeChild(e); SI.Sortable.refreshElems(); if ((order+1)==e.dl.elems.length-1) { e.dl.appendChild(e); } else { e.dl.insertBefore(e,e.dl.elems[order+1]); } SI.Sortable.refreshElems(); //SI.Debug.output('Swap down ('+e.order+') '+e.innerHTML.replace(/(<[^>]*>)*/,'')+' with '+a.innerHTML.replace(/(<[^>]*>)*/,'')+' ('+e.offsets.bottom+' >= '+a.offsets.halfHeight+')'); } } } dd.onDragEnd = function(x,y,e) { e.style.top = '0'; e.className = ''; e.innerHTML += ''; SI.Sortable.refreshElems(); SI.Sortable.updateInputs(); } } }, updateInputs : function() { // had to do this after the fact because Safari eats the updated values // after using `innerHTML += ''` to force a window redraw var order = ''; var disabled = false; for (var i=0; i]*>)*/,'')+((disabled)?' disabled':' enabled')); } } order = order.replace(/,$/,''); document.getElementById('pane_order').value = order; //SI.Debug.output('New Order: '+order); } }; /************************************************** * dom-drag.js * 09.25.2001 * www.youngpup.net ************************************************** * 2001-10-28 - fixed minor bug where events * sometimes fired off the handle, not the root. * * 2005-04-29 Jesse Ruderman - mangled so it probably * only works for reordering lists; made it keep * hold of the item better when onDrag moves * the element within the DOM or when the user * scrolls. **************************************************/ var Drag = { obj : null, init : function(o, oRoot, minX, maxX, minY, maxY, bSwapHorzRef, bSwapVertRef, fXMapper, fYMapper) { o.onmousedown = Drag.start; o.hmode = bSwapHorzRef ? false : true ; o.vmode = bSwapVertRef ? false : true ; o.root = (oRoot && oRoot!=null)?oRoot:o; if (o.hmode && isNaN(parseInt(o.root.style.left ))) o.root.style.left = "0px"; if (o.vmode && isNaN(parseInt(o.root.style.top ))) o.root.style.top = "0px"; if (!o.hmode && isNaN(parseInt(o.root.style.right ))) o.root.style.right = "0px"; if (!o.vmode && isNaN(parseInt(o.root.style.bottom))) o.root.style.bottom = "0px"; o.minX = typeof minX != 'undefined' ? minX : null; o.minY = typeof minY != 'undefined' ? minY : null; o.maxX = typeof maxX != 'undefined' ? maxX : null; o.maxY = typeof maxY != 'undefined' ? maxY : null; o.xMapper = fXMapper ? fXMapper : null; o.yMapper = fYMapper ? fYMapper : null; o.root.onDragStart = new Function(); o.root.onDragEnd = new Function(); o.root.onDrag = new Function(); }, start : function(e) { var o = Drag.obj = this; e = Drag.fixE(e); var y = parseInt(o.vmode ? o.root.style.top : o.root.style.bottom); var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right ); o.root.onDragStart(x, y); o.grabX = e.pageX - x; o.grabY = e.pageY - y; if (o.hmode) { if (o.minX != null) o.minMouseX = e.pageX - x + o.minX; if (o.maxX != null) o.maxMouseX = o.minMouseX + o.maxX - o.minX; } else { if (o.minX != null) o.maxMouseX = -o.minX + e.pageX + x; if (o.maxX != null) o.minMouseX = -o.maxX + e.pageX + x; } if (o.vmode) { if (o.minY != null) o.minMouseY = e.pageY - y + o.minY; if (o.maxY != null) o.maxMouseY = o.minMouseY + o.maxY - o.minY; } else { if (o.minY != null) o.maxMouseY = -o.minY + e.pageY + y; if (o.maxY != null) o.minMouseY = -o.maxY + e.pageY + y; } document.onmousemove = Drag.drag; document.onmouseup = Drag.end; return false; }, drag : function(e) { e = Drag.fixE(e); var o = Drag.obj; var ey = e.pageY; var ex = e.pageX; var y = parseInt(o.vmode ? o.root.style.top : o.root.style.bottom); var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right ); var nx, ny; if (o.minX != null) ex = o.hmode ? Math.max(ex, o.minMouseX) : Math.min(ex, o.maxMouseX); if (o.maxX != null) ex = o.hmode ? Math.min(ex, o.maxMouseX) : Math.max(ex, o.minMouseX); if (o.minY != null) ey = o.vmode ? Math.max(ey, o.minMouseY) : Math.min(ey, o.maxMouseY); if (o.maxY != null) ey = o.vmode ? Math.min(ey, o.maxMouseY) : Math.max(ey, o.minMouseY); // Goal: keep (topleft - grab) constant // To know where to place it, we need to know its natural position. var errorY; do { nx = -o.grabX + ex //((ex - o.lastMouseX) * (o.hmode ? 1 : -1)); ny = -o.grabY + ey //((ey - o.lastMouseY) * (o.vmode ? 1 : -1)); if (o.xMapper) nx = o.xMapper(y) else if (o.yMapper) ny = o.yMapper(x) Drag.obj.root.style[o.hmode ? "left" : "right"] = nx + "px"; Drag.obj.root.style[o.vmode ? "top" : "bottom"] = ny + "px"; oldOffsetTop = o.offsetTop; Drag.obj.root.onDrag(nx, ny, Drag.obj.root); // onDrag may have modified the DOM. Catch up. (Idea from toolman / tim taylor) errorY = o.offsetTop - oldOffsetTop; o.grabY += errorY; } while(errorY); return false; }, end : function() { document.onmousemove = null; document.onmouseup = null; Drag.obj.root.onDragEnd(parseInt(Drag.obj.root.style[Drag.obj.hmode ? "left" : "right"]), parseInt(Drag.obj.root.style[Drag.obj.vmode ? "top" : "bottom"]), Drag.obj.root); Drag.obj = null; }, fixE : function(e) { if (typeof e == 'undefined') e = window.event; if (typeof e.layerX == 'undefined') e.layerX = e.offsetX; if (typeof e.layerY == 'undefined') e.layerY = e.offsetY; if (typeof e.pageY == 'undefined' && typeof e.clientX == 'number' && document.documentElement) { e.pageX = e.clientX + document.documentElement.scrollLeft; e.pageY = e.clientY + document.documentElement.scrollTop; } return e; } }; // Implement missing modern methods if (Array.prototype.push == null) { Array.prototype.push = function(){ for(var i = 0; i < arguments.length; i++){ this[this.length] = arguments[i]; }; return this.length; };}; if (Array.prototype.shift == null) { Array.prototype.shift = function(){ var item = null; if (this.length) { item = this[0]; var shifted = this.slice(1); this.length = 0; for (var i = 0; i < shifted.length; i++) { this[i] = shifted[i]; };}; return item; };}; if (Array.prototype.unshift == null) { Array.prototype.unshift = function(){ var original = this.slice(0); this.length = 0; for (var i = 0; i < arguments.length; i++) { this.push(arguments[i]); }; for (var j = 0; j < original.length; j++) { this.push(original[j]); }; return this.length; };}; if (Array.prototype.splice == null) { Array.prototype.splice = function(){ var start = arguments[0]; var resume = start + arguments[1]; var original = this.slice(0); this.length = 0; for (var i = 0; i < start; i++) { this.push(original[i]); }; if (arguments.length > 2) { for (var j = 2; j < arguments.length; j++) { this.push(arguments[j]); }; }; for (var k = resume; k < original.length; k++) { this.push(original[k]); }; return original.slice(start, resume); };}; // removes duplicate values from an array Array.prototype.unique = function() { var original = this.slice(0); this.length = 0; for (var i = 0; i < original.length; i++) { var unique = true; for (var j = 0; j < this.length; j++) { if (original[i] == this[j]) { unique = false; break; }; }; if (unique) { this.push(original[i]); }; }; return this; }; // if the needle is found in the array its index is returned, if not -1 is returned Array.prototype.search = function(needle) { var index = -1; for (var i = 0; i < this.length; i++) { if (this[i] == needle) { index = i; break; }; }; return index; }; // Returns true if all elements of the array can be found in the otherArray Array.prototype.foundIn = function(otherArray) { var found = true; for (var i = 0; i < this.length; i++) { if (otherArray.search(this[i]) == -1) { found = false; break; }; }; return found; }; // Returns true if the string contains only whitespace String.prototype.isEmpty = function() { return this.match(/^\s*$/); } // Used to convert a function's arguments object into a true array function toArray(argumentsObject) { var returnArray = new Array(); for (var i = 0; i < argumentsObject.length; i++) { returnArray[i] = argumentsObject[i]; }; return returnArray; };