4 * Generates a table of contents based on the heading structure of the
7 class XHTMLCompiler_DOMFilter_GenerateTableOfContents
extends XHTMLCompiler_DOMFilter
10 protected $name = 'GenerateTableOfContents';
12 public function process(DOMDocument
$dom, $page, $manager) {
14 // test for ToC container, if not present don't bother
15 // currently, only id="toc" is supported, which means there can
16 // only be one table of contents per page
17 $container = $this->query("//html:div[@id='toc']")->item(0);
18 if (!$container) return;
20 // grab all headings h2 and down from the document
21 $headings = array('h2', 'h3', 'h4', 'h5', 'h6');
22 foreach ($headings as $k => $v) $headings[$k] = "self::html:$v";
23 $query_headings = implode(' or ', $headings);
24 $query = "//*[$query_headings]"; // looks like "//*[self::html:h2 or ...]"
25 $headings = $this->query($query);
27 // setup the table of contents element
28 $toc = $dom->createElement('ul');
29 $toc->setAttribute('class', 'toc-base');
30 $container->appendChild($dom->createElement('h2', 'Table of Contents'));
31 $container->appendChild($toc);
33 // iterate through headings and build the table of contents
35 $parents = array(false, $toc);
38 foreach ($headings as $node) {
39 $level = (int) $node->tagName
[1];
40 $name = $node->textContent
; // no support for formatting
42 while ($level > $current_level) {
43 if (!$parents[$current_level-1]->lastChild
) {
44 $parents[$current_level-1]->appendChild(
45 $dom->createElement('li')
48 $sublist = $dom->createElement('ul');
49 $parents[$current_level - 1]->lastChild
->appendChild($sublist);
50 $parents[$current_level] = $sublist;
52 $indexes[$current_level - 2] = 0;
55 while ($level < $current_level) {
56 unset($indexes[$current_level - 2]);
60 $indexes[$current_level - 2]++
;
63 $line = $dom->createElement('li');
64 $label = $dom->createElement('span', implode('.', $indexes) . '.');
65 $label->setAttribute('class', 'toc-label');
66 $line->appendChild($label);
67 $link = $dom->createElement('a', htmlspecialchars($name));
68 $line->appendChild($link);
69 $parents[$current_level-1]->appendChild($line);
72 $header_id = $node->getAttribute('id');
74 // automatically generate a header. These are volatile,
75 // so it's highly recommended that you manually specify
77 // TODO: generate based on the contents of the header node
78 $header_id = 'toclink' . $i;
79 $node->setAttribute('id', $header_id);
82 $link->setAttribute('href', '#' . $header_id);