Difference between revisions of "Extension:Treeview4.php"

From Organic Design wiki
(4.0.8 - added custom image support)
Line 8: Line 8:
 
if (!defined('MEDIAWIKI')) die('Not an entry point.');
 
if (!defined('MEDIAWIKI')) die('Not an entry point.');
 
   
 
   
define('TREEVIEW4_VERSION','4.0.7, 2007-09-24');
+
define('TREEVIEW4_VERSION','4.0.8, 2007-10-10');
 
   
 
   
 
# Set any unset images to default titles
 
# Set any unset images to default titles
Line 28: Line 28:
 
   
 
   
 
$wgTreeView4Magic              = "tree"; # the parser-function name for trees
 
$wgTreeView4Magic              = "tree"; # the parser-function name for trees
$wgTreeViewIconMagic          = "tree"; # the parser-function name for setting icons for specific rows
 
 
$wgTreeViewIndent              = 0;      # the number of pixels each level indents by (0 means doc-icon width)
 
$wgTreeViewIndent              = 0;      # the number of pixels each level indents by (0 means doc-icon width)
 
$wgTreeViewShowLines          = false;  # whether to render the dotted lines joining nodes
 
$wgTreeViewShowLines          = false;  # whether to render the dotted lines joining nodes
Line 51: Line 50:
 
   
 
   
 
# Constructor
 
# Constructor
function TreeView4($magic) {
+
function TreeView4() {
global $wgParser,$wgHooks,$wgTreeViewImages,$wgTreeViewIndent;
+
global $wgParser,$wgHooks,$wgTreeView4Magic,$wgTreeViewIconMagic,$wgTreeViewImages,$wgTreeViewIndent;
 
 
# Set hooks
 
$wgParser->setFunctionHook($magic,array($this,'Tree'));
 
  
 
# Convert image titles to file paths and obtain pixel width of items
 
# Convert image titles to file paths and obtain pixel width of items
Line 69: Line 65:
  
 
$this->uid = uniqid('TVUNIQ');
 
$this->uid = uniqid('TVUNIQ');
 +
$wgParser->setFunctionHook($wgTreeView4Magic,array($this,'Tree'));
 
}
 
}
 
   
 
   
Line 94: Line 91:
 
# Convert a bullet list into a treeview
 
# Convert a bullet list into a treeview
 
function treeview($text,$argv,&$parser) {
 
function treeview($text,$argv,&$parser) {
global $wgTreeViewImages,$wgTreeViewIconMagic;;
+
global $wgTreeViewImages;
 
   
 
   
 
$id      = $argv['id'];
 
$id      = $argv['id'];
 +
$uid    = $this->uid;
 
$ver    = $this->version;
 
$ver    = $this->version;
 
$width  = $this->width;
 
$width  = $this->width;
Line 116: Line 114:
 
 
 
# Protect the asterisk structure and wiki-parse the bullet tree
 
# Protect the asterisk structure and wiki-parse the bullet tree
 +
$text = preg_replace("/(?<=\\*)\\s*\\[\\[Image:(.+?)\\]\\]/","{$uid}3$1{$uid}4",$text);
 
$text = preg_replace_callback("/^(\\*+)(.*?)$/m",array($this,'protectTree'),$text);
 
$text = preg_replace_callback("/^(\\*+)(.*?)$/m",array($this,'protectTree'),$text);
 
$out  = $parser->parse($text,$parser->mTitle,$parser->mOptions,false,false);
 
$out  = $parser->parse($text,$parser->mTitle,$parser->mOptions,false,false);
Line 121: Line 120:
  
 
# Extract the valid rows and process if any
 
# Extract the valid rows and process if any
if (preg_match_all("/1{$this->uid}([0-9]+)-(\\{\\{#$wgTreeViewIconMagic:(.+?)\}\})?(.+?){$this->uid}2/",$text,$matches,PREG_SET_ORDER)) {
+
if (preg_match_all("/1{$uid}([0-9]+)-({$uid}3(.+?){$uid}4)?(.+?){$uid}2/",$text,$matches,PREG_SET_ORDER)) {
  
 
# Parse 1
 
# Parse 1
Line 132: Line 131:
 
# Parse 2
 
# Parse 2
 
for ($row = count($rows)-1; $row >= 0; $row--) {
 
for ($row = count($rows)-1; $row >= 0; $row--) {
list($depth,$icon,$item) = $rows[$row];
+
list($depth,$i,$item) = $rows[$row];
 
$diff = $depth - $next;
 
$diff = $depth - $next;
 
$show = $depth > $default ? " style='display:none'" : "";
 
$show = $depth > $default ? " style='display:none'" : "";
Line 145: Line 144:
 
if ($depth >= $next) { $open = "<img src='$spacer' width='$width'/>"; $icon = $doc; $ibg = ''; }
 
if ($depth >= $next) { $open = "<img src='$spacer' width='$width'/>"; $icon = $doc; $ibg = ''; }
 
else $open = "<a href='javascript:toggleTreeviewItem(\"$id\",$row)'><img id='tvi$id$row' src='$open'/></a>";
 
else $open = "<a href='javascript:toggleTreeviewItem(\"$id\",$row)'><img id='tvi$id$row' src='$open'/></a>";
 +
 +
# Handle custom image
 +
if ($i) {
 +
$i = Image::newFromTitle(Title::newFromText($i,NS_IMAGE));
 +
if ($i && $i->exists()) $icon = $i->getURL();
 +
}
  
 
# Construct the dotted joining lines and position the open/close link in the last one
 
# Construct the dotted joining lines and position the open/close link in the last one
Line 203: Line 208:
 
var img    = document.getElementById("tvi"+id+row);
 
var img    = document.getElementById("tvi"+id+row);
 
var fld    = document.getElementById("tvf"+id+row);
 
var fld    = document.getElementById("tvf"+id+row);
fld.setAttribute("src",close ? closed : opened);
+
var src    = fld.getAttribute("src");
 +
if (src == opened) fld.setAttribute("src",closed);
 +
if (src == closed) fld.setAttribute("src",opened);
 
fld.setAttribute("style",close ? "" : "background:url('.$vert.') repeat-y");
 
fld.setAttribute("style",close ? "" : "background:url('.$vert.') repeat-y");
 
img.setAttribute("src",close ? plus : minus);
 
img.setAttribute("src",close ? plus : minus);
Line 224: Line 231:
 
# Called from $wgExtensionFunctions array when initialising extensions
 
# Called from $wgExtensionFunctions array when initialising extensions
 
function wfSetupTreeView4() {
 
function wfSetupTreeView4() {
global $wgTreeView4,$wgTreeView4Magic;
+
global $wgTreeView4;
$wgTreeView4 = new TreeView4($wgTreeView4Magic);
+
$wgTreeView4 = new TreeView4();
 
$wgTreeView4->addJS(); # Make code unconditional for now due to parser caching
 
$wgTreeView4->addJS(); # Make code unconditional for now due to parser caching
 
}
 
}
Line 231: Line 238:
 
# Needed in MediaWiki >1.8.0 for magic word hooks to work properly
 
# Needed in MediaWiki >1.8.0 for magic word hooks to work properly
 
function wfTreeView4LanguageGetMagic(&$magicWords,$langCode = 0) {
 
function wfTreeView4LanguageGetMagic(&$magicWords,$langCode = 0) {
global $wgTreeView4Magic;
+
global $wgTreeView4,$wgTreeView4Magic;
 
$magicWords[$wgTreeView4Magic] = array(0,$wgTreeView4Magic);
 
$magicWords[$wgTreeView4Magic] = array(0,$wgTreeView4Magic);
 
return true;
 
return true;
 
}
 
}
 
?>
 
?>

Revision as of 07:07, 10 October 2007

<?php

  1. MediaWiki Treeview ExtensionTemplate:Php
Info.svg These are the MediaWiki extensions we're using and/or developing. Please refer to the information on the mediawiki.org wiki for installation and usage details. Extensions here which have no corresponding mediawiki article are either not ready for use or have been superseded. You can also browse our extension code in our local Subversion repository or our GitHub mirror.
  1. - See http://www.mediawiki.org/wiki/Extension:Tree_view for installation and usage details
  2. - Licenced under LGPL (http://www.gnu.org/copyleft/lesser.html)
  3. - Author: http://www.organicdesign.co.nz/nad
  4. - Started: (Version4) 2007-09-06

if (!defined('MEDIAWIKI')) die('Not an entry point.');

define('TREEVIEW4_VERSION','4.0.8, 2007-10-10');

  1. Set any unset images to default titles

if (!is_array($wgTreeViewImages)) $wgTreeViewImages = array(); if (!isset($wgTreeViewImages['plus'])) $wgTreeViewImages['plus'] = 'Plus.gif'; if (!isset($wgTreeViewImages['minus'])) $wgTreeViewImages['minus'] = 'Minus.gif'; if (!isset($wgTreeViewImages['opened'])) $wgTreeViewImages['opened'] = 'Folder_opn_sml_yel.gif'; if (!isset($wgTreeViewImages['closed'])) $wgTreeViewImages['closed'] = 'Folder_sml_yel.gif'; if (!isset($wgTreeViewImages['doc'])) $wgTreeViewImages['doc'] = 'Doc-icon.gif'; if (!isset($wgTreeViewImages['spacer'])) $wgTreeViewImages['spacer'] = 'Blank.gif';

  1. These images are needed if you have $wgTreeViewShowLines set

if (!isset($wgTreeViewImages['vert'])) $wgTreeViewImages['vert'] = 'Vertline.gif'; if (!isset($wgTreeViewImages['node'])) $wgTreeViewImages['node'] = 'Node.gif'; if (!isset($wgTreeViewImages['last'])) $wgTreeViewImages['last'] = 'Lastnode.gif';

  1. Keep track of JavaScript added to page to avoid doubleups

if (!isset($wgJS)) $wgJS = array();

$wgTreeView4Magic = "tree"; # the parser-function name for trees $wgTreeViewIndent = 0; # the number of pixels each level indents by (0 means doc-icon width) $wgTreeViewShowLines = false; # whether to render the dotted lines joining nodes $wgExtensionFunctions[] = 'wfSetupTreeView4'; $wgHooks['LanguageGetMagic'][] = 'wfTreeView4LanguageGetMagic';

$wgExtensionCredits['parserhook'][] = array( 'name' => 'Treeview4', 'author' => 'User:Nad', 'url' => 'http://www.mediawiki.org/wiki/Extension:Treeview', 'description' => 'Allows dynamic tree-views to be made with bullet-list syntax', 'version' => TREEVIEW4_VERSION );

class TreeView4 {

var $version = TREEVIEW4_VERSION; var $width = 16; var $uniq = array(); var $uid = ; var $js = 0;

# Constructor function TreeView4() { global $wgParser,$wgHooks,$wgTreeView4Magic,$wgTreeViewIconMagic,$wgTreeViewImages,$wgTreeViewIndent;

# Convert image titles to file paths and obtain pixel width of items if ($wgTreeViewIndent) $this->width = $wgTreeViewIndent; foreach ($wgTreeViewImages as $k => $v) { $title = Title::newFromText($v,NS_IMAGE); $image = Image::newFromTitle($title); if ($image && $image->exists()) { $wgTreeViewImages[$k] = $image->getURL(); if ($wgTreeViewIndent < 1 && $k == 'doc') $this->width = $image->getWidth(); } }

$this->uid = uniqid('TVUNIQ'); $wgParser->setFunctionHook($wgTreeView4Magic,array($this,'Tree')); }

# Restructure recursive trees into a single bullet list surrounded by internal treeview4 tags function Tree(&$parser) { global $wgParser; $id = uniqid(); $args = "id='$id'"; foreach (func_get_args() as $arg) if (!is_object($arg)) { if (preg_match('/^(.+?=.+)$/',$arg,$m)) $args .= " $arg"; else $text = $arg; }

# Black magic $text = $this->uniq[$id] = preg_replace( '/^\\*(\\**)\\s*(\\x07UNIQ.+?-treeview4(.+?)-.+?-QINU\\x07?)/me', '$this->uniq["$3"] ? preg_replace("/^(\\*+)/m","$1\$1",$this->uniq["$3"]) : "$1$2"', $text );

# And a little more voodoo here $wgParser->setHook("treeview4$id",array($this,'treeview')); return "<treeview4$id $args>$text</treeview4$id>"; }

# Convert a bullet list into a treeview function treeview($text,$argv,&$parser) { global $wgTreeViewImages;

$id = $argv['id']; $uid = $this->uid; $ver = $this->version; $width = $this->width; $plus = $wgTreeViewImages['plus']; $minus = $wgTreeViewImages['minus']; $opened = $wgTreeViewImages['opened']; $closed = $wgTreeViewImages['closed']; $spacer = $wgTreeViewImages['spacer']; $doc = $wgTreeViewImages['doc']; $vert = $wgTreeViewImages['vert']; $node = $wgTreeViewImages['node']; $last = $wgTreeViewImages['last']; $default = isset($argv['openlevels']) ? $argv['openlevels']+1 : 1; $rows = array(); $lasts = array(); $cols = 0; $next = 0; $tree = ;

# Protect the asterisk structure and wiki-parse the bullet tree $text = preg_replace("/(?<=\\*)\\s*\\[\\[Image:(.+?)\\]\\]/","{$uid}3$1{$uid}4",$text); $text = preg_replace_callback("/^(\\*+)(.*?)$/m",array($this,'protectTree'),$text); $out = $parser->parse($text,$parser->mTitle,$parser->mOptions,false,false); $text = $out->getText();

# Extract the valid rows and process if any if (preg_match_all("/1{$uid}([0-9]+)-({$uid}3(.+?){$uid}4)?(.+?){$uid}2/",$text,$matches,PREG_SET_ORDER)) {

# Parse 1 foreach ($matches as $row) { list(,$depth,,$icon,$item) = $row; if ($depth > $cols) $lasts[$cols = $depth] = true; $rows[] = array($depth,$icon,$item); }

# Parse 2 for ($row = count($rows)-1; $row >= 0; $row--) { list($depth,$i,$item) = $rows[$row]; $diff = $depth - $next; $show = $depth > $default ? " style='display:none'" : ""; $span = $cols+2-$depth; $span = $span == 1 ? "" : " colspan='$span'"; $td = ""; $ibg = "";

# Determine the open/close link and the folder/doc icon if ($depth >= $default) { $open = $plus; $icon = $closed; } else { $open = $minus; $icon = $opened; $ibg = " style='background: url($vert) 0 10px no-repeat'"; } if ($depth >= $next) { $open = "<img src='$spacer' width='$width'/>"; $icon = $doc; $ibg = ; } else $open = "<a href='javascript:toggleTreeviewItem(\"$id\",$row)'><img id='tvi$id$row' src='$open'/></a>";

# Handle custom image if ($i) { $i = Image::newFromTitle(Title::newFromText($i,NS_IMAGE)); if ($i && $i->exists()) $icon = $i->getURL(); }

# Construct the dotted joining lines and position the open/close link in the last one if ($diff > 0) $lasts[$depth] = true; for ($col = $depth+1; $col < $cols; $col++) $lasts[$col] = true; for ($col = 1; $col <= $depth; $col++) { if ($diff > 1 && $col > $next && $col < $depth-1) $lasts[$col] = true; if ($col == $depth) { $fg = $open; $bg = $lasts[$col] ? $last : $node; } else { $fg = ""; $bg = $lasts[$col] ? $spacer : $vert; }

$td .= "$fg";

} $lasts[$depth] = false;

# Add the icon and the item content and append a table row to the tree definition

$td .= "<img id='tvf$id$row' src='$icon'/>"; $td .= "$item"; $tree = "<tr$show depth='$depth' id='tvr$id$row'>$td\n$tree"; $next = $depth; } } # This invisible row at the start fixes a bug making some text items not maximum width $td = ; for ($col = 1; $col <= $cols+1; $col++) $td .= ""; $tree = "$td\n$tree"; return "

\n$tree

";

}

# Protect asterisk bullet structure from wiki parser function protectTree($m) { return "1{$this->uid}".strlen($m[1])."-$m[2]{$this->uid}2\n"; }

# Add the javascript to the output object if not added yet and there is at least one tree function addJS() { global $wgOut,$wgTreeViewImages,$wgJS,$wgJsMimeType; if (isset($wgJS['TreeView4'])) return; $wgJS['TreeView4'] = true; $plus = $wgTreeViewImages['plus']; $minus = $wgTreeViewImages['minus']; $opened = $wgTreeViewImages['opened']; $closed = $wgTreeViewImages['closed']; $spacer = $wgTreeViewImages['spacer']; $doc = $wgTreeViewImages['doc']; $vert = $wgTreeViewImages['vert']; $wgOut->addScript('<script type="'.$wgJsMimeType.'"> function toggleTreeviewItem(id,row) { var plus = "'.$plus.'"; var minus = "'.$minus.'"; var opened = "'.$opened.'"; var closed = "'.$closed.'"; var doc = "'.$doc.'"; var item = document.getElementById("tvr"+id+row); var next = document.getElementById("tvr"+id+(row+1)); var depth = 0+item.getAttribute("depth"); var close = next.style.display != "none"; var img = document.getElementById("tvi"+id+row); var fld = document.getElementById("tvf"+id+row); var src = fld.getAttribute("src"); if (src == opened) fld.setAttribute("src",closed); if (src == closed) fld.setAttribute("src",opened); fld.setAttribute("style",close ? "" : "background:url('.$vert.') repeat-y"); img.setAttribute("src",close ? plus : minus); while ((item = document.getElementById("tvr"+id+(++row))) && (0+item.getAttribute("depth") > depth)) { if (close) item.style.display = "none"; else if (depth == item.getAttribute("depth")-1) { item.style.display = ""; if (img = document.getElementById("tvi"+id+row)) img.setAttribute("src",plus); if (fld = document.getElementById("tvf"+id+row)) if (fld.getAttribute("src") == opened) { fld.setAttribute("src",closed); fld.serAttribute("style",""); } } } }</script>'); } }

  1. Called from $wgExtensionFunctions array when initialising extensions

function wfSetupTreeView4() { global $wgTreeView4; $wgTreeView4 = new TreeView4(); $wgTreeView4->addJS(); # Make code unconditional for now due to parser caching }

  1. Needed in MediaWiki >1.8.0 for magic word hooks to work properly

function wfTreeView4LanguageGetMagic(&$magicWords,$langCode = 0) { global $wgTreeView4,$wgTreeView4Magic; $magicWords[$wgTreeView4Magic] = array(0,$wgTreeView4Magic); return true; } ?>