xref: /plugin/siteexport/syntax/toc.php (revision 0571ece201b9e3bc14846f6c88d943a4f1512014)
17d101cc1SGerry Weißbach<?php
27d101cc1SGerry Weißbach/**
37d101cc1SGerry Weißbach * Search with Scopes
47d101cc1SGerry Weißbach *
57d101cc1SGerry Weißbach * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
67d101cc1SGerry Weißbach * @author     i-net software <tools@inetsoftware.de>
77d101cc1SGerry Weißbach * @author     Gerry Weissbach <gweissbach@inetsoftware.de>
87d101cc1SGerry Weißbach */
97d101cc1SGerry Weißbach
107d101cc1SGerry Weißbach// must be run within Dokuwiki
117d101cc1SGerry Weißbachif (!defined('DOKU_INC')) die();
127d101cc1SGerry Weißbachif (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/');
137d101cc1SGerry Weißbach
147d101cc1SGerry Weißbachrequire_once(DOKU_PLUGIN . 'syntax.php');
157d101cc1SGerry Weißbach
167d101cc1SGerry Weißbachclass syntax_plugin_siteexport_toc extends DokuWiki_Syntax_Plugin {
177d101cc1SGerry Weißbach
187d101cc1SGerry Weißbach	var $insideToc = false;
197d101cc1SGerry Weißbach	var $savedToc = array();
205321bc23SGerry Weißbach	var $options = array();
217d101cc1SGerry Weißbach
227d101cc1SGerry Weißbach	var $mergedPages = array();
237d101cc1SGerry Weißbach	var $includedPages = array();
247d101cc1SGerry Weißbach
257d101cc1SGerry Weißbach	function getType() { return 'protected'; }
267d101cc1SGerry Weißbach	function getPType() { return 'block'; }
277d101cc1SGerry Weißbach	function getAllowedTypes() { return array('container'); }
287d101cc1SGerry Weißbach	function getSort() { return 100; }
297d101cc1SGerry Weißbach
307d101cc1SGerry Weißbach	/**
317d101cc1SGerry Weißbach	 * Connect pattern to lexer
327d101cc1SGerry Weißbach	 */
337d101cc1SGerry Weißbach	function connectTo($mode) {
347d101cc1SGerry Weißbach		$this->Lexer->addEntryPattern('<toc>(?=.*?</toc>)', $mode, 'plugin_siteexport_toc');
357d101cc1SGerry Weißbach		$this->Lexer->addEntryPattern('<toc .+?>(?=.*?</toc>)', $mode, 'plugin_siteexport_toc');
367d101cc1SGerry Weißbach		$this->Lexer->addSpecialPattern("\[\[.+?\]\]", $mode, 'plugin_siteexport_toc');
377d101cc1SGerry Weißbach	}
387d101cc1SGerry Weißbach
397d101cc1SGerry Weißbach	function postConnect() {
407d101cc1SGerry Weißbach		$this->Lexer->addExitPattern('</toc.*?>', 'plugin_siteexport_toc');
417d101cc1SGerry Weißbach	}
427d101cc1SGerry Weißbach
431a51ced3SGerry Weißbach	function handle($match, $state, $pos, Doku_Handler $handler) {
447d101cc1SGerry Weißbach		global $ID, $INFO;
457d101cc1SGerry Weißbach
467d101cc1SGerry Weißbach		switch ($state) {
477d101cc1SGerry Weißbach			case DOKU_LEXER_ENTER:
487d101cc1SGerry Weißbach
497d101cc1SGerry Weißbach				$this->insideToc = true;
507d101cc1SGerry Weißbach
515321bc23SGerry Weißbach				$this->options = explode(' ', substr($match, 5, -1));
52d04831eaSGerry Weißbach
535321bc23SGerry Weißbach				return array('start' => true, 'pos' => $pos, 'options' => $this->options);
547d101cc1SGerry Weißbach				break;
557d101cc1SGerry Weißbach
567d101cc1SGerry Weißbach			case DOKU_LEXER_SPECIAL:
577d101cc1SGerry Weißbach
587d101cc1SGerry Weißbach				if ($this->insideToc) {
597d101cc1SGerry Weißbach
607d101cc1SGerry Weißbach					$link = preg_replace(array('/^\[\[/', '/\]\]$/u'), '', $match);
617d101cc1SGerry Weißbach					// Split title from URL
627d101cc1SGerry Weißbach					$link = explode('|', $link, 2);
637d101cc1SGerry Weißbach					if (!isset($link[1])) {
647d101cc1SGerry Weißbach						$link[1] = NULL;
657d101cc1SGerry Weißbach					} else if (preg_match('/^\{\{[^\}]+\}\}$/', $link[1])) {
667d101cc1SGerry Weißbach						// If the title is an image, convert it to an array containing the image details
677d101cc1SGerry Weißbach						$link[1] = Doku_Handler_Parse_Media($link[1]);
687d101cc1SGerry Weißbach					}
697d101cc1SGerry Weißbach					$link[0] = trim($link[0]);
707d101cc1SGerry Weißbach
717d101cc1SGerry Weißbach					if (!(preg_match('/^[a-zA-Z0-9\.]+>{1}.*$/u', $link[0]) ||
727d101cc1SGerry Weißbach					preg_match('/^\\\\\\\\[\w.:?\-;,]+?\\\\/u', $link[0]) ||
737d101cc1SGerry Weißbach					preg_match('#^([a-z0-9\-\.+]+?)://#i', $link[0]) ||
747d101cc1SGerry Weißbach					preg_match('<' . PREG_PATTERN_VALID_EMAIL . '>', $link[0]) ||
757d101cc1SGerry Weißbach					preg_match('!^#.+!', $link[0]))
767d101cc1SGerry Weißbach					) {
777d101cc1SGerry Weißbach
787d101cc1SGerry Weißbach						// Get current depth from call stack
797d101cc1SGerry Weißbach						$depth = 1;
807d101cc1SGerry Weißbach						if ($handler->CallWriter instanceof Doku_Handler_List) {
817d101cc1SGerry Weißbach
827d101cc1SGerry Weißbach							$calls = array_reverse($handler->CallWriter->calls);
837d101cc1SGerry Weißbach							$call = $calls[0];
847d101cc1SGerry Weißbach							foreach ($calls as $item) {
857d101cc1SGerry Weißbach								if (in_array($item[0], array('list_item', 'list_open'))) { $call = $item; break; }
867d101cc1SGerry Weißbach							}
877d101cc1SGerry Weißbach
88a99d6deeSGerry Weißbach							$depth = $handler->CallWriter->interpretSyntax($call[1][0], $listType)-1; // Minus one because of plus one inside the interpret function
897d101cc1SGerry Weißbach						}
907d101cc1SGerry Weißbach
917d101cc1SGerry Weißbach						if (empty($link[0])) { break; } // No empty elements. This would lead to problems
927d101cc1SGerry Weißbach						return array($link[0], $link[1], $depth);
937d101cc1SGerry Weißbach						break;
947d101cc1SGerry Weißbach					} else {
957d101cc1SGerry Weißbach						// use parser! - but with another p
967d101cc1SGerry Weißbach						$handler->internallink($match, $state, $pos);
977d101cc1SGerry Weißbach					}
987d101cc1SGerry Weißbach				} else {
997d101cc1SGerry Weißbach					// use parser!
1007d101cc1SGerry Weißbach					$handler->internallink($match, $state, $pos);
1017d101cc1SGerry Weißbach				}
1027d101cc1SGerry Weißbach
1037d101cc1SGerry Weißbach				return false;
1047d101cc1SGerry Weißbach			case DOKU_LEXER_UNMATCHED:
1057d101cc1SGerry Weißbach
1067d101cc1SGerry Weißbach    			$handler->_addCall('cdata', array($match), $pos);
1075321bc23SGerry Weißbach
1087d101cc1SGerry Weißbach				return false;
1097d101cc1SGerry Weißbach				break;
1107d101cc1SGerry Weißbach			case DOKU_LEXER_EXIT:
1117d101cc1SGerry Weißbach
1127d101cc1SGerry Weißbach				$this->insideToc = false;
1137d101cc1SGerry Weißbach				return 'save__meta';
1147d101cc1SGerry Weißbach				break;
1157d101cc1SGerry Weißbach		}
1167d101cc1SGerry Weißbach		return false;
1177d101cc1SGerry Weißbach	}
1187d101cc1SGerry Weißbach
119e983d60aSGerry Weißbach	function render($mode, Doku_Renderer $renderer, $data) {
1207d101cc1SGerry Weißbach		global $ID, $lang, $INFO;
1217d101cc1SGerry Weißbach
1227d101cc1SGerry Weißbach		list($SID, $NAME, $DEPTH) = $data;
1237d101cc1SGerry Weißbach
1247d101cc1SGerry Weißbach		resolve_pageid(getNS($ID), $SID, $exists);
1254d9989ecSGerry Weißbach//		$SID = cleanID($SID); // hier kein cleanID, da sonst moeglicherweise der anker verloren geht
1267d101cc1SGerry Weißbach
1277d101cc1SGerry Weißbach        //    Render XHTML and ODT
1287d101cc1SGerry Weißbach		if ($mode == 'xhtml' || $mode == 'odt') {
1297d101cc1SGerry Weißbach
1307d101cc1SGerry Weißbach		    // TOC Title
131d04831eaSGerry Weißbach			if (is_array($data) && $data['start'] == true) {
1327d101cc1SGerry Weißbach
1337d101cc1SGerry Weißbach			    if (is_Array($data['options'])) {
1347d101cc1SGerry Weißbach                    foreach ($data['options'] as $opt) {
1357d101cc1SGerry Weißbach    					switch ($opt) {
1367d101cc1SGerry Weißbach    						case 'description' : $renderer->meta['sitetoc']['showDescription'] = true; break;
1377d101cc1SGerry Weißbach    						case 'notoc' : $renderer->meta['sitetoc']['noTOC'] = true; break;
1387d101cc1SGerry Weißbach    						case 'merge' : $renderer->meta['sitetoc']['mergeDoc'] = true; break;
1397d101cc1SGerry Weißbach    						case 'nohead' : $renderer->meta['sitetoc']['noTocHeader'] = true; break;
1405321bc23SGerry Weißbach    						case 'mergeheader' : $renderer->meta['sitetoc']['mergeHeader'] = true; break;
14122a479aeSGerry Weißbach    						case 'pagebreak' : $renderer->meta['sitetoc']['pagebreak'] = true; break;
1427d101cc1SGerry Weißbach    					}
1437d101cc1SGerry Weißbach    				}
1447d101cc1SGerry Weißbach			    }
1457d101cc1SGerry Weißbach
1467d101cc1SGerry Weißbach				$renderer->section_open("1 sitetoc");
1477d101cc1SGerry Weißbach				if ($renderer->meta['sitetoc']['noTocHeader'] === false) {
1487d101cc1SGerry Weißbach					$renderer->header($lang['toc'], 1, $data['pos']);
1497d101cc1SGerry Weißbach				}
1507d101cc1SGerry Weißbach
1517d101cc1SGerry Weißbach				return true;
152d04831eaSGerry Weißbach			} else
1537d101cc1SGerry Weißbach
1547d101cc1SGerry Weißbach			// All Output has been done
1557d101cc1SGerry Weißbach			if (!is_array($data) && $data == 'save__meta') {
1567d101cc1SGerry Weißbach
1577d101cc1SGerry Weißbach				// Close TOC
1587d101cc1SGerry Weißbach				$renderer->section_close();
1597d101cc1SGerry Weißbach
1607d101cc1SGerry Weißbach				if ($renderer->meta['sitetoc']['noTOC'] === true) {
1617d101cc1SGerry Weißbach					$renderer->doc = preg_replace("/<div.*?sitetoc.*?$/si", "", $renderer->doc);
1627d101cc1SGerry Weißbach				}
1637d101cc1SGerry Weißbach
1647d101cc1SGerry Weißbach				// If this is not set, we may have it as Metadata
1657d101cc1SGerry Weißbach				if (!$this->mergedPages && $renderer->meta['sitetoc']['mergeDoc']) {
1667d101cc1SGerry Weißbach					$toc = $renderer->meta['sitetoc']['siteexportTOC'];
167a99d6deeSGerry Weißbach
1687d101cc1SGerry Weißbach					if (is_array($toc)) {
1697d101cc1SGerry Weißbach						foreach ($toc as $tocItem) {
170a99d6deeSGerry Weißbach							$this->mergedPages[] = array($tocItem['id'], $tocItem['depth']);
1717d101cc1SGerry Weißbach						}
1727d101cc1SGerry Weißbach					}
173a99d6deeSGerry Weißbach
1747d101cc1SGerry Weißbach				}
1757d101cc1SGerry Weißbach
1767d101cc1SGerry Weißbach				// If there is some data to be merged
1777d101cc1SGerry Weißbach				if (count($this->mergedPages) > 0) {
1787d101cc1SGerry Weißbach
1795321bc23SGerry Weißbach					$renderer->doc = ''; // Start fresh!
1805321bc23SGerry Weißbach
1817d101cc1SGerry Weißbach					$renderer->section_open("1 mergedsite");
1827d101cc1SGerry Weißbach
1837d101cc1SGerry Weißbach					// Prepare lookup Array
1847d101cc1SGerry Weißbach					foreach ($this->mergedPages as $tocItem) {
185a99d6deeSGerry Weißbach						$this->includedPages[] = array_shift(explode('#', $tocItem[0]));
1867d101cc1SGerry Weißbach					}
1877d101cc1SGerry Weißbach
1885321bc23SGerry Weißbach					// Load the instructions
1895321bc23SGerry Weißbach					$instr = array();
190a99d6deeSGerry Weißbach					foreach ($this->mergedPages as $tocElement) {
191a99d6deeSGerry Weißbach
192a99d6deeSGerry Weißbach					    list($tocItem, $depth) = $tocElement;
1935321bc23SGerry Weißbach						$file = wikiFN($tocItem);
1946792d0cfSGerry Weißbach
1956792d0cfSGerry Weißbach						if (@file_exists($file)) {
1966792d0cfSGerry Weißbach							$instructions = p_cached_instructions($file, false, $tocItem);
1976792d0cfSGerry Weißbach						} else {
1986792d0cfSGerry Weißbach							$instructions = p_get_instructions(io_readWikiPage($file, $tocItem));
1996792d0cfSGerry Weißbach						}
2005321bc23SGerry Weißbach
201a99d6deeSGerry Weißbach						// Convert Link and header instructions
202a99d6deeSGerry Weißbach						$instructions = $this->_convertInstructions($instructions, $addID, $renderer, $depth);
2035321bc23SGerry Weißbach
2045321bc23SGerry Weißbach						if ($renderer->meta['sitetoc']['mergeHeader'] && !empty($instr)) {
2055321bc23SGerry Weißbach							// Merge
2065321bc23SGerry Weißbach							$instr = $this->_mergeWithHeaders($instr, $instructions, 1);
20722a479aeSGerry Weißbach						} else
20822a479aeSGerry Weißbach						if ($renderer->meta['sitetoc']['pagebreak']) {
20922a479aeSGerry Weißbach    						$instr = array_merge($instr, $instructions, $this->_convertInstructions(p_get_instructions('<sitepagebreak>'), $addID, $renderer, $depth));
2105321bc23SGerry Weißbach						} else {
2115321bc23SGerry Weißbach							// Concat
2125321bc23SGerry Weißbach							$instr = array_merge($instr, $instructions);
2137d101cc1SGerry Weißbach						}
2145321bc23SGerry Weißbach					}
2155321bc23SGerry Weißbach
216d04831eaSGerry Weißbach					if (!empty($instr)) {
2175321bc23SGerry Weißbach    					$this->_cleanInstructions($instr, '/section_(close|open)/');
2185321bc23SGerry Weißbach    					$this->_cleanInstructions($instr, '/listu_(close|open)/');
2195321bc23SGerry Weißbach    					$this->_cleanInstructions($instr, '/listo_(close|open)/');
2205321bc23SGerry Weißbach
22122a479aeSGerry Weißbach						//if its the document start, cut off the first element(document information)
22222a479aeSGerry Weißbach                        if ($instr[count($instr)-1][1][0] == 'siteexport_pagebreak') {
22322a479aeSGerry Weißbach                            $instr = array_slice($instr, 0, -1);
22422a479aeSGerry Weißbach                        }
22522a479aeSGerry Weißbach
2265321bc23SGerry Weißbach    					$this->_render_output($renderer, $mode, $instr);
227d04831eaSGerry Weißbach					}
228d04831eaSGerry Weißbach
2297d101cc1SGerry Weißbach					$renderer->section_close();
2307d101cc1SGerry Weißbach				}
2317d101cc1SGerry Weißbach				return true;
2327d101cc1SGerry Weißbach			}
2337d101cc1SGerry Weißbach
2347d101cc1SGerry Weißbach			// Save the current ID
2357d101cc1SGerry Weißbach			$LNID = $SID;
2367d101cc1SGerry Weißbach
2377d101cc1SGerry Weißbach			// Add ID to flags['mergeDoc']
2387d101cc1SGerry Weißbach			if ($renderer->meta['sitetoc']['mergeDoc'] === true) { // || (count($renderer->meta['sitetoc']['siteexportTOC']) > 0 && $renderer->meta['sitetoc']['siteexportMergeDoc'] === true) ) {
239a99d6deeSGerry Weißbach				$this->mergedPages[] = array($SID, $DEPTH);
2407d101cc1SGerry Weißbach				$default = $renderer->_simpleTitle($SID); $isImage = false;
2417d101cc1SGerry Weißbach				resolve_pageid(getNS($ID), $SID, $exists);
2427d101cc1SGerry Weißbach
2437d101cc1SGerry Weißbach				$NAME = empty($NAME) ? p_get_first_heading($SID, true) : $NAME;
2447d101cc1SGerry Weißbach				$LNID = "$ID#" . sectionID($SID, $check);
245a99d6deeSGerry Weißbach
2465321bc23SGerry Weißbach			} else {
2475321bc23SGerry Weißbach				// // print normal internal link (XHTML odt)
2487d101cc1SGerry Weißbach				$renderer->internallink($LNID, $NAME, null);
2497d101cc1SGerry Weißbach
2507d101cc1SGerry Weißbach				// Display Description underneath
2517d101cc1SGerry Weißbach				if ($renderer->meta['sitetoc']['showDescription'] === true) {
2527d101cc1SGerry Weißbach					// $renderer->p_open();
2537d101cc1SGerry Weißbach					$renderer->cdata(p_get_metadata($SID, 'description abstract', true));
2547d101cc1SGerry Weißbach					// $renderer->p_close();
2557d101cc1SGerry Weißbach				}
2565321bc23SGerry Weißbach			}
2577d101cc1SGerry Weißbach
2587d101cc1SGerry Weißbach			// Render Metadata
2597d101cc1SGerry Weißbach		} else if ($mode == 'metadata') {
2607d101cc1SGerry Weißbach			if (!is_array($data) && $data == 'save__meta') {
2617d101cc1SGerry Weißbach				$renderer->meta['sitetoc']['siteexportTOC'] = $this->savedToc;
2627d101cc1SGerry Weißbach
2637d101cc1SGerry Weißbach                foreach ($this->savedToc as $page) {
2647d101cc1SGerry Weißbach                    $renderer->meta['relation']['references'][$page['id']] = $page['exists'];
2657d101cc1SGerry Weißbach                }
2667d101cc1SGerry Weißbach
2677d101cc1SGerry Weißbach				$this->savedToc = array();
2687d101cc1SGerry Weißbach			} else if (!isset($data['start']) && !isset($data['pos'])) {
2697d101cc1SGerry Weißbach				$this->savedToc[] = $this->__addTocItem($SID, $NAME, $DEPTH, $renderer);
2707d101cc1SGerry Weißbach			}
2717d101cc1SGerry Weißbach		} else {
2727d101cc1SGerry Weißbach			return false;
2737d101cc1SGerry Weißbach		}
2747d101cc1SGerry Weißbach
2757d101cc1SGerry Weißbach		return true;
2767d101cc1SGerry Weißbach	}
2777d101cc1SGerry Weißbach
2787d101cc1SGerry Weißbach	/*
2797d101cc1SGerry Weißbach	 * pull apart the ID and create an Entry for the TOC
2807d101cc1SGerry Weißbach	 */
2817d101cc1SGerry Weißbach	function __addTocItem($id, $name, $depth, $renderer) {
2827d101cc1SGerry Weißbach		global $conf;
2837d101cc1SGerry Weißbach		global $ID;
2847d101cc1SGerry Weißbach
2857d101cc1SGerry Weißbach		// Render Title
2867d101cc1SGerry Weißbach		$default = $renderer->_simpleTitle($id);
2877d101cc1SGerry Weißbach		$exists = false; $isImage = false; $linktype = null;
2887d101cc1SGerry Weißbach		resolve_pageid(getNS($ID), $id, $exists);
2897d101cc1SGerry Weißbach		$name = $renderer->_getLinkTitle($name, $default, $isImage, $id, $linktype);
2907d101cc1SGerry Weißbach
2917d101cc1SGerry Weißbach		//keep hash anchor
2927d101cc1SGerry Weißbach		list($id, $hash) = explode('#', $id, 2);
2937d101cc1SGerry Weißbach		if (!empty($hash)) $hash = $renderer->_headerToLink($hash);
2947d101cc1SGerry Weißbach
2957d101cc1SGerry Weißbach		// Build Sitetoc Item
2967d101cc1SGerry Weißbach		$item = array();
2977d101cc1SGerry Weißbach		$item['id'] = $id;
2987d101cc1SGerry Weißbach		$item['name'] = $name;
2997d101cc1SGerry Weißbach		$item['anchor'] = $hash;
3007d101cc1SGerry Weißbach		$item['depth'] = $depth;
3017d101cc1SGerry Weißbach		$item['exists'] = $exists;
3027d101cc1SGerry Weißbach		if (!$conf['skipacl'] && auth_quickaclcheck($item['id']) < AUTH_READ) {
3037d101cc1SGerry Weißbach			return false;
3047d101cc1SGerry Weißbach		}
3057d101cc1SGerry Weißbach
3067d101cc1SGerry Weißbach		return $item;
3077d101cc1SGerry Weißbach	}
3087d101cc1SGerry Weißbach
3097d101cc1SGerry Weißbach	/*
3107d101cc1SGerry Weißbach	 * Render the output of one page
3117d101cc1SGerry Weißbach	 */
3125321bc23SGerry Weißbach	function _render_output($renderer, $mode, $instr) {
3137d101cc1SGerry Weißbach		global $ID;
3147d101cc1SGerry Weißbach
3157d101cc1SGerry Weißbach		// Section IDs
3165321bc23SGerry Weißbach		// $addID = sectionID($addID, $check);	//not possible to use a:b:c for id
3177d101cc1SGerry Weißbach
3187d101cc1SGerry Weißbach		if ($mode == 'xhtml') {
3195321bc23SGerry Weißbach
3207d101cc1SGerry Weißbach			//--------RENDER
3217d101cc1SGerry Weißbach			//renderer information(TOC build / Cache used)
3227d101cc1SGerry Weißbach			$info = array();
3237d101cc1SGerry Weißbach			$content = p_render($mode, $instr, $info);
3247d101cc1SGerry Weißbach
3257d101cc1SGerry Weißbach			//Remove TOC`s, section edit buttons and tags
3267d101cc1SGerry Weißbach			$content = $this->_cleanXHTML($content);
3277d101cc1SGerry Weißbach
3287d101cc1SGerry Weißbach			// embed the included page
3296792d0cfSGerry Weißbach			// $renderer->doc .= '<div class="include">';
3307d101cc1SGerry Weißbach			//add an anchor to find start of a inserted page
3315321bc23SGerry Weißbach			// $renderer->doc .= "<a name='$addID' id='$addID'>";
3327d101cc1SGerry Weißbach			$renderer->doc .= $content;
3336792d0cfSGerry Weißbach			// $renderer->doc .= '</div>';
3347d101cc1SGerry Weißbach		} else if ($mode == 'odt') {
3357d101cc1SGerry Weißbach
3367d101cc1SGerry Weißbach			// Loop through the instructions
3377d101cc1SGerry Weißbach			foreach ($instr as $instruction) {
3387d101cc1SGerry Weißbach				// Execute the callback against the Renderer
3397d101cc1SGerry Weißbach				call_user_func_array(array($renderer, $instruction[0]), $instruction[1]);
3407d101cc1SGerry Weißbach			}
3417d101cc1SGerry Weißbach		}
3427d101cc1SGerry Weißbach	}
3437d101cc1SGerry Weißbach
3447d101cc1SGerry Weißbach	/*
3457d101cc1SGerry Weißbach	 * Corrects relative internal links and media and
3467d101cc1SGerry Weißbach	 * converts headers of included pages to subheaders of the current page
3477d101cc1SGerry Weißbach	 */
348a99d6deeSGerry Weißbach	function _convertInstructions($instr, $id, &$renderer, $depth = 1) {
3497d101cc1SGerry Weißbach		global $ID;
3507d101cc1SGerry Weißbach		global $conf;
3517d101cc1SGerry Weißbach
3527d101cc1SGerry Weißbach		$n = count($instr);
3537d101cc1SGerry Weißbach
3547d101cc1SGerry Weißbach		for ($i = 0; $i < $n; $i++) {
3557d101cc1SGerry Weißbach			//internal links(links inside this wiki) an relative links
3567d101cc1SGerry Weißbach			if ((substr($instr[$i][0], 0, 12) == 'internallink')) {
3577d101cc1SGerry Weißbach				$this->_convert_link($renderer, $instr[$i], $id);
3587d101cc1SGerry Weißbach			}
3597d101cc1SGerry Weißbach			else if ((substr($instr[$i][0], 0, 13) == 'internalmedia')) {
3607d101cc1SGerry Weißbach				$this->_convert_media($renderer, $instr[$i], $id);
3617d101cc1SGerry Weißbach			}
362a99d6deeSGerry Weißbach			else if ((substr($instr[$i][0], 0, 6) == 'header')) {
363a99d6deeSGerry Weißbach				$this->_convert_header($renderer, $instr[$i], $depth-1); // -1 because the depth starts at 1
364a99d6deeSGerry Weißbach			}
365a99d6deeSGerry Weißbach			else if ((substr($instr[$i][0], 0, 12) == 'section_open')) {
366a99d6deeSGerry Weißbach				$this->_convert_section($renderer, $instr[$i], $depth-1); // -1 because the depth starts at 1
367a99d6deeSGerry Weißbach			}
3687d101cc1SGerry Weißbach		}
3697d101cc1SGerry Weißbach
3707d101cc1SGerry Weißbach		//if its the document start, cut off the first element(document information)
3717d101cc1SGerry Weißbach		if ($instr[0][0] == 'document_start')
3727d101cc1SGerry Weißbach		return array_slice($instr, 1, -1);
3737d101cc1SGerry Weißbach		else
3747d101cc1SGerry Weißbach		return $instr;
3757d101cc1SGerry Weißbach	}
3767d101cc1SGerry Weißbach
3777d101cc1SGerry Weißbach	/*
3787d101cc1SGerry Weißbach	 * Convert link of given instruction
3797d101cc1SGerry Weißbach	 */
3807d101cc1SGerry Weißbach	function _convert_link(&$renderer, &$instr, $id) {
3817d101cc1SGerry Weißbach		global $ID;
3827d101cc1SGerry Weißbach
3837d101cc1SGerry Weißbach		$exists = false;
3847d101cc1SGerry Weißbach
3857d101cc1SGerry Weißbach		resolve_pageid(getNS($id), $instr[1][0], $exists);
3867d101cc1SGerry Weißbach		list($pageID, $pageReference) = explode("#", $instr[1][0], 2);
3877d101cc1SGerry Weißbach
3887d101cc1SGerry Weißbach		if (in_array($pageID, $this->includedPages)) {
3897d101cc1SGerry Weißbach			// Crate new internal Links
3907d101cc1SGerry Weißbach			$check = null;
3917d101cc1SGerry Weißbach
3927d101cc1SGerry Weißbach			// Either get existing reference or create from first heading. If still not there take the alternate ID
3937d101cc1SGerry Weißbach			$pageNameLink = empty($pageReference) ? sectionID($pageID, $check) : $pageReference;
3947d101cc1SGerry Weißbach
3957d101cc1SGerry Weißbach			$instr[1][0] = $ID . "#" . $pageNameLink;
3967d101cc1SGerry Weißbach
3977d101cc1SGerry Weißbach		} else {
3987d101cc1SGerry Weißbach			// Convert external Links to plain Text
3997d101cc1SGerry Weißbach
4007d101cc1SGerry Weißbach			$instr = array(
4017d101cc1SGerry Weißbach						"cdata",
4027d101cc1SGerry Weißbach			array($instr[1][1]),
4037d101cc1SGerry Weißbach			$instr[2]
4047d101cc1SGerry Weißbach			);
4057d101cc1SGerry Weißbach		}
4067d101cc1SGerry Weißbach	}
4077d101cc1SGerry Weißbach
4087d101cc1SGerry Weißbach	/*
4097d101cc1SGerry Weißbach	 * Convert internalmedia of given instruction
4107d101cc1SGerry Weißbach	 */
4117d101cc1SGerry Weißbach	function _convert_media(&$renderer, &$instr, $id) {
4127d101cc1SGerry Weißbach		global $ID;
4137d101cc1SGerry Weißbach
4147d101cc1SGerry Weißbach		// Resolvemedia returns the absolute path to media by reference
4157d101cc1SGerry Weißbach		$exists = false;
4167d101cc1SGerry Weißbach		resolve_mediaid(getNS($id), $instr[1][0], $exists);
4177d101cc1SGerry Weißbach	}
4187d101cc1SGerry Weißbach
419*0571ece2SScrutinizer Auto-Fixer	/**
420*0571ece2SScrutinizer Auto-Fixer	 * @param integer $depth
421*0571ece2SScrutinizer Auto-Fixer	 */
422a99d6deeSGerry Weißbach	function _convert_header(&$renderer, &$instr, $depth) {
423a99d6deeSGerry Weißbach    	// More Depth!
424a99d6deeSGerry Weißbach    	$instr[1][1] += $depth;
425a99d6deeSGerry Weißbach	}
426a99d6deeSGerry Weißbach
427*0571ece2SScrutinizer Auto-Fixer	/**
428*0571ece2SScrutinizer Auto-Fixer	 * @param integer $depth
429*0571ece2SScrutinizer Auto-Fixer	 */
430a99d6deeSGerry Weißbach	function _convert_section(&$renderer, &$instr, $depth) {
431a99d6deeSGerry Weißbach    	// More Depth!
432a99d6deeSGerry Weißbach    	$instr[1][0] += $depth;
433a99d6deeSGerry Weißbach	}
434a99d6deeSGerry Weißbach
4355321bc23SGerry Weißbach	function _mergeWithHeaders($existing, $newInstructions, $level = 1) {
4365321bc23SGerry Weißbach
4375321bc23SGerry Weißbach		$returnInstructions = array();
4385321bc23SGerry Weißbach		$preparedInstructions = array();
4395321bc23SGerry Weißbach		$existingStart = $existingEnd = 0;
4405321bc23SGerry Weißbach		$firstRun = true;
4415321bc23SGerry Weißbach
4425321bc23SGerry Weißbach		while ($this->_findNextHeaderSection($existing, $level, $existingStart, $existingEnd)) {
4435321bc23SGerry Weißbach
4445321bc23SGerry Weißbach			if ($firstRun) {
4455321bc23SGerry Weißbach				$returnInstructions = array_merge($returnInstructions, array_slice($existing, 0, $existingStart));
4465321bc23SGerry Weißbach				$firstRun = false;
4475321bc23SGerry Weißbach			}
4485321bc23SGerry Weißbach
4495321bc23SGerry Weißbach			$currentSlice = array_slice($existing, $existingStart, $existingEnd-$existingStart);
4505321bc23SGerry Weißbach
4515321bc23SGerry Weißbach			// Find matching part with headername
4525321bc23SGerry Weißbach			$newStart = $newEnd = 0;
4535321bc23SGerry Weißbach			if ($this->_findNextHeaderSection($newInstructions, $level, $newStart, $newEnd, $currentSlice[0][1][0])) {
4545321bc23SGerry Weißbach
4555321bc23SGerry Weißbach				$newSlice = array_slice($newInstructions, $newStart, $newEnd-$newStart);
4565321bc23SGerry Weißbach				if ($newSlice[0][0] == 'header')
4575321bc23SGerry Weißbach					array_shift($newSlice); // Remove Heading
4585321bc23SGerry Weißbach
4595321bc23SGerry Weißbach				// merge found parts on next level.
4605321bc23SGerry Weißbach				$returnedInstructions = $this->_mergeWithHeaders($currentSlice, $newSlice, $level+1);
4615321bc23SGerry Weißbach
4625321bc23SGerry Weißbach				// Put them at the end!
4635321bc23SGerry Weißbach				$preparedInstructions = array_merge($preparedInstructions, $returnedInstructions);
4645321bc23SGerry Weißbach
4655321bc23SGerry Weißbach				// Remove from input
4665321bc23SGerry Weißbach				array_splice($newInstructions, $newStart, $newEnd-$newStart);
4675321bc23SGerry Weißbach			} else {
4685321bc23SGerry Weißbach				$preparedInstructions = array_merge($preparedInstructions, $currentSlice);
4695321bc23SGerry Weißbach			}
4705321bc23SGerry Weißbach
4715321bc23SGerry Weißbach			$existingStart = $existingEnd;
4725321bc23SGerry Weißbach		}
4735321bc23SGerry Weißbach
4745321bc23SGerry Weißbach		// Append the rest
4755321bc23SGerry Weißbach		$returnInstructions = array_merge($returnInstructions, array_slice($existing, $existingStart));
4765321bc23SGerry Weißbach
4775321bc23SGerry Weißbach		// Check for section close inconsistencies and put one at the very end ...
4785321bc23SGerry Weißbach		$section_postpend = array();
4799490aa3bSAlain		if (
4809490aa3bSAlain		    (
4819490aa3bSAlain			($tmp = array_slice($newInstructions, -1))
4829490aa3bSAlain			&& ($tmp[0][0] == 'section_close')
4839490aa3bSAlain		    )
4849490aa3bSAlain		    &&
4859490aa3bSAlain		    (
4869490aa3bSAlain			($tmp = array_slice($newInstructions, -2))
4879490aa3bSAlain			&& ($tmp[0][0] == 'section_close')
4889490aa3bSAlain		    )
4899490aa3bSAlain		) {
4905321bc23SGerry Weißbach			$section_postpend = array_splice($newInstructions, -1);
4915321bc23SGerry Weißbach		}
4929490aa3bSAlain		if (
4939490aa3bSAlain		    (
4949490aa3bSAlain			($tmp = array_slice($returnInstructions, -1))
4959490aa3bSAlain			&& ($tmp[0][0] == 'section_close')
4969490aa3bSAlain		    )
4979490aa3bSAlain		    &&
4989490aa3bSAlain		    (
4999490aa3bSAlain			($tmp = array_slice($returnInstructions, -2))
5009490aa3bSAlain			&& ($tmp[0][0] == 'section_close')
5019490aa3bSAlain		    )
5029490aa3bSAlain		) {
5035321bc23SGerry Weißbach			$section_postpend = array_merge($section_postpend, array_splice($returnInstructions, -1));
5045321bc23SGerry Weißbach		}
5055321bc23SGerry Weißbach
5065321bc23SGerry Weißbach		// What if there are headings left inside the $newInstructions?????
5075321bc23SGerry Weißbach		// Find matching part with headername
5085321bc23SGerry Weißbach		$newStart = $newEnd = 0;
5095321bc23SGerry Weißbach		$section_prepend = array();
5105321bc23SGerry Weißbach		if ($this->_findNextHeaderSection($newInstructions, $level, $newStart, $newEnd)) {
5115321bc23SGerry Weißbach			// If there are header in here, build a prepend and have the rest at the end
5125321bc23SGerry Weißbach			$section_prepend = array_splice($newInstructions, 0, $newStart);
5135321bc23SGerry Weißbach		} else {
5145321bc23SGerry Weißbach			// If not, prepend all of it.
5155321bc23SGerry Weißbach			$section_prepend = $newInstructions;
5165321bc23SGerry Weißbach			$newInstructions = array();
5175321bc23SGerry Weißbach		}
5185321bc23SGerry Weißbach
5195321bc23SGerry Weißbach		$returnInstructions = array_merge($returnInstructions, $section_prepend, $preparedInstructions, $newInstructions, $section_postpend);
5205321bc23SGerry Weißbach
5215321bc23SGerry Weißbach		return $returnInstructions;
5225321bc23SGerry Weißbach	}
5235321bc23SGerry Weißbach
524*0571ece2SScrutinizer Auto-Fixer	/**
525*0571ece2SScrutinizer Auto-Fixer	 * @param integer $level
526*0571ece2SScrutinizer Auto-Fixer	 */
5275321bc23SGerry Weißbach	function _findNextHeaderSection($section, $level, &$start, &$end, $headerName = null) {
5285321bc23SGerry Weißbach
5295321bc23SGerry Weißbach		$inCount = count($section);
5305321bc23SGerry Weißbach		$currentSlice = -1;
5315321bc23SGerry Weißbach
5325321bc23SGerry Weißbach		// Find Level 1 Header that matches.
5335321bc23SGerry Weißbach		for ($i = $start; $i < $inCount; $i++) {
5345321bc23SGerry Weißbach
5355321bc23SGerry Weißbach			$instruction = $section[$i];
5365321bc23SGerry Weißbach			$end = $i; // Or it will be lost and a section close will be missing.
5375321bc23SGerry Weißbach
5385321bc23SGerry Weißbach			// First Level Header
5395321bc23SGerry Weißbach			if ($instruction[0] == 'header' && $instruction[1][1] == $level) {
5405321bc23SGerry Weißbach
5415321bc23SGerry Weißbach				if ($currentSlice > 0) {
5425321bc23SGerry Weißbach					return true;
5435321bc23SGerry Weißbach				}
5445321bc23SGerry Weißbach
5455321bc23SGerry Weißbach				if ($headerName == null || ($headerName == $instruction[1][0])) {
5465321bc23SGerry Weißbach					// Begin of new slice ...
5475321bc23SGerry Weißbach					$start = $currentSlice = $i;
5485321bc23SGerry Weißbach				}
5495321bc23SGerry Weißbach			}
5505321bc23SGerry Weißbach		}
5515321bc23SGerry Weißbach
5525321bc23SGerry Weißbach		// Nothing found
5535321bc23SGerry Weißbach		$end = $i; // Or it will be lost and a section close will be missing.
5545321bc23SGerry Weißbach		return $currentSlice > 0;
5555321bc23SGerry Weißbach	}
5565321bc23SGerry Weißbach
557*0571ece2SScrutinizer Auto-Fixer	/**
558*0571ece2SScrutinizer Auto-Fixer	 * @param string $tag
559*0571ece2SScrutinizer Auto-Fixer	 */
5605321bc23SGerry Weißbach	function _cleanInstructions(&$instructions, $tag) {
5615321bc23SGerry Weißbach
5625321bc23SGerry Weißbach		$inCount = count($instructions);
5635321bc23SGerry Weißbach		for ($i = 0; $i < $inCount; $i++) {
5645321bc23SGerry Weißbach
5655321bc23SGerry Weißbach			// Last instruction
5665321bc23SGerry Weißbach			if ($i == $inCount-1) {
5675321bc23SGerry Weißbach				break;
5685321bc23SGerry Weißbach			}
5695321bc23SGerry Weißbach
5705321bc23SGerry Weißbach			if (preg_match($tag, $instructions[$i][0]) && preg_match($tag, $instructions[$i+1][0]) && $instructions[$i][0] != $instructions[$i+1][0]) {
5715321bc23SGerry Weißbach
5725321bc23SGerry Weißbach				// found different tags, but both match the expression and follow each other - so they can be elliminated
5735321bc23SGerry Weißbach				array_splice($instructions, $i, 2);
5745321bc23SGerry Weißbach				$inCount -= 2;
5755321bc23SGerry Weißbach				$i--;
5765321bc23SGerry Weißbach			}
5775321bc23SGerry Weißbach
5785321bc23SGerry Weißbach		}
5795321bc23SGerry Weißbach	}
5805321bc23SGerry Weißbach
5817d101cc1SGerry Weißbach	/**
5827d101cc1SGerry Weißbach	 * Remove TOC, section edit buttons and tags
5837d101cc1SGerry Weißbach	 */
5847d101cc1SGerry Weißbach	function _cleanXHTML($xhtml) {
5857d101cc1SGerry Weißbach		$replace = array(
5867d101cc1SGerry Weißbach			'!<div class="toc">.*?(</div>\n</div>)!s' => '', // remove TOCs
5877d101cc1SGerry Weißbach			'#<!-- SECTION \[(\d*-\d*)\] -->#e'       => '', // remove section edit buttons
5887d101cc1SGerry Weißbach			'!<div id="tags">.*?(</div>)!s'           => ''  // remove category tags
5897d101cc1SGerry Weißbach		);
5907d101cc1SGerry Weißbach		$xhtml = preg_replace(array_keys($replace), array_values($replace), $xhtml);
5917d101cc1SGerry Weißbach		return $xhtml;
5927d101cc1SGerry Weißbach	}
5937d101cc1SGerry Weißbach
5947d101cc1SGerry Weißbach
5957d101cc1SGerry Weißbach	/**
5967d101cc1SGerry Weißbach	 * Allow the plugin to prevent DokuWiki creating a second instance of itself
5977d101cc1SGerry Weißbach	 *
5987d101cc1SGerry Weißbach	 * @return bool   true if the plugin can not be instantiated more than once
5997d101cc1SGerry Weißbach	 */
6007d101cc1SGerry Weißbach	function isSingleton() {
6017d101cc1SGerry Weißbach		return true;
6027d101cc1SGerry Weißbach	}
6037d101cc1SGerry Weißbach}
6047d101cc1SGerry Weißbach// vim:ts=4:sw=4:et:enc=utf-8:
605