box plugin

boxes plugin by Christopher Smith
Highlight particularly important parts of your wiki in boxes that stand out

Last updated on 2008-11-11. Provides Syntax.
Compatible with DokuWiki 2008-05-05 - 2005-09-22.

Conflicts with boxes_mod!
Similar to boxes_mod, class, note.

Tagged with boxes, div, highlight.

This plugin brings boxes to DokuWiki allowing you to highlight particularly important parts of your wiki in boxes that standout. The plugin comes with the ability to make ordinary square boxes, snazzyTM boxes with rounded corners, boxes with titles and boxes of varying widths. DokuWiki markup is allowed inside the box - where pretty well anything goes - and inside the title where only text markup, links, smileys and the like should be used.

It is probably sensible to set the style of the box you will most commonly use to be the default box. For details refer to the style.css

Notes

  • My version of this page - which could be more recently updated - can be found here

Acknowledgement

The rounded corners are based on snazzy borders by Stu Nicholls of CSS Play which in turn were inspired by Alessandro Fulciniti's nifty corners.

Syntax

A simple box:

<box> the box contents </box>

Some more complex boxes

<box 80% round orange|a title> the box contents</box>
<box 50% left blue>the box contents</box|a caption>
<box 60% round #f99 #fc9 #fcc #f60|title>the box contents></box|caption>

The full syntax:

<box width classes colours | title text> contents text </box>

  • width — any legal CSS width value
  • classes — any number of classes which use the styles in your template or the plugin's own stylesheet to determine the look of the box. The box plugins comes with the following classes already defined:
    • round — box will have rounded corners
    • blue — blue colour scheme
    • red — red colour scheme
    • green — green colour scheme
    • orange — orange colour scheme
    • left — float the box left within the wiki page
    • right — float the box right within the wiki page

if no classes are specified the default styles will be used, that is square corners in a colour scheme based on the default DokuWiki colour scheme.

  • colours — 1-4 colours in CSS hex or RGB notation, e.g. #F00 #fcab94 rgb(255,255,0). The colours are applied in order to:
    1. content background
    2. title background
    3. outer box background
    4. borders

if less than four colours are specified, the first colour is used for the missing colours.

  • title text — text (including DokuWiki markup) displayed above the box contents, with distinct style.
  • caption text — text (no markup allowed) displayed below the box contents, with distinct style.

The opening <box … > including the title must all appear on one line. The box contents can appear over as many lines as are needed.

See the plugin in action here. The sample page shows all the styles available with the plugin.

Configuration

The plugin has no configuration settings, although you may want to review the default colour scheme in style.css to ensure it is appropriate for your wiki.

Installation

Sources:

If your wiki uses either the plugin manager or the darcs plugin you can use them with the links above to install the plugin.

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/box, and install the plugin.

The folder will contain:

style.css                              all the box styles
syntax.php                             plugin script

The plugin is now installed.

Details

The plugin consists of two files, the plugin script syntax.php, lots of style rules for different box appearances in style.css.

syntax.php

This is the code for the release version of DokuWiki. Users of the development version of DokuWiki should get the source from the darcs repository, either through darcs or through the web browser interface.

<?php
/**
 * Box Plugin: Draw highlighting boxes around wiki markup
 *
 * Syntax:     <box width% classes|title>
 *   width%    width of the box, must use % unit
 *   classes   one or more classes used to style the box, several predefined styles included in style.css
 *   title     (optional) all text after '|' will be rendered above the main code text with a
 *             different style.
 *
 * Acknowledgments:
 *  Rounded corners based on snazzy borders by Stu Nicholls (http://www.cssplay.co.uk/boxes/snazzy) 
 *  which is in turn based on nifty corners by Alessandro Fulciniti (http://pro.html.it/esempio/nifty/)
 * 
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
 * @author     Christopher Smith <chris@jalakai.co.uk>  
 */
 
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_box extends DokuWiki_Syntax_Plugin {
 
    var $title_mode = false;
 
    // the following are used in rendering and are set by _xhtml_boxopen()
    var $_xb_colours      = '';
    var $_content_colours = '';
    var $_title_colours   = '';
 
    /**
     * return some info
     */
    function getInfo(){
      return array(
        'author' => 'Christopher Smith',
        'email'  => 'chris@jalakai.co.uk',
        'date'   => '2008-11-11',
        'name'   => 'Box Plugin',
        'desc'   => 'Boxes with titles, colour and rounded corners. 
                     Syntax: <box width class colours|title> ... </box|caption>
                     width, class, colours title & caption are optional.
                     The title can include some wiki markup, the box
                     contents can include almost any wiki markup.',
        'url'    => 'http://www.dokuwiki.org/plugin:boxes',
      );
    }
 
    function getType(){ return 'protected';}
    function getAllowedTypes() { return array('container','substition','protected','disabled','formatting','paragraphs'); }
    function getPType(){ return 'block';}
 
    // must return a number lower than returned by native 'code' mode (200)
    function getSort(){ return 195; }
 
    // 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 pattern to lexer
     */
    function connectTo($mode) {       
      $this->Lexer->addEntryPattern('<box>(?=.*?</box.*?>)',$mode,'plugin_box');
      $this->Lexer->addEntryPattern('<box\s[^\r\n\|]*?>(?=.*?</box.*?>)',$mode,'plugin_box');
      $this->Lexer->addEntryPattern('<box\|(?=[^\r\n]*?\>.*?</box.*?\>)',$mode,'plugin_box');      
      $this->Lexer->addEntryPattern('<box\s[^\r\n\|]*?\|(?=[^\r\n]*?>.*?</box.*?>)',$mode,'plugin_box');      
    }
 
    function postConnect() {
      $this->Lexer->addPattern('>', 'plugin_box');
      $this->Lexer->addExitPattern('</box.*?>', 'plugin_box');
    }
 
    /**
     * Handle the match
     */
    function handle($match, $state, $pos, &$handler){
 
        switch ($state) {
            case DOKU_LEXER_ENTER:
                $data = $this->_boxstyle(trim(substr($match, 4, -1)));
                if (substr($match, -1) == '|') {
                    $this->title_mode = true;
                    return array('title_open',$data);
                } else {
                    return array('box_open',$data);
                }
 
            case DOKU_LEXER_MATCHED:
                if ($this->title_mode) {
                    $this->title_mode = false;
                    return array('box_open','');
                } else {
                    return array('data', $match);
                }
 
            case DOKU_LEXER_UNMATCHED:                
                $handler->_addCall('cdata',array($match), $pos);
                return false;
 
            case DOKU_LEXER_EXIT:
                $data = trim(substr($match, 5, -1));
                $title =  ($data && $data{0} == "|") ? substr($data,1) : '';
 
                return array('box_close', $title);
 
        }       
        return false;
    }
 
    /**
     * Create output
     */
    function render($mode, &$renderer, $indata) {
 
      if (empty($indata)) return false;
      list($instr, $data) = $indata;
 
      if($mode == 'xhtml'){
          switch ($instr) {
          case 'title_open' : 
            $this->title_mode = true;
            $renderer->doc .= $this->_xhtml_boxopen($data)."<p class='box_title'{$this->_title_colours}>";
            break;
 
          case 'box_open' :   
            if ($this->title_mode) {
              $this->title_mode = false;
              $renderer->doc .= "</p>\n<div class='box_content'{$this->_content_colours}>";
            } else {
              $renderer->doc .= $this->_xhtml_boxopen($data)."<div class='box_content'{$this->_content_colours}>";
            }
            break;
 
          case 'data' :      
            $renderer->doc .= $renderer->_xmlEntities($data); 
            break;
 
          case 'box_close' : 
            $renderer->doc .= "</div>\n";
 
            if ($data) { 
              $renderer->doc .= "<p class='box_caption'{$this->_title_colours}>".$renderer->_xmlEntities($data)."</p>\n";
            }
            $renderer->doc .= $this->_xhtml_boxclose(); 
            break;
        }
 
        return true;
      }
      return false;
    }
 
    function _boxstyle($str) {
      if (!strlen($str)) return array();
 
      $styles = array();
 
      $tokens = preg_split('/\s+/', $str, 9);                      // limit is defensive
      foreach ($tokens as $token) {
          if (preg_match('/^\d*\.?\d+(%|px|em|ex|pt|cm|mm|pi|in)$/', $token)) {
            $styles['width'] = $token;
            continue;
          }
 
          if (preg_match('/^(
              (\#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}))|        #colorvalue
              (rgb\(([0-9]{1,3}%?,){2}[0-9]{1,3}%?\))     #rgb triplet
              )$/x', $token)) {
            $styles['colour'][] = $token;
            continue;
          }
 
          // 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;
      }
      if (!empty($styles['colour'])) {
        $styles['colour'] = $this->_box_colours($styles['colour']);
      }
 
      return $styles;
    }
 
    function _box_colours($colours) {
      $triplets = array();
 
      // only need the first four colours
      if (count($colours) > 4) $colours = array_slice($colours,0,4);
      foreach ($colours as $colour) {
        $triplet[] = $this->_colourToTriplet($colour);
      }
 
      // there must be one colour to get here - the primary background
      // calculate title background colour if not present
      if (empty($triplet[1])) {
        $triplet[1] = $triplet[0];
      }
 
      // calculate outer background colour if not present
      if (empty($triplet[2])) {
        $triplet[2] = $triplet[0];
      }
 
      // calculate border colour if not present
      if (empty($triplet[3])) {
        $triplet[3] = $triplet[0];
      }
 
      // convert triplets back to style sheet colours
      $style_colours['content_background'] = 'rgb('.join(',',$triplet[0]).')';
      $style_colours['title_background'] = 'rgb('.join(',',$triplet[1]).')';
      $style_colours['outer_background'] = 'rgb('.join(',',$triplet[2]).')';
      $style_colours['borders'] = 'rgb('.join(',',$triplet[3]).')';
 
      return $style_colours;
    }
 
    function _colourToTriplet($colour) {
      if ($colour{0} == '#') {
        if (strlen($colour) == 4) {
          // format #FFF
          return array(hexdec($colour{1}.$colour{1}),hexdec($colour{2}.$colour{2}),hexdec($colour{3}.$colour{3}));
        } else {
          // format #FFFFFF
          return array(hexdec(substr($colour,1,2)),hexdec(substr($colour,3,2)), hexdec(substr($colour,5,2)));
        }
      } else {
        // format rgb(x,y,z)
        return explode(',',substr($colour,4,-1));
      }
    }
 
    function _xhtml_boxopen($styles) {
      $class = 'class="box' . (isset($styles['class']) ? ' '.$styles['class'] : '') . '"';
      $style = isset($styles['width']) ? "width: {$styles['width']};" : '';
 
      if (isset($styles['colour'])) {
        $colours = 'background-color: '.$styles['colour']['outer_background'].'; ';
        $colours .= 'border-color: '.$styles['colour']['borders'].';';
 
        $this->_content_colours = 'style="background-color: '.$styles['colour']['content_background'].'; border-color: '.$styles['colour']['borders'].'"';
        $this->_title_colours = 'style="background-color: '.$styles['colour']['title_background'].';"';
 
      } else {
        $colours = '';
 
        $this->_content_colours = '';
        $this->_title_colours = '';
      }
 
      if ($style || $colours) $style = ' style="'.$style.' '.$colours.'"';
      if ($colours) $colours = ' style="'.$colours.'"';
 
      $this->_xb_colours = $colours;
 
      $html = "<div $class$style>\n";
      $html .="  <b class='xtop'><b class='xb1'$colours></b><b class='xb2'$colours></b><b class='xb3'$colours></b><b class='xb4'$colours></b></b>\n";
      $html .="  <div class='xbox'$colours>\n";
 
      return $html;
    }
 
    function _xhtml_boxclose() {
 
      $colours = $this->_xb_colours;
 
      $html = "  </div>\n";
      $html .= "  <b class='xbottom'><b class='xb4'$colours></b><b class='xb3'$colours></b><b class='xb2'$colours></b><b class='xb1'$colours></b></b>\n";
      $html .= "</div>\n";
 
      return $html;
    }
 
}
 
//Setup VIM: ex: et ts=4 enc=utf-8 :

style.css

These may be modified to suit your own requirements.

The file print.css is a duplicate of this file.

/* plugin:box */
div.box {
  width: 50%;
  margin: 1em auto;
  border: 1px solid;
  padding: 4px;
  overflow: hidden;
}
 
/* rounded corners styles from Stu Nicholls snazzy borders, http://www.cssplay.co.uk/boxes/snazzy.html */
.xtop, .xbottom {background:transparent; font-size:0; line-height: 1px;}
.xb1, .xb2, .xb3, .xb4 {display:block; overflow:hidden; border-style: solid;}
.xb2, .xb3 {height:1px;}
.xb2, .xb3, .xb4 {border-width:0 1px;}
.xb1 {height: 0; margin:0 5px; border-width:1px 0 0 0;}
.xb2 {margin:0 3px; border-width:0 2px;}
.xb3 {margin:0 2px;}
.xb4 {height:2px; margin:0 1px;}
 
div.box .xtop, div.box .xbottom {display: none;}
div.box.round > .xtop, div.box.round > .xbottom {display: block;}
 
div.box.round { border: none; padding: 0;}
div.box.round > .xbox {display:block; border-width:0 1px; border-style: solid; padding: 0 4px; }
 
div.box p.box_title, div.box p.box_caption {
  font-size: 90%;
  margin: 0;
  padding: 2px 6px;
  line-height: 1.2;
}
 
div.box p.box_title { margin-bottom: 4px;}
div.box p.box_caption { margin-top: 4px;}
 
div.box .box_content {
  margin: 0;
  padding: 0 6px;
  border-width: 1px;
  border-style: dashed;
  line-height: 1.2;
}
 
/* floating alignment */
 
div.box.left {
  float: left;
  margin-right: 1em;
}
 
div.box.right {
  float: right;
  margin-left: 1em;
}
 
/* colours */
/* default */
div.box, div.box .box_content, div.box .xbox, div.box .xb1, div.box .xb2, div.box .xb3, div.box .xb4 {
  border-color:  __dark__;
}
 
div.box, div.box .xbox, div.box .xb1, div.box .xb2, div.box .xb3, div.box .xb4 {
  background: __light__;
}
 
div.box p.box_title, div.box p.box_caption { background: __medium__;}
div.box .box_content { background: __lighter__;}
 
/* blue */
div.box.blue, div.box.blue > * > .box_content, div.box.blue > .xbox, 
div.box.blue > * > .xb1, div.box.blue > * > .xb2, div.box.blue > * > .xb3, div.box.blue > * > .xb4 {
  border-color:  #bbbbdd;
}
 
div.box.blue, div.box.blue > .xbox, 
div.box.blue > * > .xb1, div.box.blue > * > .xb2, div.box.blue > * > .xb3, div.box.blue > * > .xb4 {
  background: #e4ecf8;
}
 
div.box.blue > * > p.box_title, div.box.blue > * > p.box_caption {background: #cad0ee;}
div.box.blue > * > .box_content {background: #f4f8fd;}
 
/* red */
div.box.red, div.box.red > * > .box_content, div.box.red > .xbox, 
div.box.red > * > .xb1, div.box.red > * > .xb2, div.box.red > * > .xb3, div.box.red > * > .xb4 {
  border-color:  #ddbbbb;
}
 
div.box.red, div.box.red > .xbox, 
div.box.red > * > .xb1, div.box.red > * > .xb2, div.box.red > * > .xb3, div.box.red > * > .xb4 {
  background: #f8ece4;
}
 
div.box.red > * > p.box_title, div.box.red > * > p.box_caption {background: #eed0ca;}
div.box.red > * > .box_content {background: #fdf4ec;}
 
/* green */
div.box.green, div.box.green > * > .box_content, div.box.green > .xbox, 
div.box.green > * > .xb1, div.box.green > * > .xb2, div.box.green > * > .xb3, div.box.green > * > .xb4 {
  border-color:  #bbddbb;
}
 
div.box.green, div.box.green > .xbox, 
div.box.green > * > .xb1, div.box.green > * > .xb2, div.box.green > * > .xb3, div.box.green > * > .xb4 {
  background: #e4f8f2;
}
 
div.box.green > * > p.box_title, div.box.green > * > p.box_caption {background: #c4e4d4;}
div.box.green > * > .box_content {background: #ecfaf6;}
 
/* orange */
div.box.orange, div.box.orange > * > .box_content, div.box.orange > .xbox, 
div.box.orange > * > .xb1, div.box.orange > * > .xb2, div.box.orange > * > .xb3, div.box.orange > * > .xb4 {
  border-color:  #da3;
}
 
div.box.orange, div.box.orange > .xbox, 
div.box.orange > * > .xb1, div.box.orange > * > .xb2, div.box.orange > * > .xb3, div.box.orange > * > .xb4 {
  background: #f4e8ca;
}
 
div.box.orange > * > p.box_title, div.box.orange > * > p.box_caption {background: #f0d499;}
div.box.orange > * > .box_content {background: #f8f0da;}
 
/* must come last to override coloured background when using rounded corners */
 
div.box.round {
  background: transparent !important;
}
 
/* IE fixes for unsupported child selector \*/
 
* html div.box div.box, * html div.box div.box .box_content, * html div.box div.box .xbox, 
* html div.box div.box .xb1, * html div.box div.box .xb2, 
* html div.box div.box .xb3, * html div.box div.box .xb4 {
  border-color:  __dark__;
}
 
* html div.box div.box, * html div.box div.box .xbox, 
* html div.box div.box .xb1, * html div.box div.box .xb2, 
* html div.box div.box .xb3, * html div.box div.box .xb4 {
  background: __light__;
}
 
* html div.box div.box p.box_title, * html div.box div.box p.box_caption { background: __medium__;}
* html div.box div.box .box_content { background: __lighter__;}
 
* html div.box.round .xtop, * html div.box.round .xbottom {display: block;}
* html div.box.round .xbox {display:block; border-width:0 1px; border-style: solid; padding: 0 4px; }
 
/* blue */
* html div.box.blue .box_content, * html div.box.blue .xbox, 
* html div.box.blue .xb1, * html div.box.blue .xb2, * html div.box.blue .xb3, * html div.box.blue .xb4 {
  border-color:  #bbbbdd;
}
 
* html div.box.blue .xbox, 
* html div.box.blue .xb1, * html div.box.blue .xb2, * html div.box.blue .xb3, * html div.box.blue .xb4 {
  background: #e4ecf8;
 
 
 
}
 
* html div.box.blue p.box_title, * html div.box.blue p.box_caption {background: #cad0ee;}
* html div.box.blue .box_content {background: #f4f8fd;}
 
/* nested blue */
* html div.box div.box.blue .box_content, * html div.box div.box.blue .xbox, 
* html div.box div.box.blue .xb1, * html div.box div.box.blue .xb2, 
* html div.box div.box.blue .xb3, * html div.box div.box.blue .xb4 {
  border-color:  #bbbbdd;
}
 
* html div.box div.box.blue .xbox, 
* html div.box div.box.blue .xb1, * html div.box div.box.blue .xb2, 
* html div.box div.box.blue .xb3, * html div.box div.box.blue .xb4 {
  background: #e4ecf8;
}
 
* html div.box div.box.blue p.box_title, 
* html div.box div.box.blue p.box_caption {background: #cad0ee;}
* html div.box div.box.blue .box_content {background: #f4f8fd;}
 
/* red */
* html div.box.red .box_content, * html div.box.red .xbox, 
* html div.box.red .xb1, * html div.box.red .xb2, * html div.box.red .xb3, * html div.box.red .xb4 {
  border-color:  #ddbbbb;
}
 
* html div.box.red .xbox, 
* html div.box.red .xb1, * html div.box.red .xb2, * html div.box.red .xb3, * html div.box.red .xb4 {
  background: #f8ece4;
}
 
* html div.box.red p.box_title, * html div.box.red p.box_caption {background: #eed0ca;}
* html div.box.red .box_content {background: #fdf4ec;}
 
/* nested red */
* html div.box div.box.red .box_content, * html div.box div.box.red .xbox, 
* html div.box div.box.red .xb1, * html div.box div.box.red .xb2, 
* html div.box div.box.red .xb3, * html div.box div.box.red .xb4 {
  border-color:  #ddbbbb;
}
 
* html div.box div.box.red .xbox, 
* html div.box div.box.red .xb1, * html div.box div.box.red .xb2, 
* html div.box div.box.red .xb3, * html div.box div.box.red .xb4 {
  background: #f8ece4;
}
 
* html div.box div.box.red p.box_title, * html div.box div.box.red p.box_caption {background: #eed0ca;}
* html div.box div.box.red .box_content {background: #fdf4ec;}
 
/* green */
* html div.box.green .box_content, * html div.box.green .xbox, 
* html div.box.green .xb1, * html div.box.green .xb2, * html div.box.green .xb3, * html div.box.green .xb4 {
  border-color:  #bbddbb;
}
 
* html div.box.green .xbox, 
* html div.box.green .xb1, * html div.box.green .xb2, * html div.box.green .xb3, * html div.box.green .xb4 {
  background: #e4f8f2;
}
 
* html div.box.green p.box_title, * html div.box.green p.box_caption {background: #c4e4d4;}
* html div.box.green .box_content {background: #ecfaf6;}
 
/* nested green */
* html div.box div.box.green .box_content, * html div.box div.box.green .xbox, 
* html div.box div.box.green .xb1, * html div.box div.box.green .xb2, 
* html div.box div.box.green .xb3, * html div.box div.box.green .xb4 {
  border-color:  #bbddbb;
}
 
* html div.box div.box.green .xbox, 
* html div.box div.box.green .xb1, * html div.box div.box.green .xb2, 
* html div.box div.box.green .xb3, * html div.box div.box.green .xb4 {
  background: #e4f8f2;
}
 
* html div.box div.box.green p.box_title, * html div.box div.box.green p.box_caption {background: #c4e4d4;}
* html div.box div.box.green .box_content {background: #ecfaf6;}
 
/* orange */
* html div.box.orange .box_content, * html div.box.orange .xbox, 
* html div.box.orange .xb1, * html div.box.orange .xb2, * html div.box.orange .xb3, * html div.box.orange .xb4 {
  border-color:  #da3;
}
 
* html div.box.orange .xbox, 
* html div.box.orange .xb1, * html div.box.orange .xb2, * html div.box.orange .xb3, * html div.box.orange .xb4 {
  background: #f4e8ca;
}
 
* html div.box.orange p.box_title, * html div.box.orange p.box_caption {background: #f0d499;}
* html div.box.orange .box_content {background: #f8f0da;}
 
/* nestedorange */
* html div.box div.box.orange .box_content, * html div.box div.box.orange .xbox, 
* html div.box div.box.orange .xb1, * html div.box div.box.orange .xb2, 
* html div.box div.box.orange .xb3, * html div.box div.box.orange .xb4 {
  border-color:  #da3;
}
 
* html div.box div.box.orange .xbox, 
* html div.box div.box.orange .xb1, * html div.box div.box.orange .xb2, 
* html div.box div.box.orange .xb3, * html div.box div.box.orange .xb4 {
  background: #f4e8ca;
}
 
* html div.box div.box.orange p.box_title, * html div.box div.box.orange p.box_caption {background: #f0d499;}
* html div.box div.box.orange .box_content {background: #f8f0da;}
 
/* end plugin:box */

Revision History

  • 2008-11-11 — Add print.css, change plugin URL + other minor alterations
  • 2008-03-03 — Security fix + add support for specifying colours in box syntax
  • 2006-04-25 — XSS vulnerability fixed
  • 2006-04-20 — darcs update only
    • markup updated inline with DokuWiki fixes for PType block
    • corrections to syntax description
    • minor style changes for line-heights
  • 2006-03-11 — 2006-01-24 patch applied to non-darcs package;
    • support for all CSS length units added
    • styles added to support box nesting
    • lists can now be included in boxes
  • 2006-01-24 — darcs update only (package release held until after next DokuWiki update)
    • support nesting of boxes
    • default style now uses DokuWiki CSS substitutions
  • 2005-11-25 — Added caption text (displayed below main box content). Added left & right styles.
  • 2005-10-25 — Bug fix for merged paragraphs in boxes (thanks Matthias).
  • 2005-10-17 — Bug fix for some windows PHP installations (thanks Pablo).
  • 2005-10-12 — Released.

Security Fix

This fix is only applicable to those using older versions box plugin with DokuWiki versions prior to March 2006. Those running a Mar 2006 or later version of DokuWiki should update the plugin using the sources lists above.

Also apply Fix #2 detailed below.

Instructions

  • locate the file lib/plugins/box/syntax.php
  • open it for editing in a text editor
  • replace the function _boxstyle($str) (around line #150) with the code given below.
        function _boxstyle($str) {
          if (!strlen($str)) return array();
     
          $styles = array();
     
          $tokens = preg_split('/\s+/', $str, 9);                      // limit is defensive
          foreach ($tokens as $token) {
              if (preg_match('/^\d*\.?\d+(%|px|em|ex|pt|cm|mm|pi|in)$/', $token)) {
                $styles['width'] = $token;
                continue;
              }
     
              // 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 $styles;
        }
  • save the file

This restricts the characters available for use in any custom style names to alphanumeric characters plus dash and underscore (e.g. A-Z, a-z, 0-9, _ -). It also updates box width detection to support any valid CSS length value. See syntax for details.

Security Fix 2

This fix applies to all versions of the plugin prior to Mar 3, 2008. It is recommended that users of the plugin upgrade DW and this plugin to the most recent versions. For those interested who wish to fix the vulnerability with out updating.

          case 'box_close' : 
            $renderer->doc .= "</div>\n";
 
            if ($data) { 
-              $renderer->doc .= "<p class='box_caption'>".$data."</p>\n";
+              $renderer->doc .= "<p class='box_caption'>".$renderer->_xmlEntities($data)."</p>\n";
            }
            $renderer->doc .= $this->_xhtml_boxclose(); 
            break;

Thanks to Andy Webber of Oracle's Ethical Hacking Team for discovering this flaw. — Christopher Smith 2008-03-03 17:46

To Do

Bugs

  • Boxes can overlay TOC at top of the page. CSS fix needed.

Render bug with IE 6.0 - Running box plugin with roundbox template. Scrolling (or if box is big enough just page refreshes) sometimes causes lines/blocks of the box to not be updated leaving the background colour on display. Managed to replicate problem on box home DokuWiki here. The bad region seems to be bigger if the box is larger (more text in it). — Jonathan Alexander 2005-12-06 14:49