source: documentation/trunk/wiki/plugins/simpletabs/syntax.php@ 30325

Last change on this file since 30325 was 30325, checked in by jmt12, 8 years ago

And this time I'll turn off debugging

File size: 12.7 KB
Line 
1<?php
2/**
3 * A simple tabbed area component, developed from the tutorial given here:
4 * http://net.tutsplus.com/tutorials/html-css-techniques/how-to-create-a-slick-tabbed-content-area/
5 *
6 * Syntax:
7 * <TABAREA tabs="comma,separated,list">
8 * <TAB>Content of 'comma' including [[:syntax|wiki syntax]]</TAB>
9 * <TAB>Content of 'separated' and here **is** //some// ''formatting''</TAB>
10 * <TAB>Content of 'list'</TAB>
11 * </TABAREA>
12 *
13 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
14 */
15
16if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
17if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
18require_once(DOKU_PLUGIN.'syntax.php');
19
20/**
21 * All DokuWiki plugins to extend the parser/rendering mechanism
22 * need to inherit from this class
23 */
24class syntax_plugin_simpletabs
25extends DokuWiki_Syntax_Plugin
26{
27 // The name of currently rendering tab - useful for ensuring syntax (no
28 // close tab before open, for example)
29 var $current_tab;
30
31 var $current_tab_number;
32
33 // Print debug messages
34 var $debug;
35
36 // The count of tabbed areas encountered on this page (so we can ensure a
37 // unique identifier is assigned)
38 var $tab_area_counter;
39
40 var $tab_counter;
41
42 var $tabs;
43
44 var $divide_edit_section;
45
46 function __construct()
47 {
48 global $PARSER_MODES;
49 $this->allowedModes = array_merge($PARSER_MODES['container'],
50 $PARSER_MODES['formatting'],
51 $PARSER_MODES['substition'],
52 $PARSER_MODES['protected'],
53 $PARSER_MODES['disabled'],
54 $PARSER_MODES['paragraphs']);
55 // Init
56 $this->debug = false;
57 $this->divide_edit_section = false;
58 $this->tab_area_counter = 0;
59 $this->tab_counter = 0;
60 }
61 /** __construct() **/
62
63
64 /** @function
65 *
66 */
67 function _debugPrint($msg)
68 {
69 if ($this->debug)
70 {
71 echo "<p><b>[DEBUG]</b> " . $msg . "</p>\n";
72 }
73 }
74 /** _debugPrint() **/
75
76
77 /**
78 * Should return the type of syntax this plugin defines.
79 */
80 function getType()
81 {
82 return 'container';
83 }
84 /** getType() **/
85
86
87 /**
88 * Returns a number used to determine in which order modes are added.
89 */
90 function getSort()
91 {
92 return 45;
93 }
94
95
96 /**
97 * What kind of syntax do we allow (optional)
98 */
99 function getAllowedTypes()
100 {
101 return array('container','formatting','substition','protected','disabled','paragraphs');
102 }
103 /** getAllowedTypes() **/
104
105
106 /**
107 * Define how this plugin is handled regarding paragraphs.
108 *
109 * <p>
110 * This method is important for correct XHTML nesting. It returns
111 * one of the following values:
112 * </p>
113 * <dl>
114 * <dt>normal</dt><dd>The plugin can be used inside paragraphs.</dd>
115 * <dt>block</dt><dd>Open paragraphs need to be closed before
116 * plugin output.</dd>
117 * <dt>stack</dt><dd>Special case: Plugin wraps other paragraphs.</dd>
118 * </dl>
119 */
120 function getPType()
121 {
122 return 'normal';
123 }
124
125
126 /**
127 * Connect lookup pattern to lexer.
128 */
129 function connectTo($mode)
130 {
131 $this->Lexer->addEntryPattern('<TABAREA tabs=".*?">(?=.*?</TABAREA>)$',$mode,'plugin_simpletabs');
132 // The tabs
133 $this->Lexer->addPattern('<TAB>', 'plugin_simpletabs');
134 $this->Lexer->addPattern('</TAB>', 'plugin_simpletabs');
135 // Hide comments always (sometimes used as separator)
136 $this->Lexer->addPattern('<!--.*?-->', 'plugin_simpletabs');
137 // Special things inside the content we want to manually handle.
138 $this->Lexer->addPattern( '^[ \t]*={2,6}\s?[^\n]+={2,6}[ \t]*(?=\n)', 'plugin_simpletabs');
139 }
140
141 function postConnect()
142 {
143 $this->Lexer->addExitPattern('</TABAREA>','plugin_simpletabs');
144 }
145
146
147 /**
148 * Handler to prepare matched data for the rendering process.
149 *
150 * <p>
151 * The <tt>$aState</tt> parameter gives the type of pattern
152 * which triggered the call to this method:
153 * </p>
154 * <dl>
155 * <dt>DOKU_LEXER_ENTER</dt>
156 * <dd>a pattern set by <tt>addEntryPattern()</tt></dd>
157 * <dt>DOKU_LEXER_MATCHED</dt>
158 * <dd>a pattern set by <tt>addPattern()</tt></dd>
159 * <dt>DOKU_LEXER_EXIT</dt>
160 * <dd> a pattern set by <tt>addExitPattern()</tt></dd>
161 * <dt>DOKU_LEXER_SPECIAL</dt>
162 * <dd>a pattern set by <tt>addSpecialPattern()</tt></dd>
163 * <dt>DOKU_LEXER_UNMATCHED</dt>
164 * <dd>ordinary text encountered within the plugin's syntax mode
165 * which doesn't match any pattern.</dd>
166 * </dl>
167 * @param $aMatch String The text matched by the patterns.
168 * @param $aState Integer The lexer state for the match.
169 * @param $aPos Integer The character position of the matched text.
170 * @param $aHandler Object Reference to the Doku_Handler object.
171 * @return Integer The current lexer state for the match.
172 * @public
173 * @see render()
174 * @static
175 */
176 function handle($match, $state, $pos, &$handler)
177 {
178 switch ($state)
179 {
180 case DOKU_LEXER_ENTER:
181 // Increment the counter for tabbed area identifiers
182 $this->tab_area_counter++;
183 // Reset these two variables used to track progress through tabbed area
184 $this->current_tab = '';
185 $this->tab_counter = 0;
186 // Separate the tab names - hopefully there are the same number as tabbed
187 // areas otherwise things will go strange
188 $this->tab_names = array();
189 if (preg_match('/tabs="(.+)"/', $match, $matches))
190 {
191 $this->tab_names = explode(',', $matches[1]);
192 }
193 // When rendered this command will create the unordered list that acts as
194 // the tabs themselves as well as the precursor for the tabbed content.
195 $this->_debugPrint("Handler=>enter tabbed area: " . $matches[1]);
196 return array($state, array('action' => 'open tabbed area',
197 'tab_area_id' => $this->tab_area_counter,
198 'tab_names' => $this->tab_names,
199 'default_tab' => $this->getConf('defaulttab'),
200 'bytepos' => $pos));
201 break;
202
203 case DOKU_LEXER_MATCHED:
204 // Open tab area
205 if ($match == '<TAB>' && $this->current_tab == '')
206 {
207 $this->current_tab = $this->tab_names[$this->tab_counter];
208 $this->tab_counter++;
209 $this->current_tab_number = $this->tab_counter;
210 $active = false;
211 if ($this->current_tab == $this->getConf('defaulttab'))
212 {
213 $active = true;
214 }
215 // When rendered this command will open the div serving as a tabbed
216 // area's content
217 $this->_debugPrint("Handler=>open tab: " . $this->current_tab);
218 return array($state, array('action' => 'open tab',
219 'tab_area_id' => $this->tab_area_counter,
220 'tab_number' => $this->tab_counter,
221 'active' => $active,
222 'bytepos' => $pos));
223 }
224 if ($match == '</TAB>')
225 {
226 $this->_debugPrint("Handler=>close tab: " . $this->current_tab);
227 // Housekeeping
228 $this->current_tab = '';
229 $this->current_tab_number = 0;
230 // When rendered this command closes the tabbed area content div
231 return array($state, array('action' => 'close tab',
232 'bytepos' => $pos + strlen($match)));
233 }
234 // note: we only handle comments inside tabbed area but outside of tabs
235 if (empty($this->current_tab) && preg_match('/<!--(.*)?-->/s', $match, $matches))
236 {
237 $this->_debugPrint("Handler=>comment: " . htmlspecialchars($matches[1]));
238 $params = array();
239 $params['action'] = 'comment';
240 $params['comment'] = $matches[1];
241 return array($state, $params);
242 }
243 if (preg_match('/(={2,6})\s*(.+?)\s*={2,6}/', $match, $matches))
244 {
245 $this->_debugPrint("Handler=>header: " . htmlspecialchars($match));
246 $params = array();
247 $params['action'] = 'heading';
248 $params['title'] = $matches[2];
249 $params['level'] = 7 - strlen($matches[1]);
250 return array($state, $params);
251 //$handler->_addCall('header',array($params['title'],$params['level'],$pos),$pos);
252 //return false;
253 }
254 break;
255
256 case DOKU_LEXER_EXIT:
257 $this->_debugPrint("Handler=>exit tabbed area");
258 return array($state, array('action' => 'close tabbed area',
259 'bytepos' => $pos + strlen($match)));
260 break;
261
262 case DOKU_LEXER_UNMATCHED:
263 $this->_debugPrint("Handler=>unmatched: " . htmlspecialchars($match));
264 return array($state, $match);
265 break;
266 }
267
268 $this->_debugPrint("Unhandled: " . htmlspecialchars($match));
269 return array(DOKU_LEXER_UNMATCHED, $match);
270 }
271
272 /**
273 * Handle the actual output creation.
274 *
275 * <p>
276 * The method checks for the given <tt>$aFormat</tt> and returns
277 * <tt>FALSE</tt> when a format isn't supported. <tt>$aRenderer</tt>
278 * contains a reference to the renderer object which is currently
279 * handling the rendering. The contents of <tt>$aData</tt> is the
280 * return value of the <tt>handle()</tt> method.
281 * </p>
282 * @see handle()
283 */
284 function render($mode, &$renderer, $data)
285 {
286 if($mode == 'xhtml')
287 {
288 list($state, $params) = $data;
289
290 switch ($state)
291 {
292 case DOKU_LEXER_ENTER:
293 if ($this->divide_edit_section && method_exists($renderer, 'finishSectionEdit'))
294 {
295 $renderer->finishSectionEdit($params['bytepos']);
296 }
297 $renderer->doc .= '</p>'; // Provide match for illegal wrapping <p>
298 $renderer->doc .= '
299
300<!-- Tabbed Area - Begin -->
301<div class="tabbed_area" id="simpletabs-t' . $params['tab_area_id'] . '">
302 <ul class="tabs">
303';
304 $total_tab_count = count($params['tab_names']);
305 $tab_count = 0;
306 foreach ($params['tab_names'] as $tab_name)
307 {
308 $tab_count++;
309 $renderer->doc .= ' <li><a href="javascript:tabSwitch(' . $params['tab_area_id'] . ',' . $total_tab_count . ',' . $tab_count . ');" id="simpletabs-t' . $params['tab_area_id'] . '_' . $tab_count . '"';
310 if ($tab_name == $params['default_tab'])
311 {
312 $renderer->doc .= ' class="active"';
313 }
314 $renderer->doc .= '>' . $tab_name . '</a></li>
315';
316 }
317 $renderer->doc .= ' </ul>
318';
319 break;
320
321 case DOKU_LEXER_MATCHED:
322 switch($params['action'])
323 {
324 case 'open tab':
325 $extra_classy = '';
326 if ($this->divide_edit_section && method_exists($renderer, 'startSectionEdit'))
327 {
328 $extra_classy = ' ' . $renderer->startSectionEdit($params['bytepos'], 'plugin_simpletabs');
329 }
330 $renderer->doc .= ' <div id="simpletabs-tc' . $params['tab_area_id'] . '_' . $params['tab_number'] . '" class="tab' . $extra_classy . '"';
331 if (!$params['active'])
332 {
333 $renderer->doc .= ' style="display:none;"';
334 }
335 $renderer->doc .= '>';
336 $renderer->doc .= '<p>'; // Open bogus </p>
337 break;
338 case 'close tab':
339 if ($this->divide_edit_section && method_exists($renderer, 'finishSectionEdit'))
340 {
341 $renderer->finishSectionEdit($params['bytepos']);
342 }
343 $renderer->doc .= '</p>'; // Close bogus <p>
344 $renderer->doc .= '<div style="clear:both;height:0px;"></div>';
345 $renderer->doc .= '</div>';
346 break;
347 case 'comment':
348 $renderer->doc .= '<!-- ' . $params['comment'] . ' -->';
349 break;
350 case 'heading':
351 $renderer->doc .= '<h' . $params['level'] . '>' . $params['title'] . '</h' . $params['level'] . '>';
352 break;
353 default:
354 $renderer->doc .= '<p>Error! Unknown action: ' . $params['action'] . '</p>';
355 }
356 break;
357
358 case DOKU_LEXER_EXIT:
359 $renderer->doc .= '</div>
360<!-- Tabbed Area - End -->
361';
362 $renderer->doc .= '<p>'; // Provide match for illegal wrapping <p>
363 if ($this->divide_edit_section && method_exists($renderer, 'startSectionEdit'))
364 {
365 $class = $renderer->startSectionEdit($params['bytepos'], 'plugin_simpletabs');
366 $renderer->doc .= '<div class="' . $class . '">';
367 }
368 break;
369
370 case DOKU_LEXER_UNMATCHED:
371 $renderer->doc .= $params;
372 break;
373 }
374 return true;
375 }
376 return false;
377 }
378}
379
380//Setup VIM: ex: et ts=4 enc=utf-8 :
381?>
Note: See TracBrowser for help on using the repository browser.