/*------------------------------------------ the UI event handlers -------------------------------------------*/ function somethingWasClicked(evt){ var evnt, obj, className; if (isIE4) evnt = window.event; else evnt = evt; obj = getTarget(evnt); button = getButton(evnt); className = getAttrVal(obj,'class'); evnt.cancelBubble = true; if (contextNode) {if (obj != contextNode){unContext(contextNode);} else {return true;}} switch (className) { case 'outlineText': if (evnt.ctrlKey && (getAttrValEx(obj.parentNode, 'type') == 'link')){ // let ctrl-click through window.open(getAttrValEx(obj.parentNode, 'url')); return false; } setContext(obj); if (evnt.altKey){ editNode(obj); return false; } break; case 'markerOpen': hideThisBro(obj,evnt.shiftKey); refreshScreen(isIE4); return false; break; case 'markerClosed': showThisBro(obj,evnt.shiftKey); refreshScreen(isIE4); return false; break; default: evnt.cancelBubble = false; break; } } function mouseOver(evt){ var evnt, obj, className; if (isIE4) evnt = window.event; else evnt = evt; obj = getTarget(evnt); className = getAttrVal(obj,'class'); evnt.cancelBubble = true; switch (className) { case 'outlineText': if (obj != contextNode){ obj.style.color = 'indigo'; obj.style.background = 'lavender'; // get rid of the following 'if' block if your mouseovers are slow if (getAttrValEx(obj.parentNode, 'type') == 'link'){ obj.style.cursor = 'hand'; obj.style.textDecoration = 'underline'; } } return false; break; case 'markerOpen': return false; break; case 'markerClosed': return false; break; default: evnt.cancelBubble = false; break; } } function mouseOut(evt){ var evnt, obj, className; if (isIE4) evnt = window.event; else evnt = evt; obj = getTarget(evnt); className = getAttrVal(obj,'class'); evnt.cancelBubble = true; switch (className) { case 'outlineText': if (obj != contextNode){clearStyle(obj);} return false; break; case 'markerOpen': return false; break; case 'markerClosed': return false; break; default: evnt.cancelBubble = false; break; } } function keyStruck(evt){ var k; if (isIE4) evnt = window.event; else evnt = evt; if (isIE4){k = evnt.keyCode;} else {k = evnt.which;} evnt.cancelBubble = true; switch (k){ case 27: // escape if (contextNode && inEdit){unEdit(contextNode);return false;} break; case 13: // 'Enter' if (evnt.ctrlKey){ if (contextNode && !inEdit){editNode(contextNode);return false;} } break; case 88: // 'X' if (!inEdit && evnt.ctrlKey){ toggleOPML(); } return false; break; case 75: // 'K' if (contextNode && !inEdit && evnt.ctrlKey){return(nodeLink(contextNode.parentNode));} break; case 191: // '/' if (contextNode && !inEdit){return(nodeCommentToggle(contextNode.parentNode));} break; case 46: // delete if (contextNode && !inEdit){ if (confirm('Do you really want to delete this node and all child nodes?!?')){ blastNode(contextNode); return false; }} break; case 37: // left arrow if (contextNode && !inEdit && evnt.ctrlKey){ if(nodeLeft(contextNode.parentNode)) refreshScreen(isIE4 || isNav6);return false;} break; case 38: // up arrow if (contextNode && !inEdit && evnt.ctrlKey){ if(nodeUp(contextNode.parentNode)) refreshScreen(isIE4 || isNav6);return false;} break; case 39: // right arrow if (contextNode && !inEdit && evnt.ctrlKey){ if(nodeRight(contextNode.parentNode)) refreshScreen(isIE4);return false;} break; case 40: // down arrow if (contextNode && !inEdit && evnt.ctrlKey){ if(nodeDown(contextNode.parentNode)) refreshScreen(isIE4 || isNav6);return false;} break; case 45: // insert if (contextNode && !inEdit){ var newNode = nodeNew(contextNode.parentNode); if (newNode){ refreshScreen(isIE4); unContext(contextNode); setContext(getOutlineText(newNode)); editNode(getOutlineText(newNode)); return false; }} break; default: break; } // alert(k); evnt.cancelBubble = false; return true; } /*------------------------------------------ outline manipulation routines -------------------------------------------*/ function hideThisBro(mark,doAll){ var curNode, nextNode, collapsed, i, j collapsed = false; for (i = 0; i < mark.parentNode.childNodes.length; i++){ curNode = mark.parentNode.childNodes.item(i); if (getAttrVal(curNode, 'class') == 'outline'){ if (doAll){ nextNode = getOutlineMarker(curNode); if(nextNode){ window.status = 'collapsing nodes...' hideThisBro(nextNode,true); window.status = ''; }} curNode.style.display = 'none'; collapsed = true; }} if (collapsed) setAttrVal(mark,'class','markerClosed'); return collapsed; } function showThisBro(mark,doAll){ var curNode, nextNode, i, j; for (i = 0; i < mark.parentNode.childNodes.length; i++){ curNode = mark.parentNode.childNodes.item(i) if (getAttrVal(curNode, 'class') == 'outline'){ if (doAll){ nextNode = getOutlineMarker(curNode); if (nextNode){ window.status = 'expanding nodes...'; showThisBro(nextNode,true); window.status = ''; }} curNode.style.display = 'block'; }} setAttrVal(mark,'class','markerOpen'); } function applyExpansionState(){ // not implemented } function editNode(obj){ if (isIE55) {htmlEdit(obj);} else { var newVal = window.prompt('edit',obj.innerHTML); if(newVal != null){obj.innerHTML = newVal;} refreshScreen(isIE4); } } function htmlEdit(obj){ obj.contentEditable = true; inEdit = true; } function unEdit(obj){ obj.contentEditable = false; inEdit = false; refreshScreen(isIE4); } function setContext(obj){ obj.style.color = 'black'; obj.style.border = '1px silver dotted'; obj.style.backgroundColor = 'blanchedalmond'; obj.style.textDecoration = 'none'; obj.style.cursor = 'default'; contextNode = obj; } function unContext(obj){ clearStyle(obj); if (isIE55){if (inEdit) {unEdit(obj);}} contextNode = null; } function clearStyle(obj){ if (isNav6){obj.removeAttribute('style');} else {obj.style.cssText = '';} } function blastNode(obj){ // deletes node and all children obj.parentNode.parentNode.removeChild(obj.parentNode); contextNode = null; refreshScreen(isIE4); } function nodeUp(obj){ var sibNode = getPreviousSibling(obj,'outline'); if (!sibNode){return false;} sibNode.parentNode.insertBefore(obj,sibNode); return true; } function nodeDown(obj){ var sibNode = getNextSibling(obj,'outline'); if (!sibNode){return false;} obj.parentNode.insertBefore(sibNode,obj); return true; } function nodeRight(obj){ var sibNode = getPreviousSibling(obj,'outline'); if (!sibNode){return false;} sibNode.insertBefore(obj,null); return true; } function nodeLeft(obj){ var pNode = obj.parentNode; if (pNode){ if (getAttrVal(pNode,'class') == 'outline'){ var sibNode = getNextSibling(pNode,'outline'); pNode.parentNode.insertBefore(obj,sibNode); return true; } } return false; } function nodeNew(obj){ /* inserts a sibling node with text 'New Node' directly preceding 'obj', and returns the new node. */ var oNode, pNode, newNode, peerNode oNode = document.createElement('div'); peerNode = obj; pNode = obj.parentNode; newNode = pNode.insertBefore(oNode,peerNode); if (newNode){ setAttrVal(newNode,'class','outline'); newNode.innerHTML = '' + document.getElementById('markerNormal').innerHTML + 'New Node' return newNode; } return null; } function nodeLink(obj){ var url = ''; var isLink = (getAttrValEx(obj,'type') == 'link'); var isComment = (getAttrValEx(obj,'isComment') == 'true'); if (isLink){ url = getAttrValEx(obj,'url'); } url = window.prompt('Enter URL:',url); if (url == null) return false; if (url == '') { if (!isLink) return false; if (window.confirm('Remove this link and switch node to a normal node?')){ setAttrValEx(obj,'url',null); setAttrValEx(obj,'type',null); getOutlineMarker(obj).innerHTML = document.getElementById('markerNormal').innerHTML; return false; } } setAttrValEx(obj,'url',url); if (!isLink){ setAttrValEx(obj,'type','link'); getOutlineMarker(obj).innerHTML = document.getElementById('markerLink').innerHTML; if (isComment){setAttrValEx(obj,'isComment',null);} return false; } return true; } function nodeCommentToggle(obj){ var isLink = (getAttrValEx(obj,'type') == 'link'); var isComment = (getAttrValEx(obj,'isComment') == 'true'); if (isLink) {alert('Cannot comment a link. First delete URL reference for this link (use ctrl-k)'); return false;} if (isComment){ getOutlineMarker(obj).innerHTML = document.getElementById('markerNormal').innerHTML; setAttrValEx(obj,'isComment','true'); }else{ setAttrValEx(obj,'isComment','true'); getOutlineMarker(obj).innerHTML = document.getElementById('markerComment').innerHTML; } return false; } /* ------------------------------------------------ outline traversal functions --------------------------------------------------*/ function getOutlineMarker(obj){ var nextNode; for(j=0; j < obj.childNodes.length; j++){ nextNode = obj.childNodes.item(j); className = 'unknown'; className = getAttrVal(nextNode, 'class'); if (className == 'markerOpen' || className == 'markerClosed'){ return nextNode; } } return null; } function getOutlineText(obj){ var nextNode; for(j=0; j < obj.childNodes.length; j++){ nextNode = obj.childNodes.item(j); className = 'unknown'; className = getAttrVal(nextNode, 'class'); if (className == 'outlineText'){ return nextNode; } } return null; } function getPreviousSibling(obj, className){ var sibNode sibNode = obj; while (sibNode.previousSibling != null){ sibNode = sibNode.previousSibling; if (getAttrVal(sibNode,'class') == className){return sibNode;} } return null; } function getNextSibling(obj, className){ var sibNode sibNode = obj; while (sibNode.nextSibling != null){ sibNode = sibNode.nextSibling; if (getAttrVal(sibNode,'class') == className){return sibNode;} } return null; } /*------------------------------------------ manipulate attributes. the 'Ex' functions are a way of storing 'attributes' that are not DHTML attributes; 'Ex' attributes are defined as any child 'SPAN' element with class='outlineAttribute', title=attribName, and the innerHTML content being the value. -------------------------------------------*/ function getAttrVal(obj,aname){ try{ if (obj.attributes){ if (isNav6) {if (obj.attributes.getNamedItem(aname)){ return (obj.attributes.getNamedItem(aname).nodeValue); }} if (isIE4) {if (obj.attributes.item(aname)){if (obj.attributes.item(aname).nodeValue){ return (obj.attributes.item(aname).nodeValue); }}} }} catch(er){ } return('unknown'); } function setAttrVal(obj,aname,aval){ if (obj.attributes){ if (isNav6){ return(obj.setAttribute(aname,aval)); } if (isIE4){ try{obj.attributes.item(aname).nodeValue = aval;} catch (er){} } } return (false); } function getAttrValEx(obj,aname){ for (i = 0; i < obj.childNodes.length; i++){ curNode = obj.childNodes.item(i) if (curNode.nodeName == 'SPAN'){ if (getAttrVal(curNode, 'class') == 'outlineAttribute'){ if (getAttrVal(curNode, 'title') == aname) return curNode.innerHTML; }}} return ('unknown'); } function setAttrValEx(obj,aname,aval){ for (i = 0; i < obj.childNodes.length; i++){ curNode = obj.childNodes.item(i) if (curNode.nodeName == 'SPAN'){ if (getAttrVal(curNode, 'class') == 'outlineAttribute'){ if (getAttrVal(curNode, 'title') == aname){ if (aval == null){ curNode.parentNode.removeChild(curNode); return true; }else{ curNode.innerHTML = aval; return true; } }}}} if (aval == null) return true; // node does not exist -- create it now var oNode, pNode, newNode, peerNode oNode = document.createElement('span'); peerNode = obj.childNodes.item(0); pNode = obj; newNode = pNode.insertBefore(oNode,peerNode); if (newNode){ setAttrVal(newNode,'class','outlineAttribute'); setAttrVal(newNode,'title',aname); newNode.innerHTML = aval; return true; } return false; } /*------------------------------------------ get information about an event and mask browser differences to caller. -------------------------------------------*/ function getTarget(evnt){ if (isIE4){obj = evnt.srcElement;} else{ obj = evnt.target; while (obj.nodeName != 'DIV' && obj.nodeName != 'SPAN' && obj.parentNode){obj = obj.parentNode;} } return (obj); } function getButton(evnt){ if (isIE4) {return ((evnt.button == 1)?'left':'right');} else{return ((evnt.which == 1)?'left':'right');} } /*------------------------------------------ screen refresh functions to compensate for a very peculiar IE bug (and an even stranger Netscape 6 bug!) -------------------------------------------*/ function refreshScreen(condition){ if (condition){ if (contextNode){ scTopPrevious = ((isNav6)?window.scrollY:window.screenTop); } squeeze(); window.setTimeout('relax()',5); } return true; } function squeeze(){ var curNode curNode = document.getElementById('outlineRoot'); curNode.style.visibility = 'hidden'; curNode.style.marginLeft = '10%'; curNode.style.marginRight = '10%'; if (isNav6){ document.getElementsByTagName('body').item(0).style.visibility = 'hidden'; curNode.style.display = 'none'; } } function relax(){ var curNode, scLeft, scTop curNode = document.getElementById('outlineRoot'); if (isNav6) { curNode.style.display = 'block'; document.getElementsByTagName('body').item(0).style.visibility = ''; } curNode.style.marginLeft = ''; curNode.style.marginRight = ''; curNode.style.visibility = ''; if (contextNode){ scLeft = ((isNav6)?window.scrollX:window.screenLeft); scTop = ((isNav6)?window.scrollY:window.screenTop); if (scTop != scTopPrevious) window.scrollTo(scLeft,scTopPrevious); } } /*------------------------------------------ routines for round-trip back to OPML -------------------------------------------*/ function toggleOPML(){ if (inOPMLView){ document.getElementById('opmlForm').style.display = 'none'; document.getElementById('opmlText').value = ''; document.getElementById('outlineRoot').style.display = 'block'; inOPMLView = false; } else { document.getElementById('outlineRoot').style.display = 'none'; document.getElementById('opmlForm').style.display = 'block'; document.getElementById('opmlText').value = genOPML(); inOPMLView = true; } } function genOPML(){ // generates OPML from the current document var nRoot, nCurrent, i, strOPML window.status = 'saving OPML structure...'; strOPML = '' + crlf; strOPML = strOPML + '' + crlf; strOPML = strOPML + tab + '' + crlf; nRoot = document.getElementById('outlineRoot'); for (i = 0; i < nRoot.childNodes.length; i++){ nCurrent = nRoot.childNodes.item(i); if (getAttrVal(nCurrent,'class') == 'outlineAttribute'){ strAttrDecl = '<' + getAttrVal(nCurrent,'title') + '>' + xmlEncode(htmlToISO(nCurrent.innerHTML)) + ''; strOPML = strOPML + tab + tab + strAttrDecl + crlf; } } strOPML = strOPML + tab + '' + crlf; strOPML = strOPML + tab + '' + crlf; for (i = 0; i < nRoot.childNodes.length; i++){ nCurrent = nRoot.childNodes.item(i); if (getAttrVal(nCurrent,'class') == 'outline'){ strOPML = strOPML + genSubOPML(nCurrent,String(tab + tab)); } } strOPML = strOPML + tab + '' + crlf; strOPML = strOPML + '' + crlf; window.status = ''; return strOPML; } function genSubOPML(nRoot,prepend){ var strSubOPML, nCurrent, i strSubOPML = prepend + '' + crlf; } strSubOPML = strSubOPML + genSubOPML(nCurrent,String(tab + prepend)); } } if (bChildren){strSubOPML = strSubOPML + tab + prepend + '' + crlf;} else {strSubOPML = strSubOPML + '/>' + crlf;} return strSubOPML; } /*------------------------------------------ initialization -------------------------------------------*/ function initUI(){ // inserts any extra UI stuff you want available var el = document.createElement('FORM'); el.style.display = 'none'; setAttrVal(el,'id','opmlForm'); setAttrVal(el,'method','post'); el.innerHTML = '
'; document.body.insertBefore(el,null); } /*------------------------------------------ load event handlers -------------------------------------------*/ var isNav6, isIE4, isIE55, contextNode, inEdit, scTopPrevious var inOPMLView = false; if (parseInt(navigator.appVersion.charAt(0)) >= 4) { isNav6 = (navigator.appName == "Netscape"); isIE4 = (navigator.appName.indexOf("Microsoft") > -1); } isIE55 = (isIE4 && (navigator.appVersion.indexOf("5.5") > -1)); if (isNav6) { document.captureEvents(Event.MOUSEDOWN); document.captureEvents(Event.MOUSEOVER); document.captureEvents(Event.MOUSEOUT); document.captureEvents(Event.KEYPRESS); } document.onmousedown = somethingWasClicked; document.onmouseover = mouseOver; document.onmouseout = mouseOut; document.onkeyup = keyStruck; window.onload = initUI; var crlf = "\r\n"; var tab = "\t"; /*------------------------------- Encoding functions --------------------------------*/ function xmlEncode(strng){ return String(strng).replace(/\&/g,'&').replace(//g,'>').replace(/\"/g,'"').replace(/\'/g,'''); } function htmlToISO(strEncoded){ // converts html entity-encoded string to plain ISO var strOut = String(strEncoded); var b = strOut.lastIndexOf('&'); while (b > -1){ var e = ((b < (strOut.length - 1))?strOut.indexOf(';',b + 1):-1); if (e > b){ var strEntity = strOut.substr(b + 1,e-b-1); var nCode = oEntityDictionary.lookup(strEntity); if (nCode){ var re = new RegExp('\&' + strEntity + '\;','g'); strOut = strOut.replace(re,String.fromCharCode(nCode)); }} b = ((b > 0)?strOut.lastIndexOf('&', b - 1) : -1); } return strOut; } /*-------------------------------- Create a Dictionary and load ---------------------------------*/ function cDictionary() { this.add = m_add; this.lookup = m_lookup; this.remove = m_remove; } function m_lookup(strKeyName) { return(this[strKeyName]); } function m_add() { this[m_add.arguments[0]] = m_add.arguments[1]; } function m_remove(strKeyName) { this[m_remove.arguments[0]] = null; } var oEntityDictionary = new cDictionary(); oEntityDictionary.add('quot',34); oEntityDictionary.add('amp',38); oEntityDictionary.add('apos',39); oEntityDictionary.add('lt',60); oEntityDictionary.add('gt',62); oEntityDictionary.add('nbsp',160); oEntityDictionary.add('iexcl',161); oEntityDictionary.add('cent',162); oEntityDictionary.add('pound',163); oEntityDictionary.add('curren',164); oEntityDictionary.add('yen',165); oEntityDictionary.add('brvbar',166); oEntityDictionary.add('sect',167); oEntityDictionary.add('uml',168); oEntityDictionary.add('copy',169); oEntityDictionary.add('ordf',170); oEntityDictionary.add('laquo',171); oEntityDictionary.add('not',172); oEntityDictionary.add('shy',173); oEntityDictionary.add('reg',174); oEntityDictionary.add('macr',175); oEntityDictionary.add('deg',176); oEntityDictionary.add('plusmn',177); oEntityDictionary.add('sup2',178); oEntityDictionary.add('sup3',179); oEntityDictionary.add('acute',180); oEntityDictionary.add('micro',181); oEntityDictionary.add('para',182); oEntityDictionary.add('middot',183); oEntityDictionary.add('cedil',184); oEntityDictionary.add('sup1',185); oEntityDictionary.add('ordm',186); oEntityDictionary.add('raquo',187); oEntityDictionary.add('frac14',188); oEntityDictionary.add('frac12',189); oEntityDictionary.add('frac34',190); oEntityDictionary.add('iquest',191); oEntityDictionary.add('Agrave',192); oEntityDictionary.add('Aacute',193); oEntityDictionary.add('Acirc',194); oEntityDictionary.add('Atilde',195); oEntityDictionary.add('Auml',196); oEntityDictionary.add('Aring',197); oEntityDictionary.add('AElig',198); oEntityDictionary.add('Ccedil',199); oEntityDictionary.add('Egrave',200); oEntityDictionary.add('Eacute',201); oEntityDictionary.add('Ecirc',202); oEntityDictionary.add('Euml',203); oEntityDictionary.add('Igrave',204); oEntityDictionary.add('Iacute',205); oEntityDictionary.add('Icirc',206); oEntityDictionary.add('Iuml',207); oEntityDictionary.add('ETH',208); oEntityDictionary.add('Ntilde',209); oEntityDictionary.add('Ograve',210); oEntityDictionary.add('Oacute',211); oEntityDictionary.add('Ocirc',212); oEntityDictionary.add('Otilde',213); oEntityDictionary.add('Ouml',214); oEntityDictionary.add('times',215); oEntityDictionary.add('Oslash',216); oEntityDictionary.add('Ugrave',217); oEntityDictionary.add('Uacute',218); oEntityDictionary.add('Ucirc',219); oEntityDictionary.add('Uuml',220); oEntityDictionary.add('Yacute',221); oEntityDictionary.add('THORN',222); oEntityDictionary.add('szlig',223); oEntityDictionary.add('agrave',224); oEntityDictionary.add('aacute',225); oEntityDictionary.add('acirc',226); oEntityDictionary.add('atilde',227); oEntityDictionary.add('auml',228); oEntityDictionary.add('aring',229); oEntityDictionary.add('aelig',230); oEntityDictionary.add('ccedil',231); oEntityDictionary.add('egrave',232); oEntityDictionary.add('eacute',233); oEntityDictionary.add('ecirc',234); oEntityDictionary.add('euml',235); oEntityDictionary.add('igrave',236); oEntityDictionary.add('iacute',237); oEntityDictionary.add('icirc',238); oEntityDictionary.add('iuml',239); oEntityDictionary.add('eth',240); oEntityDictionary.add('ntilde',241); oEntityDictionary.add('ograve',242); oEntityDictionary.add('oacute',243); oEntityDictionary.add('ocirc',244); oEntityDictionary.add('otilde',245); oEntityDictionary.add('ouml',246); oEntityDictionary.add('divide',247); oEntityDictionary.add('oslash',248); oEntityDictionary.add('ugrave',249); oEntityDictionary.add('uacute',250); oEntityDictionary.add('ucirc',251); oEntityDictionary.add('uuml',252); oEntityDictionary.add('yacute',253); oEntityDictionary.add('thorn',254); oEntityDictionary.add('yuml',255);