DokuWiki

It's better when it's simple

User Tools

Site Tools


plugin:boxwh

boxwh Plugin

Compatible with DokuWiki

2009-02-14b

plugin Extension of Christopher Smiths box plugin: includes now a height parameter.

Last updated on
2009-12-04
Provides
Syntax
Conflicts with
box, boxes_mod

This extension has not been updated in over 2 years. It may no longer be maintained or supported and may have compatibility issues.

Similar to box, boxes_mod

Tagged with boxes

This plugins is a modification of Christopher Smiths box plugin which offers in addition a height parameter. The syntax only differs in the definition of the width and height of a box. Both parameters stay optional, i.e. only width, only height or both can be specified.

All width and height values can be set in %, px, em etc.

Notice that this plugin is not compatible with box.

Installation Warning

:!: boxwh should never should be installed together with box or boxes_mod as it uses a class name not matching the used folder. It also have an extra folder __MACOSX which will show up as a broken plugin in the plugin manager. PHP don't allow a class being declared more than once, having two plugins installed at the same time (and enabled) sharing the same class name will cause a fatal error “Cannot redeclare class …”. Then you have to manually remove the files to get the wiki started again.

Syntax

A simple box:

<box> the box contents </box>

Some more specified boxes:

<box w=80% h=200px round orange|a title> the box contents, 80% in width, 200px in height</box>
<box w=100px left blue>the box contents. 100px in width, height automatically adjusted.</box|a caption>
<box h=60% round #f99 #fc9 #fcc #f60|title>the box contents. 60% in height, width automatically adjusted.</box|caption>

A more complex example:

More complex example including exttab2 in a box

…using fixed height and an embedded table with the exttab2 plugin one can build box based pages quite easily:

You can find the code for this example here.

Furthermore, box is compatible with the include plugin, so you can include sections of other wiki pages in the boxes.

For more information about style please visit the box plugin page. As the styles do not differ from the original box plugin, the appended style.css is identical.

Installation

Sources:

To install the plugin, download the zip file and copy the folder to your plugin folder, lib/plugins.

The folder contains:

print.css
style.css                              all the box styles (identical to the one of the box plugin)
style_custom.css                       modified style used in the more complex example above
syntax.php                             plugin script

Details

The plugin consists of two files, the plugin script syntax.php, and style rules for different box appearances in style.css. Furthermore, you can take a look at some modified styles in style_custom.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 w=width% h=height% classes|title>
 *   width in %/px/... 
 *   height in %/px/..
 *   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     Joachim Schäfer <mail@joachimschaefer.de>, based on the box plugin by 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:boxwh',
      );
    }
 
    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);                      // limited
      foreach ($tokens as $token) {
	  // the new syntax requires a w= in front of the width parameter, and a h= in front of height
	  // the two bytes are substracted from the token
          if (preg_match('/^w=\d*\.?\d+(%|px|em|ex|pt|cm|mm|pi|in)$/', $token)) {
            // $styles['width'] = $token;
            $styles['width'] = substr($token,2);
            continue;
          }
 
		  if (preg_match('/^h=\d*\.?\d+(%|px|em|ex|pt|cm|mm|pi|in)$/', $token)) {
            // $styles['width'] = $token;
            $styles['height'] = substr($token,2);
            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'] : '') . '"';
      if (isset($styles['width'])) {
          if (isset($styles['height'])) {
      	  // $style = (isset($styles['width']) && isset($styles['height'])) ? "width: {$styles['width']}; height: {$styles['height']};" : '';
          $style = "width: {$styles['width']}; height: {$styles['height']};";
      	  }
      	  else {
          $style = "width: {$styles['width']};";
     	  }
      }
      else {
          if (isset($styles['height'])) {
          $style = "height: {$styles['height']};";
          }
      }
 
      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 :

Discussion

plugin/boxwh.txt · Last modified: 2016-01-24 19:12 by Aleksandr