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;
19 $manager->addDependency(__FILE__
);
21 // grab all headings h2 and down from the document
22 $headings = array('h2', 'h3', 'h4', 'h5', 'h6');
23 foreach ($headings as $k => $v) $headings[$k] = "self::html:$v";
24 $query_headings = implode(' or ', $headings);
25 $query = "//*[$query_headings]"; // looks like "//*[self::html:h2 or ...]"
26 $headings = $this->query($query);
28 // setup the table of contents element
29 $toc = $dom->createElement('ul');
30 $toc->setAttribute('class', 'toc-base');
31 $container->appendChild($dom->createElement('h2', 'Table of Contents'));
32 $container->appendChild($toc);
34 // iterate through headings and build the table of contents
36 $parents = array(false, $toc);
39 foreach ($headings as $node) {
40 $level = (int) $node->tagName
[1];
41 $name = $node->textContent
; // no support for formatting
43 while ($level > $current_level) {
44 if (!$parents[$current_level-1]->lastChild
) {
45 $parents[$current_level-1]->appendChild(
46 $dom->createElement('li')
49 $sublist = $dom->createElement('ul');
50 $parents[$current_level - 1]->lastChild
->appendChild($sublist);
51 $parents[$current_level] = $sublist;
53 $indexes[$current_level - 2] = 0;
56 while ($level < $current_level) {
57 unset($indexes[$current_level - 2]);
61 $indexes[$current_level - 2]++
;
64 $line = $dom->createElement('li');
65 $label = $dom->createElement('span', implode('.', $indexes) . '.');
66 $label->setAttribute('class', 'toc-label');
67 $line->appendChild($label);
68 $link = $dom->createElement('a', htmlspecialchars($name));
69 $line->appendChild($link);
70 $parents[$current_level-1]->appendChild($line);
73 $header_id = $node->getAttribute('id');
75 // automatically generate a header. These are volatile,
76 // so it's highly recommended that you manually specify
78 // TODO: generate based on the contents of the header node
79 $header_id = 'toclink' . $i;
80 $node->setAttribute('id', $header_id);
83 $link->setAttribute('href', '#' . $header_id);