From f7cff273b77911ed3da8f1e970a3c6195edeb069 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Sat, 21 Nov 2009 02:32:08 +0000 Subject: [PATCH] MINOR Moved jsparty/tree to cms/javascript/tree git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@92545 467b73ca-7a2a-4603-9d3b-597d59a354a9 --- javascript/tree/images/i-bottom.gif | Bin 0 -> 125 bytes javascript/tree/images/i-repeater.gif | Bin 0 -> 91 bytes javascript/tree/images/insertBetween.gif | Bin 0 -> 1026 bytes javascript/tree/images/l.gif | Bin 0 -> 131 bytes javascript/tree/images/minus.gif | Bin 0 -> 146 bytes javascript/tree/images/page-closedfolder.gif | Bin 0 -> 210 bytes javascript/tree/images/page-closedfolder.png | Bin 0 -> 210 bytes javascript/tree/images/page-file.gif | Bin 0 -> 211 bytes javascript/tree/images/page-file.png | Bin 0 -> 211 bytes javascript/tree/images/page-openfolder.gif | Bin 0 -> 219 bytes javascript/tree/images/page-openfolder.png | Bin 0 -> 219 bytes javascript/tree/images/plus.gif | Bin 0 -> 149 bytes javascript/tree/images/t.gif | Bin 0 -> 94 bytes javascript/tree/tree.css | 160 ++++ javascript/tree/tree.js | 927 +++++++++++++++++++ 15 files changed, 1087 insertions(+) create mode 100644 javascript/tree/images/i-bottom.gif create mode 100644 javascript/tree/images/i-repeater.gif create mode 100644 javascript/tree/images/insertBetween.gif create mode 100644 javascript/tree/images/l.gif create mode 100644 javascript/tree/images/minus.gif create mode 100644 javascript/tree/images/page-closedfolder.gif create mode 100644 javascript/tree/images/page-closedfolder.png create mode 100644 javascript/tree/images/page-file.gif create mode 100644 javascript/tree/images/page-file.png create mode 100644 javascript/tree/images/page-openfolder.gif create mode 100644 javascript/tree/images/page-openfolder.png create mode 100644 javascript/tree/images/plus.gif create mode 100644 javascript/tree/images/t.gif create mode 100644 javascript/tree/tree.css create mode 100644 javascript/tree/tree.js diff --git a/javascript/tree/images/i-bottom.gif b/javascript/tree/images/i-bottom.gif new file mode 100644 index 0000000000000000000000000000000000000000..f07fa991db7a3ae02ffa947e43f27484a28aa601 GIT binary patch literal 125 zcmZ?wbhEHb6ksr7*vtR|4Pe{=rW$~}hK2(N4m310{0EBvXZR1MfHaT=1d2ad7#SFN z8FYY>3?MTYShO~r^jy8y;`Q0x{}VL&QZnadtXh{-yyX)2Y2CB8wAa1T?Ej^{z%xQ= JQjH*kH2_BKFBbp+ literal 0 HcmV?d00001 diff --git a/javascript/tree/images/i-repeater.gif b/javascript/tree/images/i-repeater.gif new file mode 100644 index 0000000000000000000000000000000000000000..d5ab0890b4e115b24782b8d9358a6bc764d25ec1 GIT binary patch literal 91 zcmZ?wbhEHb6kuRt*vtR|4Pe{=rW$~}hK2(N4m310{0EBvXZR1MfHaT=1d2ad7#SFN Z8FYY>3?MTYSU5JEyveuM;xq??H2~bg9D4u& literal 0 HcmV?d00001 diff --git a/javascript/tree/images/insertBetween.gif b/javascript/tree/images/insertBetween.gif new file mode 100644 index 0000000000000000000000000000000000000000..bc375da30d27a47adc43fd0faed00c90c06bf47c GIT binary patch literal 1026 zcmZ?wbhEHb)M4ae_|Cxa{r6wrdDpdjE=V<^_W%EXhEXsY0>dZ-bU=Oq+Y$otFNz5INT-cy=~3S z%^8arV74J2yW+zreX$&Ue?AmzP)A>Ki;b;K0mk!p_j}Lc022b0?f?J) literal 0 HcmV?d00001 diff --git a/javascript/tree/images/l.gif b/javascript/tree/images/l.gif new file mode 100644 index 0000000000000000000000000000000000000000..1e8c7079ee35efd7d8237f2acb47fee6fdffd287 GIT binary patch literal 131 zcmZ?wbhEHb6ksr7*vtR|4Pe{=rW$~}hK2(N4m310{0EBvXZR1MfHaT=1d2ad7#SFN z8FYY>3?MTYSPV9t^jtml`Kwyv|FhZqrg%(x#<@)E__kZz(Vt>&#rK+9o&CReZh?o6 PRR4)3MJIE_lo_l6YnU3?MTYSnM~P^jy8y;`Q0x{}VL&QZnbQC|h&;*Pb_}drWk$e@Q%B5%;kn;ey-4 guX4NY8?Jm~Sbr=c?W<4Z`WtJ?PQR_%D9B(905feqivR!s literal 0 HcmV?d00001 diff --git a/javascript/tree/images/page-closedfolder.gif b/javascript/tree/images/page-closedfolder.gif new file mode 100644 index 0000000000000000000000000000000000000000..d26f2dc9a7403e4f0d001527b29d8220f72285c6 GIT binary patch literal 210 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFP2=EDUW%&Oe$ecf);r#i8|Nqbb zKR^Hf|M?$2eE1I*2TGv<1(UCPfkKQWL4Lsu4$p3+0XYGlE{-7;w~`YYnAKEO84aBG z9z83dlaP~>vt-GV0|%ZkF*!J@Z8uTyXf--?NJz0KWQ9jWghb0kE>T9V7N)B^n0~HY k*p|TD$dIu^fyE$!fnm`dad%Mzopr0I4HF-T(jq literal 0 HcmV?d00001 diff --git a/javascript/tree/images/page-closedfolder.png b/javascript/tree/images/page-closedfolder.png new file mode 100644 index 0000000000000000000000000000000000000000..d26f2dc9a7403e4f0d001527b29d8220f72285c6 GIT binary patch literal 210 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFP2=EDUW%&Oe$ecf);r#i8|Nqbb zKR^Hf|M?$2eE1I*2TGv<1(UCPfkKQWL4Lsu4$p3+0XYGlE{-7;w~`YYnAKEO84aBG z9z83dlaP~>vt-GV0|%ZkF*!J@Z8uTyXf--?NJz0KWQ9jWghb0kE>T9V7N)B^n0~HY k*p|TD$dIu^fyE$!fnm`dad%Mzopr0I4HF-T(jq literal 0 HcmV?d00001 diff --git a/javascript/tree/images/page-file.gif b/javascript/tree/images/page-file.gif new file mode 100644 index 0000000000000000000000000000000000000000..d3bb119a105bbc467d789c65e80db6aff4d79a6a GIT binary patch literal 211 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFP2=EDUW%&QUzP>&nAmIG@^A8?8 z`2YX^hYufs#Qgd54Gat#8XABKk->~LQj36m#*!evUeU#lkKsM~`xx@hERJxO8_x&m<8IW(|h4 pmZgr8dU^qEh8ztNUI_;n*cmSB$O&nAmIG@^A8?8 z`2YX^hYufs#Qgd54Gat#8XABKk->~LQj36m#*!evUeU#lkKsM~`xx@hERJxO8_x&m<8IW(|h4 pmZgr8dU^qEh8ztNUI_;n*cmSB$OFq$!iz%x6E?-vZmO5$M=R+ no4)@DX!)u2VIJ$WNe9=n&p#q8-_JC=733OES3j3^P6Fq$!iz%x6E?-vZmO5$M=R+ no4)@DX!)u2VIJ$WNe9=n&p#q8-_JC=733OES3j3^P63?MTYSe!PT^jy8y;`Q0x{}VL&QZnbQC|h&;*Pb_}drWjLGt@>H$Gx8-mte7l jHQQ45eEOO%S^Ns`B~PzevT{w?>9ZBoY7s literal 0 HcmV?d00001 diff --git a/javascript/tree/tree.css b/javascript/tree/tree.css new file mode 100644 index 000000000..b49b03a79 --- /dev/null +++ b/javascript/tree/tree.css @@ -0,0 +1,160 @@ +/* + * Default CSS for tree-view + */ +ul.tree{ + width: auto; + padding-left: 0; + margin-left: 0; +} + +ul.tree img { + border: none; +} + +ul.tree, ul.tree ul { + padding-left: 0; +} + +ul.tree ul { + margin-left: 16px; +} + +ul.tree li.closed ul { + display: none; +} + +ul.tree li { + list-style: none; + background: url(images/i-repeater.gif) repeat-y 1 0; + display: block; + width: auto; +} + ul.tree li.last { + list-style: none; + background-image: none; + } + +/* Span-A: I/L/I glpyhs */ +ul.tree span.a { + background: url(images/t.gif) no-repeat 0 50%; + display: block; +} +ul.tree .a.last { + background: url(images/l.gif) no-repeat 0 50%; +} + +/* Span-B: Plus/Minus icon */ +ul.tree span.b { +} +ul.tree span.a.children span.b { + display: inline-block; + background: url(images/minus.gif) no-repeat 0 50%; + cursor: pointer; +} +ul.tree li.closed span.a span.b, ul.tree span.a.unexpanded span.b { + display: inline-block; + background: url(images/plus.gif) no-repeat 0 50%; + cursor: pointer; +} + +/* Span-C: Spacing and extending tree line below the icon */ +ul.tree span.c { + margin-left: 16px; +} +ul.tree span.a.children span.c, ul.tree span.a.spanClosed span.c { + background: url(images/i-bottom.gif) no-repeat 0 50%; +} +ul.tree span.a.spanClosed span.c, ul.tree span.a.unexpanded span.c { + background-image: none; +} + +/* Anchor tag: Page icon */ +ul.tree span.c { + white-space: nowrap; +} +ul.tree a { + display: inline-block; /* IE needs this */ + white-space: pre; + overflow: hidden; + padding: 3px 0 1px 19px; + line-height: 16px; + background: url(images/page-file.png) no-repeat 0 50%; + background-position: 0 50% !important; + text-decoration: none; + outline: none; + font-size: 11px; +} + ul.tree a * { + font-size: 11px; + } + ul.tree a:hover { + text-decoration: underline; + } + +ul.tree span.a.children a { + background-image: url(images/page-openfolder.png); +} +ul.tree span.a.spanClosed a, ul.tree span.a.unexpanded a { + background-image: url(images/page-closedfolder.png); +} + +/* Unformatted tree */ +ul.tree.unformatted li { + background-image: none; + padding-left: 16px; +} +ul.tree.unformatted li li { + background-image: none; + padding-left: 0; +} + +/* + Hover / Link tags +*/ +ul.tree a:hover{ + text-decoration : none; +} + +/* + * Divs, by default store vertically aligned data + */ +/* As inside DIVs should be treated normally */ +ul.tree div a { + padding: 0; + background-image: none; + min-height: 0; + height: auto; +} + +ul.tree li a:link, +ul.tree li a:hover, +ul.tree li a:visited { + color: #111; +} + +/* + * Drag and drop styling + */ +ul.tree div.droppable { + float: none; + margin: -7px 0px -7px 16px; + height: 10px; + font-size: 1px; + z-index: 1000; +} +html > body ul.tree div.droppable { + margin: -5px 0px -5px 16px; +} + +ul.tree div.droppable.dragOver { + background: url(images/insertBetween.gif) no-repeat 50% 0; +} + +ul.tree a.dragOver, ul.tree li.dragOver a, ul.tree li.dragOver li.dragOver a { + border: 3px solid #0074C6; + margin: -3px; +} +ul.tree li.dragOver li a { + border-style: none; + margin: 0; +} \ No newline at end of file diff --git a/javascript/tree/tree.js b/javascript/tree/tree.js new file mode 100644 index 000000000..cc1c790a2 --- /dev/null +++ b/javascript/tree/tree.js @@ -0,0 +1,927 @@ +/* + * Content-separated javascript tree widget + * + * Usage: + * behaveAs(someUL, Tree) + * OR behaveAs(someUL, DraggableTree) + * + * Extended by Steven J. DeRose, deroses@mail.nih.gov, sderose@acm.org. + * + * INPUT REQUIREMENTS: + * Put class="tree" on topmost UL(s). + * Can put class="closed" on LIs to have them collapsed on startup. + * + * The structure we build is: + * li class="children last closed" <=== original li from source + * children: there's a UL child + * last: no following LI + * closed: is collapsed (may be in src) + * span class="a children spanClosed" <=== contains children before UL + * children: there's a UL (now a sib) + * spanClosed: is collapsed + * span class="b" <=== +/- click is caught here + * span class="c" <=== for spacing and lines + * a href="..." <=== original pre-UL stuff (e.g., a) + * ul... + * + */ + +Tree = Class.create(); +Tree.prototype = { + /* + * Initialise a tree node, converting all its LIs appropriately. + * This means go through all li children, and move the content of each + * (before any UL child) down into 3 intermediate spans, classes a/b/c. + */ + initialize: function(options) { + this.isDraggable = false; + var i,li; + + this.options = options ? options : {}; + if(!this.options.tree) this.options.tree = this; + + this.tree = this.options.tree; + + // Set up observer + if(this == this.tree) Observable.applyTo(this); + + // Find all LIs to process + // Don't let it re-do a node it's already done. + for(i=0;i tag into a suitable tree node + */ + castAsTreeNode: function(li) { + behaveAs(li, TreeNode, this.options); + }, + + getIdxOf : function(el) { + if(!el.treeNode) el.treeNode = el; + // Special case for TreeMultiselectField + if(el.treeNode.id.match(/^selector-([^-]+)-([0-9]+)$/)) return RegExp.$2; + // Other case for LHS tree of CMS + if(el.treeNode.id.match(/([^-]+)-(.+)$/)) return RegExp.$1; + else return el.treeNode.id; + }, + + childTreeNodes: function() { + var i,item, children = []; + for(i=0;item=this.childNodes[i];i++) { + if(item.tagName && item.tagName.toLowerCase() == 'li') children.push(item); + } + return children; + }, + hasChildren: function() { + return this.childTreeNodes().length > 0; + }, + + /** + * Turn a normal tree into a draggable one. + */ + makeDraggable: function() { + this.isDraggable = true; + var i,item,x; + + var trees = this.getElementsByTagName('ul'); + for(x in DraggableTree.prototype) this[x] = DraggableTree.prototype[x]; + DraggableTree.prototype.setUpDragability.apply(this); + + var nodes = this.getElementsByTagName('li'); + for(i=0;item=nodes[i];i++) { + for(x in DraggableTreeNode.prototype) item[x] = DraggableTreeNode.prototype[x]; + } + for(i=0;item=trees[i];i++) { + for(x in DraggableTree.prototype) item[x] = DraggableTree.prototype[x]; + } + for(i=0;item=nodes[i];i++) { + DraggableTreeNode.prototype.setUpDragability.apply(item); + } + for(i=0;item=trees[i];i++) { + DraggableTree.prototype.setUpDragability.apply(item); + } + }, + + /** + * Add the given child node to this tree node. + * If 'before' is specified, then it will be inserted before that. + */ + appendTreeNode : function(child, before) { + // Remove from the old parent node - this will ensure that the classes of the old tree + // item are updated accordingly + if(child && child.parentTreeNode) { + var oldParent = child.parentTreeNode; + oldParent.removeTreeNode(child); + } + var lastNode, i, holder = this; + if(lastNode = this.lastTreeNode()) lastNode.removeNodeClass('last'); + + // Do the actual moving + if(before) { + child.removeNodeClass('last'); + + if(holder != before.parentNode) { + throw("TreeNode.appendTreeNode: 'before' not contained within the holder"); + holder.appendChild(child); + } else { + holder.insertBefore(child, before); + } + } else { + holder.appendChild(child); + } + + if(this.parentNode && this.parentNode.fixDragHelperDivs) this.parentNode.fixDragHelperDivs(); + if(oldParent && oldParent.fixDragHelperDivs) oldParent.fixDragHelperDivs(); + + // Update the helper classes + if(this.parentNode && this.parentNode.tagName.toLowerCase() == 'li') { + if(this.parentNode.className.indexOf('closed') == -1) this.parentNode.addNodeClass('children'); + this.lastTreeNode().addNodeClass('last'); + } + + // Update the helper variables + if(this.parentNode.tagName.toLowerCase() == 'li') child.parentTreeNode = this.parentNode; + else child.parentTreeNode = null; + + if(this.isDraggable) { + for(x in DraggableTreeNode.prototype) child[x] = DraggableTreeNode.prototype[x]; + DraggableTreeNode.prototype.setUpDragability.apply(child); + } + }, + + lastTreeNode : function() { + var i, holder = this; + for(i=holder.childNodes.length-1;i>=0;i--) { + if(holder.childNodes[i].tagName && holder.childNodes[i].tagName.toLowerCase() == 'li') return holder.childNodes[i]; + } + }, + + /** + * Remove the given child node from this tree node. + */ + removeTreeNode : function(child) { + // Remove the child + var holder = this; + try { holder.removeChild(child); } catch(er) { } + + // Look for remaining children + var i, hasChildren = false; + for(i=0;i would give a recordID of 6 + if(this.id && this.id.match(/([^-]+)-(.+)$/)) + this.recordID = RegExp.$1; + + // 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'); + spanB.className = 'b'; + spanB.onclick = TreeNode_bSpan_onclick; + spanC.className = 'c'; + + this.castAsSpanA(spanA); + + // Add +/- icon to select node that has children + if (li.hasChildren() && li.className.indexOf('current') > -1) { + li.className = li.className + ' children'; + spanA.className = spanA.className + ' children'; + } + + // Find the UL within the LI, if it exists + stoppingPoint = li.childNodes.length; + startingPoint = 0; + childUL = null; + for(j=0;j startingPoint) li.insertBefore(spanA, li.childNodes[startingPoint]); + else li.appendChild(spanA); + + // Create appropriate node references; + if(li.parentNode && li.parentNode.parentNode && li.parentNode.parentNode.tagName.toLowerCase() == 'li') { + li.parentTreeNode = li.parentNode.parentNode; + } + li.aSpan = spanA; + li.bSpan = spanB; + li.cSpan = spanC; + li.treeNode = spanA.treeNode = spanB.treeNode = spanC.treeNode = li; + var aTag = spanC.getElementsByTagName('a')[0]; + if(aTag) { + aTag.treeNode = li; + li.aTag = aTag; + + } else { + throw("Tree creation: A tree needs tags inside the
  • s to work properly."); + } + + + aTag.onclick = TreeNode_aTag_onclick.bindAsEventListener(aTag); + + + // Process the children + if(childUL != null) { + if(this.castAsTree(childUL)) { /* ***** RECURSE ***** */ + if(this.className.indexOf('closed') == -1) { + this.addNodeClass('children'); + } + } + } else { + this.removeNodeClass('closed'); + } + + this.setIconByClass(); + }, + + destroy: function() { + // Debug.show(this); + + this.tree = null; + this.treeNode = null; + this.parentTreeNode = null; + + if(this.options) this.options.tree = null; + this.options = null; + + if(this.aTag) { + this.aTag.treeNode = null; + this.aTag.onclick = null; + } + if(this.aSpan) { + this.aSpan.treeNode = null; + this.aSpan.onmouseover = null; + this.aSpan.onmouseout = null; + } + if(this.bSpan) { + this.bSpan.treeNode = null; + this.bSpan.onclick = null; + } + if(this.cSpan) this.cSpan.treeNode = null; + + this.aSpan = null; + this.bSpan = null; + this.cSpan = null; + this.aTag = null; + }, + + /** + * Cast the given span as the item for this tree. + */ + castAsSpanA: function(spanA) { + var x; + for(x in TreeNode_SpanA) spanA[x] = TreeNode_SpanA[x]; + }, + /** + * Cast the child