Creates references to images/tables in your text, like the LaTeX figure references.
Compatible with DokuWiki
No compatibility info given!
This syntax plugin enables the creation of image captions in MediaWiki style and additionally create in-text references to these images. I created this plugin because we are using DokuWiki for software user manuals and we were missing the caption and image reference from LaTeX to refer to figures in your text.
Thanks a lot to the box plugin by Christopher Smith
⇒ 2008/09/11 Czech localisation added. Thanks to Jiri Vejda. Small bugfix in JavaScript. The toolbar buttons are now visible.
⇒ 2008/09/11 localisations for English, french and German added. Toolbar buttons for creating the caption and references.
⇒ 2008/08/13 included a small JavaScript which sets the right width of the box according to the image size. Also little modifications in style and syntax!
An image caption
<imgcaption image1| This is my little caption>{{:my_image.png}}</imgcaption>
You can refer to the <imgcaption> 'objects' by using
<imgref image1>
'image1' is the internal name of the imagecaption object. They are filtered and counted and the '<imgref>' tag will create a link to this image:
Fig. 1
You can set the orientation of an imgcaption:
<imgcaption image1 left| This is my text>{{:wiki:my_image.png}}</imgcaption>
<imgcaption image1 right| This is my text>{{:wiki:my_image.png}}</imgcaption>
The default orientation is center.
There are some problems with the numbering of the figures. It will generate the numbers for the imgref tags once and keep them in the cache. If you make some changes on the page, the imgref tags will be replaced with “Figure # #” until the cache is rebuild. I put the cache lifetime to 10 minutes.
This is the current code. Have fun.
<?php /** * Plugin imagereference * * Syntax: <imgref linkname> - creates a figure link to an image * <imgcaption linkname <orientation> | Image caption> Image/Table</imgcaption> * * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author Martin Heinemann <martin.heinemann@tudor.lu> */ 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'); /** * All DokuWiki plugins to extend the parser/rendering mechanism * need to inherit from this class */ class syntax_plugin_imagereference extends DokuWiki_Syntax_Plugin { var $_figure_name_array = array(""); var $_figure_map = array(); /** * Get an associative array with plugin info. * * <p> * The returned array holds the following fields: * <dl> * <dt>author</dt><dd>Author of the plugin</dd> * <dt>email</dt><dd>Email address to contact the author</dd> * <dt>date</dt><dd>Last modified date of the plugin in * <tt>YYYY-MM-DD</tt> format</dd> * <dt>name</dt><dd>Name of the plugin</dd> * <dt>desc</dt><dd>Short description of the plugin (Text only)</dd> * <dt>url</dt><dd>Website with more information on the plugin * (eg. syntax description)</dd> * </dl> * @param none * @return Array Information about this plugin class. * @public * @static */ function getInfo(){ return array( 'author' => 'Martin Heinemann', 'email' => 'martin.heinemann@tudor.lu', 'date' => '2008-05-30', 'name' => 'imagereference', 'desc' => 'Create image references like latex is doing with figures', 'url' => 'http://wiki.splitbrain.org/wiki:plugins', ); } function getType(){ return 'protected';} function getAllowedTypes() { return array('container','substition','protected','disabled','formatting','paragraphs'); } function getPType(){ return 'normal';} // must return a number lower than returned by native 'code' mode (200) function getSort(){ return 196; } // override default accepts() method to allow nesting // - ie, to get the plugin accepts its own entry syntax function accepts($mode) { if ($mode == substr(get_class($this), 7)) return true; return parent::accepts($mode); } /** * Connect lookup pattern to lexer. * * @param $aMode String The desired rendermode. * @return none * @public * @see render() */ function connectTo($mode) { $this->Lexer->addSpecialPattern('<imgref\s[^\r\n]*?>',$mode, 'plugin_imagereference'); $this->Lexer->addEntryPattern('<imgcaption\s[^\r\n\|]*?>(?=.*?</imgcaption.*?>)',$mode,'plugin_imagereference'); $this->Lexer->addEntryPattern('<imgcaption\s[^\r\n\|]*?\|(?=[^\r\n]*>.*?</imgcaption.*>)',$mode,'plugin_imagereference'); } function postConnect() { $this->Lexer->addExitPattern('</imgcaption>', 'plugin_imagereference'); } /** * Handler to prepare matched data for the rendering process. * * <p> * The <tt>$aState</tt> parameter gives the type of pattern * which triggered the call to this method: * </p> * <dl> * <dt>DOKU_LEXER_ENTER</dt> * <dd>a pattern set by <tt>addEntryPattern()</tt></dd> * <dt>DOKU_LEXER_MATCHED</dt> * <dd>a pattern set by <tt>addPattern()</tt></dd> * <dt>DOKU_LEXER_EXIT</dt> * <dd> a pattern set by <tt>addExitPattern()</tt></dd> * <dt>DOKU_LEXER_SPECIAL</dt> * <dd>a pattern set by <tt>addSpecialPattern()</tt></dd> * <dt>DOKU_LEXER_UNMATCHED</dt> * <dd>ordinary text encountered within the plugin's syntax mode * which doesn't match any pattern.</dd> * </dl> * @param $aMatch String The text matched by the patterns. * @param $aState Integer The lexer state for the match. * @param $aPos Integer The character position of the matched text. * @param $aHandler Object Reference to the Doku_Handler object. * @return Integer The current lexer state for the match. * @public * @see render() * @static */ function handle($match, $state, $pos, &$handler){ switch ($state) { // ========================================================= case DOKU_LEXER_ENTER : { /* --------------------------------------------------- */ $refLabel = trim(substr($match, 11, -1)); // ----------------------------------------------------- $parsedInput = $this->_parseParam($refLabel); // ------------------------------------------------------ //$data = $this->_imgstart($parsedInput); // store the figure name from imgcaption array_push($this->_figure_name_array, $parsedInput[0]); $this->_figure_map[$parsedInput[0]] = ""; return array('caption_open', $parsedInput); // image anchor label /* --------------------------------------------------- */ } // ========================================================= case DOKU_LEXER_UNMATCHED : { /* --------------------------------------------------- */ $parsed = $this->_parseContent($match); $this->_figure_map[end($this->_figure_name_array)] = $this->_imgend($parsed[0]); return array('data', ''); /* --------------------------------------------------- */ } // ========================================================= case DOKU_LEXER_EXIT : /* --------------------------------------------------- */ return array('caption_close', $this->_figure_map[end($this->_figure_name_array)]); /* --------------------------------------------------- */ // ========================================================= case DOKU_LEXER_MATCHED : /* --------------------------------------------------- */ return array('data', "----".$match."------"); /* --------------------------------------------------- */ // ========================================================= case DOKU_LEXER_SPECIAL : { /* --------------------------------------------------- */ $ref = substr($match, 8, -1); return array('imgref', $ref); /* --------------------------------------------------- */ } } return array(); } /** * Handle the actual output creation. * * <p> * The method checks for the given <tt>$aFormat</tt> and returns * <tt>FALSE</tt> when a format isn't supported. <tt>$aRenderer</tt> * contains a reference to the renderer object which is currently * handling the rendering. The contents of <tt>$aData</tt> is the * return value of the <tt>handle()</tt> method. * </p> * @param $aFormat String The output format to generate. * @param $aRenderer Object A reference to the renderer object. * @param $aData Array The data created by the <tt>handle()</tt> * method. * @return Boolean <tt>TRUE</tt> if rendered successfully, or * <tt>FALSE</tt> otherwise. * @public * @see handle() */ function render($mode, &$renderer, $indata) { list($case, $data) = $indata; if($mode == 'xhtml'){ // --------------------------------------------- switch ($case) { case 'imgref' : { /* --------------------------------------- */ $refNumber = array_search($data, $this->_figure_name_array); if ($refNumber == null || $refNumber == "") $refNumber = "##"; $str = "<a href=\"#".$data."\">".$this->getLang('figure').$refNumber." </a>"; $renderer->doc .= $str; break; // $renderer->_xmlEntities($str);break; /* --------------------------------------- */ } case 'caption_open' : $renderer->doc .= $this->_imgstart($data); break; case 'caption_close' : { // ------------------------------------------------------- list($name, $number, $caption) = $data; $layout = "<div class=\"undercaption\">".$this->getLang('fig').$number.": <a name=\"".$name."\">".$caption."</a><a href=\" \"><span></span></a> </div></div>"; $renderer->doc .= $layout; break; } // ------------------------------------------------------- // data is mostly empty!!! case 'data' : $renderer->doc .= $data; break; } return true; } if($mode == 'latex') { // ----------------------------------------- switch ($case) { case 'imgref' : { /* --------------------------------------- */ $renderer->doc .= "\\ref{".$data."}"; break; /* --------------------------------------- */ } case 'caption_open' : { // -------------------------------------- $orientation = "\\centering"; switch($data[1]) { case 'left' : $orientation = "\\left";break; case 'right' : $orientation = "\\right";break; } $renderer->doc .= "\\begin{figure}[H!]{".$orientation; break; // -------------------------------------- } case 'caption_close' : { // ------------------------------------------------------- list($name, $number, $caption) = $data; $layout = "\\caption{".$caption."}\\label{".$name."}\\end{figure}"; $renderer->doc .= $layout; break; } case 'data' : $renderer->doc .= trim($data); break; } return true; // ----------------------------------------- } return false; } function _parseParam($str) { if (!strlen($str)) return array(); $styles = array(); // get the img ref name. Its the first word $parsed = explode(" ", $str, 2); $imgref = $parsed[0]; $tokens = preg_split('/\s+/', $parsed[1], 9); // limit is defensive foreach ($tokens as $token) { // restrict token (class names) characters to prevent any malicious data if (preg_match('/[^A-Za-z0-9_-]/',$token)) continue; $styles['class'] = (isset($styles['class']) ? $styles['class'].' ' : '').$token; } // return imageref name , style // e.G. image1,left return array($imgref, $styles['class']); } function _imgstart($str) { // ============================================ // if (!strlen($str)) return array(); $layout = "<div class=\"imgcaption"; //$layout = "<div><div class=\"imgcaption"; if ($str[1] != "") $layout = $layout.$str[1]; $layout = $layout."\">"; return $layout; // ============================================ // } /** * * * @param String $str the image caption * @return array(imagename, image number, image caption) */ function _imgend($str) { // ===================================================== // $figureName = end($this->_figure_name_array); // get the position of the figure in the array $refNumber = array_search($figureName, $this->_figure_name_array); return array($figureName, $refNumber, $str); $layout = "<div class=\"undercaption\">".$this->getLang('fig').$refNumber.": <a name=\"".end($this->_figure_name_array)."\">".$str."</a></div>"; //$layout = "<div id=\"undercaption\">Fig. ".$refNumber.": //<a name=\"".end($this->_figure_name_array)."\">".$str."</a></div></div></div>"; return $layout; // ===================================================== } /** * divides the image caption and the content between the tags * */ function _parseContent($str) { // ====================================================== if (!strlen($str)) return ""; // parse for '>' $parsed = explode(">", $str, 2); return $parsed; // ====================================================== } } //Setup VIM: ex: et ts=4 enc=utf-8 : ?>
Don't forget this, otherwise it will look very uargs.
.scheisse {} /* this is some strange thing. If there is nothing on top of the div.imgcaption, the centered images will not have a colored bounding box and the image is left aligned. might be a bug of an older DokuWiki version. */ div.imgcaption { border: 1px solid #ccc; padding: 3px !important; background-color: #f9f9f9; font-size: 94%; text-align: center; width: auto; overflow: hidden; margin: 1px auto; float: none; } div.imgcaptionleft { border: 1px solid #ccc; padding: 3px !important; background-color: #f9f9f9; font-size: 94%; text-align: center; width: auto; overflow: hidden; margin: 1px; float: left; } div.imgcaptionright { border: 1px solid #ccc; padding: 3px !important; background-color: #f9f9f9; font-size: 94%; text-align: center; width: auto; overflow: hidden; margin: 1px; float: right; } div.imgcaption a img { border: 1px solid #ccc; background-color:#FFFFFF; } div.imgcaptionleft a img { border: 1px solid #ccc; background-color:#FFFFFF; } div.imgcaptionright a img { border: 1px solid #ccc; background-color:#FFFFFF; } div.dokuwiki .undercaption { font-size: 95%; } div.dokuwiki .undercaption a:hover { text-decoration:none; } div.dokuwiki .undercaption span { background-image:url(./magnify-clip.png); background-repeat:no-repeat; margin:2px; padding-left:15px; display:none; } div.imgcaption img.mediaright { float: none; margin: 0 0 0.5em 0; } div.imgcaption img.medialeft { float: none; margin: 0 0 0.5em 0; }
This resizes the grey box around the image to the image's size.
function checkImages() { var divs=document.getElementsByTagName("DIV"); for (var i=0;i<divs.length;i++) { if (divs[i].className == "imgcaption" || divs[i].className == "imgcaptionleft" || divs[i].className == "imgcaptionright") { var children = divs[i].getElementsByTagName("IMG"); // check if there is a link encapsulating the image var tmpImg = divs[i].childNodes[0].childNodes[0]; if (tmpImg == null) tmpImg = divs[i].childNodes[0]; else { // we have link and we can build the link image var innerElements = divs[i]; var iLink = innerElements.childNodes[1].childNodes[2]; var iSpan = iLink.childNodes[0]; // set the href of the link to the image link iLink.href= innerElements.childNodes[0].href; // show the link image iSpan.style.display="inline"; } //var tmpLink = divs[i].childNodes[0]; divs[i].style.width=(tmpImg.width + 8)+"px"; } } } if(window.toolbar!=undefined){ toolbar[toolbar.length] = {"type":"format", "title":"Adds an ImageCaption tag", "icon":"../../plugins/imagereference/button.png", "key":"", "open":"<imgcaption image1|>", "close":"</imgcaption>"}; toolbar[toolbar.length] = {"type":"format", "title":"Adds an ImageReference tag", "icon":"../../plugins/imagereference/refbutton.png", "key":"", "open":"<imgref ", "sample":"image1", "close":">"}; } addInitEvent(function(){checkImages();});
default localisation file
<?php /** * english language file */ $lang['fig'] = 'Fig. '; $lang['figure'] = 'figure'; ?>
there are also German, French and Czech localisations in the downloadable archives.
To install the plugin manually, download the source to your plugin folder, lib/plugins and extract its contents. That will create a new plugin folder, lib/plugins/imagereference, and install the plugin.
The folder will contain:
style.css style-sheet for the figures and captions syntax.php plugin script script.js javascript code magnify-clip.png a small image to display wether the image can be viewed in bigger size button.png toolbar button for inserting the image caption tag refbutton.png toolbar button for inserting the image reference tag /lang/ folder storing the localisation files
The plugin is now installed.
Current (2008/08/13) version conflicts with toolbar above editor (see also toolbar), probably due to new JavaScript code, pre-2008/08/13 version works.
The Firefox Error console shows this error message:
Error: missing ; before statement
Source File: http://myside/dokuwiki/lib/exe/js.php?edit=1&write=1
Line: 1, Column: 79
Source Code:
].className=="imgcaptionright"){var children=divs[i].getElementsByTagName("IMG")var tmpImg=divs[i].childNodes[0].childNodes[0];if(tmpImg==null)tmpImg=divs[i].childNodes[0];else{var innerElements=divs[i];var iLink=innerElements.childNodes[1].childNodes[2];
It seams to be the missing ; in one var declaration in the JavaScript, that is in the downloadable tgz file. The code from the codebox above works correct. christian
jslint (www.jslint.com) reprorted several problems with the 2009-01-07 version of script.js. Here's what it said:
Error:
Implied global: addInitEvent 47, document 3, toolbar 31 37, window 30
Problem at line 11 character 24: Use '===' to compare with 'null'.
if (tmpImg == null)
Problem at line 12 character 17: Expected '{' and instead saw 'tmpImg'.
tmpImg = divs[i].childNodes[0];
Problem at line 30 character 20: Use '!==' to compare with 'undefined'.
if(window.toolbar!=undefined){
Global checkImages 1 checkImages() Variable divs, i, iLink, iSpan, innerElements, tmpImg Unused children 47 "addInitEvent"() Global checkImages
Thanks, Kingsley
The image captions do not work correctly when they contain acronyms recognized by DokuWiki. The acronyms get pulled out and placed BEFORE the image tag in the HTML, and it renders badly.
It does not work with the svg_pureinsert plugin as it is. This bug is caused by the iframe reporting the width as a string. To fix it, change line 24 in script.js to:
divs[i].style.width=(parseInt(tmpImg.width) + 8)+"px";
Also, the box isn't sized correctly with this plugin, because it uses the object tag instead of img.
This plugin breaks XHTML compatibility because it adds a <div> tag inside a <p> tag. To fix it, change line 61 from
function getPType(){ return 'normal';}
to
function getPType(){ return 'block';}