8 /* root -> base node (typically a tbody or a table)
9 * filter -> comma separated list of portal_types
11 TreeMaker = function (root
, filter
, baseImgUrl
) {
14 this.root
.onclick = function(evt
) { tm
.refreshTree(evt
); };
16 this.baseImgUrl
= baseImgUrl
;
17 this.depthCpt
= new Array();
18 this._lastAniImg
= null;
21 var images
= ['pl.png', 'pl_ani.png', 'mi.png', 'mi_ani.png'], img
;
22 for (var i
=0 ; i
< images
.length
; i
++) {
24 img
.src
= this.baseImgUrl
+ images
[i
];
29 * expand / collapse handler
30 * object loading trigger
32 TreeMaker
.prototype.refreshTree = function (evt
) {
33 var target
= getTargetedObject(evt
);
37 if (target
.tagName
== 'IMG') {
38 target
.parentNode
.blur();
39 var srcParts
= target
.src
.split("/");
40 var imgId
= srcParts
[srcParts
.length
-1];
41 var parentTd
= target
.parentNode
.parentNode
;
42 var parentRow
= parentTd
.parentNode
;
48 var linkCell
= parentTd
.nextSibling
;
49 while (linkCell
.nodeType
!= 1)
50 linkCell
= linkCell
.nextSibling
;
52 var obUrl
= linkCell
.getElementsByTagName("A")[0].href
;
54 var req
= new XMLHttpRequest();
56 req
.onreadystatechange = function() {
57 switch (req
.readyState
) {
63 tm
.importRows(req
, parentRow
);
66 target
.src
= this.baseImgUrl
+ "mi_ani.png";
67 this._lastAniImg
= target
;
68 window
.setTimeout(function(){tm
._removeLastAniImg();}, 500);
70 req
.open("POST", obUrl
+ "/xml_nav_tree", true);
71 req
.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
72 req
.send("filter=" + encodeURIComponent(this.filter
) +
73 "&root_name=" + encodeURIComponent(this.root
.id
) +
74 "&expansion=" + encodeURIComponent(this.getExpansion()));
80 this.removeChildNodes(parentRow
);
81 target
.src
= this.baseImgUrl
+ "pl_ani.png";
82 this._lastAniImg
= target
;
84 window
.setTimeout(function(){tm
._removeLastAniImg();}, 500);
85 document
.cookie
= encodeURIComponent(this.root
.id
) + '-state=' + encodeURIComponent(this.getExpansion()) +
88 } // end switch (imgId)
90 disablePropagation(evt
);
95 TreeMaker
.prototype._removeLastAniImg = function() {
96 if (this._lastAniImg
) {
97 this._lastAniImg
.src
= this._lastAniImg
.src
.replace("_ani", "");
101 TreeMaker
.prototype.getExpansion = function() {
102 var rows
= this.root
.getElementsByTagName('TR');
103 var row
, cells
, stateCell
, button
, expid
, node_depth
, last_depth
= -1, dd
, step
;
104 var steps
= new Array();
105 steps
.push(this.root
.getAttribute('name'));
107 var expanded
= (/.*mi\.png$|.*mi_ani\.png$/);
108 for(i
=0 ; i
< rows
.length
; i
++) {
110 cells
= row
.getElementsByTagName('TD');
111 stateCell
= cells
[cells
.length
-2]; // cell where the +/- button is
112 button
= stateCell
.getElementsByTagName('IMG');
116 if (expanded
.test(button
.src
)) {
117 expid
= button
.parentNode
.getAttribute("name");
118 node_depth
= cells
[0].getAttribute('colspan') || 0;
119 dd
= last_depth
- node_depth
+ 1;
120 last_depth
= node_depth
;
123 for (var j
= 0 ; j
< dd
; j
++)
130 return steps
.join(':');
135 * expand the tree: sends request and imports rows based on xml response.
137 TreeMaker
.prototype.importRows = function(req
, parentRow
) {
138 var rows
= req
.responseXML
.documentElement
.getElementsByTagName("row");
139 var clickedCells
= parentRow
.getElementsByTagName("TD");
140 var row
, newRow
, indentCell
, stateCell
, linkCell
, img
, a
, indentValue
, colspan
,
141 incTableDepth
=false, cols
, linkCellColSpan
;
143 for (var i
= 0 ; i
< rows
.length
; i
++ ) {
147 newRow
= document
.createElement("TR");
148 indentCell
= document
.createElement("TD");
149 stateCell
= document
.createElement("TD");
150 stateCell
.width
= "16";
151 linkCell
= document
.createElement("TD");
152 linkCell
.width
= "99%";
155 if (clickedCells
.length
== 3) {
156 indentValue
= parseInt(clickedCells
[0].getAttribute("colspan"));
157 colspan
= parseInt(clickedCells
[2].getAttribute("colspan"));
161 colspan
= parseInt(clickedCells
[1].getAttribute("colspan"));
164 cols
= indentValue
+ colspan
;
167 incTableDepth
= true;
169 indentCell
.colSpan
= indentValue
+ 1;
170 if (!this.depthCpt
[indentValue
])
171 this.depthCpt
[indentValue
] = 1;
173 this.depthCpt
[indentValue
] += 1;
175 // IE : it's not possible to set colSpan attr to 0 :-(((
176 linkCellColSpan
= cols
- indentValue
- 1
177 if (linkCellColSpan
== 0)
178 linkCell
.nullColSpan
= true;
180 linkCell
.colSpan
= linkCellColSpan
;
182 img
= document
.createElement("IMG");
183 img
.src
= row
.getAttribute("icon");
184 img
.height
= row
.getAttribute("height");
185 img
.width
= row
.getAttribute("width");
186 a
= document
.createElement("A");
188 a
.setAttribute("href", row
.getAttribute("url"));
189 a
.setAttribute("title", row
.getAttribute("description"));
190 a
.innerHTML
= row
.childNodes
[0].nodeValue
;
192 if (row
.getAttribute("state") == "-1") {
193 var stateLink
= document
.createElement("A");
194 stateLink
.href
= ".";
195 stateLink
.setAttribute("name", row
.getAttribute("name"));
196 var stateImg
= document
.createElement("IMG");
197 stateImg
.src
= this.baseImgUrl
+ "pl.png";
198 stateImg
.border
= "0";
199 stateImg
.height
= "16";
200 stateImg
.width
= "16";
201 stateLink
.appendChild(stateImg
)
202 stateCell
.appendChild(stateLink
);
205 stateCell
.innerHTML
= " ";
207 linkCell
.appendChild(img
);
208 linkCell
.appendChild(a
);
209 newRow
.appendChild(indentCell
);
210 newRow
.appendChild(stateCell
);
211 newRow
.appendChild(linkCell
);
214 this.root
.insertBefore(newRow
, parentRow
.nextSibling
);
218 var rows
= this.root
.getElementsByTagName("TR");
219 var cells
, lastCell
, lastColspan
;
220 for (var i
= 0 ; i
< rows
.length
; i
++) {
221 cells
= rows
[i
].getElementsByTagName("TD");
222 lastCell
= cells
[cells
.length
- 1];
224 if (lastCell
.nullColSpan
) {
225 lastCell
.nullColSpan
= false;
229 lastColspan
= parseInt(lastCell
.getAttribute("colspan"));
231 lastCell
.colSpan
= lastColspan
+ 1;
237 * collapse the tree: removes deeper rows after the 'baseRow' passed.
239 TreeMaker
.prototype.removeChildNodes = function(baseRow
) {
240 var baseCells
= baseRow
.getElementsByTagName("TD");
241 var baseColSpan
= baseCells
[baseCells
.length
-1].colSpan
;
242 var nextRow
= baseRow
.nextSibling
;
243 var tbody
= baseRow
.parentNode
;
244 var depthCpt
= this.depthCpt
;
245 var nextCells
, nextRow2
;
248 if (nextRow
.nodeType
== 1) {
249 nextCells
= nextRow
.getElementsByTagName("TD");
250 if (nextCells
.length
== 3 && nextCells
[2].colSpan
< baseColSpan
) {
251 nextRow2
= nextRow
.nextSibling
;
252 depthCpt
[nextCells
[0].colSpan
-1] -= 1;
253 tbody
.removeChild(nextRow
);
259 nextRow
= nextRow
.nextSibling
; // text node
262 // recalc colspans for Safari
263 var maxDepth
= depthCpt
.length
- 1;
264 var depthReduction
= 0;
265 while (depthCpt
[maxDepth
- depthReduction
] == 0) {
270 if (depthReduction
) {
271 var rows
= tbody
.getElementsByTagName("TR");
272 var cells
, lastCell
, lastColspan
;
273 for (var i
= 0 ; i
< rows
.length
; i
++) {
274 cells
= rows
[i
].getElementsByTagName("TD");
275 lastCell
= cells
[cells
.length
- 1];
276 lastCell
.colSpan
= parseInt(lastCell
.colSpan
) - depthReduction
;