1<?php 2/** 3 * DokuWiki Plugin tabbox (Syntax Component) 4 * 5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6 * @author Andreas Gohr <dokuwiki@cosmocode.de> 7 */ 8 9// must be run within Dokuwiki 10if(!defined('DOKU_INC')) die(); 11 12class syntax_plugin_tabbox extends DokuWiki_Syntax_Plugin { 13 14 protected $tabs = array(); 15 protected $tabids = array(); 16 protected $intab = false; 17 protected $original_doc = ''; 18 19 function accepts($mode) { 20 if($mode == 'plugin_tabbox') return true; 21 return parent::accepts($mode); 22 } 23 24 /** 25 * @return string Syntax mode type 26 */ 27 public function getType() { 28 return 'formatting'; 29 } 30 31 /** 32 * @return string Paragraph type 33 */ 34 public function getPType() { 35 return 'stack'; 36 } 37 38 /** 39 * @return int Sort order - Low numbers go before high numbers 40 */ 41 public function getSort() { 42 return 190; 43 } 44 45 /** 46 * @return array Things that may be inside the syntax 47 */ 48 function getAllowedTypes() { 49 return array('container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs'); 50 } 51 52 /** 53 * Connect lookup pattern to lexer. 54 * 55 * @param string $mode Parser mode 56 */ 57 public function connectTo($mode) { 58 $this->Lexer->addEntryPattern('<tabbox.*?>(?=.*?</tabbox>)', $mode, 'plugin_tabbox'); 59 $this->Lexer->addSpecialPattern('<tabbox.*?>(?=.*?</tabbox>)', 'plugin_tabbox', 'plugin_tabbox'); 60 } 61 62 public function postConnect() { 63 64 $this->Lexer->addExitPattern('</tabbox>', 'plugin_tabbox'); 65 } 66 67 /** 68 * Handle matches of the tabbox syntax 69 * 70 * @param string $match The match of the syntax 71 * @param int $state The state of the handler 72 * @param int $pos The position in the document 73 * @param Doku_Handler $handler The handler 74 * @return array Data for the renderer 75 */ 76 public function handle($match, $state, $pos, Doku_Handler $handler) { 77 // we treat intermediate matches like entries in rendering 78 if($state == DOKU_LEXER_SPECIAL) $state = DOKU_LEXER_ENTER; 79 80 return array($state, $match, $pos); 81 } 82 83 /** 84 * Render xhtml output or metadata 85 * 86 * @param string $mode Renderer mode (supported modes: xhtml) 87 * @param Doku_Renderer $renderer The renderer 88 * @param array $data The data from the handler() function 89 * @return bool If rendering was successful. 90 */ 91 public function render($mode, Doku_Renderer $renderer, $data) { 92 if($mode != 'xhtml') return false; 93 94 list($state, $match, $pos) = $data; 95 96 switch($state) { 97 case DOKU_LEXER_ENTER: 98 if(!$this->intab) { 99 // this is the first tab 100 $this->_openBox($renderer); 101 } else { 102 // close last tab 103 $this->_closeTab($renderer, $pos - 1); 104 } 105 // open new tab 106 $this->_openTab($renderer, substr($match, 7, -1), $pos + strlen($match) + 1 ); 107 break; 108 case DOKU_LEXER_EXIT: 109 if($this->intab) { 110 // close last tab 111 $this->_closeTab($renderer, $pos - 1); 112 } 113 $this->_closeBox($renderer); 114 break; 115 default: 116 // just render as is 117 $renderer->cdata($match); 118 } 119 120 return true; 121 } 122 123 124 125 /** 126 * Open a new tab with the given name 127 * 128 * @param Doku_Renderer_xhtml $R 129 * @param string $name 130 * @param int $pos Byte position of start of tab content 131 */ 132 protected function _openTab(Doku_Renderer_xhtml $R, $name, $pos) { 133 $name = trim($name); 134 $tabid = 'tab__' . sectionID($name, $this->tabids); 135 // use one smaller headline than current section for the tabs 136 $level = $this->_getProtected($R, 'lastlevel') + 1; 137 if($level > 5) $level = 5; 138 139 // write the header 140 $R->doc .= '<div class="tabboxtab" id="tab_'.$tabid.'">'.DOKU_LF; 141 if (defined('SEC_EDIT_PATTERN')) { 142 // for DokuWiki Greebo and more recent versions 143 $R->doc .= DOKU_LF . '<h' . $level . ' class="hl '. $R->startSectionEdit($pos, array('target' => 'section', 'name' => $name)) . '" id="' . $tabid . '">'; 144 } else { 145 $R->doc .= DOKU_LF . '<h' . $level . ' class="hl '. $R->startSectionEdit($pos, 'section', $name) . '" id="' . $tabid . '">'; 146 } 147 $R->doc .= $R->_xmlEntities($name); 148 $R->doc .= "</h$level>" . DOKU_LF; 149 150 $this->intab = true; 151 } 152 153 /** 154 * Close the current tab 155 * 156 * @param Doku_Renderer_xhtml $R 157 * @param int $pos Byte position of end of tab content 158 */ 159 protected function _closeTab(Doku_Renderer_xhtml $R, $pos) { 160 $R->finishSectionEdit($pos); 161 $R->doc .= DOKU_LF.'</div>'.DOKU_LF; 162 $this->intab = false; 163 } 164 165 /** 166 * Open a new tab box 167 * 168 * @param Doku_Renderer_xhtml $R 169 */ 170 protected function _openBox(Doku_Renderer_xhtml $R) { 171 $R->doc .= '<div class="plugin_tabbox">' . DOKU_LF; 172 173 } 174 175 /** 176 * Close the tab box 177 * 178 * @param Doku_Renderer_xhtml $R 179 */ 180 protected function _closeBox(Doku_Renderer_xhtml $R) { 181 $R->doc .= '</div>' . DOKU_LF; 182 } 183 184 /** 185 * Get the value of a protected member 186 * 187 * @author Jan Turoň 188 * @link http://stackoverflow.com/a/27754169/172068 189 * @param $obj 190 * @param $name 191 * @return mixed 192 */ 193 protected function _getProtected($obj, $name) { 194 $array = (array) $obj; 195 $prefix = chr(0) . '*' . chr(0); 196 return $array[$prefix . $name]; 197 } 198 199} 200 201// vim:ts=4:sw=4:et: 202