1<?php
2/**
3 * DokuWiki Plugin wst (Syntax Component)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  Vitalie Ciubotaru <vitalie@ciubotaru.tk>
7 */
8
9// must be run within Dokuwiki
10if (!defined('DOKU_INC')) die();
11if (!defined('DOKU_LF')) define('DOKU_LF', "\n");
12if (!defined('DOKU_TAB')) define('DOKU_TAB', "\t");
13if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
14
15class syntax_plugin_wst_template extends DokuWiki_Syntax_Plugin {
16    /**
17     * @return string Syntax mode type
18     */
19    public function getType() {
20        return 'substition';//maybe switch to 'container'
21    }
22    /**
23     * @return string Paragraph type
24     */
25    public function getPType() {
26        return 'normal'; //?
27    }
28    /**
29     * @return int Sort order - Low numbers go before high numbers
30     */
31    public function getSort() {
32        return 319; // should go before Doku_Parser_Mode_media 320
33    }
34    /**
35     * Connect lookup pattern to lexer.
36     *
37     * @param string $mode Parser mode
38     */
39    public function connectTo($mode) {
40        $this->Lexer->addSpecialPattern('\{\{[W|w][S|s][T|t]>(?:(?:[^\}]*?\{.*?\}\})|.*?)+?\}\}', $mode, 'plugin_wst_template');
41    }
42
43/**
44    public function postConnect() {
45        $this->Lexer->addExitPattern('\}\}', 'plugin_wst');
46    }
47**/
48    /**
49     * Handle matches of the wst syntax
50     *
51     * @param string          $match   The match of the syntax
52     * @param int             $state   The state of the handler
53     * @param int             $pos     The position in the document
54     * @param Doku_Handler    $handler The handler
55     * @return array Data for the renderer
56     */
57    public function handle($match, $state, $pos, Doku_Handler $handler){
58		if (empty($match)) return false;
59        $template_arguments = array();
60		$dump = trim(substr($match, 6, -2));     // remove curly brackets and "wst:" keyword
61		$dump = preg_replace_callback('/\{\{(((?!(\{\{|\}\})).*?|(?R))*)\}\}/', function($match) {return str_replace('|', '{{!}}', $match[0]);}, $dump);
62        $dump = explode('|', $dump);             // split template name and arguments
63		$template_name = $dump[0];
64		array_splice($dump, 0, 1); // leave only arguments (if any)
65        if ($dump) {
66			$template_arguments = array();
67			foreach ($dump as $key => $value) {
68				// cases with {{Template:X|key1=value1|key2=value2}}
69				if (strpos($value, '=') !== false) {
70					$tmp = explode("=", $value);
71					$template_arguments[trim($tmp[0])] = trim($tmp[1]);
72				}
73				// cases with {{Template:X|value1|value2}}, same as 1=value1
74				// start from 1, not 0
75				else $template_arguments[$key+1] = trim($value);
76			}
77		}
78		$template_arguments = str_replace('{{!}}', '|', $template_arguments);
79		$template = $this->get_template($template_name);
80		if (!$template) return;
81		$template_text = $this->replace_args($template, $template_arguments);
82		return $template_text;
83    }
84
85    /**
86     * Render xhtml output or metadata
87     *
88     * @param string         $mode      Renderer mode (supported modes: xhtml)
89     * @param Doku_Renderer  $renderer  The renderer
90     * @param array          $data      The data from the handler() function
91     * @return bool If rendering was successful.
92     */
93    public function render($mode, Doku_Renderer $renderer, $data) {
94        if($mode != 'xhtml') return false;
95        if (!$data) return false;
96		$renderer->doc .= $renderer->render_text($data, 'xhtml');
97        return true;
98    }
99
100	function get_template($name) {
101		/**
102		 * by default, a page from namespace specified in $conf['namespace'] will be loaded
103		 * To override this, prepend a colon to $name
104		**/
105		$template = rawWiki((substr($name, 0, 1) == ":") || ($this->getConf('namespace') == '') ? substr($name, 1) : $this->getConf('namespace') . ":" . $name);
106		if (!$template) return false;
107		$template = preg_replace('/<noinclude>.*?<\/noinclude>/s', '', $template);
108		$template = preg_replace('/<includeonly>|<\/includeonly>/', '', $template);
109		return $template;
110	}
111
112	function replace_args($template_text, $args) {
113		$keys = array_keys($args);
114		foreach ($keys as $key) {
115			$template_text = str_replace('{{{' . $key . '}}}', $args[$key], $template_text);
116		}
117		// replace mising arguments with a placeholder
118		$template_text = preg_replace('/\{\{\{.*?\}\}\}/', $this->getLang('missing_argument'), $template_text);
119		return $template_text;
120	}
121}
122
123