* * REMARK: depends on InlineJS embedder (syntax component) * SYNTAX: * * ... javascript ... * */ // must be run within Dokuwiki if (!defined('DOKU_INC')) die(); if (!defined('NL')) define('NL',"\n"); /** * All DokuWiki plugins to extend the parser/rendering mechanism * need to inherit from this class */ class syntax_plugin_canvas_canvas extends DokuWiki_Syntax_Plugin { protected $mode; protected $entry_pattern = '(?=.*?)'; protected $exit_pattern = ''; function __construct() { $this->mode = substr(get_class($this), 7); } function getType() { return 'protected'; } //function getPType() { return 'block'; } function getSort() { return 160; } function connectTo($mode) { $this->Lexer->addEntryPattern($this->entry_pattern, $mode, $this->mode); } function postConnect() { $this->Lexer->addExitPattern($this->exit_pattern, $this->mode); } /** * handle syntax */ public function handle($match, $state, $pos, Doku_Handler $handler){ global $conf; // check whether inlinejs plugin exists if (!plugin_isdisabled('inlinejs')) { $inlinejs = plugin_load('syntax', 'inlinejs_embedder'); if ($inlinejs->getConf('follow_htmlok') && !$conf['htmlok']) return false; } else { msg($this->getPluginName().': Plugin InlineJS disabled.',-1); return false; } switch ($state) { case DOKU_LEXER_ENTER: // at least one delimiter required to have unique canvas id. //if (strpos($match,' ') === false) { // msg($this->getPluginName().': syntax wrong.',-1); // return false; //} return array($state, $match); case DOKU_LEXER_UNMATCHED: // javascript code return array($state, $match); case DOKU_LEXER_EXIT: return array($state, ''); } return false; } /** * Render */ public function render($format, Doku_Renderer $renderer, $indata) { if (empty($indata)) return false; list($state, $data) = $indata; if ($format != 'xhtml') return false; switch ($state) { case DOKU_LEXER_ENTER: // get canvas type and id if ( substr($data, 1, 7) == 'canvas:') { $match = trim(substr($data, 8, -1)); } else { $match = trim(substr($data, 1, -1)); } list($ctype, $cid, $cparam) = explode(' ', $match, 3); if (empty($cid)) { msg($this->getPluginName().': syntax wrong -- '.hsc($data),-1); } $param = $this->getArguments($cparam, 'width'); // prepare canvas $renderer->doc.= $this->_htmlCanvas($cid, $ctype, $param); // open script tag to output embedded javascript $renderer->doc.= ''.NL; break; } return true; } /* --------------------------------------------------------- * build html of canvas * * @param $cid (string) canvas id * @param $ctype (string) canvas type * @param $opts (array) canvas options (width, height, ...) * --------------------------------------------------------- */ protected function _htmlCanvas($cid, $ctype, $opts) { // check whether canvas id is given? if (empty($cid)) return false; // set default canvas size if (!array_key_exists('width', $opts)) $opts['width'] = '300px'; if (!array_key_exists('height',$opts)) $opts['height'] = '150px'; // prepare plot container switch ($ctype) { case "jqplot": // see its project page https://bitbucket.org/cleonello/jqplot/overview // jqPlot is currently available for use in all personal or commercial projects // under both the MIT and GPL version 2.0 licenses. This means that you can // choose the license that best suits your project and use it accordingly. $html.= '
'; $html.= '
'.NL; $html.= '
'; $html.= 'Powered by jQplot'; $html.= '
'.NL; break; case "rgraph": // see http://www.rgraph.net/license // RGraph can be used free-of-charge by both commercial and non-commercial // entities (eg business, personal, charity, educational etc) on either // internal or external websites or in software that they make under the terms // of the Creative Commons Attribution 3.0 This means that you may use RGraph // for both commercial and non-commercial purposes as long as you link back to // this website (eg underneath the chart). $html.= ''.NL; $html.= '
'; $html.= 'Powered by RGraph'; $html.= '
'.NL; break; default: $html.= ''.NL; break; } return $html; } /* --------------------------------------------------------- * get each named/non-named arguments as array variable * * Named arguments is to be given as key="value" (quoted). * Non-named arguments is assumed as boolean. * * @param $args (string) arguments * @param $singlekey (string) key name if single numeric value was given * @return (array) parsed arguments in $arg['key']=value * --------------------------------------------------------- */ protected function getArguments($args='', $singlekey='height') { $arg = array(); // get named arguments (key="value"), ex: width="100" // value must be quoted in argument string. $val = "([\"'`])(?:[^\\\\\"'`]|\\\\.)*\g{-1}"; $pattern = "/(\w+)\s*=\s*($val)/"; preg_match_all($pattern, $args, $matches, PREG_SET_ORDER); foreach ($matches as $match) { $arg[$match[1]] = substr($match[2], 1, -1); // drop quates from value string $args = str_replace($match[0], '', $args); // remove parsed substring } // get named numeric value argument, ex width=100 // numeric value may not be quoted in argument string. $val = '\d+'; $pattern = "/(\w+)\s*=\s*($val)/"; preg_match_all($pattern, $args, $matches, PREG_SET_ORDER); foreach ($matches as $match) { $arg[$match[1]] = (int)$match[2]; $args = str_replace($match[0], '', $args); // remove parsed substring } // get width and/or height, specified as non-named arguments $unit = 'px'; $pattern = '/(?:^| )(\d+(%|em|pt|px)?)\s*([,xX]?(\d+(%|em|pt|px)?))?(?: |$)/'; if (preg_match($pattern, $args, $matches)) { if ($matches[4]) { // width and height with unit was given $arg['width'] = $matches[1]; if (!$matches[2]) $arg['width'].= $unit; $arg['height'] = $matches[4]; if (!$matches[5]) $arg['height'].= $unit; } elseif ($matches[2]) { // width or height(=assumed as default) with unit was given // preferred key name given as second parameter of this function $arg[$singlekey] = $matches[1]; if (!$matches[2]) $arg[$singlekey].= $unit; } elseif ($matches[1]) { // numeric token is assumed as width or height $arg[$singlekey] = $matches[1].$unit; } $args = str_replace($matches[0], '', $args); // remove parsed substring } // get flags or non-named arguments, ex: showdate, noshowfooter $tokens = preg_split('/\s+/', $args); foreach ($tokens as $token) { if (preg_match('/^(?:!|not?)(.+)/',$token, $matches)) { // denyed/negative prefixed token $arg[$matches[1]] = false; } elseif (preg_match('/^[A-Za-z]/',$token)) { $arg[$token] = true; } } return $arg; } }