Mercurial > projects > dang
comparison docs/candydoc/tree.js @ 206:d3c148ca429b
Major moving of files. all src now goes into src, all docs in docs.
author | Anders Johnsen <skabet@gmail.com> |
---|---|
date | Tue, 12 Aug 2008 18:14:56 +0200 |
parents | doc/candydoc/tree.js@4c121c2aa844 |
children |
comparison
equal
deleted
inserted
replaced
205:8387cbaa85ab | 206:d3c148ca429b |
---|---|
1 /* This file is a part of CanDyDOC fileset. | |
2 File is written by Victor Nakoryakov and placed into the public domain. | |
3 | |
4 This file is javascript with classes that represents native style tree control. */ | |
5 | |
6 var pmNone = 0; | |
7 var pmPlus = 1; | |
8 var pmMinus = 2; | |
9 | |
10 var hlNone = 0; | |
11 var hlGrey = 1; | |
12 var hlSelected = 2; | |
13 | |
14 function TreeView(hrefMode) | |
15 { | |
16 this.domEntry = document.createElement("div"); | |
17 this.children = new Array(); | |
18 this.selection = null; | |
19 this.hrefMode = hrefMode; | |
20 | |
21 this.createBranch = function(text, iconSrc) | |
22 { | |
23 var root = new TreeNode(text, iconSrc, this.hrefMode); | |
24 root.owner = this; | |
25 this.children[ this.children.length ] = root; | |
26 this.domEntry.appendChild( root.domEntry ); | |
27 return root; | |
28 } | |
29 | |
30 this.branch = function(text) | |
31 { | |
32 var ret = null; | |
33 for (var i = 0; i < this.children.length; ++i) | |
34 if (this.children[i].textElement.data == text) | |
35 { | |
36 ret = this.children[i]; | |
37 break; | |
38 } | |
39 | |
40 return ret; | |
41 } | |
42 | |
43 this.domEntry.style.fontSize = "10px"; | |
44 this.domEntry.style.cursor = "default"; | |
45 this.domEntry.style.whiteSpace = "nowrap"; | |
46 } | |
47 | |
48 var idCounter = 0; | |
49 function TreeNode(text, iconSrc, hrefMode) | |
50 { | |
51 this.id = idCounter++; | |
52 this.parentNode = null; | |
53 this.children = new Array(); | |
54 this.domEntry = document.createElement("div"); | |
55 this.icon = document.createElement("img"); | |
56 this.textElement = document.createTextNode(text); | |
57 this.textSpan = document.createElement("span"); | |
58 this.lineDiv = document.createElement("div"); | |
59 this.hierarchyImgs = new Array(); | |
60 this.onclick = null; | |
61 | |
62 function createIcon() | |
63 { | |
64 var img = document.createElement("img"); | |
65 img.style.verticalAlign = "middle"; | |
66 img.style.position = "relative"; | |
67 img.style.top = "-1px"; | |
68 img.width = 16; | |
69 img.height = 16; | |
70 return img; | |
71 } | |
72 | |
73 function createHierarchyImage() | |
74 { | |
75 var img = createIcon(); | |
76 img.pointsTop = false; | |
77 img.pointsBottom = false; | |
78 img.pointsRight = false; | |
79 img.pmState = pmNone; | |
80 return img; | |
81 } | |
82 | |
83 function genHierarchyImageSrc(hierarchyImg) | |
84 { | |
85 var name = ""; | |
86 if (hierarchyImg.pointsTop) | |
87 name += "t"; | |
88 | |
89 if (hierarchyImg.pointsBottom) | |
90 name += "b"; | |
91 | |
92 if (hierarchyImg.pointsRight) | |
93 name += "r"; | |
94 | |
95 if (hierarchyImg.pmState == pmPlus) | |
96 name += "p"; | |
97 else if (hierarchyImg.pmState == pmMinus) | |
98 name += "m"; | |
99 | |
100 if (name == "") | |
101 name = "shim"; | |
102 | |
103 return "candydoc/img/tree/" + name + ".gif"; | |
104 } | |
105 | |
106 function setSrc(icon, src) | |
107 { | |
108 icon.src = src; | |
109 // After src change width and height are reseted in IE. | |
110 // Bug workaround: | |
111 icon.width = 16; | |
112 icon.height = 16; | |
113 } | |
114 | |
115 this.createChild = function(text, iconSrc) | |
116 { | |
117 var child = new TreeNode(text, iconSrc, this.owner.hrefMode); | |
118 this.children[ this.children.length ] = child; | |
119 this.domEntry.appendChild( child.domEntry ); | |
120 child.parentNode = this; | |
121 child.owner = this.owner; | |
122 | |
123 // insert hierarchy images according to deepness level | |
124 // of created child. | |
125 | |
126 if (this.children.length > 1) | |
127 { | |
128 // there were already added child before. So copy `level-1` | |
129 // hierarchy images from it. | |
130 | |
131 var prevAddedChild = this.children[ this.children.length - 2 ]; | |
132 | |
133 for (var i = 0; i < prevAddedChild.hierarchyImgs.length - 1; ++i) | |
134 { | |
135 var prevAddedChildImg = prevAddedChild.hierarchyImgs[i]; | |
136 var img = createHierarchyImage(); | |
137 setSrc(img, prevAddedChildImg.src); | |
138 img.pointsTop = prevAddedChildImg.pointsTop; | |
139 img.pointsBottom = prevAddedChildImg.pointsBottom; | |
140 img.pointsRight = prevAddedChildImg.pointsRight; | |
141 img.pmState = prevAddedChildImg.pmState; | |
142 | |
143 child.hierarchyImgs[ child.hierarchyImgs.length ] = img; | |
144 child.lineDiv.insertBefore(img, child.icon); | |
145 } | |
146 | |
147 // change last hierarchy image of prevAddedChild from |_ to |- | |
148 var lastHierarchyImg = prevAddedChild.hierarchyImgs[ prevAddedChild.hierarchyImgs.length - 1 ]; | |
149 lastHierarchyImg.pointsBottom = true; | |
150 setSrc(lastHierarchyImg, genHierarchyImageSrc(lastHierarchyImg)); | |
151 | |
152 // change hierarchy images of prevAddedChild's children on it's last | |
153 // level to | | |
154 prevAddedChild.addHierarchyTBLine(prevAddedChild.hierarchyImgs.length - 1); | |
155 } | |
156 else | |
157 { | |
158 // this is a first child. So copy `level-2` | |
159 // hierarchy images from parent, i.e. this. | |
160 | |
161 for (var i = 0; i < this.hierarchyImgs.length - 1; ++i) | |
162 { | |
163 var parentImg = this.hierarchyImgs[i]; | |
164 var img = createHierarchyImage(); | |
165 setSrc(img, parentImg.src); | |
166 img.pointsTop = parentImg.pointsTop; | |
167 img.pointsBottom = parentImg.pointsBottom; | |
168 img.pointsRight = parentImg.pointsRight; | |
169 img.pmState = parentImg.pmState; | |
170 | |
171 child.hierarchyImgs[ child.hierarchyImgs.length ] = img; | |
172 child.lineDiv.insertBefore(img, child.icon); | |
173 } | |
174 | |
175 if (this.hierarchyImgs.length > 0) // we are not root | |
176 { | |
177 // change last hierarchy image of parent (i.e. this): add minus to it | |
178 var lastHierarchyImg = this.hierarchyImgs[ this.hierarchyImgs.length - 1]; | |
179 lastHierarchyImg.pmState = pmMinus; | |
180 setSrc(lastHierarchyImg, genHierarchyImageSrc(lastHierarchyImg)); | |
181 lastHierarchyImg.owner = this; | |
182 lastHierarchyImg.onclick = new Function("e", "this.owner.processPMClick(e);"); | |
183 | |
184 // make decision on image on `level-1`. It depends on parent's (ie this) | |
185 // image on same level. | |
186 var parentL1HierarchyImg = lastHierarchyImg; | |
187 var l1HierarchyImg = createHierarchyImage(); | |
188 if (parentL1HierarchyImg.pointsBottom) | |
189 { | |
190 l1HierarchyImg.pointsTop = true; | |
191 l1HierarchyImg.pointsBottom = true; | |
192 } | |
193 setSrc(l1HierarchyImg, genHierarchyImageSrc(l1HierarchyImg)); | |
194 child.hierarchyImgs[ child.hierarchyImgs.length ] = l1HierarchyImg; | |
195 child.lineDiv.insertBefore(l1HierarchyImg, child.icon); | |
196 } | |
197 } | |
198 | |
199 // in any case on last level our child will have icon |_ | |
200 var img = createHierarchyImage(); | |
201 img.pointsTop = true; | |
202 img.pointsRight = true; | |
203 setSrc(img, genHierarchyImageSrc(img)); | |
204 | |
205 child.hierarchyImgs[ child.hierarchyImgs.length ] = img; | |
206 child.lineDiv.insertBefore(img, child.icon); | |
207 | |
208 return child; | |
209 } | |
210 | |
211 this.lastChild = function() | |
212 { | |
213 return this.children[ this.children.length - 1 ]; | |
214 } | |
215 | |
216 this.child = function(text) | |
217 { | |
218 var ret = null; | |
219 for (var i = 0; i < this.children.length; ++i) | |
220 if (this.children[i].textElement.data == text) | |
221 { | |
222 ret = this.children[i]; | |
223 break; | |
224 } | |
225 | |
226 return ret; | |
227 } | |
228 | |
229 this.addHierarchyTBLine = function(level) | |
230 { | |
231 for (var i = 0; i < this.children.length; ++i) | |
232 { | |
233 var img = this.children[i].hierarchyImgs[level]; | |
234 img.pointsTop = true; | |
235 img.pointsBottom = true; | |
236 setSrc(img, genHierarchyImageSrc(img)); | |
237 this.children[i].addHierarchyTBLine(level); | |
238 } | |
239 } | |
240 | |
241 this.expand = function() | |
242 { | |
243 var img = this.hierarchyImgs[ this.hierarchyImgs.length - 1 ]; | |
244 | |
245 if (img.pmState == pmPlus) | |
246 { | |
247 img.pmState = pmMinus; | |
248 setSrc(img, genHierarchyImageSrc(img)); | |
249 | |
250 for (var i = 0; i < this.children.length; ++i) | |
251 this.children[i].domEntry.style.display = ""; | |
252 } | |
253 } | |
254 | |
255 this.collapse = function() | |
256 { | |
257 var img = this.hierarchyImgs[ this.hierarchyImgs.length - 1 ]; | |
258 | |
259 if (img.pmState == pmMinus) | |
260 { | |
261 img.pmState = pmPlus; | |
262 setSrc(img, genHierarchyImageSrc(img)); | |
263 | |
264 for (var i = 0; i < this.children.length; ++i) | |
265 this.children[i].domEntry.style.display = "none"; | |
266 } | |
267 } | |
268 | |
269 this.toggle = function() | |
270 { | |
271 var img = this.hierarchyImgs[ this.hierarchyImgs.length - 1 ]; | |
272 if (img.pmState == pmMinus) | |
273 this.collapse(); | |
274 else | |
275 this.expand(); | |
276 } | |
277 | |
278 this.select = function() | |
279 { | |
280 if (this.owner.selection != this) | |
281 { | |
282 if (this.owner.selection) | |
283 this.owner.selection.setHighlight(hlNone); | |
284 | |
285 this.owner.selection = this; | |
286 this.setHighlight(hlSelected); | |
287 } | |
288 } | |
289 | |
290 this.setHighlight = function(mode) | |
291 { | |
292 if (mode == hlNone) | |
293 { | |
294 this.textSpan.style.backgroundColor = ""; | |
295 this.textSpan.style.color = ""; | |
296 this.textSpan.style.border = ""; | |
297 } | |
298 else if (mode == hlGrey) | |
299 { | |
300 this.textSpan.style.backgroundColor = "#aaaaaa"; | |
301 this.textSpan.style.color = ""; | |
302 this.textSpan.style.border = ""; | |
303 } | |
304 else if (mode == hlSelected) | |
305 { | |
306 this.textSpan.style.backgroundColor = "3399cc"; | |
307 this.textSpan.style.color = "white"; | |
308 this.textSpan.style.border = "dotted 1px red"; | |
309 } | |
310 } | |
311 | |
312 this.setOnclick = function(proc) | |
313 { | |
314 this.onclick = proc; | |
315 } | |
316 | |
317 this.setRef = function(url) | |
318 { | |
319 if (this.anchor) | |
320 this.anchor.href = url; | |
321 } | |
322 | |
323 this.processPMClick = function(e) | |
324 { | |
325 this.toggle(); | |
326 | |
327 // prevent this line selection, stop bubbling | |
328 if (e) | |
329 e.stopPropagation(); // Mozilla way | |
330 if (window.event) | |
331 window.event.cancelBubble = true; // IE way | |
332 } | |
333 | |
334 this.processOnclick = function() | |
335 { | |
336 this.select(); | |
337 if (this.onclick instanceof Function) | |
338 this.onclick(); | |
339 } | |
340 | |
341 /////////////////////////////////////////////////////////////////////////// | |
342 if (iconSrc) | |
343 this.icon.src = iconSrc; | |
344 else | |
345 { | |
346 this.icon.width = 0; | |
347 this.icon.height = 0; | |
348 } | |
349 | |
350 this.icon.style.verticalAlign = "middle"; | |
351 this.icon.style.position = "relative"; | |
352 this.icon.style.top = "-1px"; | |
353 this.icon.style.paddingRight = "2px"; | |
354 | |
355 if (!hrefMode) | |
356 { | |
357 this.textSpan.appendChild( this.textElement ); | |
358 } | |
359 else | |
360 { | |
361 this.anchor = document.createElement("a"); | |
362 this.anchor.appendChild( this.textElement ); | |
363 this.textSpan.appendChild( this.anchor ); | |
364 } | |
365 | |
366 this.lineDiv.appendChild( this.icon ); | |
367 this.lineDiv.appendChild( this.textSpan ); | |
368 this.domEntry.appendChild( this.lineDiv ); | |
369 | |
370 this.lineDiv.owner = this; | |
371 | |
372 if (!hrefMode) | |
373 this.lineDiv.onclick = new Function("this.owner.processOnclick();"); | |
374 } |