1<?php 2/** 3 * DokuWiki Plugin a2s (Syntax Component) 4 * 5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6 * @author Schplurtz le Déboulonné <Schplurtz@laposte.net> 7 */ 8 9// must be run within Dokuwiki 10if (!defined('DOKU_INC')) die(); 11 12class syntax_plugin_a2s extends DokuWiki_Syntax_Plugin { 13 protected static $cssAlign=array( 14 '' => 'media', 'left' => 'medialeft', 15 'right' => 'mediaright', 'center' => 'mediacenter' 16 ); 17 protected static $opening=<<<SVG 18<?xml version="1.0" encoding="UTF-8" standalone="no"?> 19<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> 20<!-- Created with ASCIIToSVG (https://github.com/dhobsd/asciitosvg/) --> 21<svg 22SVG; 23 protected static $renderer=null; 24 protected static $align=''; 25 /** 26 * return some info. 27 * Why did I copy this function here ? old DW compat ??? 28 * 29 * @return array hash of plugin technical informations. 30 */ 31 function getInfo(){ 32 return confToHash(dirname(__FILE__).'/plugin.info.txt'); 33 } 34 35 /** 36 * @return string Syntax mode type 37 */ 38 public function getType() { 39 return 'protected'; 40 } 41 /** 42 * @return string Paragraph type 43 */ 44 public function getPType() { 45 return 'block'; 46 } 47 /** 48 * @return int Sort order - Low numbers go before high numbers 49 */ 50 public function getSort() { 51 return 610; 52 } 53 54 /** 55 * Connect lookup pattern to lexer. 56 * 57 * @param string $mode Parser mode 58 */ 59 public function connectTo($mode) { 60 $this->Lexer->addEntryPattern('< *a2s *>(?=.*?</a2s>)',$mode,'plugin_a2s'); 61 } 62 63 public function postConnect() { 64 $this->Lexer->addExitPattern('</a2s>','plugin_a2s'); 65 } 66 67 /** 68 * Handle matches of the a2s 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 switch ($state) { 78 case DOKU_LEXER_ENTER : 79 $spaces=array(); 80 preg_match( '/<( *)a2s( *)>/', $match, $spaces ); 81 $left=strlen($spaces[1]); 82 $right=strlen($spaces[2]); 83 $align=''; 84 if( ($right + $left) > 0 ) { 85 if( $right > $left ) 86 $align='left'; 87 elseif( $left > $right) 88 $align='right'; 89 else 90 $align='center'; 91 } 92 self::$align=$align; // needed to pass $align to ODT LEXER_MATCHED render 93 return array($state, $align, null); // odt renderer expects 3 values 94 case DOKU_LEXER_UNMATCHED : 95 $o = new dokuwiki\plugin\a2s\ASCIIToSVG($this->_prepare($match)); 96 $o->setDimensionScale(9, 16); 97 $o->parseGrid(); 98 // save alignment for later use by ODT renderer 99 return array($state, $o->render(), self::$align); 100 case DOKU_LEXER_EXIT : 101 return array($state, null, null); // odt renderer expects 3 values 102 } 103 return array(); 104 } 105 106 /** 107 * Render output, generic method. Call specialized renderer depending 108 * on the mode. 109 * 110 * @param string $mode Renderer mode (supported modes: xhtml, odt) 111 * @param Doku_Renderer $renderer The renderer 112 * @param array $data The data from the handler() function 113 * @return bool If rendering was successful. 114 */ 115 public function render($mode, Doku_Renderer $renderer, $data) { 116 list($state, $txtdata, $align) = $data; 117 if( $state == DOKU_LEXER_UNMATCHED ) { 118 $this->renderer = $renderer; 119 $txtdata=preg_replace_callback( 120 '/ 121 xlink:href=" 122 <INTERWIKI> 123 <([^>]*)> 124 <([^>]*)> 125 " 126 /x', 127 function( $match ) { 128 return 'xlink:href="' . 129 $this->renderer->_resolveInterWiki($match[1],$match[2]) . 130 '"'; 131 } 132 , $txtdata 133 ); 134 } 135 136 switch($mode) { 137 case 'xhtml': 138 return $this->_render_xhtml($renderer, $state, $txtdata ); 139 break; 140 case 'odt': case 'odt_pdf': 141 return $this->_render_odt($renderer, $state, $txtdata, $align ); 142 break; 143 } 144 return false; 145 } 146 147 /** 148 * Render xhtml output. add data to the renderer doc. 149 * 150 * @param Doku_Renderer $renderer The renderer 151 * @param int $state The state 152 * @param string $txtdata Textual data that handle() associated with this state 153 * @return bool If rendering was successful. 154 */ 155 protected function _render_xhtml(Doku_Renderer $renderer, $state, $txtdata) { 156 157 switch ($state) { 158 case DOKU_LEXER_ENTER : 159 $align=self::$cssAlign[$txtdata]; 160 $renderer->doc .= "<svg class=\"a2s {$align}\" "; 161 break; 162 case DOKU_LEXER_UNMATCHED : 163 $renderer->doc .= $txtdata; 164 break; 165 } 166 return true; 167 } 168 169 /** 170 * Render odt output. 171 * 172 * @param Doku_Renderer $renderer The renderer 173 * @param int $state The state 174 * @param string $txtdata Textual data that handle() associated with this state 175 * @param string $align img align 176 * @return bool If rendering was successful. 177 */ 178 protected function _render_odt(Doku_Renderer $renderer, $state, $txtdata, $align) { 179 if($state === DOKU_LEXER_UNMATCHED) { 180 $dim=$this->_extract_XY_4svg( $txtdata ); 181 $renderer->_addStringAsSVGImage(self::$opening.$txtdata, $dim[0], $dim[1], $align); 182 } 183 return true; 184 } 185 186 /** 187 * Find the SVG X and Y dimensions in the svg string of the image. 188 * it searches for 'width="nnnpx" height="mmmpx"' in the first 189 * given string and returns the dimension in inch. 190 * 191 * @param String $svgtxt The svg string to inspect 192 * @return array the X and Y dimensions suitable as SVG dimensions 193 */ 194 protected function _extract_XY_4svg( $svgtxt ) { 195 $sizes=array(); 196 preg_match( '/width="(.*?)px" height="(.*?)px"/', $svgtxt, $sizes ); 197 array_shift($sizes); 198 // assume a 96 dpi screen 199 return array_map( function($v) { return ($v/96.0)."in"; }, $sizes ); 200 } 201 /** 202 * Prepare matched text for beeing parsed. Removes unnecessary blank lines 203 * expand wikilinks to http absolute links. (absolute links because of 204 * ODT export) 205 * 206 * @param String $text The matched a2s input string 207 * @return String the prepared string 208 */ 209 protected function _prepare( $text ) { 210 return preg_replace_callback( 211 '/"a2s:link":" 212 \\[\\[ 213 ([^]|]*) # The page_id 214 (\\|[^]]*)? # |description optional 215 ]]" 216 /x', 217 function( $match ) { 218 return '"a2s:link":"' . wl( cleanID($match[1]), '', true ) . '"'; 219 }, 220 preg_replace_callback( 221 '/"a2s:link":" 222 \\[\\[ 223 ([a-z0-9][-_.a-z0-9]*[a-z0-9])>([^]]*) 224 ]]" 225 /x', 226 function( $match ) { 227 return '"a2s:link":"<INTERWIKI><' . $match[1] . '><' . $match[2] . '>"'; 228 }, 229 trim($text, "\r\n") 230 ) 231 ); 232 } 233} 234 235// vim:ts=4:sw=4:et: 236