1<?php
2/**
3 * DokuWiki plugin Diagram, Splitter component.
4 *
5 * This is a helper for Main component.
6 * The purpose is to describe, how diagram specification should be parsed in conjunction with other lexer modes.
7 * Component also provides simple match handling.
8 * Splitter can't be used without Main because we need to move wiki calls for abbreviations from their places to boxes.
9 *
10 * Should work with any DokuWiki version >= 20070626.
11 * Tested with DokuWiki versions 20090214, 20091225, 20110525a, 20121013, 20130510a,
12 * 20131208, 20140505e, 20140929d, 20150810a, 20160626e, 20170219e, 20180422a, 20200729.
13 *
14 * Install to lib/plugins/diagram/syntax/splitter.php.
15 *
16 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
17 * @author Nikita Melnichenko [http://nikita.melnichenko.name]
18 * @copyright Copyright 2007-2021, Nikita Melnichenko
19 */
20
21// includes
22if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
23if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
24require_once(DOKU_PLUGIN.'syntax.php');
25
26/**
27 * DokuWiki plugin Diagram, Splitter component.
28 *
29 * Parses diagram content to get proper wiki calls for abbreviations.
30 */
31class syntax_plugin_diagram_splitter extends DokuWiki_Syntax_Plugin
32{
33	/**
34	 * Tag name in wiki text.
35	 *
36	 * @staticvar string
37	 */
38	var $tag_name = '_diagram_';
39
40	/**
41	 * Get syntax type.
42	 *
43	 * @return string one of the mode types defined in $PARSER_MODES in parser.php
44	 */
45	function getType ()
46	{
47		// containers are complex modes that can contain many other modes
48		// plugin generates table, so type should be container
49		return 'container';
50	}
51
52	/**
53	 * Get paragraph type.
54	 *
55	 * Defines how this syntax is handled regarding paragraphs. This is important
56	 * for correct XHTML nesting. Should return one of the following:
57	 * - 'normal' - The plugin can be used inside paragraphs
58	 * - 'block'  - Open paragraphs need to be closed before plugin output
59	 * - 'stack'  - Special case. Plugin wraps other paragraphs.
60	 *
61	 * @return string
62	 */
63	function getPType ()
64	{
65		// table cannot be put inside paragraphs
66		return 'block';
67	}
68
69	/**
70	 * Get position of plugin's mode in decision list.
71	 *
72	 * @return integer
73	 */
74	function getSort ()
75	{
76		// before Doku_Parser_Mode_table
77		return 55;
78	}
79
80	/**
81	 * Get allowed mode types.
82	 *
83	 * Defines the mode types for other dokuwiki markup that maybe nested within the
84	 * plugin's own markup. Needs to return an array of one or more of the mode types
85	 * defined in $PARSER_MODES in parser.php
86	 *
87	 * @return array
88	 */
89	function getAllowedTypes()
90	{
91		return array(
92			'container',
93			'substition',
94			'protected',
95			'disabled',
96			'formatting'
97			);
98	}
99
100	/**
101	 * Connect pattern to lexer.
102	 *
103	 * @param string $mode
104	 */
105	function connectTo ($mode)
106	{
107		$this->Lexer->addEntryPattern('<'.$this->tag_name.'>',
108			$mode, 'plugin_diagram_splitter');
109	}
110
111	/**
112	 * Connect pattern to lexer (after connectTo).
113	 */
114	function postConnect ()
115	{
116		$this->Lexer->addPattern('\n',
117			'plugin_diagram_splitter');
118		$this->Lexer->addPattern('\|[A-Za-z0-9_]+=',
119			'plugin_diagram_splitter');
120		$this->Lexer->addPattern('\|[A-Za-z0-9_]+\{[^{}]*\}=',
121			'plugin_diagram_splitter');
122		$this->Lexer->addPattern('\|[^|=\n]*',
123			'plugin_diagram_splitter');
124		$this->Lexer->addExitPattern('</'.$this->tag_name.'>',
125			'plugin_diagram_splitter');
126	}
127
128	/**
129	 * Handle the match.
130	 *
131	 * @param string $match
132	 * @param integer $state one of lexer states defined in lexer.php
133	 * @param integer $pos position of first
134	 * @param Doku_Handler $handler
135	 * @return array data for rendering
136	 */
137	function handle ($match, $state, $pos, Doku_Handler $handler)
138	{
139		$res = array();
140		if ($state == DOKU_LEXER_MATCHED)
141		{
142			if ($match == "\n")
143				$res['type'] = 'newline';
144			elseif ($match[strlen($match) - 1] == '=')
145			{
146				$res['type'] = 'abbr eval';
147				// delete first '|', last '=' and whitespase
148				$abbr_and_params = trim(substr($match, 1, -1));
149				if (preg_match ('/([A-Za-z0-9_]+)\{([^{}]*)\}/', $abbr_and_params, $regs))
150				{
151					$res['abbr'] = $regs[1];
152					$res['params'] = $regs[2];
153				}
154				else
155					$res['abbr'] = $abbr_and_params;
156			}
157			else
158			{
159				$res['type'] = 'command';
160				// delete first '|' and whitespase
161				$res['command'] = trim(substr($match, 1));
162			}
163		}
164		if ($state == DOKU_LEXER_UNMATCHED)
165			$res['text'] = $match;
166		return $res;
167	}
168
169	/**
170	 * Splitter does not create XHTML text, see Main component.
171	 * The function is required after 2020-07-29 "Hogfather" update.
172	 *
173	 * @param string $mode render mode; only 'xhtml' supported
174	 * @param Doku_Renderer $renderer
175	 * @param array $data data from handler
176	 * @return bool
177	 */
178	function render ($mode, Doku_Renderer $renderer, $data)
179	{
180		return true;
181	}
182}
183