...mathematical formula.. * * format (optional) Specify which program will be used to * render the math formulae. * Support: * img (use mimetex http://www.forkosh.com/mimetex.html) * mml (use: * itex2mml http://pear.math.pitt.edu/mathzilla/itex2mml.html * plain2mml http://math.wcupa.edu/~johnston/plain2mathml ) * If might be better not to specify the format thus you * can change it at once for all math expression in your * wiki by changing the config value. * idiom (optional) Specify in which idiom (math dialect) * the math formulae is written in * So far, only 'tex' [(La)TeX] and 'plain' style are supported * 'tex': http://www.forkosh.com/mimetex.html * or http://pear.math.pitt.edu/mathzilla/itex2mml.html * 'plain': http://math.wcupa.edu/~johnston/plain2mathml/ * please note that output for plain are in mml only * if img is specified, the raw text is displayed * Might be used to merge with Christopher Smith's * math plugin (phpmathpublisher own synthax) * size (optional) Default size of the Math char [points] * * Formulae syntax: (depend on Idiom) See mimetex, itex2mml, plain2mml above * (may add phpmathpublisher own synthax) * * Config (in dokuwiki/conf/local.php) * $conf['mathmulti_iscgi'] = false; //Are eqn images produced by cgi every time the page is viewed? * $conf['mathmulti_mimetex'] = ""; //Path to mimetex bin (produce img) * $conf['mathmulti_itex2mml'] = ""; //Path to itex2mml bin (produce mathml) * $conf['mathmulti_plain2mml'] = ""; //Path to plain2mml bin (produce mathml) * $conf['mathmulti_format'] = "img"; //default mathmulti rendering format * $conf['mathmulti_idiom'] = "tex"; //default mathmulti math idiom (dialect) * $conf['mathmulti_size'] = "12"; //default mathmulti math char size [points] * * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author Stephane Chamberland * @date 2006-05-25 */ if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/'); if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); require_once(DOKU_PLUGIN.'syntax.php'); require_once(DOKU_INC.'inc/io.php'); // ----[ mathmulti plugin globals ]--------------------------------------- global $mathmultiplugin_urlimg,$mathmultiplugin_dirimg; // base url to access images, should correspond to $dirimg below. // if left at default, it will be modified to add a subfolder to avoid filling // the root media folder with clutter, refer _cacheExists() $mathmultiplugin_urlimg = DOKU_URL.'lib/exe/fetch.php?w=&h=&cache=cache&media='; $mathmultiplugin_dirimg = DOKU_INC; // ----------------------------------------------------------------------- /** * All DokuWiki plugins to extend the parser/rendering mechanism * need to inherit from this class */ class syntax_plugin_mathmulti extends DokuWiki_Syntax_Plugin { var $prefix = 'mathmulti_'; var $inlineopt = array(); //TODO: take these values from conf/metadata.php var $mathmulti_options = array( 'format' => array('img', 'mml'), 'idiom' => array('tex', 'plain'), 'size' => array('9','10','11','12','13','14','15','16','17','18') ); var $mathmulti_engines = array( 'mimetex' => array('idiom' => 'tex', 'format' => 'img'), 'itex2mml' => array('idiom' => 'tex', 'format' => 'mml'), 'plain2mml' => array('idiom' => 'plain', 'format' => 'mml') ); var $msg_disable = 'disable'; var $enable = false; var $msg_sent = false; /** * Initialization? */ function syntax_plugin_mathmulti() { $this->msg_disable = $this->getLang($this->prefix.'disable'); $this->enable = $this->_requirements_ok(); } /** * return some info */ function getInfo(){ return array( 'author' => 'Stephane Chamberland', 'email' => 'stephane.chamberland@ec.gc.ca', 'date' => '2006-05-23', 'name' => 'MathMulti Plugin'.(!$this->enable ? ' ('.$this->getLang($this->prefix.'disable').')' : ''), 'desc' => $this->getLang($this->prefix.'info'). (!$this->enable ? "\n(".$this->getLang($this->prefix.'disable').")" : ''), 'url' => 'http://wiki.splitbrain.org/plugin:math', ); } function getType(){ return 'protected'; } function getPType(){ return 'normal'; } function getSort(){ return 209; } /** * Connect pattern to lexer */ function connectTo($mode) { $this->Lexer->addEntryPattern('.*?)',$mode,'plugin_mathmulti'); } function postConnect() { $this->Lexer->addExitPattern('','plugin_mathmulti'); } /** * Handle the match */ function handle($match, $state, $pos, &$handler){ if ( $state == DOKU_LEXER_UNMATCHED ) { list($optstring, $contentstring) = preg_split('/>/u', $match, 2); // will split into format & math formulae //TODO: ?needed? string2lower($optstring); $tokens = preg_split('/\s+/', $optstring, 9); // limit is defensive $optionlist = $this->_parseoptions($this->mathmulti_options, $this->prefix,$tokens); $engine = $this->_getengine( $optionlist, $this->mathmulti_engines, $this->prefix, !$this->getConf($this->prefix.'iscgi')); $align = $this->_checkalign($contentstring); return (array($engine, $optionlist['size'], $align, trim($contentstring))); } return false; } /** * Create output */ function render($mode, &$renderer, $data) { if (!$data) return; // skip rendering for the enter and exit patterns list($engine, $size, $align, $eqn) = $data; if($mode == 'xhtml'){ $eqn_html = $renderer->_xmlEntities($eqn); if ($this->enable) { if ($engine == 'mimetex') { if ($this->getConf($this->prefix.'iscgi')) { $eqn_html = $this->_render_mimetexcgi($eqn,$eqn_html,$size, $align); } else { $eqn_html = $this->_render_mimetex($eqn,$eqn_html,$size, $align); } } else if ($engine == 'itex2mml') { $eqn_html = $this->_render_itex2mml($eqn,$eqn_html,$size, $align); } else if ($engine == 'plain2mml') { $eqn_html = $this->_render_plain2mml($eqn,$eqn_html,$size, $align); } else { $eqn_html = $this->_render_plaintext($eqn,$eqn_html,$size, $align); } } else { $this->_msg($this->msg_disable, -1); } $renderer->doc .= $eqn_html; // return to previous error reporting level error_reporting($error_level); return true; } return false; } function _render_plaintext($eqn,$eqn_html,$size,$align) { if ($align == 'normal') { return ''.$eqn_html.''; } else { return '
'.$eqn_html.'
'; } } //TODO: use $size param function _render_mimetexcgi($eqn,$eqn_html,$size,$align) { $myclass=' class="math"'; if ($align != 'normal') { $math_html = ' class="math media'.$align.'"'; } return ''.$eqn_html.''; } //TODO: create mathML eqn with mimetex function _render_mimetex($eqn,$eqn_html,$size,$align) { return $this->_render_plaintext($eqn,$eqn_html,$size, $align); } //TODO: create and cache img with mimetex // function _old_mathmultiimage() { // //return $renderer->_xmlEntities($mathmulti_eqn); // // $fontsize0_7 = max(0,min(intval($msize-9,7))); // // $hash = md5(serialize($data.strval($msize))); // // //write eqn in temp file // $tmpeqnfile= $mathmultiplugin_urlimg.""; // $fh = fopen($tmpeqnfile, 'w'); // fwrite($fh, $mathmulti_eqn); // fclose($fh); // // //TODO: remove old img.gif file if any // $oldgiffile = ""; // if (is_file($oldgiffile)) {unlink($oldgiffile);} // //TODO: define img.gif file name // $giffile = ""; // //Create img file // $fh = popen($this->getConf('mathmulti_mimetex').' -e '.$giffile.' -s '.$fontsize0_7." -f ".$mathmulti_eqn_file,'r'); // pclose($fh); // // unlink($tmpeqnfile); //TODO: remove eqn temp file // // //Write display image HTML code // $myclass=' class="math"'; // if ($align != 'normal') { // $math_html = 'class="math media'.$align.'"'; // } // return ''.$renderer->_xmlEntities($mathmulti_eqn).
//             $myclass.'/>';
//     }

    //TODO: create mathML eqn with itex2mml
    function _render_itex2mml($eqn,$eqn_html,$size, $align) {
        return $this->_render_plaintext($eqn,$eqn_html,$size, $align);
    }

   //TODO: create mathML eqn with plain2mml
    function _render_plain2mml($eqn,$eqn_html,$size, $align) {
         return $this->_render_plaintext($eqn,$eqn_html,$size, $align);
    }


    /**
     * Check string alignment (return left,right,center,normal)
     * param: Not trimed string
     */
    function _checkalign($mystring){
        $align = 'normal';
        if (strlen($mystring) > 1) {
          $c_first = $mystring{0};
          $c_last = $mystring{strlen($mystring)-1};

          $align = ($c_first == ' ') ? ($c_last == ' ' ? 'center' : 'right') : ($c_last == ' ' ? 'left' : 'normal');
        }
        return $align;
    }

    /**
     * Init options (from default config)
     * Params:
     *    $optionlistdict = array(
     *                       'option_1' => array('val_1', 'val_2'),
     *                        ...);
     *    $confprefix: [string] Prefix of options name in global $conf
     * Return:
     *    $optionlist = array(
     *                       'option_1' => 'val_opt_1',
     *                        ...);
     */
    function _initoptions($optionlistdict,$confprefix) {
        $optionlist = array();
        foreach ($optionlistdict as $option => $optlist) {
            $optionlist[$option] = $this->getConf($confprefix.$option);
        }
        return $optionlist;
    }

    /**
     * Init options (from default config + inline options)
     * Params:
     *    $optionlistdict = array(
     *                       'option_1' => array('val_1', 'val_2'),
     *                        ...);
     *    $confprefix: [string] Prefix of options name in global $conf
     *    $tokenlist: [string array] List of option keywords
     * Return:
     *    $optionlist = array(
     *                       'option_1' => 'val_opt_1',
     *                        ...);
     */
    //TODO: gengeralize to take args as in config plugin
    function _parseoptions($optionlistdict,$confprefix,$tokenlist) {
        $optionlist = $this->_initoptions($optionlistdict,$confprefix);
        foreach ($tokenlist as $token) {
            foreach ($optionlistdict as $option => $optlist) {
                foreach ($optlist as $optionval) {
                    if (trim($token) == trim($optionval)) {
                        $optionlist[$option] = $optionval;
                    }
                }
            }
        }
        return $optionlist;
    }

    /**
     * Look into options and _parseoptions() * $enginedictlist: list of engines and matching option => values * = array('engine_1' => array('option_1' => 'val_1', * 'option_2' => 'val_2',...), * ...); * $confprefix: [string] Prefix of options name in global $conf * $checkfile: [logical] Check if specified file for engine exist * Return: * $engine: [string] engine name (use to render code) * that matches default/specified options * false: if no "engine" match the options */ function _getengine($optionlist,$enginedictlist,$confprefix,$checkfile) { foreach ($enginedictlist as $engine => $engoptdict) { $engineok = true; foreach ($engoptdict as $option => $optionval) { if ($optionlist[$option] != $optionval) { $engineok = false; } } if ($engineok) { if ($checkfile) { if (!is_file($this->getConf($confprefix.$engine))) { return false; } } return $engine; } } return false; } /** * Cheque requirements... */ function _requirements_ok() { //check if at least one engine is specified $engineok = false; foreach ($this->mathmulti_engines as $engine => $engoptdict) { if ($this->getConf($this->prefix.$engine) != "") { $engineok = true; } } if (!$engineok) { $this->msg_disable .= $this->getLang($this->prefix.'noengine'); return false; } //check if the default settings/engine are ok if (!$this->_getengine( $this->_initoptions($this->mathmulti_options,$this->prefix), $this->mathmulti_engines, $this->prefix, !$this->getConf($this->prefix.'iscgi'))) { $this->msg_disable .= $this->getLang($this->prefix.'errdefault'); return false; } return true; } /** * */ function _cacheExists() { global $dirimg, $mathmultiplugin_urlimg, $conf; // check for default setting if (!isset($dirimg) || !$dirimg) { $dirimg = $this->conf['mediadir']; } if ($dirimg == $conf['mediadir']) { // we don't want to clutter the root media dir, so create our own subfolder $dirimg .= "/cache_mathmultiplugin"; $mathmultiplugin_urlimg .= "cache_mathmultiplugin%3a"; if (!@is_dir($dirimg)) { $this->_mkdir($dirimg); } } return @is_writable($dirimg); } /** * used to avoid multiple messages */ function _msg($str, $lvl=0) { if ($this->msg_sent) return; msg($str, $lvl); $this->msg_sent = true; } /** * */ // would like to see this function in io.php :) function _mkdir($d) { global $conf; umask($conf['dmask']); $ok = io_mkdir_p($d); umask($conf['umask']); return $ok; } } //Setup VIM: ex: et ts=4 enc=utf-8 :