[29] | 1 | // (C) Copyright Jonathan Turkanis 2003. |
---|
| 2 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
---|
| 3 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.) |
---|
| 4 | |
---|
| 5 | //--------------Event-handlers------------------------------------------------// |
---|
| 6 | |
---|
| 7 | function toggle(id) { get_tree().find(id).toggle(); } |
---|
| 8 | function blur_tree() |
---|
| 9 | { |
---|
| 10 | if ( window.event && |
---|
| 11 | window.event.srcElement && |
---|
| 12 | window.event.srcElement.blur && |
---|
| 13 | window.event.srcElement != document.body ) |
---|
| 14 | window.event.srcElement.blur(); |
---|
| 15 | else if (target_frame()) |
---|
| 16 | target_frame().window.focus(); |
---|
| 17 | } |
---|
| 18 | document.onclick = blur_tree; |
---|
| 19 | |
---|
| 20 | //--------------Netscape 4.x-specific-----------------------------------------// |
---|
| 21 | |
---|
| 22 | window.saved_width = window.outerWidth; |
---|
| 23 | function reload_tree() |
---|
| 24 | { |
---|
| 25 | if (window.outerWidth != window.saved_width) |
---|
| 26 | window.location.reload(); |
---|
| 27 | } |
---|
| 28 | if (window.Event && Event.RESIZE) { |
---|
| 29 | window.captureEvents(Event.RESIZE); |
---|
| 30 | window.onResize = reload_tree; |
---|
| 31 | } |
---|
| 32 | |
---|
| 33 | //--------------Functions for browser-sniffing--------------------------------// |
---|
| 34 | |
---|
| 35 | function major_version(app) |
---|
| 36 | { |
---|
| 37 | var index = navigator.userAgent.indexOf(app); |
---|
| 38 | if (index == -1) |
---|
| 39 | return -1; |
---|
| 40 | return parseInt(navigator.userAgent.charAt(index + app.length + 1)); |
---|
| 41 | } |
---|
| 42 | function dom_support() |
---|
| 43 | { |
---|
| 44 | if (dom_support.cache == null) |
---|
| 45 | dom_support.cache = dom_support_impl(); |
---|
| 46 | return dom_support.cache; |
---|
| 47 | } |
---|
| 48 | function dom_support_impl() |
---|
| 49 | { |
---|
| 50 | var version; |
---|
| 51 | if ( (version = major_version("Mozilla")) != -1 && |
---|
| 52 | navigator.userAgent.indexOf("compatible") == -1 ) |
---|
| 53 | return version > 4; |
---|
| 54 | if ((version = major_version("Opera")) != -1) |
---|
| 55 | return version > 6; |
---|
| 56 | if ((version = major_version("Konqueror")) != -1) |
---|
| 57 | return version > 2; |
---|
| 58 | if ((version = major_version("Links")) != -1) |
---|
| 59 | return false; |
---|
| 60 | return document.getElementById || document.all; |
---|
| 61 | } |
---|
| 62 | |
---|
| 63 | //--------------Utility functions---------------------------------------------// |
---|
| 64 | |
---|
| 65 | function target_frame() |
---|
| 66 | { |
---|
| 67 | return get_tree() ? top.frames[get_tree().target] : null; |
---|
| 68 | } |
---|
| 69 | function get_tree() { return document.tree_control; } |
---|
| 70 | function static_display() { return !dom_support() || get_tree().dump_html; } |
---|
| 71 | function elt_by_id(id) |
---|
| 72 | { |
---|
| 73 | return document.all ? |
---|
| 74 | document.all[id] : |
---|
| 75 | document.getElementById ? |
---|
| 76 | document.getElementById(id) : |
---|
| 77 | null; |
---|
| 78 | } |
---|
| 79 | function replace_query(url, query) |
---|
| 80 | { |
---|
| 81 | var pos; |
---|
| 82 | if ((pos = url.indexOf("?")) != -1) |
---|
| 83 | url = url.substring(0, pos); |
---|
| 84 | return url + "?" + query; |
---|
| 85 | } |
---|
| 86 | |
---|
| 87 | //--------------Functions for HTML-generation---------------------------------// |
---|
| 88 | |
---|
| 89 | function icon_char(state) |
---|
| 90 | { |
---|
| 91 | return state == tree_node.expanded ? |
---|
| 92 | "-" : |
---|
| 93 | state == tree_node.collapsed ? |
---|
| 94 | "+" : |
---|
| 95 | " "; |
---|
| 96 | } |
---|
| 97 | function html_list(id, display, margin) |
---|
| 98 | { |
---|
| 99 | return "<div id='" + id + "' style='white-space:nowrap;display:" + |
---|
| 100 | display + "'>"; |
---|
| 101 | } |
---|
| 102 | function html_list_item(content) |
---|
| 103 | { |
---|
| 104 | return "\n<div class='tree-item'>" + content + "</div>"; |
---|
| 105 | } |
---|
| 106 | function html_anchor(content, cl, href, target) |
---|
| 107 | { |
---|
| 108 | return "<A class='" + cl + "' onfocus='blur_tree()" + |
---|
| 109 | "' href='" + href + "'" + |
---|
| 110 | (target ? " target='" + target + "'" : "") + |
---|
| 111 | ">" + content + "</A>"; |
---|
| 112 | } |
---|
| 113 | |
---|
| 114 | //--------------Definition of class tree_node---------------------------------// |
---|
| 115 | |
---|
| 116 | function tree_node__add(text_or_node, link_or_hide, hide) |
---|
| 117 | { |
---|
| 118 | if (this.state == tree_node.neutral) |
---|
| 119 | this.state = tree_node.collapsed; |
---|
| 120 | var k; |
---|
| 121 | if (text_or_node.length != null) { |
---|
| 122 | k = new tree_node(text_or_node, link_or_hide); |
---|
| 123 | k.hide_kids = hide != null ? hide : false; |
---|
| 124 | } else { |
---|
| 125 | k = text_or_node; |
---|
| 126 | k.hide_kids = link_or_hide != null ? link_or_hide : false; |
---|
| 127 | } |
---|
| 128 | k.mom = this; |
---|
| 129 | if (this.kids == null) |
---|
| 130 | this.kids = new Array(); |
---|
| 131 | this.kids[this.kids.length] = k; |
---|
| 132 | return k; |
---|
| 133 | } |
---|
| 134 | function tree_node__level() |
---|
| 135 | { |
---|
| 136 | var level; |
---|
| 137 | var node; |
---|
| 138 | for (node = this.mom, level = -1; node; node = node.mom, ++level) |
---|
| 139 | ; |
---|
| 140 | return level; |
---|
| 141 | } |
---|
| 142 | function tree_node__parent() { return this.mom; } |
---|
| 143 | function tree_node__print() |
---|
| 144 | { |
---|
| 145 | var icon = |
---|
| 146 | !static_display() ? |
---|
| 147 | "<span style='font-family:monospace' class='tree-icon' id='icon" + |
---|
| 148 | this.id + "'>" + icon_char(this.state) + "</span> " : |
---|
| 149 | ""; |
---|
| 150 | var handler = |
---|
| 151 | !static_display() && this.kids ? |
---|
| 152 | "javascript:toggle(\"id" + this.id + "\")" : |
---|
| 153 | ""; |
---|
| 154 | var text = "<span class='tree-text'>" + this.text + "</span>" |
---|
| 155 | var tree = get_tree(); |
---|
| 156 | var indent = tree.indent * this.level(); |
---|
| 157 | return html_list_item( |
---|
| 158 | "<div style='margin-left:" + (2 * indent) + |
---|
| 159 | ";text-indent:-" + indent + "'>" + |
---|
| 160 | ( !tree.dump_html ? |
---|
| 161 | this.kids ? |
---|
| 162 | html_anchor(icon, "tree-icon", handler) : |
---|
| 163 | icon : |
---|
| 164 | "" ) + |
---|
| 165 | ( tree.numbered ? |
---|
| 166 | "" + "<span class='tree-label'>" + |
---|
| 167 | this.id.substring(1) + "</span>" : |
---|
| 168 | "" ) + |
---|
| 169 | " " + |
---|
| 170 | ( this.link ? |
---|
| 171 | html_anchor( text, "tree-text", this.link, |
---|
| 172 | tree.target ) : |
---|
| 173 | text ) + |
---|
| 174 | "</div>" + |
---|
| 175 | this.print_kids() |
---|
| 176 | ); |
---|
| 177 | } |
---|
| 178 | function tree_node__print_kids(margin) |
---|
| 179 | { |
---|
| 180 | var result = ""; |
---|
| 181 | if (this.kids != null && (!static_display() || !this.hide_kids)) { |
---|
| 182 | if (margin == null) |
---|
| 183 | margin = get_tree().indent; |
---|
| 184 | result += html_list( "list" + this.id, |
---|
| 185 | this.state == tree_node.collapsed && |
---|
| 186 | !static_display() |
---|
| 187 | ? "none" : "", |
---|
| 188 | margin ); |
---|
| 189 | for (var z = 0; z < this.kids.length; ++z) { |
---|
| 190 | var k = this.kids[z]; |
---|
| 191 | k.id = this.id + "." + (z + 1); |
---|
| 192 | result += k.print(); |
---|
| 193 | } |
---|
| 194 | result += "</div>"; |
---|
| 195 | } |
---|
| 196 | return result; |
---|
| 197 | } |
---|
| 198 | function tree_node__toggle(expand) |
---|
| 199 | { |
---|
| 200 | if ( static_display() || |
---|
| 201 | this.kids == null || |
---|
| 202 | expand != null && expand == |
---|
| 203 | (this.state == tree_node.expanded) ) |
---|
| 204 | { |
---|
| 205 | return; |
---|
| 206 | } |
---|
| 207 | this.state = |
---|
| 208 | this.state == tree_node.expanded ? |
---|
| 209 | tree_node.collapsed : |
---|
| 210 | tree_node.expanded; |
---|
| 211 | elt_by_id("icon" + this.id).innerHTML = |
---|
| 212 | icon_char(this.state); |
---|
| 213 | elt_by_id("list" + this.id).style.display = |
---|
| 214 | this.state == tree_node.expanded ? |
---|
| 215 | "" : |
---|
| 216 | "none"; |
---|
| 217 | } |
---|
| 218 | function add_methods(obj) |
---|
| 219 | { |
---|
| 220 | obj.add = tree_node__add; |
---|
| 221 | obj.level = tree_node__level; |
---|
| 222 | obj.parent = tree_node__parent; |
---|
| 223 | obj.print = tree_node__print; |
---|
| 224 | obj.print_kids = tree_node__print_kids; |
---|
| 225 | obj.toggle = tree_node__toggle; |
---|
| 226 | } |
---|
| 227 | function tree_node(text, link) |
---|
| 228 | { |
---|
| 229 | // Member data |
---|
| 230 | this.text = text; |
---|
| 231 | this.link = link; |
---|
| 232 | this.mom = null; |
---|
| 233 | this.kids = null; |
---|
| 234 | this.id = null; |
---|
| 235 | this.state = 0; // Neutral. |
---|
| 236 | |
---|
| 237 | if (!add_methods.prototype) |
---|
| 238 | add_methods(this); |
---|
| 239 | } |
---|
| 240 | tree_node.neutral = 0; |
---|
| 241 | tree_node.expanded = 1; |
---|
| 242 | tree_node.collapsed = 2; |
---|
| 243 | if (tree_node.prototype) |
---|
| 244 | add_methods(tree_node.prototype); |
---|
| 245 | |
---|
| 246 | //--------------Definition of class tree_control------------------------------// |
---|
| 247 | |
---|
| 248 | function tree_control__add(text, link, hide) |
---|
| 249 | { |
---|
| 250 | return this.root.add(text, link, hide); |
---|
| 251 | } |
---|
| 252 | function tree_control__draw() |
---|
| 253 | { |
---|
| 254 | var tree = get_tree(); |
---|
| 255 | var dom = dom_support(); |
---|
| 256 | var element = dom ? elt_by_id('tree_control') : null; |
---|
| 257 | if (element || !dom || tree.drawn) { |
---|
| 258 | var html = tree.html(); |
---|
| 259 | if (tree.dump_html) { |
---|
| 260 | var pat = new RegExp("<", "g"); |
---|
| 261 | html = "<pre>" + html.replace(pat, "<") + "</pre>"; |
---|
| 262 | if (document.body.innerHTML) |
---|
| 263 | document.body.innerHTML = html; |
---|
| 264 | else |
---|
| 265 | document.write(html); |
---|
| 266 | } else if (dom) { |
---|
| 267 | element.innerHTML = html; |
---|
| 268 | } else { |
---|
| 269 | document.open(); |
---|
| 270 | document.write( |
---|
| 271 | "<body>" + html + |
---|
| 272 | ( major_version("MSIE") == 3 ? |
---|
| 273 | "<noscript>" : |
---|
| 274 | document.layers ? |
---|
| 275 | "<layer visibility='hide'>" : |
---|
| 276 | "<table width=0 height=0 style='" + |
---|
| 277 | "visibility:hidden;display:none'><tr><td>" ) |
---|
| 278 | ); |
---|
| 279 | document.close(); |
---|
| 280 | } |
---|
| 281 | tree.drawn = true; |
---|
| 282 | tree.load(); |
---|
| 283 | } else { |
---|
| 284 | var t = navigator.userAgent.indexOf("Clue") != -1 ? 500 : 100; |
---|
| 285 | setTimeout("tree_control__draw()", t); |
---|
| 286 | } |
---|
| 287 | } |
---|
| 288 | function tree_control__find(id) |
---|
| 289 | { |
---|
| 290 | var indices = id.split("."); |
---|
| 291 | var node = this.root; |
---|
| 292 | for (var z = 1; z < indices.length; ++z) |
---|
| 293 | node = node.kids[indices[z] - 1]; |
---|
| 294 | return node; |
---|
| 295 | } |
---|
| 296 | function tree_control__html() |
---|
| 297 | { |
---|
| 298 | return "<table><tr><td align='left'><table width=150><tr><td>" + |
---|
| 299 | "<h1 class=tree-caption>" + this.caption + "</h1></td></tr>" + |
---|
| 300 | ( !static_display() ? |
---|
| 301 | "<tr><td><p class='tree-sync'><a title='reload current " + |
---|
| 302 | "page with a url suitable for bookmarking' class=" + |
---|
| 303 | "'tree-sync' href='javascript:get_tree().sync()'>" + |
---|
| 304 | "[link to this page]</a></p></td></tr>" : |
---|
| 305 | "" ) + |
---|
| 306 | "</table></td></tr><tr><td>" + this.root.print_kids(0) + |
---|
| 307 | "</td></tr></table>"; |
---|
| 308 | } |
---|
| 309 | function load_target(url) |
---|
| 310 | { |
---|
| 311 | var target; |
---|
| 312 | if ((target = target_frame()) && target.location.href != url) |
---|
| 313 | target.location.replace(url); |
---|
| 314 | else { |
---|
| 315 | setTimeout("load_target('" + url + "')", 100); |
---|
| 316 | } |
---|
| 317 | } |
---|
| 318 | function tree_control__load() |
---|
| 319 | { |
---|
| 320 | var query; |
---|
| 321 | if ((query = top.location.search).length == 0) |
---|
| 322 | return; |
---|
| 323 | query = query.substring(1); |
---|
| 324 | var eq; |
---|
| 325 | if ((eq = query.indexOf("=")) != -1) { |
---|
| 326 | if (query.substring(0, 4) == "page") { |
---|
| 327 | load_target(unescape(query.substring(eq + 1))); |
---|
| 328 | return; |
---|
| 329 | } |
---|
| 330 | query = query.substring(eq + 1); |
---|
| 331 | } |
---|
| 332 | var indices = query.split("."); |
---|
| 333 | if (!indices.length) |
---|
| 334 | return; |
---|
| 335 | this.reset(); |
---|
| 336 | var node = this.root; |
---|
| 337 | for (var z = 0; z < indices.length; ++z) { |
---|
| 338 | var i = parseInt(indices[z]) - 1; |
---|
| 339 | if (!node.kids || i < 0 || node.kids.length <= i) |
---|
| 340 | break; |
---|
| 341 | node = node.kids[i]; |
---|
| 342 | node.toggle(/*z != indices.length - 1*/); |
---|
| 343 | } |
---|
| 344 | if (node.link) |
---|
| 345 | load_target(node.link); |
---|
| 346 | } |
---|
| 347 | function tree_control__recurse(op) |
---|
| 348 | { |
---|
| 349 | var stack = new Array(); |
---|
| 350 | stack[stack.length] = this.root; |
---|
| 351 | while (stack.length) { |
---|
| 352 | var node = stack[stack.length - 1]; |
---|
| 353 | stack.length -=1 ; // Konqueror 2. |
---|
| 354 | op(node); |
---|
| 355 | if (node.kids) |
---|
| 356 | for (var z = 0; z < node.kids.length; ++z) |
---|
| 357 | stack[stack.length] = node.kids[z]; |
---|
| 358 | } |
---|
| 359 | } |
---|
| 360 | function tree_control__reset() |
---|
| 361 | { |
---|
| 362 | if (!dom_support()) |
---|
| 363 | return; |
---|
| 364 | this.recurse(new Function("x", "if (x.parent()) x.toggle(false);")); |
---|
| 365 | } |
---|
| 366 | function sync_node(node) |
---|
| 367 | { |
---|
| 368 | if (!node.link) |
---|
| 369 | return; |
---|
| 370 | var tgt = target_frame().location.href; |
---|
| 371 | var pos; |
---|
| 372 | if ((pos = tgt.indexOf("?")) != -1) |
---|
| 373 | tgt = tgt.substring(0, pos); |
---|
| 374 | if (node.link.indexOf("://") != -1) { |
---|
| 375 | if (node.link != tgt) |
---|
| 376 | return; |
---|
| 377 | } else { |
---|
| 378 | var base = window.location.href; |
---|
| 379 | if ((pos = base.lastIndexOf("/")) != -1) |
---|
| 380 | base = base.substring(0, pos + 1); |
---|
| 381 | if (base + node.link != tgt) |
---|
| 382 | return; |
---|
| 383 | } |
---|
| 384 | window.success = true; |
---|
| 385 | var href = replace_query( get_tree().top_url, |
---|
| 386 | "path=" + node.id.substring(1) ); |
---|
| 387 | top.location.replace(href); |
---|
| 388 | } |
---|
| 389 | function tree_control__sync() |
---|
| 390 | { |
---|
| 391 | if (!dom_support() || self == top) |
---|
| 392 | return; |
---|
| 393 | window.success = false; |
---|
| 394 | get_tree().recurse(sync_node); |
---|
| 395 | if (!window.success) |
---|
| 396 | top.location.replace( |
---|
| 397 | replace_query( get_tree().top_url, |
---|
| 398 | "page=" + escape(target_frame().location.href) ) |
---|
| 399 | ); |
---|
| 400 | } |
---|
| 401 | function tree_control(target) |
---|
| 402 | { |
---|
| 403 | // Member data |
---|
| 404 | this.root = new tree_node(""); |
---|
| 405 | this.target = target ? target : "_self"; |
---|
| 406 | this.dump_html = false; |
---|
| 407 | this.caption = "Contents"; |
---|
| 408 | this.numbered = true; |
---|
| 409 | this.indent = 15; |
---|
| 410 | this.drawn = false; |
---|
| 411 | this.top_url = top.location.href; // For Opera. |
---|
| 412 | |
---|
| 413 | this.root.state = tree_node.expanded; |
---|
| 414 | this.root.id = ""; |
---|
| 415 | |
---|
| 416 | // Member functions |
---|
| 417 | this.add = tree_control__add; |
---|
| 418 | this.draw = tree_control__draw; |
---|
| 419 | this.find = tree_control__find; |
---|
| 420 | this.html = tree_control__html; |
---|
| 421 | this.load = tree_control__load; |
---|
| 422 | this.recurse = tree_control__recurse; |
---|
| 423 | this.reset = tree_control__reset; |
---|
| 424 | this.sync = tree_control__sync; |
---|
| 425 | document.tree_control = this; |
---|
| 426 | } |
---|
| 427 | tree_control.sync = tree_control__sync; |
---|