Artifact 9da5605d97dbb6357d7254002ef64e5227d51db2
/* 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.addModule = function(mod)
{
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);
// modified by k.inaba : link for toplevel module
if (path.length == 1)
node.setRef(path[0] + ".html");
}
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)
node.setRef(path[i] + ".html");
}
}
}
///////////////////////////////////////////////////////////////////////////////
// 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 = "";
}
}