1<?php 2/** 3 * DokuWiki Plugin slider (Syntax Component) 4 * 5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6 * @author Andreas Gohr <gohr@cosmocode.de> 7 */ 8 9// must be run within Dokuwiki 10if (!defined('DOKU_INC')) die(); 11 12class syntax_plugin_slider extends DokuWiki_Syntax_Plugin { 13 14 private $inslideopener = false; 15 16 /** 17 * @return string Syntax mode type 18 */ 19 public function getType() { 20 return 'formatting'; 21 } 22 23 /** 24 * @return array Things that may be inside the syntax 25 */ 26 function getAllowedTypes() { 27 return array('container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs'); 28 } 29 30 /** 31 * @return string Paragraph type 32 */ 33 public function getPType() { 34 return 'stack'; 35 } 36 37 /** 38 * @return int Sort order - Low numbers go before high numbers 39 */ 40 public function getSort() { 41 return 190; 42 } 43 44 /** 45 * Connect lookup pattern to lexer. 46 * 47 * @param string $mode Parser mode 48 */ 49 public function connectTo($mode) { 50 $this->Lexer->addEntryPattern('<slider.*?>(?=.*?</slider>)',$mode,'plugin_slider'); 51 } 52 53 public function postConnect() { 54 $this->Lexer->addExitPattern('</slider>', 'plugin_slider'); 55 } 56 57 /** 58 * Handle matches of the slider syntax 59 * 60 * @param string $match The match of the syntax 61 * @param int $state The state of the handler 62 * @param int $pos The position in the document 63 * @param Doku_Handler $handler The handler 64 * @return array Data for the renderer 65 */ 66 public function handle($match, $state, $pos, Doku_Handler $handler){ 67 global $conf; 68 $first = false; 69 $img = ''; 70 71 // the enter state is the very first slide only 72 if($state == DOKU_LEXER_ENTER){ 73 $first = true; 74 } 75 76 // handle intermediate slider calls just like new entry patterns 77 if($state == DOKU_LEXER_UNMATCHED && substr($match, 0, 7) == '<slider'){ 78 $state = DOKU_LEXER_ENTER; 79 } 80 // handle unclosed slide opener, by getting the image url from the last call 81 if($this->inslideopener && $state == DOKU_LEXER_UNMATCHED && substr($match, 0, 7) == '>'){ 82 $lastcall = array_pop($handler->calls); 83 if(preg_match('/^https?:\/\//i', $lastcall[1][0])) $img = $lastcall[1][0]; 84 $state = DOKU_LEXER_ENTER; 85 $this->inslideopener = false; 86 } 87 88 // handle states 89 switch ($state) { 90 case DOKU_LEXER_ENTER: 91 if(substr($match, -1) != '>'){ 92 // we have a slide opener, but it contained some other syntax (probably a link) 93 // happens because we parse our own syntax from LEXER_UNMATCHED calls 94 $this->inslideopener = true; 95 return false; 96 }elseif(!$img){ 97 $img = trim(substr($match, 7,-1)); 98 } 99 return array($state, $img, $first); 100 101 case DOKU_LEXER_UNMATCHED: 102 // check if $match is a == header == 103 $headerMatch = preg_grep('/([ \t]*={2,}[^\n]+={2,}[ \t]*(?=))/msSi', array($match)); 104 if (empty($headerMatch)) { 105 $handler->_addCall('cdata', array($match), $pos); 106 } else { 107 // if it's a == header ==, use the core header() renderer 108 // (copied from core header() in inc/parser/handler.php) 109 $title = trim($match); 110 $level = 7 - strspn($title,'='); 111 if($level < 1) $level = 1; 112 $title = trim($title,'='); 113 $title = trim($title); 114 115 $handler->_addCall('header',array($title,$level,$pos), $pos); 116 // close the section edit the header could open 117 if ($title && $level <= $conf['maxseclevel']) { 118 $handler->addPluginCall('wrap_closesection', array(), DOKU_LEXER_SPECIAL, $pos, ''); 119 } 120 } 121 return false; 122 123 case DOKU_LEXER_EXIT: 124 return array($state, false, false); 125 } 126 } 127 128 /** 129 * Render xhtml output or metadata 130 * 131 * @param string $mode Renderer mode (supported modes: xhtml) 132 * @param Doku_Renderer $R The renderer 133 * @param array $data The data from the handler() function 134 * @return bool If rendering was successful. 135 */ 136 public function render($mode, Doku_Renderer $R, $data) { 137 if($mode != 'xhtml') return false; 138 list($state, $img, $first) = $data; 139 140 if($state == DOKU_LEXER_ENTER){ 141 if($first){ 142 // open the list 143 $R->doc .= '<div class="clearer"></div>'; 144 $R->doc .= '<ul class="plugin_slider">'; 145 }else{ 146 // close previous item 147 $this->close_slide($R); 148 } 149 150 // new item 151 $this->open_slide($R, $img); 152 }elseif($state == DOKU_LEXER_EXIT){ 153 // close previous item 154 $this->close_slide($R); 155 156 // close list 157 $R->doc .= '</ul>'; 158 $R->doc .= '<div class="clearer"></div>'; 159 } 160 161 return true; 162 } 163 164 /** 165 * Opens as slide and remounts the renderer document 166 * 167 * @param Doku_Renderer $R 168 * @param string $img 169 */ 170 private function open_slide($R, $img){ 171 // open the list item 172 if($img){ 173 $R->doc .= '<li class="plugin_slider_hasimg">'; 174 $R->doc .= '<img src="'.ml($img, array('w'=>$this->getConf('width'))).'" class="plugin_slider_img" alt="" />'; 175 }else{ 176 $R->doc .= '<li class="plugin_slider_noimg">'; 177 } 178 179 // remount the doc 180 $R->keepdoc = $R->doc; 181 $R->doc = ''; 182 } 183 184 /** 185 * Closes the previous slide and removes dangling paragraphs and empty content divs 186 * 187 * @param Doku_Renderer $R 188 */ 189 private function close_slide($R){ 190 // clean up dangling paragraphs 191 $R->doc = preg_replace('/<p>\s*$/','',$R->doc); 192 $R->doc = preg_replace('/^\s*<\/p>\s*/','',$R->doc); 193 $R->doc = trim($R->doc); 194 195 // wrap content if any 196 if($R->doc){ 197 $R->doc = '<div class="plugin_slider_content li">'.$R->doc.'</div>'; 198 } 199 200 // mount doument back 201 $R->doc = $R->keepdoc . $R->doc; 202 unset($R->keepdoc); 203 204 // close item 205 $R->doc .= '</li>'; 206 } 207} 208 209// vim:ts=4:sw=4:et: 210