/* ########################################################################### GLOBAL ASSETS RELEASE v6.0 BUILD DATE: 20090828 COPYRIGHT SUN MICROSYSTEMS INC. 2009 CONTACT US AT http://www.sun.com/secure/contact/cer.jsp?id=1073e17d-8d6c-43f6-b7e8-cf210cc89ba9 WITH ANY QUESTIONS ########################################################################### */ // setup the list/select goto for the a2v8 // NOTE: this file must only be used in the absence of sniff.js // ######################################################################## // START CONDITIONAL REGLIB INCLUDE if (!window.reg) { // if reglib is already included on this page, you can remove // this entire if statement and its contents in order to reduce // the size of this file /* reglib version 1.1 Copyright 2008 Released under MIT license http://code.google.com/p/reglib/ */ // you can rename window.reg to whatever you want window.reg = (function(){ var reg = {}; // this adds reg's dom helper functions and event functions to the // global namespace. don't call this method if you want to keep your // global namespace clean. alternatively you can individually import // certain sections, this is just a convenient way to do them all. reg.importAll = function() { var errStrings = []; try { reg.importSelectorAPI(); } catch (err) { errStrings.push(err.message); } try { reg.importHelperFunctions(); } catch (err) { errStrings.push(err.message); } try { reg.importEventFunctions(); } catch (err) { errStrings.push(err.message); } if (errStrings.length > 0) { if (console && console.log) { console.log(errStrings.join("\n")); } } }; function globalError(name) { return "reglib tried to add \""+name+"\" to global namespace but \""+name+"\" already existed."; } if (window.Node && Node.prototype && !Node.prototype.contains) { Node.prototype.contains = function (arg) { return !!(this.compareDocumentPosition(arg) & 16); } } // ############################################################################# // #### SELECTORS ############################################################## // ############################################################################# /* A CSS-like selector API focusing on matching not traversal: - new reg.Selector(selectorString) - new reg.Selector(selectorString).matches(someElement) For example: var sel = new reg.Selector('div#foo > ul.bar > li'); var item = document.getElementById('myListItem'); if (sel.matches(item)) { ... } */ // precompiled patterns var expressions = { leadSpace: new RegExp("^\\s+"), tagName: new RegExp("^([a-z_][a-z0-9_-]*)","i"), wildCard: new RegExp("^\\*([^=]|$)"), className: new RegExp("^(\\.([a-z0-9_-]+))","i"), id: new RegExp("^(#([a-z0-9_-]+))","i"), att: new RegExp("^(@([a-z0-9_-]+))","i"), matchType: new RegExp("(^\\^=)|(^\\$=)|(^\\*=)|(^~=)|(^\\|=)|(^=)"), spaceQuote: new RegExp("^\\s+['\"]") }; // constructor reg.Selector=function(selString) { var exp = expressions; this.items = []; // for each comma-separated selector, this array has an item var itms = []; // this will be added to this.items var count = 0; var origSel = selString; while (selString.length>0) { if (count > 100) { throw new Error("failed parsing '"+origSel+"' stuck at '"+selString+"'"); } // get rid of any leading spaces var leadSpaceChopped = false; if (exp.leadSpace.test(selString)) { selString=selString.replace(exp.leadSpace,''); leadSpaceChopped = true; } // find tag name var tagNameMatch = exp.tagName.exec(selString); if (tagNameMatch) { if (itms.length > 0 && itms[itms.length-1].name=='tag') { itms.push({name:'descendant'}); } itms.push({name:'tag',tagName:tagNameMatch[1].toLowerCase()}); selString=selString.substring(tagNameMatch[1].length); tagNameMatch=null; continue; } // explicit wildcard selector if (exp.wildCard.test(selString)) { if (itms.length > 0 && itms[itms.length-1].name=='tag') { itms.push({name:'descendant'}); } itms.push({name:'tag',tagName:'*'}); selString = selString.substring(1); continue; } var classMatch = exp.className.exec(selString); var idMatch = exp.id.exec(selString); var attMatch = exp.att.exec(selString); if (classMatch || idMatch || attMatch) { // declare descendant if necessary if (leadSpaceChopped && itms.length>0 && itms[itms.length-1].name=='tag') { itms.push({name:'descendant'}); } // create a tag wildcard * if necessary if (itms.length==0 || itms[itms.length-1].name!='tag') { itms.push({name:'tag',tagName:'*'}); } var lastTag = itms[itms.length-1]; // find class name, like .entry if (classMatch) { if (!lastTag.classNames) { lastTag.classNames = [classMatch[2]]; } else { lastTag.classNames.push(classMatch[2]); } selString=selString.substring(classMatch[1].length); classMatch=null; continue; } // find id, like #content if (idMatch) { lastTag.id=idMatch[2]; selString=selString.substring(idMatch[1].length); idMatch=null; continue; } // find attribute selector, like @src if (attMatch) { if (!lastTag.attributes) { lastTag.attributes = [{name:attMatch[2]}]; } else { lastTag.attributes.push({name:attMatch[2]}); } selString=selString.substring(attMatch[1].length); attMatch=null; continue; } } // find attribute value specifier var mTypeMatch=exp.matchType.exec(selString); if (mTypeMatch) { // this will determine how the matching is done // (lastTag should still be hanging around) if(lastTag && lastTag.attributes && !lastTag.attributes[lastTag.attributes.length-1].value){ var lastAttribute = lastTag.attributes[lastTag.attributes.length-1]; lastAttribute.matchType = mTypeMatch[0]; selString=selString.substring(lastAttribute.matchType.length); if(selString.charAt(0)!='"'&&selString.charAt(0)!="'"){ if(exp.spaceQuote.test(selString)){selString=selString.replace(exp.leadSpace,'');} else{throw new Error(origSel+" is invalid, single or double quotes required around attribute values");} } // it is enclosed in quotes, end is closing quote var q=selString.charAt(0); var lastQInd=selString.indexOf(q,1); if(lastQInd==-1){throw new Error(origSel+" is invalid, missing closing quote");} while(selString.charAt(lastQInd-1)=='\\'){ lastQInd=selString.indexOf(q,lastQInd+1); if(lastQInd==-1){throw new Error(origSel+" is invalid, missing closing quote");} } lastAttribute.value=selString.substring(1,lastQInd); if ('~=' == lastAttribute.matchType) { lastAttribute.valuePatt = new RegExp("(^|\\s)"+lastAttribute.value+"($|\\s)"); } else if ('|=' == lastAttribute.matchType) { lastAttribute.valuePatt = new RegExp("^"+lastAttribute.value+"($|\\-)"); } selString=selString.substring(lastAttribute.value.length+2);// +2 for the quotes continue; } else { throw new Error(origSel+" is invalid, "+mTypeMatch[0]+" appeared without preceding attribute identifier"); } mTypeMatch=null; } // find child selector if (selString.charAt(0) == '>') { itms.push({name:'child'}); selString=selString.substring(1); continue; } // find next sibling selector if (selString.charAt(0) == '+') { itms.push({name:'nextSib'}); selString=selString.substring(1); continue; } // find after sibling selector if (selString.charAt(0) == '~') { itms.push({name:'followingSib'}); selString=selString.substring(1); continue; } // find the comma separator if (selString.charAt(0) == ',') { this.items.push(itms); itms = []; selString = selString.substring(1); continue; } count++; } this.items.push(itms); this.selectorString=origSel; // do some structural validation for (var a=0;a=0; b--) { // loop backwards through the items var itm = itms[b]; if (itm.name == 'tag') { if (!matchIt(tempEl, itm)) { // these relational selectors require more extensive searching if (tempEl && b < itms.length-1 && itms[b+1].name=='descendant') { tempEl=tempEl.parentNode; b++; continue; } else if (tempEl && b < itms.length-1 && itms[b+1].name=='followingSib') { tempEl=tempEl.previousSibling; b++; continue; } else { continue commas; } // fail this one } } else if (itm.name == 'nextSib') { tempEl = previousElement(tempEl); } else if (itm.name == 'followingSib') { tempEl = previousElement(tempEl); } else if (itm.name == 'child') { tempEl = tempEl.parentNode; } else if (itm.name == 'descendant') { tempEl = tempEl.parentNode; } } return true; } return false; }; // subroutine for matches() above function matchIt(el, itm) { // try to falsify as soon as possible if (!el) { return false; } if (el.nodeName.toLowerCase()!=itm.tagName && itm.tagName!='*') { return false; } if (itm.classNames) { for (var i=0; iB, B->A function switchClassName(element, cName1, cName2) { if (cName1 == cName2) { throw new Error("cName1 and cName2 both equal "+cName1); } var has1 = hasClassName(element, cName1); var has2 = hasClassName(element, cName2); if (has1 && has2) { removeClassName(element, cName2); } else if (!has1 && !has2) { addClassName(element, cName1); } else if (has1) { removeClassName(element, cName1); addClassName(element, cName2); } else { removeClassName(element, cName2); addClassName(element, cName1); } } // TEST FOR CLASS NAME BY REGEXP function matchClassName(element, pattern){ var cNames = element.className.split(' '); for (var a=0; a 0) { var myNode = nodes[0]; el.removeChild(myNode); wrapperEl.appendChild(myNode); } el.appendChild(wrapperEl); } // ADD OUTER WRAPPER function outerWrap(el, wrapperEl) { el.parentNode.insertBefore(wrapperEl, el); el.parentNode.removeChild(el); wrapperEl.appendChild(el); } // GET PARENT function getParent(el, selString) { var parsedSel = new reg.Selector(selString); while (el.parentNode) { el = el.parentNode; if (el.nodeType==1 && parsedSel.matches(el)) { return el; } } return null; } // INSERT AFTER function insertAfter(insertMe, afterThis){ var beforeThis = afterThis.nextSibling; var parent = afterThis.parentNode; if (beforeThis) { parent.insertBefore(insertMe, beforeThis); } else { parent.appendChild(insertMe); } } // SHORTCUT FOR BUILDING ELEMENTS function newElement(name, atts, content) { // name: e.g. 'div', 'div.foo', 'div#bar', 'div.foo#bar', 'div#bar.foo' // atts: (optional) e.g. {'href':'page.html','target':'_blank'} // content: (optional) either a string, or an element, or an arry of strings or elements if (name.indexOf('.') + name.indexOf('#') > -2) { var className = (name.indexOf('.') > -1) ? name.replace(/^.*\.([^\.#]*).*$/,"$1") : ""; var id = (name.indexOf('#') > -1) ? name.replace(/^.*#([^\.#]*).*$/,"$1") : ""; name = name.replace(/^([^\.#]*).*$/,'$1'); } var e = document.createElement(name); if (className) { e.className = className; } if (id) { e.id = id; } if (atts) { for (var key in atts) { // setAttribute() has shaky support, try direct methods first if (!atts.hasOwnProperty(key)) { continue; } if (key == 'class') { e.className = e.className ? e.className += ' ' + atts[key] : atts[key]; } else if (key == 'for') { e.htmlFor = atts[key]; } else if (key.indexOf('on') == 0) { e[key] = atts[key]; } else { e.setAttribute(key, atts[key]); } } } if (content) { if (!(content instanceof Array)) { content = [content]; } for (var a=0; aclick here // elementText(document.getElementById('foo')) == "click here" // warning: recurses through *all* descendants of el if(!el){return '';} var chlds = el.childNodes; var result = ''; if (reg.matches(el,'img@alt,area@alt')) { result += el.alt; } else if (reg.matches(el,'input')) { result += el.value; } else { for (var a=0; a 0) { throw new Error(errStrings.join("\n")); } }; // add it to reg for (var func in helpers) { if(!helpers.hasOwnProperty(func)) { continue; } if (reg[func]) { throw new Error("Already exists under reg: "+func); } else { reg[func] = helpers[func]; } } // ############################################################################# // #### X-BROWSER EVENTS ####################################################### // ############################################################################# /* Event attachment and detachment: */ // get the element on which the event occurred function getTarget(e) { if (!e) { e = window.event; } if (e.target) { var targ = e.target; } else if (e.srcElement) { var targ = e.srcElement; } if (targ.nodeType == 3) { targ = targ.parentNode; } // safari hack return targ; } // get the element on which the event occurred function getRelatedTarget(e) { if (!e) { e = window.event; } var rTarg = e.relatedTarget; if (!rTarg) { if ('mouseover'==e.type) { rTarg = e.fromElement; } if ('mouseout'==e.type) { rTarg = e.toElement; } } return rTarg; } // cancel default action function cancelDefault(e) { if (typeof e.preventDefault != 'undefined') { e.preventDefault(); return; } e.returnValue=false; } // cancel bubble function cancelBubble(e) { if (typeof e.stopPropagation != 'undefined') { e.stopPropagation(); return; } e.cancelBubble=true; } // event registry var memEvents = {}; var aMemInd = 0; function rememberEvent(elmt,evt,handle,cptr,cleanable){ var memInd = aMemInd++; memEvents[memInd+""] = { element: elmt, event: evt, handler: handle, capture: !!cptr, cleanable: !!cleanable }; return memInd; } // event remover function removeEvent(memInd) { var key = memInd+""; var eo = memEvents[key]; if (eo) { var el=eo.element; if(el.removeEventListener) { el.removeEventListener(eo.event, eo.handler, eo.capture); delete memEvents[key]; return true; } else if(el.detachEvent) { el.detachEvent('on'+eo.event, eo.handler); delete memEvents[key]; return true; } } return false; } // if "all" is true, it nukes all events // otherwise only those created with "cleanable" flag function cleanup(all){ for (var key in memEvents) { if (!memEvents.hasOwnProperty(key)) { continue; } if (all || (memEvents[key].cleanable && !document.documentElement.contains(memEvents[key].element))) { removeEvent(key); //console.log("cleaning up event: "+key); } } } //periodically clean up all cleanable events window.setInterval(function(){ cleanup(false); },10000); // generic event adder, plus memory leak prevention // returns an int mem that you can use to later remove that event removeEvent(mem) // cptr defaults false function addEvent(elmt,evt,handler,cptr,cleanable) { if(elmt.addEventListener){ elmt.addEventListener(evt,handler,cptr); return rememberEvent(elmt,evt,handler,cptr,cleanable); }else if(elmt.attachEvent){ var actualHandler = function(){handler.call(elmt,window.event);}; elmt.attachEvent("on"+evt,actualHandler); return rememberEvent(elmt,evt,actualHandler,cptr,cleanable); } } // try to reduce memory leaks in ie addEvent(window,'unload',function(){cleanup(true)}); var events = { getTarget: getTarget, getRelatedTarget: getRelatedTarget, cancelDefault: cancelDefault, addEvent: addEvent, removeEvent: removeEvent, cancelBubble: cancelBubble }; reg.importEventFunctions = function() { var errStrings = []; for (var func in events) { if(!events.hasOwnProperty(func)) { continue; } if (window[func]) { errStrings.push(globalError(func)); } else { window[func] = events[func]; } } if (errStrings.length > 0) { throw new Error(errStrings.join("\n")); } }; for (var func in events) { if(!events.hasOwnProperty(func)) { continue; } if (reg[func]) { throw new Error("Already exists under reg: "+func); } else { reg[func] = events[func]; } } // ############################################################################# // #### ON(DOM)LOAD ACTIONS #################################################### // ############################################################################# /* Add actions to run onload: - reg.preSetup(func) - reg.setup(selString, func, firstTimeOnly) - reg.postSetup(func) !!! WARNING !!! On browsers *without* native querySelector() support reg.setup makes page load time O(MN) where M is the number of calls to reg.setup() and N is the number of elements on the page */ // these contain lists of things to do var preSetupQueue=[]; var setupQueue=[]; var setupQueueByTag={}; var postSetupQueue=[]; // traverse and act onload reg.setup=function(selector, setup, firstTimeOnly){ firstTimeOnly=!!firstTimeOnly; var sqt=setupQueueByTag; var parsedSel = new reg.Selector(selector); var tagNames=getTagNames(parsedSel); var regObj={ selector:parsedSel, setup:setup, ran:false, firstTimeOnly:firstTimeOnly }; setupQueue.push(regObj); for(var a=0;a=0; i--) { els[i] = elsList[i]; } var qSelResults = []; // crawl the dom for(var a=0,elmt;elmt=els[a++];){ if (elmt.nodeType!=1){continue;}//for ie7 var lcNodeName=elmt.nodeName.toLowerCase(); var regObjArrayAll=sqt['*']; var regObjArrayTag=sqt[lcNodeName]; // any wildcards? if(regObjArrayAll){ for(var b=0;b>> 0; if (typeof fun != "function") { throw new TypeError(); } var res = new Array(); var thisp = arguments[1]; for (var i=0; i>> 0; if (typeof fun != "function") { throw new TypeError(); } var thisp = arguments[1]; for (var i=0; i>> 0; if (typeof fun != "function") { throw new TypeError(); } var thisp = arguments[1]; for (var i=0; i>> 0; if (typeof fun != "function") { throw new TypeError(); } var res = new Array(len); var thisp = arguments[1]; for (var i=0; i>> 0; if (typeof fun != "function") { throw new TypeError(); } var thisp = arguments[1]; for (; i'); result.push(''); gebs('a@href',this).forEach(function(link){ result.push(''); }); result.push(''); form.innerHTML = result.join("\n"); this.parentNode.insertBefore(form,this); this.parentNode.removeChild(this); headingEl.parentNode.removeChild(headingEl); }); reg.change("select.goto",function(){ var href = this.options[this.options.selectedIndex].value; if (href) { location.href=href; } });