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

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

Match and hide any HTML comments that appear within a TABAREA block

File size: 12.4 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 if (preg_match('/<!--(.*)?-->/s', $match, $matches))
235 {
236 $this->_debugPrint("Handler=>comment: " . htmlspecialchars($matches[1]));
237 $params = array();
238 $params['action'] = 'comment';
239 $params['comment'] = $matches[1];
240 return array($state, $params);
241 }
242 if (preg_match('/(={2,6})\s*(.+?)\s*={2,6}/', $match, $matches))
243 {
244 $params = array();
245 $params['action'] = 'heading';
246 $params['title'] = $matches[2];
247 $params['level'] = 7 - strlen($matches[1]);
248 return array($state, $params);
249 //$handler->_addCall('header',array($params['title'],$params['level'],$pos),$pos);
250 //return false;
251 }
252 break;
253
254 case DOKU_LEXER_EXIT:
255 $this->_debugPrint("Handler=>exit tabbed area");
256 return array($state, array('action' => 'close tabbed area',
257 'bytepos' => $pos + strlen($match)));
258 break;
259
260 case DOKU_LEXER_UNMATCHED:
261 $this->_debugPrint("Handler=>unmatched: " . htmlspecialchars($match));
262 return array($state, $match);
263 break;
264 }
265
266 return array();
267 }
268
269 /**
270 * Handle the actual output creation.
271 *
272 * <p>
273 * The method checks for the given <tt>$aFormat</tt> and returns
274 * <tt>FALSE</tt> when a format isn't supported. <tt>$aRenderer</tt>
275 * contains a reference to the renderer object which is currently
276 * handling the rendering. The contents of <tt>$aData</tt> is the
277 * return value of the <tt>handle()</tt> method.
278 * </p>
279 * @see handle()
280 */
281 function render($mode, &$renderer, $data)
282 {
283 if($mode == 'xhtml')
284 {
285 list($state, $params) = $data;
286
287 switch ($state)
288 {
289 case DOKU_LEXER_ENTER:
290 if ($this->divide_edit_section && method_exists($renderer, 'finishSectionEdit'))
291 {
292 $renderer->finishSectionEdit($params['bytepos']);
293 }
294 $renderer->doc .= '</p>'; // Provide match for illegal wrapping <p>
295 $renderer->doc .= '
296
297<!-- Tabbed Area - Begin -->
298<div class="tabbed_area" id="simpletabs-t' . $params['tab_area_id'] . '">
299 <ul class="tabs">
300';
301 $total_tab_count = count($params['tab_names']);
302 $tab_count = 0;
303 foreach ($params['tab_names'] as $tab_name)
304 {
305 $tab_count++;
306 $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 . '"';
307 if ($tab_name == $params['default_tab'])
308 {
309 $renderer->doc .= ' class="active"';
310 }
311 $renderer->doc .= '>' . $tab_name . '</a></li>
312';
313 }
314 $renderer->doc .= ' </ul>
315';
316 break;
317
318 case DOKU_LEXER_MATCHED:
319 switch($params['action'])
320 {
321 case 'open tab':
322 $extra_classy = '';
323 if ($this->divide_edit_section && method_exists($renderer, 'startSectionEdit'))
324 {
325 $extra_classy = ' ' . $renderer->startSectionEdit($params['bytepos'], 'plugin_simpletabs');
326 }
327 $renderer->doc .= ' <div id="simpletabs-tc' . $params['tab_area_id'] . '_' . $params['tab_number'] . '" class="tab' . $extra_classy . '"';
328 if (!$params['active'])
329 {
330 $renderer->doc .= ' style="display:none;"';
331 }
332 $renderer->doc .= '>';
333 $renderer->doc .= '<p>'; // Open bogus </p>
334 break;
335 case 'close tab':
336 if ($this->divide_edit_section && method_exists($renderer, 'finishSectionEdit'))
337 {
338 $renderer->finishSectionEdit($params['bytepos']);
339 }
340 $renderer->doc .= '</p>'; // Close bogus <p>
341 $renderer->doc .= '<div style="clear:both;height:0px;"></div>';
342 $renderer->doc .= '</div>';
343 break;
344 case 'comment':
345 $renderer->doc .= '<!-- ' . $params['comment'] . ' -->';
346 break;
347 case 'heading':
348 $renderer->doc .= '<h' . $params['level'] . '>' . $params['title'] . '</h' . $params['level'] . '>';
349 break;
350 default:
351 $renderer->doc .= '<p>Error! Unknown action: ' . $params['action'] . '</p>';
352 }
353 break;
354
355 case DOKU_LEXER_EXIT:
356 $renderer->doc .= '</div>
357<!-- Tabbed Area - End -->
358';
359 $renderer->doc .= '<p>'; // Provide match for illegal wrapping <p>
360 if ($this->divide_edit_section && method_exists($renderer, 'startSectionEdit'))
361 {
362 $class = $renderer->startSectionEdit($params['bytepos'], 'plugin_simpletabs');
363 $renderer->doc .= '<div class="' . $class . '">';
364 }
365 break;
366
367 case DOKU_LEXER_UNMATCHED:
368 $renderer->doc .= $params;
369 break;
370 }
371 return true;
372 }
373 return false;
374 }
375}
376
377//Setup VIM: ex: et ts=4 enc=utf-8 :
378?>
Note: See TracBrowser for help on using the repository browser.