/ddoc/candydoc/explorer.js
JavaScript | 305 lines | 225 code | 53 blank | 27 comment | 54 complexity | 383e8c672290e1edf3a1d1dc45c38f44 MD5 | raw file
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 explorer window. 5 And things related to navigation. */ 6 7var explorer = new Explorer(); 8 9/////////////////////////////////////////////////////////////////////////////// 10// Current symbol marker class constructor 11/////////////////////////////////////////////////////////////////////////////// 12function Marker() 13{ 14 this.top = document.createElement("div"); 15 this.middle = document.createElement("div"); 16 this.bottom = document.createElement("div"); 17 this.container = document.createElement("div"); 18 19 this.setTo = function(term) 20 { 21 // find definition related to `term` 22 var def = term.nextSibling; 23 while (def && def.nodeName != "DD") 24 def = def.nextSibling; 25 26 var defHeight = 0; 27 var childrenHeight = 0; // children of current declaration 28 if (def) 29 { 30 defHeight = def.offsetHeight; 31 var child = def.firstChild; 32 33 // traverse until DL tag, until children definition 34 while (child && child.nodeName != "DL") 35 child = child.nextSibling; 36 37 if (child) 38 childrenHeight = child.offsetHeight; 39 } 40 41 this.top.style.height = term.offsetHeight; 42 this.middle.style.height = defHeight - childrenHeight; 43 this.bottom.style.height = childrenHeight; 44 45 if (childrenHeight == 0) 46 this.bottom.style.display = "none"; 47 else 48 this.bottom.style.display = ""; 49 50 this.container.style.left = getLeft(term) - 8; 51 this.container.style.top = getTop(term); 52 this.container.style.display = ""; 53 } 54 55 /////////////////////////////////////////////////////////////////////////// 56 this.container.style.position = "absolute"; 57 this.container.style.display = "none"; 58 59 this.top.className = "markertop"; 60 this.middle.className = "markermiddle"; 61 this.bottom.className = "markerbottom"; 62 63 this.container.appendChild(this.top); 64 this.container.appendChild(this.middle); 65 this.container.appendChild(this.bottom); 66 67 //document.body.appendChild( this.container ); 68 69 // Workaround bug in IE 5/6. We can not append anything to document body until 70 // full page load. 71 window.marker = this; 72 if (window.addEventListener) 73 window.addEventListener("load", new Function("document.body.appendChild( window.marker.container );"), false); 74 else if (window.attachEvent) 75 window.attachEvent("onload", new Function("document.body.appendChild( window.marker.container );")); 76} 77 78/////////////////////////////////////////////////////////////////////////////// 79// Outline class constructor 80/////////////////////////////////////////////////////////////////////////////// 81function Outline() 82{ 83 this.tree = new TreeView(); 84 this.mountPoint = null; 85 this.writeEnabled = false; 86 this.marker = new Marker(); 87 this.classRegExp = new RegExp; 88 this.structRegExp = new RegExp; 89 this.enumRegExp = new RegExp; 90 this.templateRegExp = new RegExp; 91 this.aliasRegExp = new RegExp; 92 this.funcRegExp = new RegExp; 93 94 this.incSymbolLevel = function() 95 { 96 if (this.mountPoint == null) 97 this.mountPoint = this.tree.children[ 0 ]; 98 else 99 this.mountPoint = this.mountPoint.lastChild(); 100 } 101 102 this.decSymbolLevel = function() 103 { 104 // place icons near items according to extracted below type 105 for (var i = 0; i < this.mountPoint.children.length; ++i) 106 { 107 child = this.mountPoint.children[i]; 108 var term = child.termRef; 109 110 // find first span node 111 var n = term.firstChild; 112 while (n && n.nodeName != "SPAN") 113 n = n.nextSibling; 114 115 if (!n) // shouldn't happen 116 continue; 117 118 var iconSrc; 119 if (n.firstChild.nodeName == "#text") 120 { 121 var text = n.firstChild.data; // text before declaration 122 123 if ( this.classRegExp.test(text) ) 124 iconSrc = "candydoc/img/outline/class.gif"; 125 else if ( this.structRegExp.test(text) ) 126 iconSrc = "candydoc/img/outline/struct.gif"; 127 else if ( this.enumRegExp.test(text) ) 128 iconSrc = "candydoc/img/outline/enum.gif"; 129 else if ( this.templateRegExp.test(text) ) 130 iconSrc = "candydoc/img/outline/template.gif"; 131 else if ( this.aliasRegExp.test(text) ) 132 iconSrc = "candydoc/img/outline/alias.gif"; 133 else // function or variable? check whether '(' ')' exists on the right 134 { 135 var np = n.firstChild; 136 while (np && np.nodeName != "SCRIPT") // find our script "onDecl" 137 np = np.nextSibling; 138 139 if (np && np.nextSibling && np.nextSibling.nodeName == "#text" && 140 this.funcRegExp.test(np.nextSibling.data)) 141 { 142 iconSrc = "candydoc/img/outline/func.gif"; 143 } 144 else 145 iconSrc = "candydoc/img/outline/var.gif"; 146 } 147 } 148 else // enum member ? 149 iconSrc = "candydoc/img/outline/var.gif"; 150 151 child.icon.src = iconSrc; 152 child.icon.width = 16; 153 child.icon.height = 16; 154 } 155 156 this.mountPoint = this.mountPoint.parentNode; 157 } 158 159 this.addDecl = function(decl) 160 { 161 function getLastLeaf(elem) 162 { 163 if (elem.childNodes.length > 0) 164 return getLastLeaf(elem.lastChild); 165 else 166 return elem; 167 } 168 169 function getCurrentTerm() 170 { 171 var ret = getLastLeaf( document.getElementById("content") ); 172 while (ret && ret.nodeName != "DT") 173 ret = ret.parentNode; 174 175 return ret; 176 } 177 178 if (this.writeEnabled) 179 { 180 var node = this.mountPoint.createChild(decl); 181 node.termRef = getCurrentTerm(); 182 node.setOnclick( new Function("explorer.outline.mark(this.termRef);") ); 183 } 184 } 185 186 this.mark = function(term) 187 { 188 this.marker.setTo(term); 189 window.scrollTo(0, getTop(term) - getWindowHeight() / 6); 190 } 191 192 193 this.classRegExp.compile("(.*\b)?class(\b.*)?"); 194 this.structRegExp.compile("(.*\b)?struct(\b.*)?"); 195 this.enumRegExp.compile("(.*\b)?enum(\b.*)?"); 196 this.templateRegExp.compile("(.*\b)?template(\b.*)?"); 197 this.aliasRegExp.compile("(.*\b)?alias(\b.*)?"); 198 this.funcRegExp.compile(/.*\(.*/); 199} 200 201 202 203 204/////////////////////////////////////////////////////////////////////////////// 205// Package explorer class constructor 206/////////////////////////////////////////////////////////////////////////////// 207function PackageExplorer() 208{ 209 this.tree = new TreeView(true); 210 211 this.addModule = function(mod) 212 { 213 var moduleIco = "candydoc/img/outline/module.gif"; 214 var packageIco = "candydoc/img/outline/package.gif"; 215 216 var path = mod.split("\."); 217 var node = this.tree.branch(path[0]); 218 if ( !node ) 219 node = this.tree.createBranch(path[0], (path.length == 1) ? moduleIco : packageIco); 220 221 for (var i = 1; i < path.length; ++i) 222 { 223 var prev = node; 224 node = node.child(path[i]); 225 if (!node) 226 node = prev.createChild(path[i], (path.length == i + 1) ? moduleIco : packageIco); 227 228 if (path.length == i + 1) 229 node.setRef(path[i] + ".html"); 230 } 231 } 232} 233 234 235 236/////////////////////////////////////////////////////////////////////////////// 237// Explorer class constructor 238/////////////////////////////////////////////////////////////////////////////// 239function Explorer() 240{ 241 this.outline = new Outline(); 242 this.packageExplorer = new PackageExplorer(); 243 this.tabs = new Array(); 244 this.tabCount = 0; 245 246 this.initialize = function(moduleName) 247 { 248 this.tabArea = document.getElementById("tabarea"); 249 this.clientArea = document.getElementById("explorerclient"); 250 251 // prevent text selection 252 this.tabArea.onmousedown = new Function("return false;"); 253 this.tabArea.onclick = new Function("return true;"); 254 this.tabArea.onselectstart = new Function("return false;"); 255 this.clientArea.onmousedown = new Function("return false;"); 256 this.clientArea.onclick = new Function("return true;"); 257 this.clientArea.onselectstart = new Function("return false;"); 258 259 this.outline.tree.createBranch( moduleName, "candydoc/img/outline/module.gif" ); 260 261 // create tabs 262 this.createTab("Outline", this.outline.tree.domEntry); 263 this.createTab("Package", this.packageExplorer.tree.domEntry); 264 } 265 266 this.createTab = function(name, domEntry) 267 { 268 var tab = new Object(); 269 this.tabs[name] = tab; 270 this.tabCount++; 271 272 tab.domEntry = domEntry; 273 tab.labelSpan = document.createElement("span"); 274 275 if (this.tabCount > 1) 276 { 277 tab.labelSpan.className = "inactivetab"; 278 tab.domEntry.style.display = "none"; 279 } 280 else 281 { 282 tab.labelSpan.className = "activetab"; 283 tab.domEntry.style.display = ""; 284 } 285 286 tab.labelSpan.appendChild( document.createTextNode(name) ); 287 tab.labelSpan.owner = this; 288 tab.labelSpan.onclick = new Function("this.owner.setSelection('" + name + "');"); 289 290 this.tabArea.appendChild( tab.labelSpan ); 291 this.clientArea.appendChild( domEntry ); 292 } 293 294 this.setSelection = function(tabName) 295 { 296 for (name in this.tabs) 297 { 298 this.tabs[name].labelSpan.className = "inactivetab"; 299 this.tabs[name].domEntry.style.display = "none"; 300 } 301 302 this.tabs[tabName].labelSpan.className = "activetab"; 303 this.tabs[tabName].domEntry.style.display = ""; 304 } 305}