--- /dev/null
+<?php
+
+/**
+ * Implementation of hook_theme().
+ */
+function toc_formatter_theme() {
+ $theme = array(
+ 'toc_formatter_table_of_contents' => array(
+ 'variables' => array('content' => NULL, 'title' => NULL, 'type' => 'ul'),
+ ),
+ 'toc_formatter_move_to_top_link' => array(
+ 'variables' => array('content' => NULL),
+ ),
+ );
+
+ return $theme;
+}
+
+
+/**
+ * Theming functions for 'Move to top' links.
+ */
+function theme_toc_formatter_move_to_top_link($variables) {
+ $content = $variables['content'];
+ $path_alias = request_uri();
+ $link = '<div class="toc-top-links">';
+ $link .= l(t('Move to top'), $path_alias, array('fragment' => 'table-of-contents'));
+ $link .= '</div>';
+
+ $output = str_ireplace('</h2>', '</h2>'. $link, $content);
+ return $output;
+}
+
+/**
+ * Generate table of contents, add anchors to headings, and add links back to top of page.
+ *
+ **/
+function theme_toc_formatter_table_of_contents($variables) {
+
+ $title = $variables['title'];
+ $content = $variables['content'];
+ $type = $variables['type'];
+
+ $path = request_uri();
+ $links = array();
+ $anchor = 0;
+ $output = '';
+
+ $dom_document = new DOMDocument('1.0','utf-8');
+ @$dom_document->loadHTML('<?xml encoding="UTF-8"><div id="toc-formatter">'. $content .'</div>');
+
+ $headers = $dom_document->getElementsByTagName('h2');
+
+ foreach ($headers as $header) {
+ $anchor++;
+
+ // TOC links.
+ $label = trim($header->nodeValue);
+ $links[] = l($label, $path, array('fragment' => 'toc-'. $anchor));
+
+ // Headings, add class.
+ $header->setAttribute('class', 'toc-headings');
+
+ // Anchors above headings.
+ $anchor_div = $dom_document->createElement('div');
+ $anchor_div->setAttribute('class', 'toc-item-anchor');
+ $target = $dom_document->createElement('a');
+ $target->setAttribute('name', 'toc-'. $anchor);
+ $anchor_div->appendChild($target);
+ $header->parentNode->insertBefore($anchor_div, $header);
+ }
+
+ if (isset($links) && !empty($links)) {
+ // Output DOM to a string.
+ // Unfortunately below PHP 5.3.6 saveHTML() doesn't expect a parameter.
+ $content_updated = $dom_document->saveHTML();
+ // So we have to remove wrapping tags ourseleves.
+ $content_fragments = explode('<div id="toc-formatter">', $content_updated);
+ $content_inner = str_replace('</div></body></html>', '', $content_fragments[1]);
+
+ $output .= '<div id="table-of-contents-links">';
+ $output .= '<a name="table-of-contents"></a>';
+ $item_list = array('#theme' => 'item_list', '#items' => $links, '#title' => $title, '#type' =>$type);
+ $output .= drupal_render($item_list);
+ $output .= '</div>';
+
+ // Back to top links.
+ $top_link = array('#theme' => 'toc_formatter_move_to_top_link', '#content' => $content_inner);
+ $output .= drupal_render($top_link);
+ }
+ else {
+ $output .= $content;
+ }
+
+ return $output;
+}