* * Download: * * * ToDo: * * automatically add "nlogo !application/octet-stream" to conf/mime.local.conf? [Rik, 2012-10-19] * * language support [Rik, 2012-10-19] * * better error messages [Rik, 2012-10-19] * * config options (eg. download url) [Rik, 2012-10-19] * * make it work with local media files. Currently reports error: "Unable to load NetLogo model from ..., please ensure: * That you can download the resource at this link * That the server containing the resource has Cross-Origin Resource Sharing configured appropriately". Tried corsharing plugin but didn't help. [Rik, 2016-11-27] * * Documentation: * NetLogo model file format * * Acknowledgements: * Thanks to Stylianos Dritsas for the applet plugin * . */ // must be run within Dokuwiki if (!defined('DOKU_INC')) die(); if (!defined('DOKU_LF')) define('DOKU_LF', "\n"); if (!defined('DOKU_TAB')) define('DOKU_TAB', "\t"); if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); require_once DOKU_PLUGIN.'syntax.php'; require_once DOKU_PLUGIN.'netlogo/inc/support.php'; class syntax_plugin_netlogo_applet extends DokuWiki_Syntax_Plugin { public function getType() { return 'substition'; } /* // don't override getPType() public function getPType() { return 'FIXME: normal|block|stack'; } */ public function getSort() { /* Should be less than 320 as defined in * /inc/parser/parser.php:class Doku_Parser_Mode_media * http://xref.dokuwiki.org/reference/dokuwiki/_classes/doku_parser_mode_media.html * After plugin:applet (316), before media (320). See https://www.dokuwiki.org/devel:parser:getsort_list */ return 317; } public function connectTo($mode) { // make regex less greedy so it doesn't include pipe in filename, eg. only match first ugh.nlogo in {{ugh.nlogo|Download ugh.nlogo}} [Rik, 2013-11-28]] $this->Lexer->addSpecialPattern('\{\{[^\}\|]+\.nlogo\?[^\} ]*do=download[^\} ]* ?\}\}',$mode,'media'); // with do=download parameter $this->Lexer->addSpecialPattern('\{\{[^\}\|]+\.nlogo ?\}\}',$mode,'plugin_netlogo_applet'); // without parameters $this->Lexer->addSpecialPattern('\{\{[^\}\|]+\.nlogo\?[^\} ]+ ?\}\}',$mode,'plugin_netlogo_applet'); // with other parameters $this->Lexer->addSpecialPattern('\{\{[^\}\|]+\.nlogo ?\|\}\}',$mode,'plugin_netlogo_applet'); // with empty title [Rik, 2013-11-16] // here are some test cases [Rik, 2012-10-12] /* // should work {{ugh.nlogo|}} {{ugh.nlogo}} {{ugh.nlogo }} {{ ugh.nlogo }} {{ ugh.nlogo}} // should work {{ugh.nlogo?818x611}} {{ugh.nlogo?818x611 }} {{ ugh.nlogo?818x611 }} {{ ugh.nlogo?818x611}} // should fail {{ugh.nlogo.x}} {{ugh.nlogo.x }} {{ ugh.nlogo.x }} {{ ugh.nlogo.x}} // should fail {{ugh.nlogo.x?818x611}} {{ugh.nlogo.x?818x611 }} {{ ugh.nlogo.x?818x611 }} {{ ugh.nlogo.x?818x611}} */ // $this->Lexer->addEntryPattern('',$mode,'plugin_netlogo_applet'); } // public function postConnect() { // $this->Lexer->addExitPattern('','plugin_netlogo_applet'); // } public function handle($match, $state, $pos, Doku_Handler $handler){ /* * Copied from DokuWiki media handler in * http://xref.dokuwiki.org/reference/dokuwiki/_functions/doku_handler_parse_media.html */ // Strip the opening and closing markup $link = preg_replace(array('/^\{\{/','/\}\}$/u'),'',$match); // Split title from URL $link = explode('|',$link,2); // Check alignment $ralign = (bool)preg_match('/^ /',$link[0]); $lalign = (bool)preg_match('/ $/',$link[0]); // Logic = what's that ;)... if ( $lalign & $ralign ) { $align = 'center'; } else if ( $ralign ) { $align = 'right'; } else if ( $lalign ) { $align = 'left'; } else { $align = NULL; } // The title... if ( !isset($link[1]) ) { $link[1] = NULL; } //remove aligning spaces $link[0] = trim($link[0]); //split into src and parameters (using the very last questionmark) $pos = strrpos($link[0], '?'); if($pos !== false){ $src = substr($link[0],0,$pos); $param = substr($link[0],$pos+1); }else{ $src = $link[0]; $param = ''; } // parse width and height (must be first parameter) if (preg_match('#^(\d+)(x(\d+))?#i',$param,$size)){ ($size[1]) ? $w = $size[1] : $w = NULL; ($size[3]) ? $h = $size[3] : $h = NULL; } else { $w = NULL; $h = NULL; } // parse 'do' action if (preg_match('#do=([a-z]+)#',$param,$action)){ // specified by user $do = $action[1]; } else { $do = "interface"; // default } // check for nlogo fileicon $nlogoiconsrc = DOKU_PLUGIN.'netlogo/fileicons/nlogo.png'; $nlogoicondest = DOKU_INC.'lib/images/fileicons/nlogo.png'; if (!file_exists($nlogoicondest)) copy($nlogoiconsrc, $nlogoicondest); $params = array( 'src'=>$src, 'title'=>$link[1], 'align'=>$align, 'width'=>$w, 'height'=>$h, 'do'=>$do, ); return $params; } public function render($mode, Doku_Renderer $renderer, $data) { global $ID, $conf; if($mode != 'xhtml') return false; // check .nlogo file read permission $src = $data['src']; /* testing: disable filetype checking. Does this allow remote download of file, eg. from github? [Rik, 2016-11-25] resolve_mediaid(getNS($ID),$src,$exists); if(auth_quickaclcheck(getNS($src).':X') < AUTH_READ){ // auth_quickaclcheck() mimicked from http://xref.dokuwiki.org/reference/dokuwiki/_functions/checkfilestatus.html $renderer->doc .= '
NetLogo: File not allowed: ' . $src . '
'; return true; } $src = mediaFN($src); if (!$exists) { $renderer->doc .= '
NetLogo: File not found: ' . $src . '
'; return true; } */ // parse file to get contents if (is_null($data['width']) || is_null($data['height']) || $data['do']==='code' || $data['do']==='info' || $data['do']==='mdinfo') { $nlogo = file_get_contents($src); $nlogoparts = explode('@#$#@#$#@', $nlogo); /* [0] => code [1] => interface [2] => info [3] => turtle shapes [4] => NetLogo version [5] => preview commands [6] => system dynamics modeler [7] => BehaviorSpace [8] => HubNet client [9] => link shapes [10] =>model settings [11] =>reserved by Michelle [12] => (empty) */ // show code if ($data['do']==='code') { $renderer->doc .= p_render('xhtml',p_get_instructions('' . $nlogoparts[0] . ''),$info); return true; } // show info if ($data['do']==='info') { $renderer->doc .= p_render('xhtml',p_get_instructions($nlogoparts[2]),$info); return true; } // show info wrapped in '...' tags if ($data['do']==='mdinfo') { $renderer->doc .= p_render('xhtml',p_get_instructions('' . $nlogoparts[2] . ''),$info); return true; } // width & height? if (is_null($data['width']) || is_null($data['height'])) { // store x,y coordinates of bottom right corner in $rightbottom[2] & $rightbottom[3], respectively preg_match_all('/(^|\n)\n[A-Z\-]+\n[0-9]+\n[0-9]+\n([0-9]+)\n([0-9]+)\n/',$nlogoparts[1],$rightbottom); if (is_null($data['width'])) $data['width'] = max($rightbottom[2])+50; if (is_null($data['height'])) $data['height'] = max($rightbottom[3])+300; } } // download libraries? Todo: move root url to config option $urlroot = 'http://ccl.northwestern.edu/netlogo/'; // $src is currently realpath. Turn into relative path from DokuWiki media folder // temporarily disabled while testing remote urls [Rik, 2016-11-26] //$src = relativePath(DOKU_INC.'data/media/',$src); // Will pass token to servefile.php to authorize. First generate secret uuid if not found. $uuidfile = 'data/tmp/plugin_netlogo_uuid'; if (!file_exists($uuidfile)) { if (!$handle = fopen($uuidfile, 'w')) { $renderer->doc .= '
NetLogo: Cannot create UUID ' . $uuidfile . '
'; return true; } // Write uuid to our opened file. if (fwrite($handle, uuid4()) === FALSE) { $renderer->doc .= '
NetLogo: Cannot write UUID to ' . $uuidfile . '
'; return true; } fclose($handle); } // read uuid from file $uuid = file_get_contents($uuidfile); // when should the servefile.php link expire? $expires = time()+min(max($conf['cachetime'],60), 3600); // expires in cachetime, but no less than 1 minute or more than 1 hour // disable caching of this page to ensure parameters passed to servefile.php are always fresh [Rik, 2012-10-06] $renderer->info['cache'] = false; // generate token for servefile.php to authorize, use $uuid as salt. servefile.php must be able to generate same token or it won't serve file. $token=hash('sha256',$uuid.$src.$expires); // replace crypt() for more than first 8 chars [Rik, 2012-10-06] // special handling for center $pcenter = false; if (!is_null($data['align']) && $data['align']==='center') { $pcenter = true; $data['align']=null; } /* old servefile method: '"lib/plugins/netlogo/inc/servefile.php?src='.urlencode($src).'&expires='.$expires.'&token='.urlencode($token).'"' may still be needed because fetch.php throws Cross-Origin Resource Sharing error [Rik, 2016-11-27] */ if ($pcenter) $renderer->doc .= '

'; $renderer->doc .= ''; if ($pcenter) $renderer->doc .= '

'; return true; } } // vim:ts=4:sw=4:et: