Conservation de l'état de déroulement de l'arborescence (seulement pour le déroulement).
[MosaicDocument.git] / default_blocks / tree_block_script.js
1 // (c) Benoît PIN 2006
2 // http://plinn.org
3 // Licence GPL
4
5 var TreeMaker;
6
7 (function() {
8 /* root -> base node (typically a tbody or a table)
9 * filter -> comma separated list of portal_types
10 */
11 TreeMaker = function (root, filter, baseImgUrl) {
12 this.root = root;
13 var tm = this;
14 this.root.onclick = function(evt) { tm.refreshTree(evt); };
15 this.filter = filter;
16 this.baseImgUrl = baseImgUrl;
17 this.depthCpt = new Array();
18 this._lastAniImg = null;
19
20 // preload images
21 var images = ['pl.gif', 'pl_ani.gif', 'mi.gif', 'mi_ani.gif'], img;
22 for (var i=0 ; i < images.length ; i++) {
23 img = new Image();
24 img.src = this.baseImgUrl + images[i];
25 }
26 }
27
28 /*
29 * expand / collapse handler
30 * object loading trigger
31 */
32 TreeMaker.prototype.refreshTree = function (evt) {
33 var target = getTargetedObject(evt);
34 if (target.blur)
35 target.blur();
36
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;
43
44
45 switch (imgId) {
46 case "pl.gif" :
47 case "pl_ani.gif" :
48 var linkCell = parentTd.nextSibling;
49 while (linkCell.nodeType != 1)
50 linkCell = linkCell.nextSibling;
51
52 var obUrl = linkCell.getElementsByTagName("A")[0].href;
53
54 var req = new XMLHttpRequest();
55 var tm = this;
56 req.onreadystatechange = function() {
57 switch (req.readyState) {
58 case 1:
59 showProgressImage();
60 break;
61 case 4:
62 hideProgressImage();
63 tm.importRows(req, parentRow);
64 };
65 };
66 target.src = this.baseImgUrl + "mi_ani.gif";
67 this._lastAniImg = target;
68 window.setTimeout(function(){tm._removeLastAniImg();}, 500);
69
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()));
75
76 break;
77
78 case "mi.gif" :
79 case "mi_ani.gif" :
80 this.removeChildNodes(parentRow);
81 target.src = this.baseImgUrl + "pl_ani.gif";
82 this._lastAniImg = target;
83 var tm = this;
84 window.setTimeout(function(){tm._removeLastAniImg();}, 500);
85 break;
86 } // end switch (imgId)
87 disableDefault(evt);
88 disablePropagation(evt);
89 }
90 };
91
92
93 TreeMaker.prototype._removeLastAniImg = function() {
94 if (this._lastAniImg) {
95 this._lastAniImg.src = this._lastAniImg.src.replace("_ani", "");
96 }
97 };
98
99 TreeMaker.prototype.getExpansion = function() {
100 var rows = this.root.getElementsByTagName('TR');
101 var row, cells, stateCell, button, expid, node_depth, last_depth = -1, dd, step;
102 var steps = new Array();
103 steps.push(this.root.getAttribute('name'));
104
105 var expanded = (/.*mi\.gif$|.*mi_ani\.gif$/);
106 for(i=0 ; i < rows.length ; i++) {
107 row = rows[i];
108 cells = row.getElementsByTagName('TD');
109 stateCell = cells[cells.length-2]; // cell where the +/- button is
110 button = stateCell.getElementsByTagName('IMG');
111 if (! button.length)
112 continue;
113 button = button[0];
114 if (expanded.test(button.src)) {
115 expid = button.parentNode.getAttribute("name");
116 node_depth = cells[0].getAttribute('colspan') || 0;
117 dd = last_depth - node_depth + 1;
118 last_depth = node_depth;
119 if (dd > 0) {
120 step = '';
121 for (var j = 0 ; j < dd ; j++)
122 step = step + '_';
123 steps.push(step);
124 }
125 steps.push(expid);
126 }
127 }
128 return steps.join(':');
129 };
130
131
132 /*
133 * expand the tree: sends request and imports rows based on xml response.
134 */
135 TreeMaker.prototype.importRows = function(req, parentRow) {
136 var rows = req.responseXML.documentElement.getElementsByTagName("row");
137 var clickedCells = parentRow.getElementsByTagName("TD");
138 var row, newRow, indentCell, stateCell, linkCell, img, a, indentValue, colspan,
139 incTableDepth=false, cols, linkCellColSpan;
140
141 for (var i = 0 ; i < rows.length ; i++ ) {
142 row = rows[i];
143
144
145 newRow = document.createElement("TR");
146 indentCell = document.createElement("TD");
147 stateCell = document.createElement("TD");
148 stateCell.width = "16";
149 linkCell = document.createElement("TD");
150 linkCell.width = "99%";
151
152
153 if (clickedCells.length == 3) {
154 indentValue = parseInt(clickedCells[0].getAttribute("colspan"));
155 colspan = parseInt(clickedCells[2].getAttribute("colspan"));
156 }
157 else {
158 indentValue = 0;
159 colspan = parseInt(clickedCells[1].getAttribute("colspan"));
160 }
161
162 cols = indentValue + colspan;
163
164 if (colspan == 1)
165 incTableDepth = true;
166
167 indentCell.colSpan = indentValue + 1;
168 if (!this.depthCpt[indentValue])
169 this.depthCpt[indentValue] = 1;
170 else
171 this.depthCpt[indentValue] += 1;
172
173 // IE : it's not possible to set colSpan attr to 0 :-(((
174 linkCellColSpan = cols - indentValue - 1
175 if (linkCellColSpan == 0)
176 linkCell.nullColSpan = true;
177 else
178 linkCell.colSpan = linkCellColSpan;
179
180 img = document.createElement("IMG");
181 img.src = row.getAttribute("icon");
182 img.height = row.getAttribute("height");
183 img.width = row.getAttribute("width");
184 a = document.createElement("A");
185
186 a.setAttribute("href", row.getAttribute("url"));
187 a.setAttribute("title", row.getAttribute("description"));
188 a.innerHTML = row.childNodes[0].nodeValue;
189
190 if (row.getAttribute("state") == "-1") {
191 var stateLink = document.createElement("A");
192 stateLink.href = ".";
193 stateLink.setAttribute("name", row.getAttribute("name"));
194 var stateImg = document.createElement("IMG");
195 stateImg.src = this.baseImgUrl + "pl.gif";
196 stateImg.border = "0";
197 stateImg.height = "16";
198 stateImg.width = "16";
199 stateLink.appendChild(stateImg)
200 stateCell.appendChild(stateLink);
201 }
202 else
203 stateCell.innerHTML = "&nbsp;&nbsp;";
204
205 linkCell.appendChild(img);
206 linkCell.appendChild(a);
207 newRow.appendChild(indentCell);
208 newRow.appendChild(stateCell);
209 newRow.appendChild(linkCell);
210
211
212 this.root.insertBefore(newRow, parentRow.nextSibling);
213 } //end for
214
215 if (incTableDepth) {
216 var rows = this.root.getElementsByTagName("TR");
217 var cells, lastCell, lastColspan;
218 for (var i = 0 ; i < rows.length ; i++) {
219 cells = rows[i].getElementsByTagName("TD");
220 lastCell = cells[cells.length - 1];
221
222 if (lastCell.nullColSpan) {
223 lastCell.nullColSpan = false;
224 lastColspan = 0;
225 }
226 else
227 lastColspan = parseInt(lastCell.getAttribute("colspan"));
228
229 lastCell.colSpan = lastColspan + 1;
230 }
231 }
232 };
233
234 /*
235 * collapse the tree: removes deeper rows after the 'baseRow' passed.
236 */
237 TreeMaker.prototype.removeChildNodes = function(baseRow) {
238 var baseCells = baseRow.getElementsByTagName("TD");
239 var baseColSpan = baseCells[baseCells.length-1].colSpan;
240 var nextRow = baseRow.nextSibling;
241 var tbody = baseRow.parentNode;
242 var depthCpt = this.depthCpt;
243 var nextCells, nextRow2;
244
245 while (nextRow) {
246 if (nextRow.nodeType == 1) {
247 nextCells = nextRow.getElementsByTagName("TD");
248 if (nextCells.length == 3 && nextCells[2].colSpan < baseColSpan) {
249 nextRow2 = nextRow.nextSibling;
250 depthCpt[nextCells[0].colSpan-1] -= 1;
251 tbody.removeChild(nextRow);
252 nextRow = nextRow2;
253 continue;
254 }
255 break;
256 }
257 nextRow = nextRow.nextSibling; // text node
258 }
259
260 // recalc colspans for Safari
261 var maxDepth = depthCpt.length - 1;
262 var depthReduction = 0;
263 while (depthCpt[maxDepth - depthReduction] == 0) {
264 depthCpt.pop();
265 depthReduction++;
266 }
267
268 if (depthReduction) {
269 var rows = tbody.getElementsByTagName("TR");
270 var cells, lastCell, lastColspan;
271 for (var i = 0 ; i < rows.length ; i++) {
272 cells = rows[i].getElementsByTagName("TD");
273 lastCell = cells[cells.length - 1];
274 lastCell.colSpan = parseInt(lastCell.colSpan) - depthReduction;
275 }
276 }
277 };
278 })();