imagereference plugin

Compatible with DokuWiki

No compatibility info given!

plugin Creates references to images/tables in your text, like the LaTeX figure references.

Last updated on
2009-01-07
Provides
Syntax

Similar to imagebox, side_note

Tagged with caption, images, links, media, references

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.

Downloadtar.gz (6.9KB)2009-01-07
Downloadzip (9.0KB)2009-01-07

Acknowledgment

Thanks a lot to the box plugin by Christopher Smith

Versions

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!

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.

Screenshot

Known Problems

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.

syntax.php

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 :
?>

style.css

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;
}

script.js

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();});

/lang/en/lang.php

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.

Installation

Sources:

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.

Bugs

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.

  • Can you tell me some more details about this bug? martin

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';}

User wishes

  1. Is there any possibility to use this plugin for tables with own numbering and name (Table 1 etc.)?
  2. Make possible to remove “fig. X” text (either admin panel or per image)
  3. Get text from image alt-text if there isn't text in reference
  4. It will be great to show a reference list when click the image reference button — lainme 2010/08/06 08:18
  5. And Hope for PHP5.3 capability — lainme 2010/08/09 11:21
  6. Please update to support the latest Dokuwiki 2011/06/17 11:21
plugin/imagereference.txt · Last modified: 2011/08/16 14:23 by 200.20.218.11
 
Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Share Alike 3.0 Unported
Imprint Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki
WikiForumIRCBugsGitXRefTranslate