PageRenderTime 57ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/lib.old/generate.php

https://github.com/lbod/api-viewer
PHP | 1356 lines | 1100 code | 116 blank | 140 comment | 234 complexity | ed8472c28f351096dd607b1ccf71658c MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /* generate_html.php
  3. * TRT 2010-02-03
  4. *
  5. * Given the page and version, generate the HTML fragment
  6. * and return it.
  7. */
  8. include("markdown/markdown.php");
  9. function convert_type($type){
  10. $base = 'object';
  11. switch($type){
  12. case 'Namespace':
  13. case 'namespace': $base='namespace'; break;
  14. case 'Constructor': $base='constructor'; break;
  15. case 'Node':
  16. case 'DOMNode':
  17. case 'DomNode': $base='domnode'; break;
  18. case 'Array': $base='array'; break;
  19. case 'Boolean': $base='boolean'; break;
  20. case 'Date': $base='date'; break;
  21. case 'Error': $base='error'; break;
  22. case 'Function': $base='function'; break;
  23. case 'Integer':
  24. case 'Float':
  25. case 'int':
  26. case 'Double':
  27. case 'integer':
  28. case 'Number': $base='number'; break;
  29. case 'RegExp': $base='regexp'; break;
  30. case 'String': $base='string'; break;
  31. default: $base='object'; break;
  32. }
  33. return $base;
  34. }
  35. function icon_url($type, $size=16){
  36. $img = "object";
  37. switch($type){
  38. case 'Namespace':
  39. case 'namespace': $img='namespace'; break;
  40. case 'Constructor': $img='constructor'; break;
  41. case 'Node':
  42. case 'DOMNode':
  43. case 'DomNode': $img='domnode'; break;
  44. case 'Array': $img='array'; break;
  45. case 'Boolean': $img='boolean'; break;
  46. case 'Date': $img='date'; break;
  47. case 'Error': $img='error'; break;
  48. case 'Function': $img='function'; break;
  49. case 'Integer':
  50. case 'Float':
  51. case 'int':
  52. case 'Double':
  53. case 'integer':
  54. case 'Number': $img='number'; break;
  55. case 'RegExp': $img='regexp'; break;
  56. case 'String': $img='string'; break;
  57. default: $img='object'; break;
  58. }
  59. return 'css/icons/' . $size . 'x' . $size . '/' . $img . '.png';
  60. }
  61. function do_markdown($text){
  62. // prep the text and run it through the Markdown parser.
  63. $lines = explode("\n", $text);
  64. $fixed = array();
  65. $b = false;
  66. foreach($lines as $line){
  67. // pull off the preceding tab.
  68. $s = $line;
  69. if(strpos($line, "\t")===0){ $s = substr($s, 1); }
  70. // deal with the munging of lists in the markdown.
  71. if(preg_match('/(\t)*\*/', $s)){
  72. if(!$b){
  73. $b = true;
  74. $s = "\n" . $s;
  75. }
  76. } else {
  77. $b = false;
  78. }
  79. $fixed[] = $s;
  80. }
  81. $str = Markdown(implode("\n", $fixed));
  82. return $str;
  83. }
  84. function format_example($text){
  85. // do this for SyntaxHighlighter use.
  86. $s = ""; // */ "\n<!--\n" . $text . "\n-->\n";
  87. // insert an additional tab if the first character is a tab.
  88. if(strpos($text, "\t")===0){
  89. $text = "\t" . $text;
  90. }
  91. $lines = explode("\n", "\n" . $text);
  92. $isCode = false;
  93. foreach($lines as &$line){
  94. if(strpos($line, "\t")===0){
  95. $line = htmlentities(substr($line, 1)); // always pull off the first tab.
  96. }
  97. if(strpos($line, "\t")===0){
  98. if(!$isCode){
  99. $isCode = true;
  100. $line = '<pre class="brush: js;" lang="javascript">' . "\n" . $line;
  101. }
  102. } else {
  103. if($isCode){
  104. $isCode = false;
  105. $line .= '</pre>';
  106. }
  107. }
  108. }
  109. if($isCode){
  110. // probably we never saw the last line, or the last line was code.
  111. $lines[] = '</pre>';
  112. }
  113. return $s . implode("\n", $lines);
  114. }
  115. // BEGIN array_filter functions
  116. function is_event($item){
  117. $public = strpos($item["name"], "on");
  118. $private = strpos($item["name"], "_on");
  119. return $public === 0 || $private === 0;
  120. }
  121. function is_method($item){
  122. $public = strpos($item["name"], "on");
  123. $private = strpos($item["name"], "_on");
  124. return $public !== 0 && $private !== 0;
  125. }
  126. function is_static($item){
  127. return $item["scope"] == "normal";
  128. }
  129. function is_not_static($item){
  130. return $item["scope"] != "normal";
  131. }
  132. function is_not_from_Object($item){
  133. return !(count($item["defines"]) == 1 && $item["defines"][0] == "Object");
  134. }
  135. function is_not_node($item){
  136. $obj = strtolower($item);
  137. return !strpos($obj, "node") && !strpos($obj, "style") && !strpos($obj, "__");
  138. }
  139. // END array_filter functions
  140. function load_docs($version){
  141. // helper function to load up the XML docs we need.
  142. global $dataDir;
  143. $data_dir = $dataDir . $version . "/";
  144. // load up the doc.
  145. $provides = "provides.xml";
  146. $resources = "resources.xml";
  147. $details = "details.xml";
  148. $f = $data_dir . $details;
  149. if(!file_exists($f)){
  150. echo "API data does not exist for the version: " . $version . "<br/>";
  151. exit();
  152. }
  153. $xml = new DOMDocument();
  154. $xml->load($f);
  155. $p_xml = new DOMDocument();
  156. $p_xml->load($data_dir . $provides);
  157. $r_xml = new DOMDocument();
  158. $r_xml->load($data_dir . $resources);
  159. $xpath = new DOMXPath($xml);
  160. $p_xpath = new DOMXPath($p_xml);
  161. $r_xpath = new DOMXPath($r_xml);
  162. $docs = array(
  163. "xml"=>$xml,
  164. "p_xml"=>$p_xml,
  165. "r_xml"=>$r_xml,
  166. "xpath"=>$xpath,
  167. "p_xpath"=>$p_xpath,
  168. "r_xpath"=>$r_xpath
  169. );
  170. return $docs;
  171. }
  172. function read_object_fields($page, $version, $docs=array()){
  173. // for the given page, grab any mixins and assemble a "flat" version of it (no prototype walking).
  174. // create a PHP-based associative array structure out of the page in question.
  175. if(!count($docs)){
  176. $docs = load_docs($version);
  177. }
  178. $xml = $docs["xml"];
  179. $p_xml = $docs["p_xml"];
  180. $r_xml = $docs["r_xml"];
  181. $xpath = $docs["xpath"];
  182. $p_xpath = $docs["p_xpath"];
  183. $r_xpath = $docs["r_xpath"];
  184. // get the XML for the page.
  185. $context = $xpath->query('//object[@location="' . $page . '"]')->item(0);
  186. if(!$context){
  187. // we got nothing, just return null.
  188. return null;
  189. }
  190. // get any mixins, and ignore if the mixin == superclass. Note that we're going to ignore any prototype mixins,
  191. // as they are (in general) applied in the same way as instance mixins.
  192. $mixinNodes = $xpath->query('mixins/mixin[@scope="instance"]', $context);
  193. $mixins = array();
  194. foreach($mixinNodes as $m){
  195. // test 1: make sure the mixin is not the superclass.
  196. if($m->getAttribute("location") == $context->getAttribute("superclass")){
  197. continue;
  198. }
  199. // test 2: make sure we can actually read the mixin definition
  200. $m_test = $xpath->query("//object[@location='" . $m->getAttribute("location") . "']");
  201. if($m_test->length){
  202. $mixins[$m->getAttribute("location")] = $m_test->item(0);
  203. }
  204. }
  205. // push in our page.
  206. $mixins[$page] = $context;
  207. $props = array();
  208. $methods = array();
  209. foreach($mixins as $location=>$node){
  210. // properties
  211. $nl = $xpath->query("properties/property", $node);
  212. foreach($nl as $n){
  213. $nm = $n->getAttribute("name");
  214. $private = $n->getAttribute("private") == "true";
  215. if(!$private && strpos($nm, "_")===0){
  216. $private = true;
  217. }
  218. if(array_key_exists($nm, $props)){
  219. // next one up in the chain overrides the original.
  220. $props[$nm]["scope"] = $n->getAttribute("scope");
  221. $props[$nm]["type"] = $n->getAttribute("type");
  222. $props[$nm]["override"] = true;
  223. $props[$nm]["defines"][] = $location;
  224. } else {
  225. $props[$nm] = array(
  226. "name"=>$nm,
  227. "scope"=>$n->getAttribute("scope"),
  228. "visibility"=>($private == true ? "private" : "public"),
  229. "type"=>$n->getAttribute("type"),
  230. "defines"=>array($location),
  231. "override"=>false
  232. );
  233. }
  234. if($n->getElementsByTagName("summary")->length){
  235. $desc = trim($n->getElementsByTagName("summary")->item(0)->nodeValue);
  236. if(strlen($desc)){
  237. $props[$nm]["summary"] = $desc;
  238. }
  239. }
  240. if($n->getElementsByTagName("description")->length){
  241. $desc = trim($n->getElementsByTagName("description")->item(0)->nodeValue);
  242. if(strlen($desc)){
  243. $props[$nm]["description"] = do_markdown($desc);
  244. }
  245. }
  246. }
  247. // methods
  248. $nl = $xpath->query("methods/method", $node);
  249. foreach($nl as $n){
  250. $nm = $n->getAttribute("name");
  251. $private = $n->getAttribute("private") == "true";
  252. if(!$private && strpos($nm, "_")===0){
  253. $private = true;
  254. }
  255. if(!strlen($nm)){
  256. $nm = "constructor";
  257. }
  258. if(array_key_exists($nm, $methods)){
  259. // next one up in the chain overrides the original.
  260. $methods[$nm]["scope"] = $n->getAttribute("scope");
  261. $methods[$nm]["override"] = true;
  262. $methods[$nm]["defines"][] = $location;
  263. if($n->getAttribute("constructor") == "constructor"){
  264. $methods[$nm]["constructor"] = true;
  265. $methods[$nm]["scope"] = "prototype";
  266. }
  267. } else {
  268. $methods[$nm] = array(
  269. "name"=>$nm,
  270. "scope"=>$n->getAttribute("scope"),
  271. "visibility"=>($private=="true"?"private":"public"),
  272. "parameters"=>array(),
  273. "return-types"=>array(),
  274. "defines"=>array($location),
  275. "override"=>false,
  276. "constructor"=>$n->getAttribute("constructor")=="constructor"
  277. );
  278. }
  279. if($n->getElementsByTagName("summary")->length){
  280. $desc = trim($n->getElementsByTagName("summary")->item(0)->nodeValue);
  281. if(strlen($desc)){
  282. $methods[$nm]["summary"] = $desc;
  283. }
  284. }
  285. if($n->getElementsByTagName("description")->length){
  286. $desc = trim($n->getElementsByTagName("description")->item(0)->nodeValue);
  287. if(strlen($desc)){
  288. $methods[$nm]["description"] = do_markdown($desc);
  289. }
  290. }
  291. $ex = $n->getElementsByTagName("example");
  292. if($ex->length){
  293. if(!array_key_exists("examples", $methods[$nm])){
  294. $methods[$nm]["examples"] = array();
  295. }
  296. foreach($ex as $example){
  297. $methods[$nm]["examples"][] = $example->nodeValue;
  298. }
  299. }
  300. if($n->getElementsByTagName("return-description")->length){
  301. $desc = trim($n->getElementsByTagName("return-description")->item(0)->nodeValue);
  302. if(strlen($desc)){
  303. $methods[$nm]["return-description"] = $desc;
  304. }
  305. }
  306. // do up the parameters and the return types.
  307. $params = $xpath->query("parameters/parameter", $n);
  308. if($params->length){
  309. // TODO: double-check that the XML will always have this.
  310. $methods[$nm]["parameters"] = array();
  311. foreach($params as $param){
  312. $item = array(
  313. "name"=>$param->getAttribute("name"),
  314. "type"=>$param->getAttribute("type"),
  315. "usage"=>$param->getAttribute("usage"),
  316. "description"=>""
  317. );
  318. if($param->getElementsByTagName("summary")->length){
  319. $desc = trim($param->getElementsByTagName("summary")->item(0)->nodeValue);
  320. if(strlen($desc)){
  321. $item["description"] = $desc;
  322. }
  323. }
  324. $methods[$nm]["parameters"][] = $item;
  325. }
  326. }
  327. if($nm == "constructor"){
  328. $methods[$nm]["return-types"] = array();
  329. $methods[$nm]["return-types"][] = array(
  330. "type"=>$location,
  331. "description"=>""
  332. );
  333. } else {
  334. $rets = $xpath->query("return-types/return-type", $n);
  335. if($rets->length){
  336. // TODO: double-check that the XML will always have this.
  337. $methods[$nm]["return-types"] = array();
  338. foreach($rets as $ret){
  339. $item = array(
  340. "type"=>$ret->getAttribute("type"),
  341. "description"=>""
  342. );
  343. $methods[$nm]["return-types"][] = $item;
  344. }
  345. }
  346. }
  347. }
  348. }
  349. return array("props"=>$props, "methods"=>$methods);
  350. }
  351. function get_Object_fields(){
  352. // simple helper function to return a fake generated prop/method set for Object.
  353. $props = array();
  354. $methods = array();
  355. // no properties other than the constructor on an object, so we'll just return that as an empty array.
  356. $native = array("constructor", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "toLocaleString", "toString", "valueOf");
  357. $returns = array("Object", "Boolean", "Boolean", "Boolean", "String", "String", "Object");
  358. $summaries = array(
  359. "A reference to the constructor function for this object.",
  360. "Checks whether an object has a locally defined (noninherited) property with a specified name.",
  361. "Check whether this object is the prototype object of a specified object.",
  362. "Checks whether a named property exists and would be enumerated by a for/in loop.",
  363. "Returns a localized string representation of the object.",
  364. "Returns a string representation of the object.",
  365. "Returns the primitve value of the object, if any."
  366. );
  367. foreach($native as $i=>$nm){
  368. $methods[$nm] = array(
  369. "name"=>$nm,
  370. "scope"=>"prototype",
  371. "visibility"=>"public",
  372. "parameters"=>array(),
  373. "return-types"=>array(),
  374. "defines"=>array("Object"),
  375. "override"=>false,
  376. "summary"=>$summaries[$i]
  377. );
  378. $methods[$nm]["return-types"][] = array(
  379. "type"=>$returns[$i],
  380. "description"=>""
  381. );
  382. if($nm == "hasOwnProperty" || $nm == "propertyIsEnumerable"){
  383. $methods[$nm]["parameters"][] = array(
  384. "name"=>"propname",
  385. "type"=>"String",
  386. "usage"=>"",
  387. "description"=>"The property to check."
  388. );
  389. }
  390. else if($nm == "isPrototypeOf"){
  391. $methods[$nm]["parameters"][] = array(
  392. "name"=>"o",
  393. "type"=>"Object",
  394. "usage"=>"",
  395. "description"=>"The object to check against."
  396. );
  397. }
  398. }
  399. return array("props"=>$props, "methods"=>$methods);
  400. }
  401. function generate_object($page, $version, $docs=array()){
  402. // create a PHP-based associative array structure out of the page in question.
  403. if(!count($docs)){
  404. $docs = load_docs($version);
  405. }
  406. $xml = $docs["xml"];
  407. $p_xml = $docs["p_xml"];
  408. $r_xml = $docs["r_xml"];
  409. $xpath = $docs["xpath"];
  410. $p_xpath = $docs["p_xpath"];
  411. $r_xpath = $docs["r_xpath"];
  412. // get the XML for the page.
  413. $context = $xpath->query('//object[@location="' . $page . '"]')->item(0);
  414. if(!$context){
  415. // we got nothing, just return null.
  416. return null;
  417. }
  418. // ok, we have a context, let's build up our object.
  419. $obj = array();
  420. // BEGIN OBJECT GRAPH ASSEMBLY.
  421. // provides
  422. $test = $p_xpath->query('//object[@location="' . $page . '"]/provides/provide');
  423. if($test && $test->length == 1){
  424. $obj["require"] = $test->item(0)->nodeValue;
  425. }
  426. // resources
  427. $test = $r_xpath->query('//object[@location="' . $page . '"]/resources/resource');
  428. if($test && $test->length == 1){
  429. $obj["resource"] = $test->item(0)->nodeValue;
  430. }
  431. // basic information.
  432. $is_constructor = ($context->getAttribute("type")=="Function" && $context->getAttribute("classlike")=="true");
  433. $nl = $xpath->query('//object[starts-with(@location, "' . $page . '.") and not(starts-with(substring-after(@location, "' . $page . '."), "_"))]');
  434. $is_namespace = ($nl->length > 0);
  435. $type = $context->getAttribute("type");
  436. if(!strlen($type)){ $type = 'Object'; }
  437. if($is_constructor){ $type = 'Constructor'; }
  438. // if($is_namespace){ $type = 'Namespace'; }
  439. $obj["type"] = $type;
  440. $obj["title"] = $context->getAttribute("location");
  441. $obj["version"] = $version;
  442. // the prototype chain
  443. $bc = array($context->getAttribute("location"));
  444. $node = $context;
  445. while($node && $node->getAttribute("superclass")){
  446. $sc = $node->getAttribute("superclass");
  447. $bc[] = $sc;
  448. $node = $xpath->query('//object[@location="' . $sc . '"]')->item(0);
  449. }
  450. $bc[] = "Object";
  451. $bc = array_reverse($bc);
  452. // note that this is "in order"; used to either fetch other objects or for something like breadcrumbs.
  453. $obj["prototypes"] = $bc;
  454. // description. Actual description node first, fall back to summary if needed.
  455. $desc = $xpath->query("description/text()", $context)->item(0);
  456. if(!$desc){ $desc = $xpath->query("summary/text()", $context)->item(0); }
  457. if($desc){ $obj["description"] = $desc->nodeValue; }
  458. // mixins
  459. // examples.
  460. $examples = $xpath->query("examples/example", $context);
  461. if($examples->length > 0){
  462. $obj["examples"] = array();
  463. foreach($examples as $example){
  464. $obj["examples"][] = $example->nodeValue;
  465. }
  466. }
  467. // now it gets ugly. We need to go get all the properties and methods of ourselves,
  468. // plus anything in the prototype chain (i.e. superclass), PLUS anything in the mixins list,
  469. // and merge them all together, AND make sure they are unique. On top of that, we need
  470. // to make sure we're getting that info from the top to the bottom.
  471. $obj["mixins"] = array();
  472. $obj["properties"] = array();
  473. $obj["methods"] = array();
  474. // start with getting the mixins.
  475. $nl = $xpath->query("mixins/mixin[@scope='instance']", $context);
  476. foreach($nl as $m){
  477. // again, this is ugly.
  478. $m_test = $xpath->query("//object[@location='" . $m->getAttribute("location") . "']");
  479. if($m_test->length){
  480. $obj["mixins"][] = $m->getAttribute("location");
  481. }
  482. }
  483. // ok. Walk the prototype chain from one to another, and get the list of props and methods for all.
  484. $protos = array();
  485. foreach($bc as $ancestor){
  486. if($ancestor == "Object"){
  487. $protos[$ancestor] = get_Object_fields();
  488. } else {
  489. $protos[$ancestor] = read_object_fields($ancestor, $version, $docs);
  490. }
  491. }
  492. // Now that we have the complete prototype chain, merge everything and include override info if needed.
  493. $props = array();
  494. $methods = array();
  495. foreach($protos as $_object=>$proto){
  496. if($proto && array_key_exists("props", $proto)){
  497. foreach($proto["props"] as $nm=>$prop){
  498. if(array_key_exists($nm, $props)){
  499. // next one up in the chain overrides the original.
  500. $props[$nm]["override"] = true;
  501. $props[$nm]["defines"][] = $_object;
  502. if(isset($prop["summary"])){
  503. $prop[$nm]["summary"] = $prop["summary"];
  504. }
  505. if(isset($prop["description"])){
  506. $prop[$nm]["description"] = $prop["description"];
  507. }
  508. } else {
  509. $props[$nm] = $prop;
  510. }
  511. }
  512. }
  513. if($proto && array_key_exists("methods", $proto)){
  514. foreach($proto["methods"] as $nm=>$method){
  515. if(array_key_exists($nm, $methods)){
  516. // next one up in the chain overrides the original.
  517. $methods[$nm]["override"] = true;
  518. $methods[$nm]["defines"][] = $_object;
  519. $methods[$nm]["scope"] = $method["scope"];
  520. if($nm == "constructor"){
  521. $methods[$nm]["return-types"][0]["type"] = $_object;
  522. }
  523. if(count($method["parameters"])){
  524. $methods[$nm]["parameters"] = $method["parameters"];
  525. }
  526. if(isset($method["summary"])){
  527. $methods[$nm]["summary"] = $method["summary"];
  528. }
  529. if(isset($method["description"])){
  530. $methods[$nm]["description"] = $method["description"];
  531. }
  532. } else {
  533. $methods[$nm] = $method;
  534. }
  535. }
  536. }
  537. }
  538. // sort the props and methods correctly (alphabetical order).
  539. $methods = array_filter($methods, "is_not_from_Object");
  540. $events = array_filter($methods, "is_event");
  541. $methods = array_filter($methods, "is_method");
  542. // put any normal scope (i.e. attached directly) first. Note that we only want
  543. // the ones attached directly to our page, and nothing from the inheritance chain.
  544. $static = array_filter($props, "is_static");
  545. $not_static = array_filter($props, "is_not_static");
  546. $tmp = array();
  547. foreach($static as $nm=>$field){
  548. if($field["defines"][0] == $page){
  549. $tmp[$page . "." . $nm] = $field;
  550. }
  551. }
  552. ksort($tmp);
  553. ksort($not_static);
  554. $props = array_merge($tmp, $not_static);
  555. $static = array_filter($methods, "is_static");
  556. $not_static = array_filter($methods, "is_not_static");
  557. $tmp = array();
  558. foreach($static as $nm=>$field){
  559. if($field["defines"][0] == $page){
  560. $tmp[$page . "." . $nm] = $field;
  561. }
  562. }
  563. ksort($tmp);
  564. ksort($not_static);
  565. $methods = array_merge($tmp, $not_static);
  566. $static = array_filter($events, "is_static");
  567. $not_static = array_filter($events, "is_not_static");
  568. $tmp = array();
  569. foreach($static as $nm=>$field){
  570. if($field["defines"][0] == $page){
  571. $tmp[$page . "." . $nm] = $field;
  572. }
  573. }
  574. ksort($tmp);
  575. ksort($not_static);
  576. $events = array_merge($tmp, $not_static);
  577. $obj["properties"] = $props;
  578. $obj["methods"] = $methods;
  579. $obj["events"] = $events;
  580. // attached objects. Try to filter out the craptacular ones.
  581. $children = $xpath->query('//object[starts-with(@location, "' . $page . '.")]');
  582. $attached = array();
  583. if($children->length){
  584. foreach($children as $node){
  585. $attached[] = $node->getAttribute("location");
  586. }
  587. $attached = array_filter($attached, "is_not_node");
  588. $obj["attached"] = $attached;
  589. }
  590. return $obj;
  591. }
  592. ///////////////////////////////////////////////////////////////////////////////////////////////
  593. //
  594. // BEGIN HTML OUTPUT GENERATION
  595. //
  596. ///////////////////////////////////////////////////////////////////////////////////////////////
  597. // private functions for pieces
  598. function _generate_property_output($prop, $name, $docs = array(), $counter = 0, $base_url = "", $suffix = ""){
  599. // create the HTML strings for a single property
  600. $s = '<li class="' . convert_type($prop["type"]) . 'Icon '
  601. . (isset($prop["visibility"]) ? $prop["visibility"] : 'public') . ' '
  602. . (isset($prop["defines"]) && count($prop["defines"]) && !$prop["override"] ? 'inherited':'')
  603. . ($counter % 2 == 0 ? ' even':' odd')
  604. . '">'
  605. . '<a class="inline-link" href="#' . $name . '">'
  606. . $name
  607. . '</a>';
  608. $details = '<div class="jsdoc-field '
  609. . (isset($prop["visibility"]) ? $prop["visibility"] : 'public') . ' '
  610. . (isset($prop["defines"]) && count($prop["defines"]) && !$prop["override"] ? 'inherited':'')
  611. . ($counter % 2 == 0 ? ' even':' odd')
  612. . '">'
  613. . '<div class="jsdoc-title">'
  614. . '<a name="' . $name . '"></a>'
  615. . '<span class="' . convert_type($prop["type"]) . 'Icon">'
  616. . $name
  617. . '</span>'
  618. . '</div>';
  619. // inheritance list.
  620. if(isset($prop["defines"]) && count($prop["defines"])){
  621. $tmp = array();
  622. foreach($prop["defines"] as $def){
  623. $tmp[] = '<a class="jsdoc-link" href="' . $base_url . implode("/", explode(".", $def)) . $suffix . '">'
  624. . $def
  625. . '</a>';
  626. }
  627. if($prop["override"]){
  628. array_pop($tmp);
  629. }
  630. $details .= '<div class="jsdoc-inheritance">'
  631. . ($prop["override"] ? "Overrides ":"Defined by ")
  632. . implode(", ", $tmp)
  633. . '</div>';
  634. }
  635. if(array_key_exists("description", $prop)){
  636. $details .= '<div class="jsdoc-summary">' . $prop["description"] . '</div>';
  637. } else if(array_key_exists("summary", $prop)){
  638. $details .= '<div class="jsdoc-summary">' . $prop["summary"] . '</div>';
  639. }
  640. if(array_key_exists("summary", $prop)){
  641. $s .= ' <span>' . $prop["summary"] . '</span>';
  642. }
  643. $s .= '</li>'; // jsdoc-title
  644. $details .= '</div>'; // jsdoc-field
  645. return array("s"=>$s, "details"=>$details);
  646. }
  647. function _generate_method_output($method, $name, $docs = array(), $counter = 0, $base_url = "", $suffix = ""){
  648. // create the HTML strings for a single method.
  649. $s = '<li class="functionIcon '
  650. . (isset($method["visibility"]) ? $method["visibility"] : 'public') . ' '
  651. . (isset($method["defines"]) && count($method["defines"]) && !$method["override"] ? 'inherited':'')
  652. . ($counter % 2 == 0 ? ' even':' odd')
  653. . '">'
  654. . '<a class="inline-link" href="#' . $name . '">'
  655. . $name
  656. . '</a>';
  657. $details = '<div class="jsdoc-field '
  658. . (isset($method["visibility"]) ? $method["visibility"] : 'public') . ' '
  659. . (isset($method["defines"]) && count($method["defines"]) && !$method["override"] ? 'inherited':'')
  660. . ($counter % 2 == 0 ? ' even':' odd')
  661. . '">'
  662. . '<div class="jsdoc-title">'
  663. . '<a name="' . $name . '"></a>'
  664. . '<span class="functionIcon">'
  665. . $name
  666. . '</span>'
  667. . '</div>';
  668. if(count($method["parameters"])){
  669. $tmp = array();
  670. foreach($method["parameters"] as $p){
  671. $tmp[] = $p["name"];
  672. }
  673. $s .= '<span class="parameters">('
  674. . implode(', ', $tmp)
  675. . ')</span>';
  676. } else {
  677. $s .= '<span class="parameters">()</span>';
  678. }
  679. if(count($method["return-types"])){
  680. $tmp = array();
  681. foreach($method["return-types"] as $rt){
  682. $tmp[] = $rt["type"];
  683. }
  684. $s .= '<span class="jsdoc-returns"> returns ' . implode("|", $tmp) . '</span>';
  685. }
  686. // inheritance list.
  687. if(isset($method["defines"]) && count($method["defines"])){
  688. $tmp = array();
  689. foreach($method["defines"] as $def){
  690. $tmp[] = '<a class="jsdoc-link" href="' . $base_url . implode("/", explode(".", $def)) . $suffix . '">'
  691. . $def
  692. . '</a>';
  693. }
  694. if($method["override"]){
  695. array_pop($tmp);
  696. }
  697. $details .= '<div class="jsdoc-inheritance">'
  698. . ($method["override"] ? "Overrides ":"Defined by ")
  699. . implode(", ", $tmp)
  700. . '</div>'; // jsdoc-inheritance
  701. }
  702. if(count($method["return-types"])){
  703. $tmp = array();
  704. foreach($method["return-types"] as $rt){
  705. $tmp[] = $rt["type"];
  706. }
  707. $details .= '<div class="jsdoc-return-type">Returns '
  708. . '<strong>'
  709. . implode("|", $tmp)
  710. . '</strong>';
  711. if(array_key_exists("return-description", $method)){
  712. $details .= ': <span class="jsdoc-return-description">'
  713. . $method["return-description"]
  714. . '</span>';
  715. }
  716. $details .= '</div>';
  717. }
  718. else if(array_key_exists("return-description", $method)){
  719. $details .= '<div class="jsdoc-return-type"><div class="jsdoc-return-description">'
  720. . $method["return-description"]
  721. . '</div></div>';
  722. }
  723. if(array_key_exists("description", $method)){
  724. $details .= '<div class="jsdoc-summary">' . do_markdown($method["description"]) . '</div>';
  725. } else if(array_key_exists("summary", $method)){
  726. $details .= '<div class="jsdoc-summary">' . $method["summary"] . '</div>';
  727. }
  728. if(array_key_exists("summary", $method)){
  729. $s .= ' <span>' . $method["summary"] . '</span>';
  730. }
  731. $s .= '</li>'; // jsdoc-title
  732. if(count($method["parameters"])){
  733. $details .= _generate_param_table($method["parameters"], $docs, $base_url, $suffix);
  734. }
  735. if(array_key_exists("examples", $method)){
  736. $details .= '<div class="jsdoc-examples">';
  737. $counter = 1;
  738. foreach($method["examples"] as $example){
  739. $details .= '<div class="jsdoc-example">'
  740. . '<div><strong>Example ' . $counter++ . '</strong></div>'
  741. . format_example($example)
  742. . '</div>';
  743. }
  744. $details .= '</div>';
  745. }
  746. $details .= '</div>'; // jsdoc-field
  747. return array("s"=>$s, "details"=>$details);
  748. }
  749. function _generate_param_table($params, $docs = array(), $base_url = "", $suffix = ""){
  750. // create the inline table for parameters; isolated so that nesting may occur on more than one level.
  751. $tmp_details = array();
  752. foreach($params as $p){
  753. $tester = explode(".", $p["type"], 2);
  754. $tester = $tester[0];
  755. $pstr = '<tr>'
  756. . '<td class="jsdoc-param-name">'
  757. . $p["name"]
  758. . '</td>'
  759. . '<td class="jsdoc-param-type">'
  760. . (strpos($tester, "__") === 0 ? "Object" : $p["type"])
  761. . '</td>'
  762. . '<td class="jsdoc-param-description">'
  763. . (strlen($p["usage"]) ? (($p["usage"] == "optional") ? '<div><em>Optional.</em></div>' : (($p["usage"] == "one-or-more") ? '<div><em>One or more can be passed.</em></div>' : '')) : '')
  764. . $p["description"];
  765. if(strpos($tester, "__")===0){
  766. // try to find the object in question, and if found list out the props.
  767. $pconfig = generate_object($p["type"], null, $docs);
  768. if($pconfig && array_key_exists("properties", $pconfig)){
  769. $p_param = array();
  770. foreach($pconfig["properties"] as $name=>$value){
  771. $tmp_str = '<tr>'
  772. . '<td class="jsdoc-param-name">'
  773. . $name
  774. . '</td>'
  775. . '<td class="jsdoc-param-type">'
  776. . $value["type"]
  777. . '</td>'
  778. . '<td class="jsdoc-param-description">';
  779. if(array_key_exists("description", $value)){
  780. $tmp_str .= do_markdown($value["description"]);
  781. } else if (array_key_exists("summary", $value)){
  782. $tmp_str .= do_markdown($value["summary"]);
  783. } else {
  784. $tmp_str .= '&nbsp;';
  785. }
  786. $p_param[] = $tmp_str . '</td></tr>';
  787. }
  788. $pstr .= '<table class="jsdoc-parameters" style="margin-left:0;margin-right:0;margin-bottom:0;">'
  789. . '<tr>'
  790. . '<th>Parameter</th>'
  791. . '<th>Type</th>'
  792. . '<th>Description</th>'
  793. . '</tr>'
  794. . implode('', $p_param)
  795. . '</table>';
  796. }
  797. }
  798. $pstr .= '</td>'
  799. . '</tr>';
  800. $tmp_details[] = $pstr;
  801. }
  802. return '<table class="jsdoc-parameters">'
  803. . '<tr>'
  804. . '<th>Parameter</th>'
  805. . '<th>Type</th>'
  806. . '<th>Description</th>'
  807. . '</tr>'
  808. . implode('', $tmp_details)
  809. . '</table>';
  810. }
  811. function _generate_properties_output($properties, $docs = array(), $field_counter = 0, $base_url = "", $suffix = "", $title="Property"){
  812. // generate all of the properties output
  813. $s = '<h2 class="jsdoc-summary-heading">Property Summary <span class="jsdoc-summary-toggle"></span></h2>'
  814. . '<div class="jsdoc-summary-list">'
  815. . '<ul>';
  816. $details = '<h2>Properties</h2>';
  817. foreach($properties as $name=>$prop){
  818. $tmp = _generate_property_output($prop, $name, $docs, $field_counter, $base_url, $suffix);
  819. $s .= $tmp["s"];
  820. $details .= $tmp["details"];
  821. $field_counter++;
  822. }
  823. $s .= '</ul></div>'; // property-summary
  824. return array("s"=>$s, "details"=>$details, "counter"=>$field_counter);
  825. }
  826. function _generate_methods_output($methods, $docs = array(), $field_counter = 0, $base_url = "", $suffix = "", $title="Method"){
  827. // generate all of the methods output
  828. $s = "";
  829. $details = "";
  830. if(count($methods)){
  831. $s .= '<h2 class="jsdoc-summary-heading">' . $title . ' Summary <span class="jsdoc-summary-toggle"></span></h2>'
  832. . '<div class="jsdoc-summary-list">'
  833. . '<ul>';
  834. $details .= '<h2>' . $title . 's</h2>';
  835. foreach($methods as $name=>$method){
  836. $html = _generate_method_output($method, $name, $docs, $field_counter, $base_url, $suffix);
  837. $s .= $html["s"];
  838. $details .= $html["details"];
  839. $field_counter++;
  840. }
  841. $s .= '</ul></div>'; // method-summary
  842. }
  843. return array("s"=>$s, "details"=>$details, "counter"=>$field_counter);
  844. }
  845. function generate_object_html($page, $version, $base_url = "", $suffix = "", $versioned = true, $docs = array()){
  846. // $page:
  847. // The object to render, i.e. "dojox.charting.Chart2D"
  848. // $version:
  849. // The version against which to generate the page.
  850. // $base_url:
  851. // A URL fragment that will be prepended to any link generated.
  852. // $suffx:
  853. // A string that will be appended to any link generated, i.e. ".html"
  854. // $docs:
  855. // An optional array of XML documents to run the function against. See spider.php
  856. // for example usage.
  857. if(!isset($page)){
  858. throw new Exception("generate_html: you must pass an object name!");
  859. }
  860. if(!isset($version)){
  861. throw new Exception("generate_html: you must pass a version!");
  862. }
  863. if(strpos($page, "/") > 0){
  864. $page = implode(".", explode("/", $page));
  865. }
  866. $data_dir = dirname(__FILE__) . "/../data/" . $version . "/";
  867. // get the docs to run against. this can be optionally provided;
  868. // if they are they ALL need to be there.
  869. if(!count($docs)){
  870. $docs = load_docs($version);
  871. }
  872. $xml = $docs["xml"];
  873. $p_xml = $docs["p_xml"];
  874. $r_xml = $docs["r_xml"];
  875. $xpath = $docs["xpath"];
  876. $p_xpath = $docs["p_xpath"];
  877. $r_xpath = $docs["r_xpath"];
  878. // check if we're to build links versioned and if so, add that to the base url.
  879. if($versioned){
  880. $base_url .= $version . '/';
  881. }
  882. // get our object
  883. $obj = generate_object($page, $version, $docs);
  884. if(!$obj){
  885. $s = '<div style="font-weight: bold;color: #900;">The requested object was not found.</div>';
  886. echo $s;
  887. exit();
  888. }
  889. // process it and output us some HTML.
  890. $s = '<div class="jsdoc-permalink" style="display:none;">' . $base_url . implode('/', explode(".", $page)) . $suffix . '</div>';
  891. // page heading.
  892. $s .= '<h1 class="jsdoc-title ' . convert_type($obj["type"]) . 'Icon36">'
  893. . $obj["title"]
  894. . ' <span style="font-size:11px;color:#999;">(version ' . $version . ')</span>'
  895. . '</h1>';
  896. // prototype chain
  897. $s .= '<div class="jsdoc-prototype">';
  898. foreach($obj["prototypes"] as $i=>$p){
  899. if($i){ $s .= ' &raquo; '; }
  900. if($p != $page && $p != "Object"){
  901. $name = implode("/", explode(".", $p));
  902. $s .= '<a class="jsdoc-link" href="' . $base_url . $name . $suffix . '">' . $p . '</a>';
  903. } else {
  904. $s .= $p;
  905. }
  906. }
  907. $s .= '</div>';
  908. if($page == "dojo"){
  909. $s .= '<div class="jsdoc-require">&lt;script src="path/to/dojo.js"&gt;&lt;/script&gt;</div>';
  910. } else if(array_key_exists("require", $obj)) {
  911. $s .= '<div class="jsdoc-require">dojo.require("' . $obj["require"] . '");</div>';
  912. }
  913. if(array_key_exists("resource", $obj)){
  914. $s .= '<div class="jsdoc-prototype">Defined in ' . $obj["resource"] . '</div>';
  915. }
  916. // usage. Go look for a constructor.
  917. if(array_key_exists("methods", $obj) && array_key_exists("constructor", $obj["methods"])){
  918. $fn = $obj["methods"]["constructor"];
  919. $s .= '<div class="jsdoc-function-information"><h3>Usage:</h3>'
  920. . '<div class="function-signature">'
  921. . '<span class="keyword">var</span> foo = new '
  922. . $page
  923. . '(';
  924. if(count($fn["parameters"])){
  925. $tmp = array();
  926. foreach($fn["parameters"] as $param){
  927. $tmp[] = '<span class="jsdoc-comment-type">/* '
  928. . $param["type"]
  929. . ($param["usage"] == "optional" ? "?":"")
  930. . ' */</span> '
  931. . $param["name"];
  932. }
  933. $s .= implode(", ", $tmp);
  934. }
  935. $s .= ');</div></div>';
  936. }
  937. if(array_key_exists("description", $obj)){
  938. $s .= '<div class="jsdoc-full-summary">'
  939. . do_markdown($obj["description"])
  940. . "</div>";
  941. }
  942. // examples.
  943. if(array_key_exists("examples", $obj)){
  944. $examples = $obj["examples"];
  945. if(count($examples)){
  946. $s .= '<div class="jsdoc-examples">'
  947. . '<h2>Examples:</h2>';
  948. $counter = 1;
  949. foreach($examples as $example){
  950. $s .= '<div class="jsdoc-example">'
  951. . '<h3>Example ' . $counter++ . '</h3>'
  952. . format_example($example)
  953. . '</div>';
  954. }
  955. $s .= '</div>';
  956. }
  957. }
  958. // mixins
  959. if(array_key_exists("mixins", $obj)){
  960. $tmp = array();
  961. $super = $obj["prototypes"][count($obj["prototypes"])-2];
  962. foreach($obj["mixins"] as $mixin){
  963. if($mixin != $super){
  964. $name = implode("/", explode('.', $mixin));
  965. $tmp[] = '<a class="jsdoc-link" href="' . $base_url . $name . $suffix . '">' . $mixin . '</a>';
  966. }
  967. }
  968. if(count($tmp)){
  969. $s .= '<div class="jsdoc-mixins"><label>mixins: </label>'
  970. . implode(", ", $tmp)
  971. . '</div>';
  972. }
  973. }
  974. // Properties, methods, events, and attached objects.
  975. $s .= '<div class="jsdoc-children">';
  976. $s .= '<div class="jsdoc-field-list">';
  977. $details = '<div class="jsdoc-children">'
  978. . '<div class="jsdoc-fields">';
  979. $field_counter = 0;
  980. $props = $obj["properties"];
  981. $methods = $obj["methods"];
  982. $events = $obj["events"];
  983. if(count($props) || count($methods) || count($events)){
  984. if(count($props)){
  985. $tmp = _generate_properties_output($props, $docs, $field_counter, $base_url, $suffix, "Properties");
  986. $s .= $tmp["s"];
  987. $details .= $tmp["details"];
  988. $field_counter = $tmp["counter"];
  989. }
  990. if(count($methods)){
  991. $tmp = _generate_methods_output($methods, $docs, $field_counter, $base_url, $suffix, "Method");
  992. $s .= $tmp["s"];
  993. $details .= $tmp["details"];
  994. $field_counter = $tmp["counter"];
  995. }
  996. if(count($events)){
  997. $tmp = _generate_methods_output($events, $docs, $field_counter, $base_url, $suffix, "Event");
  998. $s .= $tmp["s"];
  999. $details .= $tmp["details"];
  1000. }
  1001. }
  1002. // child objects: put up a list of any child objects that are attached to this particular one.
  1003. if(array_key_exists("attached", $obj) && count($obj["attached"])){
  1004. $children = $obj["attached"];
  1005. $s .= '<h2 class="jsdoc-summary-heading">Attached Objects <span class="jsdoc-summary-toggle"></span></h2>'
  1006. . '<div class="jsdoc-summary-list">';
  1007. foreach($children as $child){
  1008. $s .= '<div class="jsdoc-field">'
  1009. . '<div class="jsdoc-title">'
  1010. . '<span class="';
  1011. $tmp = $xpath->query('//object[@location="' . $child . '"]')->item(0);
  1012. if($tmp){
  1013. if($tmp->getAttribute("type") == "Function" && $tmp->getAttribute("classlike") == "true"){
  1014. $s .= "constructor";
  1015. } else {
  1016. $s .= convert_type($tmp->getAttribute("type"));
  1017. }
  1018. } else {
  1019. $s .= convert_type("Object");
  1020. }
  1021. $s .= '">'
  1022. . '<a class="jsdoc-link" href="' . $base_url . implode("/", explode(".", $child)) . $suffix . '">'
  1023. . $child
  1024. . '</a>'
  1025. . '</span>'
  1026. . '</div>' // jsdoc-title
  1027. . '</div>'; // jsdoc-field
  1028. }
  1029. $s .= '</div>';
  1030. }
  1031. $s .= '</div>'; // jsdoc-field-list.
  1032. $s .= '</div>'; // jsdoc-children.
  1033. $details .= '</div></div>';
  1034. return $s . $details;
  1035. }
  1036. // sorting functions used for the tree
  1037. function object_node_sorter($a, $b){
  1038. if($a->getAttribute("location") == $b->getAttribute("location")){ return 0; }
  1039. return ($a->getAttribute("location") > $b->getAttribute("location")) ? 1 : -1;
  1040. }
  1041. function node_reference_sorter($a, $b){
  1042. if(strtolower($a["_reference"]) == strtolower($b["_reference"])) return 0;
  1043. return (strtolower($a["_reference"]) > strtolower($b["_reference"])) ? 1 : -1;
  1044. }
  1045. // generate a hierarchical representation of the object tree; based on the class-tree.
  1046. // Note that this structure is generated based on the structure of dojo.data.
  1047. function generate_object_tree($version, $roots=array(), $filter=true, $docs=array()){
  1048. // $version:
  1049. // The version of the object tree to generate.
  1050. // $roots:
  1051. // The objects to be considered the root nodes of the list generated. If empty,
  1052. // this will simply look for any objects that do not have a period in the name.
  1053. // $filter:
  1054. // A boolean that filters out anything that is considered "private" (i.e. beginning with
  1055. // an underscore "_")
  1056. // $docs:
  1057. // An optional array of XML document objects that will be used as the sources for the tree.
  1058. // get our source.
  1059. if(!count($docs)){
  1060. $data_dir = dirname(__FILE__) . "/../data/" . $version . "/";
  1061. $f = $data_dir . "objects.xml";
  1062. if(!file_exists($f)){
  1063. throw new Exception("generate_object_tree_html: the required directory/file was not found.");
  1064. }
  1065. $xml = new DOMDocument();
  1066. $xml->load($f);
  1067. $xpath = new DOMXPath($xml);
  1068. } else {
  1069. $xml = $docs["xml"];
  1070. $xpath = $docs["xpath"];
  1071. }
  1072. $objects = $xpath->query("//object");
  1073. $ret = array();
  1074. $counter = 0;
  1075. // set our top-level objects
  1076. $show = array();
  1077. $keys = array();
  1078. if(count($roots)){
  1079. // we were given a specific set of root locations.
  1080. foreach($roots as $key=>$value){
  1081. $show[$key] = $value;
  1082. $keys[] = $key;
  1083. }
  1084. } else {
  1085. $r = $xpath->query("//object[not(contains(@location, '.'))]");
  1086. foreach($r as $node){
  1087. if($node->getAttribute("type") == "Function" && $node->getAttribute("classlike") == "true"){
  1088. $show[$node->getAttribute("location")] = -1;
  1089. $keys[] = $node->getAttribute("location");
  1090. }
  1091. }
  1092. }
  1093. // ok, let's create our internal structure.
  1094. foreach($objects as $node){
  1095. $name = $node->getAttribute("location");
  1096. $type = $node->getAttribute("type");
  1097. $classlike = $node->getAttribute("classlike");
  1098. $name_parts = explode(".", $name);
  1099. $short_name = array_pop($name_parts);
  1100. if ($type=="Function" && $classlike=="true") {
  1101. $val = array(
  1102. "id"=>$name, /* "object-" . $counter++, */
  1103. "name"=>$short_name,
  1104. "fullname"=>$name,
  1105. "type"=>"constructor"
  1106. );
  1107. } else {
  1108. $val = array(
  1109. "id"=>$name, /* "object-" . $counter++, */
  1110. "name"=>$short_name,
  1111. "fullname"=>$name,
  1112. "type"=>(strlen($type) ? strtolower($type): "object")
  1113. );
  1114. }
  1115. if(isset($val)){
  1116. if($filter && strpos($short_name, "_") === 0){
  1117. unset($val);
  1118. continue;
  1119. }
  1120. if(count($name_parts)){
  1121. $finder = implode(".", $name_parts);
  1122. foreach($ret as &$obj){
  1123. if($obj["fullname"] == $finder){
  1124. if(!array_key_exists("children", $obj)){
  1125. $obj["children"] = array();
  1126. }
  1127. $obj["children"][] = array(
  1128. "_reference"=>$val["id"]
  1129. );
  1130. // $obj["type"] = "namespace";
  1131. break;
  1132. }
  1133. }
  1134. }
  1135. $ret[] = $val;
  1136. unset($val);
  1137. }
  1138. }
  1139. // go through the top-level objects and reset the type on it.
  1140. $counter = 0;
  1141. foreach($ret as &$obj){
  1142. $name = $obj["fullname"];
  1143. if(array_key_exists($name, $show)){
  1144. $obj["type"] = "root";
  1145. $show[$name] = $counter;
  1146. }
  1147. $counter++;
  1148. }
  1149. // finally, move the given namespaces to the top of the array.
  1150. $fin = array();
  1151. foreach($show as $item){
  1152. if(array_key_exists("children", $ret[$item])){
  1153. usort($ret[$item]["children"], "node_reference_sorter");
  1154. }
  1155. $fin[] = &$ret[$item];
  1156. }
  1157. foreach($ret as &$obj){
  1158. if(!array_key_exists($obj["fullname"], $show)){
  1159. if(array_key_exists("children", $obj)){
  1160. usort($obj["children"], "node_reference_sorter");
  1161. }
  1162. $fin[] = $obj;
  1163. }
  1164. }
  1165. return $fin;
  1166. }
  1167. function _get_branch($obj, $root){
  1168. // given the object generated by the tree, find all objects that are referenced as children
  1169. // and return an array. Note that you should pass both params by reference (i.e. &$myTree)
  1170. //
  1171. // $obj
  1172. // The actual tree object to be used for lookup.
  1173. // $root
  1174. // The parent object to use for getting children.
  1175. $ret = array();
  1176. foreach($root["children"] as $child){
  1177. foreach($obj as $object){
  1178. if($object["id"] == $child["_reference"]){
  1179. $ret[] = $object;
  1180. break;
  1181. }
  1182. }
  1183. }
  1184. return $ret;
  1185. }
  1186. function _generate_branch_html($tree, $obj, $base_url = "", $suffix = ""){
  1187. // recursive private function to "listify" the given branch.
  1188. $s = '<li class="' . ($obj["type"]=="root"?"namespace":$obj["type"]) . 'Icon">'
  1189. . '<a class="jsdoc-link" href="' . $base_url . implode("/", explode(".", $obj["fullname"])) . $suffix . '">'
  1190. . $obj["name"]
  1191. . '</a>';
  1192. if(array_key_exists("children", $obj)){
  1193. $s .= "\n". '<ul class="jsdoc-children">';
  1194. $branch = _get_branch($tree, $obj);
  1195. foreach($branch as $child){
  1196. $s .= _generate_branch_html($tree, $child, $base_url, $suffix);
  1197. }
  1198. $s .= '</ul>' . "\n";
  1199. }
  1200. return $s . '</li>' . "\n";
  1201. }
  1202. function generate_object_tree_html($tree, $root, $base_url = "", $suffix = ""){
  1203. // summary:
  1204. // Given an object tree (such as generated above), create an HTML
  1205. // version, complete with links.
  1206. // $tree:
  1207. // The array structure as given from above.
  1208. // $root:
  1209. // The string indicating what root object to use for branching.
  1210. // $base_url:
  1211. // A string prepended to any links generated.
  1212. // $suffix:
  1213. // A string appended to any links generated.
  1214. if(!isset($tree)){
  1215. throw new Exception("generate_object_tree_html: you must pass in an object tree.");
  1216. }
  1217. // find the root object in the tree.
  1218. $roots = array();
  1219. foreach($tree as $object){
  1220. if($object["type"] == "root"){
  1221. $roots[] = $object;
  1222. }
  1223. }
  1224. // let's give it a start.
  1225. $s = '<ul class="jsdoc-navigation">' . "\n";
  1226. foreach($roots as $r){
  1227. if($r["id"] == $root){
  1228. $s .= _generate_branch_html($tree, $r, $base_url, $suffix);
  1229. } else {
  1230. $s .= '<li class="namespaceIcon">'
  1231. . '<a class="jsdoc-link" href="' . $base_url . implode("/", explode(".", $r["fullname"])) . $suffix . '">'
  1232. . $r["name"]
  1233. . '</a>'
  1234. . '</li>' . "\n";
  1235. }
  1236. }
  1237. $s .= '</ul>' . "\n";
  1238. return $s;
  1239. }
  1240. ?>