Difference between revisions of "Sandbox"

From Organic Design wiki
Line 1: Line 1:
*foo
+
<?php
**bar
+
/**
***baz
+
* TreeAndMenu extension - Adds #tree, #menu and #star parser functions which contain bullet-lists to be rendered as collapsible treeview's or dropdown menus
*biz
+
*
 +
* See http://www.mediawiki.org/wiki/Extension:TreeAndMenu for installation and usage details
 +
* See http://www.organicdesign.co.nz/Extension_talk:TreeAndMenu.php for development notes and disucssion
 +
*
 +
* @file
 +
* @ingroup Extensions
 +
* @author Aran Dunkley [http://www.organicdesign.co.nz/nad User:Nad]
 +
* @copyright © 2007 Aran Dunkley
 +
* @licence GNU General Public Licence 2.0 or later
 +
*/
 +
 
 +
if( !defined( 'MEDIAWIKI' ) ) die( 'Not an entry point.' );
 +
 
 +
define( 'TREEANDMENU_VERSION','2.0.1, 2012-01-28' );
 +
 
 +
// Set any unset images to default titles
 +
if( !isset( $wgTreeViewImages ) || !is_array( $wgTreeViewImages ) ) $wgTreeViewImages = array();
 +
 
 +
$wgTreeMagic                  = "tree"; // the parser-function name for trees
 +
$wgMenuMagic                  = "menu"; // the parser-function name for dropdown menus
 +
$wgStarMagic                  = "star"; // the parser-function name for radial star menus
 +
$wgTreeViewShowLines          = false;  // whether to render the dotted lines joining nodes
 +
$wgExtensionFunctions[]        = 'wfSetupTreeAndMenu';
 +
$wgHooks['LanguageGetMagic'][] = 'wfTreeAndMenuLanguageGetMagic';
 +
 
 +
$wgExtensionCredits['parserhook'][] = array(
 +
'path'        => __FILE__,
 +
'name'        => 'TreeAndMenu',
 +
'author'      => array( '[http://www.organicdesign.co.nz/User:Nad Nad]', '[http://www.organicdesign.co.nz/User:Sven Sven]' ),
 +
'url'        => 'http://www.mediawiki.org/wiki/Extension:TreeAndMenu',
 +
'description' => 'Adds #tree, #menu and #star parser functions which contain bullet-lists to be rendered as collapsible treeview\'s or dropdown menus.
 +
                  The treeview\'s use the [http://www.destroydrop.com/javascripts/tree dTree] JavaScript tree menu,
 +
                  and the dropdown menu\'s use [http://www.htmldog.com/articles/suckerfish/dropdowns/ Son of Suckerfish]',
 +
'version'    => TREEANDMENU_VERSION
 +
);
 +
 
 +
class TreeAndMenu {
 +
 
 +
var $version    = TREEANDMENU_VERSION;
 +
var $uniq      = '';      // uniq part of all tree id's
 +
var $uniqname  = 'tam';  // input name for uniqid
 +
var $id        = '';      // id for specific tree
 +
var $baseDir    = '';      // internal absolute path to treeview directory
 +
var $baseUrl    = '';      // external URL to treeview directory (relative to domain)
 +
var $images    = '';      // internal JS to update dTree images
 +
var $useLines  = true;    // internal variable determining whether to render connector lines
 +
var $args      = array(); // args for each tree
 +
 
 +
/**
 +
* Constructor
 +
*/
 +
function __construct() {
 +
global $wgOut, $wgHooks, $wgParser, $wgJsMimeType, $wgExtensionAssetsPath, $wgResourceModules,
 +
$wgTreeMagic, $wgMenuMagic, $wgStarMagic, $wgTreeViewImages, $wgTreeViewShowLines;
 +
 
 +
// Add hooks
 +
$wgParser->setFunctionHook( $wgTreeMagic, array( $this,'expandTree' ) );
 +
$wgParser->setFunctionHook( $wgMenuMagic, array( $this,'expandMenu' ) );
 +
$wgParser->setFunctionHook( $wgStarMagic, array( $this,'expandStar' ) );
 +
$wgHooks['ParserAfterTidy'][] = array( $this, 'renderTreeAndMenu' );
 +
 
 +
// Update general tree paths and properties
 +
$this->baseDir  = dirname( __FILE__ );
 +
$this->baseUrl  = $wgExtensionAssetsPath . '/' . basename( dirname( __FILE__ ) );
 +
$this->useLines = $wgTreeViewShowLines ? 'true' : 'false';
 +
$this->uniq    = uniqid( $this->uniqname );
 +
 
 +
// Convert image titles to file paths and store as JS to update dTree
 +
foreach( $wgTreeViewImages as $k => $v ) {
 +
$image = wfLocalFile( $v );
 +
$v = ( is_object( $image ) && $image->exists() ) ? $image->getURL() : $wgTreeViewImages[$k];
 +
$this->images .= "tree.icon['$k'] = '$v';";
 +
}
 +
}
 +
 
 +
/**
 +
* Expand #tree parser-functions
 +
*/
 +
public function expandTree() {
 +
$args = func_get_args();
 +
return $this->expandTreeAndMenu( 'tree', $args );
 +
}
 +
 
 +
/**
 +
* Expand #menu parser-functions
 +
*/
 +
public function expandMenu() {
 +
$args = func_get_args();
 +
return $this->expandTreeAndMenu( 'menu', $args );
 +
}
 +
 
 +
/**
 +
* Expand #star parser-functions
 +
*/
 +
public function expandStar() {
 +
$args = func_get_args();
 +
return 'not done yet';
 +
}
 +
 
 +
/**
 +
* Expand either kind of parser-function (reformats tree rows for matching later) and store args
 +
*/
 +
private function expandTreeAndMenu( $magic, $args ) {
 +
$parser = array_shift( $args );
 +
 
 +
// Store args for this tree for later use
 +
$text = '';
 +
foreach( $args as $arg ) if ( preg_match( '/^(\\w+?)\\s*=\\s*(.+)$/s', $arg, $m ) ) $args[$m[1]] = $m[2]; else $text = $arg;
 +
 
 +
// If root, parse as wikitext
 +
if( isset( $args['root'] ) ) {
 +
$p = clone $parser;
 +
$o = clone $parser->mOptions;
 +
$o->mTidy = $o->mEnableLimitReport = false;
 +
$html = $p->parse( $args['root'], $parser->mTitle, $o, false, true )->getText();
 +
$args['root'] = addslashes( $html );
 +
}
 +
 
 +
// Create a unique id for this tree or use id supplied in args and store args wrt id
 +
$this->id = isset($args['id']) ? $args['id'] : uniqid( '' );
 +
$args['type'] = $magic;
 +
$this->args[$this->id] = $args;
 +
 
 +
// Reformat tree rows for matching in ParserAfterStrip
 +
$text = preg_replace( '/(?<=\\*)\\s*\\[\\[Image:(.+?)\\]\\]/', "{$this->uniq}3$1{$this->uniq}4", $text );
 +
$text = preg_replace_callback( '/^(\\*+)(.*?)$/m', array( $this, 'formatRow' ), $text );
 +
 
 +
return $text;
 +
}
 +
 
 +
 
 +
/**
 +
* Reformat tree bullet structure recording row, depth and id in a format which is not altered by wiki-parsing
 +
* - format is: 1{uniq}-{id}-{depth}-{item}-2{uniq}
 +
* - sequences of this format will be matched in ParserAfterTidy and converted into dTree JavaScript
 +
* - NOTE: we can't encode a unique row-id because if the same tree instranscluded twice a cached version
 +
*        may be used (even if parser-cache disabled) this also means that tree id's may be repeated
 +
*/
 +
private function formatRow( $m ) {
 +
return "\x7f1{$this->uniq}\x7f{$this->id}\x7f" . ( strlen( $m[1] )-1 ) . "\x7f$m[2]\x7f2{$this->uniq}";
 +
}
 +
 
 +
 
 +
/**
 +
* Called after parser has finished (ParserAfterTidy) so all transcluded parts can be assembled into final trees
 +
*/
 +
public function renderTreeAndMenu( &$parser, &$text ) {
 +
global $wgJsMimeType, $wgOut;
 +
$u = $this->uniq;
 +
 
 +
// Determine which trees are sub trees
 +
// - there should be a more robust way to do this,
 +
//  it's just based on the fact that all sub-tree's have a minus preceding their row data
 +
if( !preg_match_all( "/\x7f\x7f1$u\x7f(.+?)\x7f/", $text, $subs ) ) $subs = array( 1 => array() );
 +
 
 +
// Extract all the formatted tree rows in the page and if any, replace with dTree JavaScript
 +
if( preg_match_all( "/\x7f1$u\x7f(.+?)\x7f([0-9]+)\x7f({$u}3(.+?){$u}4)?(.*?)(?=\x7f[12]$u)/", $text, $matches, PREG_SET_ORDER ) ) {
 +
 
 +
// PASS-1: build $rows array containing depth, and tree start/end information
 +
$rows  = array();
 +
$depths = array( '' => 0 ); // depth of each tree root
 +
$rootId = '';              // the id of the current root-tree (used as tree id in PASS2)
 +
$lastId = '';
 +
$lastDepth = 0;
 +
foreach( $matches as $match ) {
 +
list( , $id, $depth,, $icon, $item ) = $match;
 +
$start = false;
 +
if( $id != $lastId ) {
 +
if( !isset( $depths[$id] ) ) $depths[$id] = $depths[$lastId]+$lastDepth;
 +
if( $start = $rootId != $id && !in_array( $id, $subs[1] ) ) $depths[$rootId = $id] = 0;
 +
}
 +
if( $item ) $rows[] = array( $rootId, $depth + $depths[$id], $icon, addslashes( $item ), $start );
 +
$lastId    = $id;
 +
$lastDepth = $depth;
 +
}
 +
 
 +
// PASS-2: build the JavaScript and replace into $text
 +
$parents  = array(); // parent node for each depth
 +
$parity    = array(); // keep track of odd/even rows for each depth
 +
$node      = 0;
 +
$last      = -1;
 +
$nodes    = '';
 +
$opennodes = array();
 +
foreach( $rows as $i => $info ) {
 +
$node++;
 +
list( $id, $depth, $icon, $item, $start ) = $info;
 +
$objid = $this->uniqname . preg_replace( '/\W/', '', $id );
 +
$args  = $this->args[$id];
 +
$type  = $args['type'];
 +
$end  = $i == count( $rows )-1 || $rows[$i+1][4];
 +
if( !isset( $args['root'] ) ) $args['root'] = ''; // tmp - need to handle rootless trees
 +
$openlevels = isset( $args['openlevels'] ) ? $args['openlevels']+1 : 0;
 +
if( $start ) $node = 1;
 +
 
 +
// Append node script for this row
 +
if( $depth > $last ) $parents[$depth] = $node-1;
 +
$parent = $parents[$depth];
 +
if( $type == 'tree' ) {
 +
$nodes .= "$objid.add($node, $parent, '$item');\n";
 +
if( $depth > 0 && $openlevels > $depth ) $opennodes[$parent] = true;
 +
}
 +
else {
 +
if( !$start ) {
 +
if( $depth < $last ) $nodes .= str_repeat( '</ul></li>', $last - $depth );
 +
elseif( $depth > $last ) $nodes .= "\n<ul>";
 +
}
 +
$parity[$depth] = isset( $parity[$depth] ) ? $parity[$depth]^1 : 0;
 +
$class = $parity[$depth] ? 'odd' : 'even';
 +
$nodes .= "<li class=\"$class\">$item";
 +
if( $depth >= $rows[$node][1] ) $nodes .= "</li>\n";
 +
}
 +
$last = $depth;
 +
 
 +
// Last row of current root, surround nodes dtree or menu script and div etc
 +
if( $end ) {
 +
$class = isset( $args['class'] ) ? $args['class'] : "d$type";
 +
if( $type == 'tree' ) {
 +
 
 +
static $dtree = false;
 +
if( !$dtree ) {
 +
$wgOut->addScriptFile( $this->baseUrl . '/dtree.js' );
 +
$dtree = true;
 +
}
 +
 
 +
// Finalise a tree
 +
$add = isset( $args['root'] ) ? "tree.add(0,-1,'".$args['root']."');" : '';
 +
$top = $bottom = $root = $opennodesjs = '';
 +
foreach( array_keys( $opennodes ) as $i ) $opennodesjs .= "$objid.o($i);";
 +
foreach( $args as $arg => $pos )
 +
if( ( $pos == 'top' || $pos == 'bottom' || $pos == 'root' ) && ( $arg == 'open' || $arg == 'close' ) )
 +
$$pos .= "<a href=\"javascript: $objid.{$arg}All();\">&#160;{$arg} all</a>&#160;";
 +
if( $top ) $top = "<p>&#160;$top</p>";
 +
if( $bottom ) $bottom = "<p>&#160;$bottom</p>";
 +
 
 +
// Define the script to build this tree
 +
$script = "// TreeAndMenu-{$this->version}\ntree = new dTree('$objid');
 +
for (i in tree.icon) tree.icon[i] = '{$this->baseUrl}/'+tree.icon[i];{$this->images}
 +
tree.config.useLines = {$this->useLines};
 +
$add
 +
$objid = tree;
 +
$nodes
 +
document.getElementById('$id').innerHTML = $objid.toString();
 +
$opennodesjs
 +
for(i in window.tamOnload_$objid) { window.tamOnload_{$objid}[i](); }";
 +
$wgOut->addScript( "<script type=\"$wgJsMimeType\">$(function(){\n$script\n});</script>" );
 +
$html = "$top<div class='$class' id='$id'></div>$bottom";
 +
$html .= "<script type=\"$wgJsMimeType\">window.tamOnload_$objid=[]</script>";
 +
 
 +
} else {
 +
 
 +
// Finalise a menu
 +
if( $depth > 0 ) $nodes .= str_repeat( '</ul></li>', $depth );
 +
$nodes = preg_replace( "/<(a.*? )title=\".+?\".*?>/", "<$1>", $nodes ); // IE has problems with title attribute in suckerfish menus
 +
$html = "<ul class='$class' id='$id'>\n$nodes</ul><div style=\"clear:both\"></div>";
 +
$script = "if (window.attachEvent) {
 +
var sfEls = document.getElementById('$id').getElementsByTagName('li');
 +
for (var i=0; i<sfEls.length; i++) {
 +
sfEls[i].onmouseover=function() { this.className+=' sfhover'; }
 +
sfEls[i].onmouseout=function()  { this.className=this.className.replace(new RegExp(' sfhover *'),''); }
 +
}
 +
}";
 +
$wgOut->addScript( "<script type=\"$wgJsMimeType\">$(function(){\n$script\n});</script>" );
 +
}
 +
 
 +
$text  = preg_replace( "/\x7f1$u\x7f$id\x7f.+?$/m", $html, $text, 1 ); // replace first occurence of this trees root-id
 +
$nodes = '';
 +
$last  = -1;
 +
}
 +
}
 +
}
 +
$text = preg_replace( "/\x7f1$u\x7f.+?[\\r\\n]+/m", '', $text ); // Remove all unreplaced row information
 +
return true;
 +
}
 +
 
 +
}
 +
 
 +
/**
 +
* Called from $wgExtensionFunctions array when initialising extensions
 +
*/
 +
function wfSetupTreeAndMenu() {
 +
global $wgTreeAndMenu;
 +
$wgTreeAndMenu = new TreeAndMenu();
 +
}
 +
 
 +
/**
 +
* Reserve magic words
 +
*/
 +
function wfTreeAndMenuLanguageGetMagic( &$magicWords, $langCode = 0 ) {
 +
global $wgTreeMagic, $wgMenuMagic, $wgStarMagic;
 +
$magicWords[$wgTreeMagic] = array( 0, $wgTreeMagic );
 +
$magicWords[$wgMenuMagic] = array( 0, $wgMenuMagic );
 +
$magicWords[$wgStarMagic] = array( 0, $wgStarMagic );
 +
return true;
 +
}

Revision as of 00:10, 29 January 2012

<?php /**

* TreeAndMenu extension - Adds #tree, #menu and #star parser functions which contain bullet-lists to be rendered as collapsible treeview's or dropdown menus
*
* See http://www.mediawiki.org/wiki/Extension:TreeAndMenu for installation and usage details
* See http://www.organicdesign.co.nz/Extension_talk:TreeAndMenu.php for development notes and disucssion
* 
* @file
* @ingroup Extensions
* @author Aran Dunkley User:Nad
* @copyright © 2007 Aran Dunkley
* @licence GNU General Public Licence 2.0 or later
*/

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

define( 'TREEANDMENU_VERSION','2.0.1, 2012-01-28' );

// Set any unset images to default titles if( !isset( $wgTreeViewImages ) || !is_array( $wgTreeViewImages ) ) $wgTreeViewImages = array();

$wgTreeMagic = "tree"; // the parser-function name for trees $wgMenuMagic = "menu"; // the parser-function name for dropdown menus $wgStarMagic = "star"; // the parser-function name for radial star menus $wgTreeViewShowLines = false; // whether to render the dotted lines joining nodes $wgExtensionFunctions[] = 'wfSetupTreeAndMenu'; $wgHooks['LanguageGetMagic'][] = 'wfTreeAndMenuLanguageGetMagic';

$wgExtensionCredits['parserhook'][] = array( 'path' => __FILE__, 'name' => 'TreeAndMenu', 'author' => array( 'Nad', 'Sven' ), 'url' => 'http://www.mediawiki.org/wiki/Extension:TreeAndMenu', 'description' => 'Adds #tree, #menu and #star parser functions which contain bullet-lists to be rendered as collapsible treeview\'s or dropdown menus. The treeview\'s use the dTree JavaScript tree menu, and the dropdown menu\'s use Son of Suckerfish', 'version' => TREEANDMENU_VERSION );

class TreeAndMenu {

var $version = TREEANDMENU_VERSION; var $uniq = ; // uniq part of all tree id's var $uniqname = 'tam'; // input name for uniqid var $id = ; // id for specific tree var $baseDir = ; // internal absolute path to treeview directory var $baseUrl = ; // external URL to treeview directory (relative to domain) var $images = ; // internal JS to update dTree images var $useLines = true; // internal variable determining whether to render connector lines var $args = array(); // args for each tree

/** * Constructor */ function __construct() { global $wgOut, $wgHooks, $wgParser, $wgJsMimeType, $wgExtensionAssetsPath, $wgResourceModules, $wgTreeMagic, $wgMenuMagic, $wgStarMagic, $wgTreeViewImages, $wgTreeViewShowLines;

// Add hooks $wgParser->setFunctionHook( $wgTreeMagic, array( $this,'expandTree' ) ); $wgParser->setFunctionHook( $wgMenuMagic, array( $this,'expandMenu' ) ); $wgParser->setFunctionHook( $wgStarMagic, array( $this,'expandStar' ) ); $wgHooks['ParserAfterTidy'][] = array( $this, 'renderTreeAndMenu' );

// Update general tree paths and properties $this->baseDir = dirname( __FILE__ ); $this->baseUrl = $wgExtensionAssetsPath . '/' . basename( dirname( __FILE__ ) ); $this->useLines = $wgTreeViewShowLines ? 'true' : 'false'; $this->uniq = uniqid( $this->uniqname );

// Convert image titles to file paths and store as JS to update dTree foreach( $wgTreeViewImages as $k => $v ) { $image = wfLocalFile( $v ); $v = ( is_object( $image ) && $image->exists() ) ? $image->getURL() : $wgTreeViewImages[$k]; $this->images .= "tree.icon['$k'] = '$v';"; } }

/** * Expand #tree parser-functions */ public function expandTree() { $args = func_get_args(); return $this->expandTreeAndMenu( 'tree', $args ); }

/** * Expand #menu parser-functions */ public function expandMenu() { $args = func_get_args(); return $this->expandTreeAndMenu( 'menu', $args ); }

/** * Expand #star parser-functions */ public function expandStar() { $args = func_get_args(); return 'not done yet'; }

/** * Expand either kind of parser-function (reformats tree rows for matching later) and store args */ private function expandTreeAndMenu( $magic, $args ) { $parser = array_shift( $args );

// Store args for this tree for later use $text = ; foreach( $args as $arg ) if ( preg_match( '/^(\\w+?)\\s*=\\s*(.+)$/s', $arg, $m ) ) $args[$m[1]] = $m[2]; else $text = $arg;

// If root, parse as wikitext if( isset( $args['root'] ) ) { $p = clone $parser; $o = clone $parser->mOptions; $o->mTidy = $o->mEnableLimitReport = false; $html = $p->parse( $args['root'], $parser->mTitle, $o, false, true )->getText(); $args['root'] = addslashes( $html ); }

// Create a unique id for this tree or use id supplied in args and store args wrt id $this->id = isset($args['id']) ? $args['id'] : uniqid( ); $args['type'] = $magic; $this->args[$this->id] = $args;

// Reformat tree rows for matching in ParserAfterStrip $text = preg_replace( '/(?<=\\*)\\s*\\[\\[Image:(.+?)\\]\\]/', "{$this->uniq}3$1{$this->uniq}4", $text ); $text = preg_replace_callback( '/^(\\*+)(.*?)$/m', array( $this, 'formatRow' ), $text );

return $text; }


/** * Reformat tree bullet structure recording row, depth and id in a format which is not altered by wiki-parsing * - format is: 1{uniq}-{id}-{depth}-{item}-2{uniq} * - sequences of this format will be matched in ParserAfterTidy and converted into dTree JavaScript * - NOTE: we can't encode a unique row-id because if the same tree instranscluded twice a cached version * may be used (even if parser-cache disabled) this also means that tree id's may be repeated */ private function formatRow( $m ) { return "\x7f1{$this->uniq}\x7f{$this->id}\x7f" . ( strlen( $m[1] )-1 ) . "\x7f$m[2]\x7f2{$this->uniq}"; }


/** * Called after parser has finished (ParserAfterTidy) so all transcluded parts can be assembled into final trees */ public function renderTreeAndMenu( &$parser, &$text ) { global $wgJsMimeType, $wgOut; $u = $this->uniq;

// Determine which trees are sub trees // - there should be a more robust way to do this, // it's just based on the fact that all sub-tree's have a minus preceding their row data if( !preg_match_all( "/\x7f\x7f1$u\x7f(.+?)\x7f/", $text, $subs ) ) $subs = array( 1 => array() );

// Extract all the formatted tree rows in the page and if any, replace with dTree JavaScript if( preg_match_all( "/\x7f1$u\x7f(.+?)\x7f([0-9]+)\x7f({$u}3(.+?){$u}4)?(.*?)(?=\x7f[12]$u)/", $text, $matches, PREG_SET_ORDER ) ) {

// PASS-1: build $rows array containing depth, and tree start/end information $rows = array(); $depths = array( => 0 ); // depth of each tree root $rootId = ; // the id of the current root-tree (used as tree id in PASS2) $lastId = ; $lastDepth = 0; foreach( $matches as $match ) { list( , $id, $depth,, $icon, $item ) = $match; $start = false; if( $id != $lastId ) { if( !isset( $depths[$id] ) ) $depths[$id] = $depths[$lastId]+$lastDepth; if( $start = $rootId != $id && !in_array( $id, $subs[1] ) ) $depths[$rootId = $id] = 0; } if( $item ) $rows[] = array( $rootId, $depth + $depths[$id], $icon, addslashes( $item ), $start ); $lastId = $id; $lastDepth = $depth; }

// PASS-2: build the JavaScript and replace into $text $parents = array(); // parent node for each depth $parity = array(); // keep track of odd/even rows for each depth $node = 0; $last = -1; $nodes = ; $opennodes = array(); foreach( $rows as $i => $info ) { $node++; list( $id, $depth, $icon, $item, $start ) = $info; $objid = $this->uniqname . preg_replace( '/\W/', , $id ); $args = $this->args[$id]; $type = $args['type']; $end = $i == count( $rows )-1 || $rows[$i+1][4]; if( !isset( $args['root'] ) ) $args['root'] = ; // tmp - need to handle rootless trees $openlevels = isset( $args['openlevels'] ) ? $args['openlevels']+1 : 0; if( $start ) $node = 1;

// Append node script for this row if( $depth > $last ) $parents[$depth] = $node-1; $parent = $parents[$depth]; if( $type == 'tree' ) { $nodes .= "$objid.add($node, $parent, '$item');\n"; if( $depth > 0 && $openlevels > $depth ) $opennodes[$parent] = true; } else { if( !$start ) {

if( $depth < $last ) $nodes .= str_repeat( '', $last - $depth ); elseif( $depth > $last ) $nodes .= "\n

    "; } $parity[$depth] = isset( $parity[$depth] ) ? $parity[$depth]^1 : 0; $class = $parity[$depth] ? 'odd' : 'even'; $nodes .= "
  • $item"; if( $depth >= $rows[$node][1] ) $nodes .= "
  • \n";

    } $last = $depth;

    // Last row of current root, surround nodes dtree or menu script and div etc if( $end ) { $class = isset( $args['class'] ) ? $args['class'] : "d$type"; if( $type == 'tree' ) {

    static $dtree = false; if( !$dtree ) { $wgOut->addScriptFile( $this->baseUrl . '/dtree.js' ); $dtree = true; }

    // Finalise a tree $add = isset( $args['root'] ) ? "tree.add(0,-1,'".$args['root']."');" : ; $top = $bottom = $root = $opennodesjs = ; foreach( array_keys( $opennodes ) as $i ) $opennodesjs .= "$objid.o($i);"; foreach( $args as $arg => $pos ) if( ( $pos == 'top' || $pos == 'bottom' || $pos == 'root' ) && ( $arg == 'open' || $arg == 'close' ) ) $$pos .= "<a href=\"javascript: $objid.{$arg}All();\"> {$arg} all</a> ";

    if( $top ) $top = "

     $top

    "; if( $bottom ) $bottom = "

     $bottom

    ";

    // Define the script to build this tree $script = "// TreeAndMenu-{$this->version}\ntree = new dTree('$objid'); for (i in tree.icon) tree.icon[i] = '{$this->baseUrl}/'+tree.icon[i];{$this->images} tree.config.useLines = {$this->useLines}; $add $objid = tree; $nodes document.getElementById('$id').innerHTML = $objid.toString(); $opennodesjs for(i in window.tamOnload_$objid) { window.tamOnload_{$objid}[i](); }"; $wgOut->addScript( "<script type=\"$wgJsMimeType\">$(function(){\n$script\n});</script>" );

    $html = "$top
    $bottom";

    $html .= "<script type=\"$wgJsMimeType\">window.tamOnload_$objid=[]</script>";

    } else {

    // Finalise a menu

    if( $depth > 0 ) $nodes .= str_repeat( '

', $depth );

$nodes = preg_replace( "/<(a.*? )title=\".+?\".*?>/", "<$1>", $nodes ); // IE has problems with title attribute in suckerfish menus

$html = "

    \n$nodes

";

$script = "if (window.attachEvent) { var sfEls = document.getElementById('$id').getElementsByTagName('li'); for (var i=0; i<sfEls.length; i++) { sfEls[i].onmouseover=function() { this.className+=' sfhover'; } sfEls[i].onmouseout=function() { this.className=this.className.replace(new RegExp(' sfhover *'),); } } }"; $wgOut->addScript( "<script type=\"$wgJsMimeType\">$(function(){\n$script\n});</script>" ); }

$text = preg_replace( "/\x7f1$u\x7f$id\x7f.+?$/m", $html, $text, 1 ); // replace first occurence of this trees root-id $nodes = ; $last = -1; } } } $text = preg_replace( "/\x7f1$u\x7f.+?[\\r\\n]+/m", , $text ); // Remove all unreplaced row information return true; }

}

/**

* Called from $wgExtensionFunctions array when initialising extensions
*/

function wfSetupTreeAndMenu() { global $wgTreeAndMenu; $wgTreeAndMenu = new TreeAndMenu(); }

/**

* Reserve magic words
*/

function wfTreeAndMenuLanguageGetMagic( &$magicWords, $langCode = 0 ) { global $wgTreeMagic, $wgMenuMagic, $wgStarMagic; $magicWords[$wgTreeMagic] = array( 0, $wgTreeMagic ); $magicWords[$wgMenuMagic] = array( 0, $wgMenuMagic ); $magicWords[$wgStarMagic] = array( 0, $wgStarMagic ); return true; }