1<?php 2/** 3 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 4 * @author Brend Wanders <b.wanders@utwente.nl> 5 */ 6// must be run within Dokuwiki 7if(!defined('DOKU_INC')) die('Meh.'); 8 9use dokuwiki\Parsing\Parser; 10use dokuwiki\Parsing\Handler\Block; 11 12 13/** 14 * The 'render as wiki text' type. 15 */ 16class plugin_strata_type_wiki extends plugin_strata_type { 17 function normalize($value, $hint) { 18 $ins = $this->_instructions($value); 19 20 $value = "\n".str_replace("\r\n","\n",$value)."\n"; 21 22 for($i=count($ins)-1;$i>=0;$i--) { 23 switch($ins[$i][0]) { 24 case 'internallink': 25 $replacement = $this->_normalize_internallink($ins[$i][1]); 26 break; 27 case 'locallink': 28 $replacement = $this->_normalize_locallink($ins[$i][1]); 29 break; 30 case 'internalmedia': 31 $replacement = $this->_normalize_media($ins[$i][1]); 32 break; 33 case 'externallink': 34 $replacement = $this->_linkSyntax($ins[$i][1], $ins[$i][1][0]); 35 break; 36 default: 37 continue 2; 38 } 39 40 $value = substr_replace($value, $replacement, $ins[$i][2], $ins[$i+1][2] - $ins[$i][2]); 41 } 42 43 // strip off only the inserted newlines 44 return substr($value,1,-1); 45 } 46 47 /** 48 * Normalizes an internal link. 49 */ 50 function _normalize_internallink($instruction) { 51 global $ID; 52 53 // split off query string 54 $parts = explode('?', $instruction[0] ,2); 55 56 $id = $parts[0]; 57 58 list($id,$hash) = explode('#', $id, 2); 59 // normalize selflink 60 if($id === '') { 61 $id = $ID; 62 } 63 64 // actually resolve the page 65 resolve_pageid(getNS($ID), $id, $exists); 66 // make the resolved pageid absolute, so it does not re-resolve to something else later on 67 $id = ':'.$id; 68 69 // render the link 70 return $this->_linkSyntax($instruction, $id.'#'.$hash); 71 } 72 73 /** 74 * Normalizes a local link. 75 */ 76 function _normalize_locallink($instruction) { 77 global $ID; 78 79 // simply prefix the current page 80 return $this->_linkSyntax($instruction, $ID.'#'.$instruction[0]); 81 } 82 83 /** 84 * Normalizes a media array. 85 */ 86 function _normalize_media($instruction) { 87 global $ID; 88 89 // construct media structure based on input 90 if(isset($instruction['type'])) { 91 $media = $instruction; 92 } else { 93 list($src, $title, $align, $width, $height, $cache, $linking) = $instruction; 94 $media = compact('src','title','align','width','height'); 95 $media['type']= 'internalmedia'; 96 } 97 98 // normalize internal media links 99 if($media['type'] == 'internalmedia') { 100 list($src,$hash) = explode('#',$media['src'],2); 101 resolve_mediaid(getNS($ID),$src, $exists); 102 if($hash) $src.='#'.$hash; 103 $media['src'] = ':'.$src; 104 } 105 106 // render the media structure 107 return $this->_mediaSyntax($media); 108 } 109 110 /** 111 * Renders the media syntax. 112 */ 113 function _mediaSyntax($media) { 114 // the source 115 $src = $media['src']; 116 117 // the resizing part 118 if(isset($media['width'])) { 119 $size = '?'.$media['width']; 120 if(isset($media['height'])) { 121 $size .= 'x'.$media['height']; 122 } 123 } else { 124 $size = ''; 125 } 126 127 // the title part 128 if(isset($media['title'])) { 129 $title = '|'.$media['title']; 130 } else { 131 $title = ''; 132 } 133 134 // the alignment parts 135 if(isset($media['align'])) { 136 switch($media['align']) { 137 case 'left': 138 $al = ''; $ar = ' '; break; 139 case 'right': 140 $al = ' '; $ar = ''; break; 141 case 'center': 142 $al = ' '; $ar = ' '; break; 143 } 144 } 145 146 // construct the syntax 147 return '{{'.$al.$src.$size.$ar.$title.'}}'; 148 } 149 150 /** 151 * Renders the link syntax, invoking media normalization 152 * if required. 153 */ 154 function _linkSyntax($instruction, $newLink) { 155 // fetch params from old link 156 $parts = explode('?', $instruction[0],2); 157 if(count($parts) === 2) { 158 $params = '?'.$parts[1]; 159 } else { 160 $params = ''; 161 } 162 163 // determine title 164 $title = ''; 165 if(isset($instruction[1])) { 166 if(is_array($instruction[1])) { 167 if($instruction[1]['type'] == 'internalmedia') { 168 $title='|'.$this->_normalize_media($instruction[1]); 169 } else { 170 $title='|'.$this->_mediaSyntax($instruction[1]); 171 } 172 } else { 173 $title = '|'.$instruction[1]; 174 } 175 } 176 177 // construct a new link string 178 return '[['.$newLink.$params.$title.']]'; 179 180 } 181 182 function render($mode, &$R, &$T, $value, $hint) { 183 // though this breaks backlink functionality, we really do not want 184 // metadata renders of included pieces of wiki. 185 if($mode == 'xhtml' || $mode == 'odt') { 186 $instructions = $this->_instructions($value); 187 $instructions = array_slice($instructions, 2, -2); 188 189 // last-minute fix of newline in front of content 190 if(!empty($instructions[0][0]) && $instructions[0][0]=='cdata') { 191 $instructions[0][1][0] = ltrim($instructions[0][1][0]); 192 } 193 194 // actual render of content 195 $R->nest($instructions); 196 } 197 } 198 199 function getInfo() { 200 return array( 201 'desc'=>'Allows the use of dokuwiki syntax; only non-block syntax is allowed (only links, formatting, etc.; no tables, headers, and other large stuff). The hint is ignored.', 202 'tags'=>array() 203 ); 204 } 205 206 function _instructions($text) { 207 // determine all parser modes that are allowable as inline modes 208 // (i.e., those that are allowed inside a table cell, minus those 209 // that have a paragraph type other than 'normal') 210 211 // determine all modes allowed inside a table cell or list item 212 213 // import parser classes and mode definitions to make the $PARSER_MODES global available to us 214 require_once(DOKU_INC . 'inc/parser/parser.php'); 215 global $PARSER_MODES; 216 $allowedModes = array_merge( 217 $PARSER_MODES['formatting'], 218 $PARSER_MODES['substition'], 219 $PARSER_MODES['disabled'], 220 $PARSER_MODES['protected'] 221 ); 222 223 // determine all modes that are not allowed either due to paragraph 224 // handling, or because they're blacklisted as they don't make sense. 225 $blockHandler = new Block(); 226 $disallowedModes = array_merge( 227 // inlined from Block::blockOpen due to being protected: 228 array( 229 'header', 230 'listu_open','listo_open','listitem_open','listcontent_open', 231 'table_open','tablerow_open','tablecell_open','tableheader_open','tablethead_open', 232 'quote_open', 233 'code','file','hr','preformatted','rss', 234 'htmlblock','phpblock', 235 'footnote_open', 236 ), 237 // inlined from Block::stackOpen due to being protected: 238 array( 239 'section_open', 240 ), 241 array('notoc', 'nocache') 242 ); 243 244 $allowedModes = array_diff($allowedModes, $disallowedModes); 245 246 $parser = new Parser(new Doku_Handler()); 247 248 foreach(p_get_parsermodes() as $mode) { 249 if(!in_array($mode['mode'], $allowedModes)) continue; 250 $parser->addMode($mode['mode'], $mode['obj']); 251 } 252 253 trigger_event('PARSER_WIKITEXT_PREPROCESS', $text); 254 $p = $parser->parse($text); 255 return $p; 256 } 257} 258