1<?php 2/* 3 * Plugin pgn4web: PGN Viewer pgn4web for dokuwiki 4 * 5 * @name pgn4web Plugin 6 * @license GPL 3 (http://www.gnu.org/licenses/gpl.html) 7 * @author Michael Arlt <michael.arlt@sk-schwanstetten.de> 8 * @version 2018-05-12 9 * 10 * pgn4web.js changes: "=" -> "||" ; "+" -> "\u2192" 11 * 12 * This program is free software: you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation, either version 3 of the License, or 15 * (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program. If not, see <http://www.gnu.org/licenses/>. 24 * 25*/ 26 27if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../../').'/'); 28if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 29require_once(DOKU_PLUGIN.'syntax.php'); 30 31/** 32 * All DokuWiki plugins to extend the parser/rendering mechanism 33 * need to inherit from this class 34 */ 35class syntax_plugin_pgn4web extends DokuWiki_Syntax_Plugin { 36 37 /** 38 * function constructor 39 */ 40 function syntax_plugin_pgn4web(){ 41 // enable direct access to language strings 42 $this->setupLocale(); 43 } 44 45 /** 46 * return some info 47 */ 48 function getInfo(){ 49 return array( 50 'author' => 'Michael Arlt', 51 'email' => 'michael.arlt@sk-schwanstetten.de', 52 'date' => '2016-07-24', 53 'name' => 'pgn4web Plugin', 54 'desc' => $this->getLang('desc') , 55 'license'=> 'GPL v3 (http://www.gnu.org/licenses/gpl.html)', 56 'url' => 'http://wiki.splitbrain.org/plugin:pgn4web' 57 ); 58 } 59 60 /** 61 * What kind of syntax are we? 62 */ 63 function getType(){ 64 return 'substition'; 65 } 66 67 /** 68 * Where to sort in? 69 */ 70 function getSort(){ 71 return 38; 72 } 73 74 /** 75 * Connect pattern to lexer 76 */ 77 function connectTo($mode) { 78 $this->Lexer->addSpecialPattern('<pgn>.+?</pgn>',$mode,'plugin_pgn4web'); 79 } 80 81 /** 82 * Handle the match 83 */ 84 function handle($match, $state, $pos, Doku_Handler $handler) { 85 $match=substr($match,6,-7); 86 return $match; 87 } 88 89 /** 90 * Create output 91 */ 92 function render($mode, Doku_Renderer $renderer,$data) 93 { 94 if($mode == 'xhtml') 95 { 96 $shadow_size=20; 97 98 // defaults 99 $set = $this->getConf('set'); 100 $setsizeportrait = $this->getConf('setsizeportrait'); 101 $setsizelandscape = $this->getConf('setsizelandscape'); 102 $pluginwidthportrait = $this->getConf('pluginwidthportrait'); 103 $pluginwidthlandscape = $this->getConf('pluginwidthlandscape'); 104 $font = $this->getConf('font'); 105 $infowidth = $this->getConf('infowidth'); 106 $textheight = $this->getConf('textheight'); 107 $layout = $this->getConf('layout'); 108 //error_log("set:$set setsizeportrait:$setsizeportrait font:$font"); 109 $squaresizeportrait=intval($setsizeportrait/2); 110 $squaresizelandscape=intval($setsizelandscape/2); 111 $boardsizeportrait=8*($squaresizeportrait+12)+16; 112 $boardsizelandscape=8*($squaresizelandscape+12)+16; 113 if ($layout == "portrait") { 114 $boardsizelandscape = $boardsizeportrait; 115 $setsizelandscape = $setsizeportrait; 116 $pluginwidthlandscape = $pluginwidthportrait; 117 } 118 if ($layout == "landscape") { 119 $boardsizeportrait = $boardsizelandscape; 120 $setsizeportrait = $setsizelandscape; 121 $pluginwidthportrait = $pluginwidthlandscape; 122 } 123 124 $renderer->doc .= ' 125<div id=\'pgn4web_fontcontainer\'> 126<style type="text/css"> 127.move, .variation, .commentMove { font-family: "pgn4web ' . $font . '", "pgn4web Liberation Sans", sans-serif; } 128</style> 129</div>'; 130 131 $renderer->doc .= ' 132<style type="text/css"> 133label.pgn4web { width:' . $infowidth . '; } 134 135@media all and (orientation:portrait) { 136 <!-- .pieceImage { width: ' . $setsizeportrait . 'px; height: ' . $setsizeportrait . 'px; } --> 137 .pieceImage { width: auto; height: auto; } 138 .whiteSquare, .blackSquare, .highlightWhiteSquare, .highlightBlackSquare { 139 width: ' . $squaresizeportrait . 'px !important; 140 height: ' . $squaresizeportrait . 'px !important; 141 border-style: solid; border-width: 2px; 142 } 143 #GameBoard, #boardTable { width: ' . $boardsizeportrait . 'px !important; height: ' . $boardsizeportrait . 'px !important; } 144 #boardTable { table-layout: fixed !important; } 145 #boardTable td { border: 0px; height: 12.5% !important; width: 12.5% !important; } 146 #GameButtons table { 147 width:100% !important; 148 } 149 #GameButtons td { 150 padding:0px !important; 151 width: 12.5% !important; 152 } 153 #GameButtons td input { 154 width:100% !important; 155 } 156 td.buttonControlSpace { 157 display: none; 158 } 159} 160@media not all and (orientation:portrait) { 161 <!-- .pieceImage { width: ' . $setsizelandscape . 'px; height: ' . $setsizelandscape . 'px; } --> 162 .pieceImage { width: auto; height: auto; } 163 .whiteSquare, .blackSquare, .highlightWhiteSquare, .highlightBlackSquare { 164 width: ' . $squaresizelandscape . 'px !important; 165 height: ' . $squaresizelandscape . 'px !important; 166 border-style: solid; border-width: 2px; 167 } 168 #GameBoard, #boardTable { width: ' . $boardsizelandscape . 'px !important; height: ' . $boardsizelandscape . 'px !important; } 169 #boardTable { table-layout: fixed !important; } 170 #boardTable td { border: 0px; height: 12.5% !important; width: 12.5% !important; } 171 #GameButtons table { 172 width:100% !important; 173 } 174 #GameButtons td { 175 padding:0px !important; 176 width: 12.5% !important; 177 } 178 #GameButtons td input { 179 width:100% !important; 180 } 181 td.buttonControlSpace { 182 display: none; 183 } 184} 185 186</style>'; 187 // check set folder 188 // TODO! 189 if (! is_dir( DOKU_PLUGIN . "pgn4web/pgn4web/images/$relative_pieces_path")) { 190 $problem = true; 191 if (preg_match("/svg/",$set)) { 192 $renderer->doc .= pgn4web_error(sprintf($this->getLang('err_font_dir'),$pieces_fs_path)); 193 } else { 194 if ($set >=0 && $set <= 6) { # set is valid -> err_size if folder not found 195 $renderer->doc .= pgn4web_error(sprintf($this->getLang('err_size'),$setsizeportrait,$set+1)); 196 } 197 } 198 } 199 // check single pgn4web instance 200 if (defined('PGN4WEB')) { 201 $problem = true; 202 $renderer->doc .= pgn4web_info($this->getConf('err_instance')); 203 if (auth_quickaclcheck($ID) >= AUTH_EDIT) { 204 $renderer->doc .= pgn4web_info($this->getConf('err_instance_author')); 205 } 206 } else { 207 define('PGN4WEB',true); 208 } 209 if ($problem) { 210 return true; 211 } 212 213 // ausgabe 214 $renderer->doc .= '<script src="' . DOKU_BASE . 'lib/plugins/pgn4web/pgn4web/pgn4web.js" type="text/javascript"></script>'; 215 $renderer->doc .= '<form style="display: none;"><textarea style="display: none;" id="pgnText">'; 216 $renderer->doc .= $data; 217 $renderer->doc .= '</textarea></form>'; 218 $renderer->doc .= ' 219<script type="text/javascript"> 220 221 function autoScrollToCurrentMove(objId) { 222 if (!objId) { return; } 223 var theContainerObj = document.getElementById(objId); 224 if (theContainerObj) { 225 if (CurrentPly == StartPly) { theContainerObj.scrollTop = 0; } 226 else { 227 var theMoveObj = document.getElementById("Var" + CurrentVar + "Mv" + CurrentPly); 228 if (theMoveObj) { 229 var theContainerObjOffsetVeryTop = objOffsetVeryTop(theContainerObj); 230 var theMoveObjOffsetVeryTop = objOffsetVeryTop(theMoveObj); 231 theContainerObj.scrollTop = theMoveObjOffsetVeryTop - theContainerObjOffsetVeryTop; 232 } 233 } 234 } 235 } 236 "use strict"; 237 238 var pgn4web_set = "' . $set . '".split(" ",1); 239 var pgn4web_setsizeportrait = "' . $setsizeportrait . '"; 240 var pgn4web_setsizelandscape = "' . $setsizelandscape . '"; 241 var pgn4web_font = "' . $font . '"; 242 var pgn4web_infowidth = "' . $infowidth . '"; 243 var pgn4web_textheight = "' . $textheight . '"; 244 var pgn4web_layout = "' . $layout . '"; 245 var pgn4web_squaresizeportrait = ' . $squaresizeportrait . '; 246 var pgn4web_squaresizelandscape = ' . $squaresizelandscape . '; 247 var pgn4web_boardsizeportrait = ' . $boardsizeportrait . '; 248 var pgn4web_boardsizelandscape = ' . $boardsizelandscape . '; 249 var pgn4web_pluginwidthlandscape = "' . $pluginwidthlandscape . '"; 250 var pgn4web_pluginwidthportrait = "' . $pluginwidthportrait . '"; 251 252 var pgn4web_textheightlandscape = pgn4web_boardsizelandscape + 28 + "px"; 253 var pgn4web_textheightportrait = pgn4web_textheight; 254 255 function pgn4web_orientationdata() { 256 var w=window,d=document,e=d.documentElement,g=d.getElementsByTagName("body")[0],x=w.innerWidth||e.clientWidth||g.clientWidth,y=w.innerHeight||e.clientHeight||g.clientHeight; 257 if (pgn4web_layout == "portrait" || (y > x && pgn4web_layout == "auto")) { 258 return [pgn4web_boardsizeportrait + "px", pgn4web_pluginwidthportrait, pgn4web_setsizeportrait, pgn4web_textheightportrait]; 259 } else { 260 return [pgn4web_boardsizelandscape + "px", pgn4web_pluginwidthlandscape, pgn4web_setsizelandscape, pgn4web_textheightlandscape]; 261 } 262 } 263 pgn4web_od = pgn4web_orientationdata(); 264 pgn4web_boardsize = pgn4web_od[0]; 265 pgn4web_pluginwidth = pgn4web_od[1]; 266 pgn4web_setsize = pgn4web_od[2]; 267 pgn4web_activetextheight = pgn4web_od[3]; 268 269 function pgn4web_getpiecepathandtype(set) { 270 var path = "' . DOKU_BASE . 'lib/plugins/pgn4web/pgn4web/images/" + set; 271 if (/svg/.test(set)) { 272 var type = "svg"; 273 } else { 274 path += "/" + pgn4web_setsize; 275 var type = "png"; 276 } 277 return [path,type]; 278 } 279 280 function pgn4web_setchessset(index) { 281 if (index >= 0 && index < pgn4web_sets.length) { 282 var set = pgn4web_sets[index].split(" ",1); 283 var images = document.images; 284 var pgn4web_imagedata = pgn4web_getpiecepathandtype(set); 285 var path = pgn4web_imagedata[0]; 286 var type = pgn4web_imagedata[1]; 287 SetImagePath(path); 288 SetImageType(type); 289 InitImages(); 290 for (var i=0; i<images.length; i++) { 291 if (images[i].className == "pieceImage") { 292 figure=images[i].src.match(/([^\/]+)(?=\.\w+$)/)[0]; 293 images[i].src=path+"/"+figure+"."+type; 294 } 295 } 296 } 297 } 298 function pgn4web_setchessfont(index) { 299 if (index >= 0 && index < pgn4web_fonts.length) { 300 var showpgntextelement = document.getElementById("ShowPgnText").childNodes; 301 for (var i=0; i<showpgntextelement.length; i++) { 302 var classes = showpgntextelement[i].className.split(" "); 303 for (var j=0; j<classes.length; j++) { 304 if (classes[j] == "move" || classes[j] == "variation" || classes[j] == "commentMove") { 305 showpgntextelement[i].style.fontFamily = "\'pgn4web " + pgn4web_fonts[index] + "\', \'pgn4web Liberation Sans\', sans-serif"; 306 break; 307 } 308 } 309 } 310 } 311 } 312 313 314 var board = "<div id=\'GameBoard\'></div><div id=\'GameButtons\'></div>"; 315 var game_text = "<div id=\'GameText\' style=\'height:" + pgn4web_activetextheight + "; overflow-y:auto; resize:vertical; padding-right:1ex;\'></div>"; 316 317 document.writeln("<div style=\'width:" + pgn4web_pluginwidth + ";\'>"); 318 document.writeln("<form><fieldset class=\'pgn4web\' style=\'width:100%;\'><ul class=\'pgn4web\'>"); 319 320 // select set 321 var pgn4web_sets = new Array ("alpha","merida","uscf","igorsvg","svgchess","tilesvg");'; 322 323if ($this->getConf('showsetselect')) { 324$renderer->doc .= ' 325 document.writeln("<li class=\'pgn4web\'><label class=\'pgn4web\' for=\'pgn4web_set\'>' . $this->getLang('selectset') . '</label>"); 326 document.writeln("<select name=\'pgn4web_set\' size=\'1\' onchange=\'pgn4web_setchessset(this.form.pgn4web_set.selectedIndex)\'>"); 327 document.writeln("<optgroup label=\'png\'>"); 328 for (var i=0; i<3; i++) { 329 if (pgn4web_sets[i] == pgn4web_set) { 330 document.writeln("<option selected>" + pgn4web_sets[i] + "</option>"); 331 } else { 332 document.writeln("<option>" + pgn4web_sets[i] + "</option>"); 333 } 334 } 335 document.writeln("</optgroup>"); 336 document.writeln("<optgroup label=\'svg\'>"); 337 for (var i=3; i<pgn4web_sets.length; i++) { 338 if (pgn4web_sets[i] == pgn4web_set) { 339 document.writeln("<option selected>" + pgn4web_sets[i] + "</option>"); 340 } else { 341 document.writeln("<option>" + pgn4web_sets[i] + "</option>"); 342 } 343 } 344 document.writeln("</optgroup>"); 345 document.writeln("</select>"); 346 document.writeln("</li>");'; 347} 348 349$renderer->doc .= ' 350 // select font 351 var pgn4web_fonts = new Array ("ChessSansAlpha","ChessSansMerida","ChessSansPiratf","ChessSansUscf","ChessSansUsual"); 352'; 353 354if ($this->getConf('showfontselect')) { 355$renderer->doc .= ' 356 document.writeln("<li class=\'pgn4web\'><label class=\'pgn4web\' for=\'pgn4web_set\'>' . $this->getLang('selectfont') . '</label>"); 357 document.writeln("<select name=\'pgn4web_font\' size=\'1\' onchange=\'pgn4web_setchessfont(this.form.pgn4web_font.selectedIndex)\'>"); 358 for (var i=0; i<pgn4web_fonts.length; i++) { 359 if (pgn4web_fonts[i] == "' . $font . '") { 360 document.writeln("<option selected>" + pgn4web_fonts[i] + "</option>"); 361 } else { 362 document.writeln("<option>" + pgn4web_fonts[i] + "</option>"); 363 } 364 } 365 document.writeln("</select>"); 366 document.writeln("</li>");'; 367} 368 369$renderer->doc .= ' 370 // game_info 371 document.writeln("<li class=\'pgn4web\'> <label class=\'pgn4web\' for=\'GameSelector\'>' . $this->getLang('GameSelector') . '</label> <span id=\'GameSelector\'></span> </li> <li class=\'pgn4web\'> <label class=\'pgn4web\' for=\'GameDate\'>' . $this->getLang('GameDate') . '</label> <span id=\'GameDate\'></span> </li> <li class=\'pgn4web\'> <label class=\'pgn4web\' for=\'GameSite\'>' . $this->getLang('GameSite') . '</label> <span id=\'GameSite\'></span> </li> <li class=\'pgn4web\'> <label class=\'pgn4web\' for=\'GameEvent\'>' . $this->getLang('GameEvent') . '</label> <span id=\'GameEvent\'></span> </li> <li class=\'pgn4web\'> <label class=\'pgn4web\' for=\'GameWhite\'>' . $this->getLang('GameWhite') . '</label> <span id=\'GameWhite\'></span> </li> <li class=\'pgn4web\'> <label class=\'pgn4web\' for=\'GameBlack\'>' . $this->getLang('GameBlack') . '</label> <span id=\'GameBlack\'></span> </li> <li class=\'pgn4web\'> <label class=\'pgn4web\' for=\'GameResult\'>' . $this->getLang('GameResult') . '</label> <span id=\'GameResult\'></span> </li>"); 372 373 document.writeln("</ul></fieldset></form>"); 374 document.writeln("<div id=\'pgn4web_container\'>"); 375 document.writeln(" <div id=\'pgn4web_boarddiv\' style=\'float:left; padding-right:1ex;\'>" + board + "</div>"); 376 document.writeln(" <div id=\'pgn4web_textdiv\' style=\'float:left; width:100%; \'>" + game_text + "</div>"); 377 document.writeln(" <div style=\'clear:both\'></div>"); 378 document.writeln("</div>"); 379 document.writeln("</div>"); 380 381 var pgn4web_imagedata = pgn4web_getpiecepathandtype(pgn4web_set); 382 SetImagePath(pgn4web_imagedata[0]); 383 SetImageType(pgn4web_imagedata[1]); 384 SetHighlightOption(true); 385 SetCommentsIntoMoveText(true); 386 SetCommentsOnSeparateLines(true); 387 SetAutoplayDelay(1000); // milliseconds 388 SetAutostartAutoplay(false); 389 SetAutoplayNextGame(false); // if set, move to the next game at the end of the current game during autoplay 390 SetInitialVariation(0); // number for the variation to be shown at load, 0 (default) for main variation 391 SetInitialHalfmove(0,false); // halfmove number to be shown at load, 0 (default) for start position; values (keep the quotes) of "start", "end", "random", "comment" (go to first comment or variation), "variation" (go to the first variation) are also accepted. Second parameter if true applies the setting to every selected game instead of startup only 392enableAutoScrollToCurrentMove("GameText"); 393 window.addEventListener("resize", autoScrollToCurrentMoveIfEnabled); 394 395function orientationChange() { 396 pgn4web_od = pgn4web_orientationdata(); 397 pgn4web_boardsize = pgn4web_od[0]; 398 pgn4web_pluginwidth = pgn4web_od[1]; 399 document.getElementById("pgn4web_textdiv").style.width="100%"; 400 document.getElementById("GameText").style.height = pgn4web_activetextheight; 401 pgn4web_setsize = pgn4web_od[2]; 402 pgn4web_activetextheight = pgn4web_od[3]; 403 document.getElementById("pgn4web_boarddiv").style.width = pgn4web_boardsize; 404 document.getElementById("GameText").style.height = pgn4web_activetextheight; 405 remainingwidth=document.getElementById("pgn4web_container").clientWidth - document.getElementById("pgn4web_boarddiv").clientWidth; 406 if (remainingwidth > 80) { 407 document.getElementById("pgn4web_textdiv").style.width = remainingwidth - 4 + "px"; 408 } else { 409 document.getElementById("pgn4web_textdiv").style.width = "100%"; 410 } 411} 412 413window.addEventListener("resize", orientationChange); 414orientationChange(); 415 </script>'; 416 417 418 return true; 419 } 420 return false; 421 } 422} 423 424function pgn4web_info($text) { 425 return "<div class='info'>$text</div>"; 426} 427function pgn4web_error($text) { 428 $problem = true; 429 return "<div class='error'>$text</div>"; 430} 431 432//Setup VIM: ex: et ts=4 : 433