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 }