Table of Contents
InlineTOC Plugin
Compatible with DokuWiki
2010-11-07, 2011-05-25, Angua, Adora Belle, Weatherwax, Hrun
Installation
Search and install the plugin using the Extension Manager. Refer to Plugins on how to install plugins manually.
Examples/Usage
Notes
The div created has the class set to inlinetoc2. The 2 is here to not enter in conflict with the TOC plugin which already use the class inlinetoc.
The plugin won't work if you specify {{NOTOC}} on the page because it relies on Dokuwiki's internal toc processor to build the page's toc.
Change Log
- 2015-06-19
- merge pull request
- Set PType to avoid an open 'p'
- Use DokuWikis way to disable the original TOC
- 2013-07-27
- fixed to work with recent versions of Dokuwiki - cf issue on github
- 2011-09-03
- replaced inline javascript with addInitEvent call
- 2011-08-12
- Dokuwiki's toc is hidden on page where inlinetoc is used
- Fixed print issue
- 2011-07-16
- Added CSS to hide DokuWiki's TOC.
Note that this will hide DokuWiki's TOC on every pages, not just pages with an inlinetoc.
If you want to enable it, edit the plugins/inlinetoc/style.css file and uncomment (remove the underscore) at the beginning of div.toc.
- 2011-05-30
- Initial release
Wishes
- Can this plugin be enabled for whole wiki?
Not really because it's built as a replacement plugin, not a general purpose plugin. It could be adapted but I believe it would make more sense to make a completely separate plugin for that purpose. Andreone 30/12/2011
- Could it be possible to limit the displayed level of headings?
e.g.{
{
INLINETOC 3}
}
will only display level1…level3 in the TOC Joachim 11.01.2012
As the plugin directly use Dokuwiki's TOC, I don't think I can do that. I will think about this however. Andreone 13/01/2012
Improvements
This improvement allows to create multiple tocs inside of the document (different deeps and start points)
Syntax
{{INLINETOC}}
⇒ normal inlinetoc as you know
{{INLINETOC> ns }}
⇒ inlinetoc beginning at current header(namespace in document)
{{INLINETOC> ns:specified_namespace }}
⇒ inlinetoc beginning at specified header(namespace in document)
{{INLINETOC> el:1 }}
⇒ normal inlinetoc with endlevel (deep) of 1
{{INLINETOC> ns el:1 }}
⇒ inlinetoc beginning at current header(namespace in document) with endlevel (deep) of 1
Code
- action.php
<?php /** * InlineTOC-Plugin: Renders the page's toc inside the page content * * @license GPL v2 (http://www.gnu.org/licenses/gpl.html) * @author Andreone */ if(!defined('DOKU_INC')) die(); if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); require_once(DOKU_PLUGIN.'action.php'); class action_plugin_inlinetoc extends DokuWiki_Action_Plugin { /** * Register event handlers */ function register(&$controller) { $controller->register_hook('RENDERER_CONTENT_POSTPROCESS', 'AFTER', $this, 'handle_renderer_content_postprocess', array()); $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'handle_tpl_metaheader_output', array()); } /** * Replace our placeholder with the actual toc content */ function handle_renderer_content_postprocess(&$event, $param) { global $TOC; if ($TOC) { dbglog($event->data[1], 'html'); $KEY_WORD = '<!-- INLINETOCPLACEHOLDER '; $KEY_WORD_END = '-->'; // find first toc entry $pos = strpos($event->data[1], $KEY_WORD); $pos_end = strpos($event->data[1], $KEY_WORD_END, $pos); // as long tocs found while ($pos > 0) { $TOC2=$TOC; // get arguments for toc $begin_level = -1; $end_level = -1; $autons = 0; $namespace = ''; $match = substr($event->data[1], $pos, ($pos_end - $pos)); $spacer = strpos($match, '>'); $param_ans = 'ans:'; // param autonamespace $param_ns = 'ns:'; // param namespace $param_bl = 'bl:'; // param begin level $param_el = 'el:'; // param end level if ($spacer > 0 ) // check if contains parmeters { $param_string = preg_split('/>/u', $match, 2); $params = preg_split('/ /u', $param_string[1]); foreach ($params as &$param) { dbglog("param: $param"); if ($param_ans === substr($param, 0, strlen($param_ans))) // check if should use auto namespace { $autons = intval(substr($param, strlen($param_ans))); } else if ($param_ns === substr($param, 0, strlen($param_ns))) // check if should use namespace { $namespace = substr($param, strlen($param_ns)); } else if ($param_bl === substr($param, 0, strlen($param_bl))) // check if should use begin level { $begin_level = intval(substr($param, strlen($param_bl))); } else if ($param_el === substr($param, 0, strlen($param_el))) // check if should use end level { $end_level = intval(substr($param, strlen($param_el))); } } dbglog("bl: $begin_level"); dbglog("el: $end_level"); dbglog("ans: $autons"); dbglog("namespace: $namespace"); } $head_level = 0; $head_id = ''; // check if we use the auto head namepsace function if ($autons == 1) { // search for previours head $head = strrpos($event->data[1], '<h', - (strlen($event->data[1]) - $pos)); // check if head found if ($head) { // find id $head_id_key_start = strpos($event->data[1], 'id="', $head) + 4; $head_id_key_fin = strpos($event->data[1], '"', $head_id_key_start); $head_id = substr($event->data[1], $head_id_key_start , $head_id_key_fin - $head_id_key_start); dbglog("found head pos: name: $head_id"); } } else { $head_id = $namespace; } // check if head namespace selected if ($head_id == '') { $in_section = true; } else { $in_section = false; } foreach ($TOC2 as &$element) { $element_level = intval($element['level']); $element_id = substr($element['link'], 1); dbglog("element: $element_level $element_id"); // check if its the head if ($element_id == $head_id) { $in_section = true; $head_level = $element_level; unset($TOC2[array_search($element, $TOC2)]); } else { // check if outside of head level if ($element_level <= $head_level) { $in_section = false; } // filter begin level if ($element_level < $head_level + $begin_level) { unset($TOC2[array_search($element, $TOC2)]); } // filter end level relative to head level if ($end_level > 0 and $element_level > $end_level + $head_level) { unset($TOC2[array_search($element, $TOC2)]); } } if (!$in_section) { unset($TOC2[array_search($element, $TOC2)]); } else { //modify level to begin on top $element['level']= $element['level'] - $head_level - 1; } } // remove unselected $TOC2 = array_values($TOC2); // build html toc $html = '<div id="inlinetoc2" class="inlinetoc2">' . html_buildlist($TOC2, 'inlinetoc2', 'html_list_inlinetoc2') . '</div>'; // replace placeholder $event->data[1] = substr_replace($event->data[1], $html, $pos, ($pos_end - $pos) + strlen($KEY_WORD_END)); // get next pos $pos = strpos($event->data[1], $KEY_WORD, $pos + 1); $pos_end = strpos($event->data[1], $KEY_WORD_END, $pos); } } } /** * Include javascript */ function handle_tpl_metaheader_output(&$event, $param) { $event->data["script"][] = array ( "type" => "text/javascript", "src" => DOKU_BASE . "lib/plugins/inlinetoc/inlinetoc.js", "_data" => "", ); } } /** * Callback for html_buildlist. * Builds list items with inlinetoc2 printable class instead of dokuwiki's toc class which isn't printable. */ function html_list_inlinetoc2($item){ if(isset($item['hid'])){ $link = '#'.$item['hid']; }else{ $link = $item['link']; } return '<span class="li"><a href="'.$link.'" class="inlinetoc2">'. hsc($item['title']).'</a></span>'; }
- syntax.php
<?php /** * InlineTOC-Plugin: Renders the page's toc inside the page content * * @license GPL v2 (http://www.gnu.org/licenses/gpl.html) * @author Andreone */ if (!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../../') . '/'); require_once(DOKU_INC . 'inc/init.php'); if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/'); require_once(DOKU_PLUGIN . 'syntax.php'); class syntax_plugin_inlinetoc extends DokuWiki_Syntax_Plugin { /** * What kind of syntax are we? */ function getType() { return 'substition'; } /** * Where to sort in? (took the same as for ~~NOTOC~~) */ function getSort() { return 30; } /** * Connect pattern to lexer */ function connectTo($mode) { // to keep compatible to old dokuwiki pages $this->Lexer->addSpecialPattern('{{INLINETOC}}', $mode, 'plugin_inlinetoc'); $this->Lexer->addSpecialPattern('{{INLINETOC>.+?}}', $mode, 'plugin_inlinetoc'); } /** * Handle the match */ function handle($match, $state, $pos, &$handler) { $begin_level = -1; $end_level = -1; $autons = false; $namespace = ''; $spacer = strpos($match, '>'); $param_ns = 'ns'; // param namespace $param_bl = 'bl:'; // param begin level $param_el = 'el:'; // param end level if ($spacer > 0 ) // check if contains parmeters { $param_string = preg_split('/>/u', $match, 2); $params = preg_split('/ /u', $param_string[1]); foreach($params as &$param) { dbglog("param: $param"); if ($param_ns === substr($param, 0, strlen($param_ns))) // check if should use namespace { dbglog("contains namespace"); $namespace = substr($param, strlen($param_ns) + 1); if ($namespace === false or $namespace === '') { dbglog("use autons"); $autons = true; } dbglog("ns: |$namespace|"); } else if ($param_bl === substr($param, 0, strlen($param_bl))) // check if should use begin level { dbglog("contains begin level"); $begin = intval(substr($param, strlen($param_bl))); } else if ($param_el === substr($param, 0, strlen($param_el))) // check if should use end level { dbglog("contains end level"); $end = intval(substr($param, strlen($param_el))); } } } dbglog($namespace, "namespace:"); return array( 'begin' => $begin, 'end' => $end, 'autons' => $autons, 'namespace' => $namespace); } /** * Add placeholder to cached page (will be replaced by action component) */ function render($mode, &$renderer, $data) { dbglog($data, "render data"); $begin_level = $data['begin']; $end_level = $data['end']; $autons = $data['autons']; $namespace = $data['namespace']; $renderer->doc .= "<!-- INLINETOCPLACEHOLDER > bl:$begin_level el:$end_level ans:$autons ns:$namespace -->"; } }
About
We have needed this functions in our company for internal documentation and it would be nice to see those features in your next release.
Best regards and thanks for your work, — hop3l3ss1990 2014-08-20 09:39
Discussion
How to I disable the built-in TOC without also disabling inlinetoc?
I tried but couldn't find a way when I implemented inlinetoc. This reason is because it uses the toc definition generated by Dokuwiki. But, to disable the built-in TOC, you have to put {{NOTOC}} on your page, which causes Dokuwiki to not generate the toc definition.
To achieve what you want, that would means to parse the raw page to built the toc, something I wanted to avoid. This may come in a V2 if it appears to be a popular demand.
I added a note about this issue on this page. Andreone, 2011/06/23Maybe the plugin author could hide the built-in TOC via CSS? I see it is wrapped in <div class="toc">...</div>. Just a thought. — Rik Blok 2011/06/30 06:35I know the Dokuwiki's toc can be hidden with a little CSS, but in this case it's always hidden, including on pages that don't have an inlinetoc. What I want to do, is only hide Dokuwiki's toc on pages that have the inlinetoc tag.
I tried hooking TPL_METAHEADER_OUTPUT to inject a stylesheet but again it would always hide Dokuwiki's toc.
I've committed a version with a commented CSS to hide Dokuwiki's toc for those aren't interested with Dokuwiki's toc (remove the _ before div.toc in plugins/inlinetoc/style.css to enable the style).
Andreone, 2011/07/16
I finally managed to disabled dokuwiki's toc only on pages where inlinetoc is used with a bit of javascript.
Andreone, 2011/08/12
Very nice! You should refreshLast update
on plugin page. Thore, 2011/08/16Totally forgot, thanks.
Hiding Dokuwiki TOC for Adora Belle
Until the plugin is updated, here is what you'll have to change in order to hide the Dokuwiki TOC. Edit inlinetoc.js:
if(elements[i].className == 'toc') {
to
if(elements[i].id == 'dw__toc') {
Also see issue on Github.
inlinetoc.js jQuery version for Adora Belle and Weatherwax (solved)
Here is a jQuery solution to make DokuWiki TOC invisible.
- inlinetoc.js
function hideDokuwikiToc() { var $toc = jQuery('#dw__toc'); var $toc2= jQuery('div.inlinetoc2'); if($toc2.length && $toc.length) { $toc.css('display', 'none'); } } jQuery(function(){ hideDokuwikiToc(); });
— s.sahara 2013/05/13
Thanks s.sahara, I've created a fork with your code for Weatherwax. Here's the GitHub zip for download. — Rik Blok 2013/07/20 08:11 This plugin has been updated to work with Weatherwax so my fork isn't needed anymore. — Rik Blok 2013/07/27 21:00
Thank you both of you for providing a working solution during my coma. – Andreone 2013/07/27 22:30
Problem: no output on screen, INLINETOC not working? (solved)
I inserted
{{INLINETOC}}
at the beginning of a page, but no toc is generated.
Any idea would goes wrong? 24.08.2011 Joachim
At first, do you correctly installed the plugin? When downloaded from github, the directory inside the archive must be renamed to inlinetoc.
Do you still see the standard TOC or absolutely nothing?
Your test page must have at least three header lines so dokuwiki generates toc entries (that inlinetoc use). Andreone, 2011/08/24- plugin directory is correct
- standard TOC is visible
- more than three header lines
After some investigation it seems to be a conflict with sortablejs plugin and/or plugin searchtablejs
If I disable these plugins, INLINETOC works well.
On other pages with no sortablejs/searchtablejs INLINETOC also works well.2011-08-25 Joachim
Examples:
not working
====== plugin inlinetoc ====== {{INLINETOC}} ===== - Header 1 ===== ==== - Header 1.2 ==== ==== - Header 1.2 ==== ===== - Header 2 ===== <sortable> <searchtable> ^ Header ^ | Test 1 | | Test 2 | </searchtable> </sortable>
working
====== plugin inlinetoc ====== {{INLINETOC}} ===== - Header 1 ===== ==== - Header 1.2 ==== ==== - Header 1.2 ==== ===== - Header 2 ===== <searchtable> <sortable> ^ Header ^ | Test 1 | | Test 2 | </sortable> </searchtable>
Thanks for the update. I'll try to see if I can do something about that conflict. Andreone, 2011/08/25
INLINETOC functionality with <searchtable> and <sortable> on the same page depends on the order of <searchtable> and <sortable>
Solved: Use the following order and INLINETOC will work: 1. <searchtable> and 2. <sortable>
see example above! 2011-08-30 Joachim
Disabling numbering (solved)
I use the numberedheadings plugin to number the headings of the pages.
In print output, INLINETOC also numbers the headings (first number):
1. Header 1 1. 1 Header 2 1. 1.1 Header 3 2. 1.2 Header 3 2. 2 Header 2 etc.
On screen, a bullet point is shown.
Is it possible to disable this (per page)?2011-09-14 Joachim
Solved: I added the following to conf/userprint.css: 2011-09-15 Joachim
div.inlinetoc2 ul { list-style-type: square; line-height: 1.5em; _margin-left: 2em; }
Solved 2015-05-14 / Skyscraper disable list-style-type - edit file dokuwiki/lib/plugins/inlinetoc/all.css
change from div.inlinetoc2 ul { list-style-type: decimal; line-height: 1.5em; _margin-left: 2em; } to div.inlinetoc2 ul { list-style-type: none; line-height: 1.5em; _margin-left: 2em; }
Bootstrap3 template
The new way to disable dokuwiki TOC doesn't work with Bootstrap3 template. Switch to back to the previous version will do. – changed by coastGNU 2015-11-11
Bootstrap3 template supports inlinetoc
— coastGNU 2015-11-11 14:26