DokuWiki

It's better when it's simple

User Tools

Site Tools


plugin:inlinetoc

InlineTOC Plugin

Compatible with DokuWiki

  • 2017-02-19 "Frusterick Manners" unknown
  • 2016-06-26 "Elenor Of Tsort" unknown
  • 2015-08-10 "Detritus" unknown
  • 2014-09-29 "Hrun" yes

plugin Renders the toc of a page inside the page content, like Mediawiki

Last updated on
2015-06-19
Provides
Syntax, Action
Repository
Source
Conflicts with
toctweak

Similar to toc, tocselect

Tagged with mediawiki, toc

Installation

Install the plugin using the Plugin Manager and the download URL above, which points to latest version of the plugin. Refer to Plugins on how to install plugins manually.

Examples/Usage

{{INLINETOC}}

Sample result:

Click to view full size

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
  • 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

  1. 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

  2. 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, — hop3l3ss1990hop3l3ss1990

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/23
Maybe 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 BlokRik Blok
rikblok

2011/06/30 06:35
I 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 refresh Last update on plugin page. Thore, 2011/08/16
Totally 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.saharas.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 BlokRik Blok
rikblok

2013/07/20 08:11
This plugin has been updated to work with Weatherwax so my fork isn't needed anymore. — Rik BlokRik Blok
rikblok

2013/07/27 21:00

Thank you both of you for providing a working solution during my coma. – AndreoneAndreone
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 coastGNUThomas Templin
coastGNU

2015-11-11

Bootstrap3 template supports inlinetoc

coastGNUThomas Templin
coastGNU

2015-11-11 14:26

plugin/inlinetoc.txt · Last modified: 2016-11-24 14:12 by turnermm