diff options
Diffstat (limited to 'src/usr/local/www/tree/tree.js')
-rwxr-xr-x | src/usr/local/www/tree/tree.js | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/src/usr/local/www/tree/tree.js b/src/usr/local/www/tree/tree.js new file mode 100755 index 0000000..8e9651e --- /dev/null +++ b/src/usr/local/www/tree/tree.js @@ -0,0 +1,195 @@ +/* + * Content-separated javascript tree widget + * Copyright (C) 2005 SilverStripe Limited + * Feel free to use this on your websites, but please leave this message in the fies + * http://www.silverstripe.com/blog +*/ + +/* + * Initialise all trees identified by <ul class="tree"> + */ +function autoInit_trees() { + var candidates = document.getElementsByTagName('ul'); + for(var i=0;i<candidates.length;i++) { + if(candidates[i].className && candidates[i].className.indexOf('tree') != -1) { + initTree(candidates[i]); + candidates[i].className = candidates[i].className.replace(/ ?unformatted ?/, ' '); + } + } +} + +/* + * Initialise a tree node, converting all its LIs appropriately + */ +function initTree(el) { + var i,j; + var spanA, spanB, spanC; + var startingPoint, stoppingPoint, childUL; + + // Find all LIs to process + for(i=0;i<el.childNodes.length;i++) { + if(el.childNodes[i].tagName && el.childNodes[i].tagName.toLowerCase() == 'li') { + var li = el.childNodes[i]; + + // Create our extra spans + spanA = document.createElement('span'); + spanB = document.createElement('span'); + spanC = document.createElement('span'); + spanA.appendChild(spanB); + spanB.appendChild(spanC); + spanA.className = 'a ' + li.className.replace('closed','spanClosed'); + spanA.onMouseOver = function() {}; + spanB.className = 'b'; + spanB.onclick = treeToggle; + spanC.className = 'c'; + + + // Find the UL within the LI, if it exists + stoppingPoint = li.childNodes.length; + startingPoint = 0; + childUL = null; + for(j=0;j<li.childNodes.length;j++) { + if(li.childNodes[j].tagName && li.childNodes[j].tagName.toLowerCase() == 'div') { + startingPoint = j + 1; + continue; + } + + if(li.childNodes[j].tagName && li.childNodes[j].tagName.toLowerCase() == 'ul') { + childUL = li.childNodes[j]; + stoppingPoint = j; + break; + } + } + + // Move all the nodes up until that point into spanC + for(j=startingPoint;j<stoppingPoint;j++) { + spanC.appendChild(li.childNodes[startingPoint]); + } + + // Insert the outermost extra span into the tree + if(li.childNodes.length > startingPoint) li.insertBefore(spanA, li.childNodes[startingPoint]); + else li.appendChild(spanA); + + // Process the children + if(childUL != null) { + if(initTree(childUL)) { + addClass(li, 'children', 'closed'); + addClass(spanA, 'children', 'spanClosed'); + } + } + } + } + + if(li) { + // li and spanA will still be set to the last item + + addClass(li, 'last', 'closed'); + addClass(spanA, 'last', 'spanClosed'); + return true; + } else { + return false; + } + +} + + +/* + * +/- toggle the tree, where el is the <span class="b"> node + * force, will force it to "open" or "close" + */ +function treeToggle(el, force) { + el = this; + + while(el != null && (!el.tagName || el.tagName.toLowerCase() != "li")) el = el.parentNode; + + // Get UL within the LI + var childSet = findChildWithTag(el, 'ul'); + var topSpan = findChildWithTag(el, 'span'); + + if( force != null ){ + + if( force == "open"){ + treeOpen( topSpan, el ); + } + else if( force == "close" ){ + treeClose( topSpan, el ); + } + + } + + else if( childSet != null) { + // Is open, close it + if(!el.className.match(/(^| )closed($| )/)) { + treeClose( topSpan, el ); + // Is closed, open it + } else { + treeOpen( topSpan, el ); + } + } +} + + +function treeOpen( a, b ){ + removeClass(a,'spanClosed'); + removeClass(b,'closed'); +} + + +function treeClose( a, b ){ + addClass(a,'spanClosed'); + addClass(b,'closed'); +} + +/* + * Find the a child of el of type tag + */ +function findChildWithTag(el, tag) { + for(var i=0;i<el.childNodes.length;i++) { + if(el.childNodes[i].tagName != null && el.childNodes[i].tagName.toLowerCase() == tag) return el.childNodes[i]; + } + return null; +} + +/* + * Functions to add and remove class names + * Mac IE hates unnecessary spaces + */ +function addClass(el, cls, forceBefore) { + if(forceBefore != null && el.className.match(new RegExp('(^| )' + forceBefore))) { + el.className = el.className.replace(new RegExp("( |^)" + forceBefore), '$1' + cls + ' ' + forceBefore); + + } else if(!el.className.match(new RegExp('(^| )' + cls + '($| )'))) { + el.className += ' ' + cls; + el.className = el.className.replace(/(^ +)|( +$)/g, ''); + } +} +function removeClass(el, cls) { + var old = el.className; + var newCls = ' ' + el.className + ' '; + newCls = newCls.replace(new RegExp(' (' + cls + ' +)+','g'), ' '); + el.className = newCls.replace(/(^ +)|( +$)/g, ''); +} + +/* + * Handlers for automated loading + */ + _LOADERS = Array(); + +function callAllLoaders() { + var i, loaderFunc; + for(i=0;i<_LOADERS.length;i++) { + loaderFunc = _LOADERS[i]; + if(loaderFunc != callAllLoaders) loaderFunc(); + } +} + +function appendLoader(loaderFunc) { + if(window.onload && window.onload != callAllLoaders) + _LOADERS[_LOADERS.length] = window.onload; + + window.onload = callAllLoaders; + + _LOADERS[_LOADERS.length] = loaderFunc; +} + +appendLoader(autoInit_trees); |