/* This file is a part of CanDyDOC fileset. File is written by Victor Nakoryakov and placed into the public domain. This file is javascript with classes that represents explorer window. And things related to navigation. */ var explorer = new Explorer(); /////////////////////////////////////////////////////////////////////////////// // Current symbol marker class constructor /////////////////////////////////////////////////////////////////////////////// function Marker() { this.top = document.createElement("div"); this.middle = document.createElement("div"); this.bottom = document.createElement("div"); this.container = document.createElement("div"); this.setTo = function(term) { // find definition related to `term` var def = term.nextSibling; while (def && def.nodeName != "DD") def = def.nextSibling; var defHeight = 0; var childrenHeight = 0; // children of current declaration if (def) { defHeight = def.offsetHeight; var child = def.firstChild; // traverse until DL tag, until children definition while (child && child.nodeName != "DL") child = child.nextSibling; if (child) childrenHeight = child.offsetHeight; } this.top.style.height = term.offsetHeight; this.middle.style.height = defHeight - childrenHeight; this.bottom.style.height = childrenHeight; if (childrenHeight == 0) this.bottom.style.display = "none"; else this.bottom.style.display = ""; this.container.style.left = getLeft(term) - 8; this.container.style.top = getTop(term); this.container.style.display = ""; } /////////////////////////////////////////////////////////////////////////// this.container.style.position = "absolute"; this.container.style.display = "none"; this.top.className = "markertop"; this.middle.className = "markermiddle"; this.bottom.className = "markerbottom"; this.container.appendChild(this.top); this.container.appendChild(this.middle); this.container.appendChild(this.bottom); //document.body.appendChild( this.container ); // Workaround bug in IE 5/6. We can not append anything to document body until // full page load. window.marker = this; if (window.addEventListener) window.addEventListener("load", new Function("document.body.appendChild( window.marker.container );"), false); else if (window.attachEvent) window.attachEvent("onload", new Function("document.body.appendChild( window.marker.container );")); } /////////////////////////////////////////////////////////////////////////////// // Outline class constructor /////////////////////////////////////////////////////////////////////////////// function Outline() { this.tree = new TreeView(); this.mountPoint = null; this.writeEnabled = false; this.marker = new Marker(); this.classRegExp = new RegExp; this.structRegExp = new RegExp; this.enumRegExp = new RegExp; this.templateRegExp = new RegExp; this.aliasRegExp = new RegExp; this.funcRegExp = new RegExp; this.incSymbolLevel = function() { if (this.mountPoint == null) this.mountPoint = this.tree.children[ 0 ]; else this.mountPoint = this.mountPoint.lastChild(); } this.decSymbolLevel = function() { // place icons near items according to extracted below type for (var i = 0; i < this.mountPoint.children.length; ++i) { child = this.mountPoint.children[i]; var term = child.termRef; // find first span node var n = term.firstChild; while (n && n.nodeName != "SPAN") n = n.nextSibling; if (!n) // shouldn't happen continue; var iconSrc; if (n.firstChild.nodeName == "#text") { var text = n.firstChild.data; // text before declaration if ( this.classRegExp.test(text) ) iconSrc = "candydoc/img/outline/class.gif"; else if ( this.structRegExp.test(text) ) iconSrc = "candydoc/img/outline/struct.gif"; else if ( this.enumRegExp.test(text) ) iconSrc = "candydoc/img/outline/enum.gif"; else if ( this.templateRegExp.test(text) ) iconSrc = "candydoc/img/outline/template.gif"; else if ( this.aliasRegExp.test(text) ) iconSrc = "candydoc/img/outline/alias.gif"; else // function or variable? check whether '(' ')' exists on the right { var np = n.firstChild; while (np && np.nodeName != "SCRIPT") // find our script "onDecl" np = np.nextSibling; if (np && np.nextSibling && np.nextSibling.nodeName == "#text" && this.funcRegExp.test(np.nextSibling.data)) { iconSrc = "candydoc/img/outline/func.gif"; } else iconSrc = "candydoc/img/outline/var.gif"; } } else // enum member ? iconSrc = "candydoc/img/outline/var.gif"; child.icon.src = iconSrc; child.icon.width = 16; child.icon.height = 16; } this.mountPoint = this.mountPoint.parentNode; } this.addDecl = function(decl) { function getLastLeaf(elem) { if (elem.childNodes.length > 0) return getLastLeaf(elem.lastChild); else return elem; } function getCurrentTerm() { var ret = getLastLeaf( document.getElementById("content") ); while (ret && ret.nodeName != "DT") ret = ret.parentNode; return ret; } if (this.writeEnabled) { var node = this.mountPoint.createChild(decl); node.termRef = getCurrentTerm(); node.setOnclick( new Function("explorer.outline.mark(this.termRef);") ); } } this.mark = function(term) { this.marker.setTo(term); window.scrollTo(0, getTop(term) - getWindowHeight() / 6); } this.classRegExp.compile("(.*\b)?class(\b.*)?"); this.structRegExp.compile("(.*\b)?struct(\b.*)?"); this.enumRegExp.compile("(.*\b)?enum(\b.*)?"); this.templateRegExp.compile("(.*\b)?template(\b.*)?"); this.aliasRegExp.compile("(.*\b)?alias(\b.*)?"); this.funcRegExp.compile(/.*\(.*/); } /////////////////////////////////////////////////////////////////////////////// // Package explorer class constructor /////////////////////////////////////////////////////////////////////////////// function PackageExplorer() { this.tree = new TreeView(true); this.addModule2 = function(mod, full) { var moduleIco = "candydoc/img/outline/module.gif"; var packageIco = "candydoc/img/outline/package.gif"; var path = mod.split("\."); var node = this.tree.branch(path[0]); if ( !node ) node = this.tree.createBranch(path[0], (path.length == 1) ? moduleIco : packageIco); for (var i = 1; i < path.length; ++i) { var prev = node; node = node.child(path[i]); if (!node) node = prev.createChild(path[i], (path.length == i + 1) ? moduleIco : packageIco); if (path.length == i + 1) { if (full) node.setRef(mod + ".html"); else node.setRef(path[i] + ".html"); } } } this.addModuleFull = function(mod) { this.addModule2(mod, true); } this.addModule = function(mod) { this.addModule2(mod, false); } } /////////////////////////////////////////////////////////////////////////////// // Explorer class constructor /////////////////////////////////////////////////////////////////////////////// function Explorer() { this.outline = new Outline(); this.packageExplorer = new PackageExplorer(); this.tabs = new Array(); this.tabCount = 0; this.initialize = function(moduleName) { this.tabArea = document.getElementById("tabarea"); this.clientArea = document.getElementById("explorerclient"); // prevent text selection this.tabArea.onmousedown = new Function("return false;"); this.tabArea.onclick = new Function("return true;"); this.tabArea.onselectstart = new Function("return false;"); this.clientArea.onmousedown = new Function("return false;"); this.clientArea.onclick = new Function("return true;"); this.clientArea.onselectstart = new Function("return false;"); this.outline.tree.createBranch( moduleName, "candydoc/img/outline/module.gif" ); // create tabs this.createTab("Outline", this.outline.tree.domEntry); this.createTab("Package", this.packageExplorer.tree.domEntry); } this.createTab = function(name, domEntry) { var tab = new Object(); this.tabs[name] = tab; this.tabCount++; tab.domEntry = domEntry; tab.labelSpan = document.createElement("span"); if (this.tabCount > 1) { tab.labelSpan.className = "inactivetab"; tab.domEntry.style.display = "none"; } else { tab.labelSpan.className = "activetab"; tab.domEntry.style.display = ""; } tab.labelSpan.appendChild( document.createTextNode(name) ); tab.labelSpan.owner = this; tab.labelSpan.onclick = new Function("this.owner.setSelection('" + name + "');"); this.tabArea.appendChild( tab.labelSpan ); this.clientArea.appendChild( domEntry ); } this.setSelection = function(tabName) { for (name in this.tabs) { this.tabs[name].labelSpan.className = "inactivetab"; this.tabs[name].domEntry.style.display = "none"; } this.tabs[tabName].labelSpan.className = "activetab"; this.tabs[tabName].domEntry.style.display = ""; } }