/ddoc/candydoc/explorer.js

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