1<?php
2/**
3 * Abstract Syntax Component for the Ad-Hoc Tags Plugin
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Anika Henke <anika@selfthinker.org>
7 * @author     Sascha Leib <sascha.leib(at)kolmio.com>
8 */
9
10class syntax_plugin_adhoctags_abstract extends DokuWiki_Syntax_Plugin {
11
12	protected $tag				= null;
13    protected $special_pattern = '<%t%\b[^>\r\n]*?/>';
14    protected $entry_pattern   = '<%t%\b[^>]*>(?=.*?</%t%>)';
15    protected $exit_pattern    = '</%t%>';
16	protected $enabled			= false; /* will be set by the constructors of instances */
17	protected $output_tag		= null;  /* allows overriding the tag name for output */
18	protected $configName		= 'allowedElements';
19	protected $pluginName		= 'adhoctags';
20
21	/* hook to override the registration process, if needed: */
22	protected function registerTag() {
23
24		$arr = explode(',', $this->getConf($this->configName));
25
26		return in_array($this->tag, $arr);
27	}
28
29    function getType(){ return 'formatting';}
30    function getAllowedTypes() {
31		return array('container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs');
32	}
33    function getPType(){ return 'stack';}
34    function getSort(){ return 195; }
35    // override default accepts() method to allow nesting - ie, to get the plugin accepts its own entry syntax
36    function accepts($mode) {
37        if ($mode == substr(get_class($this), 7)) {
38			return true;
39		} else {
40			return parent::accepts($mode);
41		}
42    }
43
44	/* allow additional attributes by overriding this function: */
45	function allowAttribute(&$name, &$value) {
46		return false;
47	}
48
49    /**
50     * Connect pattern to lexer
51     */
52    function connectTo($mode) {
53
54		if ($this->tag && $this->registerTag()) {
55
56			/* debug:
57			if ($mode == 'plugin_adhoctags_pre')
58				dbg('connectTo plugin_adhoctags_pre called for ' . $this->tag .', output = ' . $this->output_tag ); */
59
60			if ($this->special_pattern !== '') {
61				$this->Lexer->addSpecialPattern(str_replace('%t%', $this->tag, $this->special_pattern),$mode,'plugin_' . $this->pluginName.'_'.$this->getPluginComponent());
62			}
63			if ($this->entry_pattern !== '') {
64				$this->Lexer->addEntryPattern(str_replace('%t%', $this->tag, $this->entry_pattern),$mode,'plugin_' . $this->pluginName.'_'.$this->getPluginComponent());
65			}
66		}
67    }
68    function postConnect() {
69
70		if ($this->tag && $this->registerTag()) {
71			if ($this->exit_pattern !== '') {
72				$this->Lexer->addExitPattern(str_replace('%t%', $this->tag, $this->exit_pattern), 'plugin_' . $this->pluginName.'_'.$this->getPluginComponent());
73			}
74		}
75    }
76
77	/**
78	 * Overrideable hooks for different handle states:
79	 **/
80	function handleEnterSpecial($match, $state, $pos, Doku_Handler $handler) {
81
82		//dbg('handleEnterSpecial: "' . $match );
83
84		$data = trim(substr($match,strpos($match,' '),-1)," \t\n/");
85		return array($state, $data);
86	}
87
88	function handleUnmatched($match, $state, $pos, Doku_Handler $handler) {
89        global $conf;
90
91		//dbg('handleUnmatched: "' . $match );
92
93		if (substr($match, 0, 2) == '==') { // special case: it's a headline
94			$title = trim($match);
95			$level = max(7 - strspn($title,'='), 1);
96			$title = trim($title,'= ');
97
98			$handler->_addCall('header',array($title,$level,$pos), $pos);
99			// close the section edit the header could open
100			if ($title && $level <= $conf['maxseclevel']) {
101				$handler->addPluginCall('wrap_closesection', array(), DOKU_LEXER_SPECIAL, $pos, '');
102			}
103		} else {
104			$handler->addCall('cdata', array($match), $pos);
105		}
106		return false;
107	}
108
109	function handleMatched($match, $state, $pos, Doku_Handler $handler) {
110
111		//dbg('DOKU_LEXER_MATCHED: ' . $match);
112	}
113
114	function handleExit($match, $state, $pos, Doku_Handler $handler) {
115
116		//dbg('handleExit: "' . $match );
117
118		return array($state, '');
119
120	}
121
122    /**
123     * Handle the match
124     */
125    function handle($match, $state, $pos, Doku_Handler $handler){
126
127		//dbg('handle: "' . $match );
128
129        switch ($state) {
130            case DOKU_LEXER_ENTER:
131            case DOKU_LEXER_SPECIAL:
132
133                return $this->handleEnterSpecial($match, $state, $pos, $handler);
134
135            case DOKU_LEXER_UNMATCHED :
136
137				return $this->handleUnmatched($match, $state, $pos, $handler);
138
139            case DOKU_LEXER_MATCHED:
140
141				return $this->handleMatched($match, $state, $pos, $handler);
142
143            case DOKU_LEXER_EXIT :
144
145                return array($state, '');
146
147        }
148        return false;
149    }
150
151    /**
152     * Create output
153     */
154    function render($format, Doku_Renderer $renderer, $indata) {
155        static $type_stack = array ();
156
157		//dbg('render: format="' . $format .'", indata="' . implode(', ', $indata) . '"');
158
159        if (empty($indata)) return false;
160        list($state, $data) = $indata;
161
162		// is there an overridden output tag?
163		$outTag = ($this->output_tag ? $this->output_tag : $this->tag);
164
165        if($format == 'xhtml'){
166            switch ($state) {
167                case DOKU_LEXER_ENTER:
168                case DOKU_LEXER_SPECIAL:
169                    $wrap = $this->loadHelper('adhoctags', true);
170                    $attr = $wrap->buildAttributes($data, $this);
171
172                    $renderer->doc .= '<'.$outTag . $attr.'>';
173                    if ($state == DOKU_LEXER_SPECIAL) $renderer->doc .= '</'.$outTag.'>';
174                    break;
175
176                case DOKU_LEXER_EXIT:
177                    $renderer->doc .= '</'.$outTag.'>';
178                    break;
179            }
180            return true;
181        }
182        if($format == 'odt'){
183            switch ($state) {
184                case DOKU_LEXER_ENTER:
185                    array_push ($type_stack, $this->renderODTElementOpen($renderer, $outTag , $data));
186                    break;
187
188                case DOKU_LEXER_SPECIAL:
189
190
191                case DOKU_LEXER_EXIT:
192                    $element = array_pop ($type_stack);
193                    $this->renderODTElementClose ($renderer, $element);
194                    break;
195            }
196            return true;
197        }
198        return false;
199    }
200
201    /**
202     * render ODT element, Open
203     * (get Attributes, select ODT element that fits, render it, return element name)
204     */
205    function renderODTElementOpen($renderer, $HTMLelement, $data) {
206		//dbg('renderODTElementOpen: ' . $HTMLelement);
207    }
208
209    /**
210     * render ODT element, Close
211     */
212    function renderODTElementClose($renderer, $element) {
213		//dbg('renderODTElementClose: ' . $element);
214    }
215
216}