r34642 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r34641‎ | r34642 | r34643 >
Date:05:05, 12 May 2008
Author:nad
Status:old
Tags:
Comment:
Modified paths:
  • /trunk/extensions/TreeAndMenu (added) (history)
  • /trunk/extensions/TreeAndMenu/TreeAndMenu.php (added) (history)
  • /trunk/extensions/TreeAndMenu/dtree.js (added) (history)
  • /trunk/extensions/TreeAndMenu/img (added) (history)
  • /trunk/extensions/TreeAndMenu/img/base.gif (added) (history)
  • /trunk/extensions/TreeAndMenu/img/cd.gif (added) (history)
  • /trunk/extensions/TreeAndMenu/img/empty.gif (added) (history)
  • /trunk/extensions/TreeAndMenu/img/folder.gif (added) (history)
  • /trunk/extensions/TreeAndMenu/img/folderopen.gif (added) (history)
  • /trunk/extensions/TreeAndMenu/img/globe.gif (added) (history)
  • /trunk/extensions/TreeAndMenu/img/imgfolder.gif (added) (history)
  • /trunk/extensions/TreeAndMenu/img/join.gif (added) (history)
  • /trunk/extensions/TreeAndMenu/img/joinbottom.gif (added) (history)
  • /trunk/extensions/TreeAndMenu/img/line.gif (added) (history)
  • /trunk/extensions/TreeAndMenu/img/minus.gif (added) (history)
  • /trunk/extensions/TreeAndMenu/img/minusbottom.gif (added) (history)
  • /trunk/extensions/TreeAndMenu/img/musicfolder.gif (added) (history)
  • /trunk/extensions/TreeAndMenu/img/nolines_minus.gif (added) (history)
  • /trunk/extensions/TreeAndMenu/img/nolines_plus.gif (added) (history)
  • /trunk/extensions/TreeAndMenu/img/page.gif (added) (history)
  • /trunk/extensions/TreeAndMenu/img/plus.gif (added) (history)
  • /trunk/extensions/TreeAndMenu/img/plusbottom.gif (added) (history)
  • /trunk/extensions/TreeAndMenu/img/question.gif (added) (history)
  • /trunk/extensions/TreeAndMenu/img/trash.gif (added) (history)

Diff [purge]

Index: trunk/extensions/TreeAndMenu/img/folder.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/TreeAndMenu/img/folder.gif
___________________________________________________________________
Added: svn:mime-type
11 + application/octet-stream
Added: svn:executable
22 + *
Index: trunk/extensions/TreeAndMenu/img/musicfolder.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/TreeAndMenu/img/musicfolder.gif
___________________________________________________________________
Added: svn:mime-type
33 + application/octet-stream
Added: svn:executable
44 + *
Index: trunk/extensions/TreeAndMenu/img/page.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/TreeAndMenu/img/page.gif
___________________________________________________________________
Added: svn:mime-type
55 + application/octet-stream
Added: svn:executable
66 + *
Index: trunk/extensions/TreeAndMenu/img/minusbottom.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/TreeAndMenu/img/minusbottom.gif
___________________________________________________________________
Added: svn:mime-type
77 + application/octet-stream
Added: svn:executable
88 + *
Index: trunk/extensions/TreeAndMenu/img/trash.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/TreeAndMenu/img/trash.gif
___________________________________________________________________
Added: svn:mime-type
99 + application/octet-stream
Added: svn:executable
1010 + *
Index: trunk/extensions/TreeAndMenu/img/nolines_minus.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/TreeAndMenu/img/nolines_minus.gif
___________________________________________________________________
Added: svn:mime-type
1111 + application/octet-stream
Added: svn:executable
1212 + *
Index: trunk/extensions/TreeAndMenu/img/plus.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/TreeAndMenu/img/plus.gif
___________________________________________________________________
Added: svn:mime-type
1313 + application/octet-stream
Added: svn:executable
1414 + *
Index: trunk/extensions/TreeAndMenu/img/joinbottom.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/TreeAndMenu/img/joinbottom.gif
___________________________________________________________________
Added: svn:mime-type
1515 + application/octet-stream
Added: svn:executable
1616 + *
Index: trunk/extensions/TreeAndMenu/img/cd.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/TreeAndMenu/img/cd.gif
___________________________________________________________________
Added: svn:mime-type
1717 + application/octet-stream
Added: svn:executable
1818 + *
Index: trunk/extensions/TreeAndMenu/img/line.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/TreeAndMenu/img/line.gif
___________________________________________________________________
Added: svn:mime-type
1919 + application/octet-stream
Added: svn:executable
2020 + *
Index: trunk/extensions/TreeAndMenu/img/globe.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/TreeAndMenu/img/globe.gif
___________________________________________________________________
Added: svn:mime-type
2121 + application/octet-stream
Added: svn:executable
2222 + *
Index: trunk/extensions/TreeAndMenu/img/minus.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/TreeAndMenu/img/minus.gif
___________________________________________________________________
Added: svn:mime-type
2323 + application/octet-stream
Added: svn:executable
2424 + *
Index: trunk/extensions/TreeAndMenu/img/folderopen.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/TreeAndMenu/img/folderopen.gif
___________________________________________________________________
Added: svn:mime-type
2525 + application/octet-stream
Added: svn:executable
2626 + *
Index: trunk/extensions/TreeAndMenu/img/empty.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/TreeAndMenu/img/empty.gif
___________________________________________________________________
Added: svn:mime-type
2727 + application/octet-stream
Added: svn:executable
2828 + *
Index: trunk/extensions/TreeAndMenu/img/join.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/TreeAndMenu/img/join.gif
___________________________________________________________________
Added: svn:mime-type
2929 + application/octet-stream
Added: svn:executable
3030 + *
Index: trunk/extensions/TreeAndMenu/img/question.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/TreeAndMenu/img/question.gif
___________________________________________________________________
Added: svn:mime-type
3131 + application/octet-stream
Added: svn:executable
3232 + *
Index: trunk/extensions/TreeAndMenu/img/imgfolder.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/TreeAndMenu/img/imgfolder.gif
___________________________________________________________________
Added: svn:mime-type
3333 + application/octet-stream
Added: svn:executable
3434 + *
Index: trunk/extensions/TreeAndMenu/img/plusbottom.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/TreeAndMenu/img/plusbottom.gif
___________________________________________________________________
Added: svn:mime-type
3535 + application/octet-stream
Added: svn:executable
3636 + *
Index: trunk/extensions/TreeAndMenu/img/nolines_plus.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/TreeAndMenu/img/nolines_plus.gif
___________________________________________________________________
Added: svn:mime-type
3737 + application/octet-stream
Added: svn:executable
3838 + *
Index: trunk/extensions/TreeAndMenu/img/base.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/TreeAndMenu/img/base.gif
___________________________________________________________________
Added: svn:mime-type
3939 + application/octet-stream
Added: svn:executable
4040 + *
Index: trunk/extensions/TreeAndMenu/TreeAndMenu.php
@@ -0,0 +1,267 @@
 2+<?php
 3+/**
 4+* MediaWiki TreeAndMenu Extension
 5+* - See http://www.mediawiki.org/wiki/Extension:TreeAndMenu for installation and usage details
 6+* - Sww http://www.organicdesign.co.nz/Extension_talk:TreeAndMenu.php for development notes and disucssion
 7+* - Licenced under LGPL (http://www.gnu.org/copyleft/lesser.html)
 8+* - Author: http://www.organicdesign.co.nz/nad
 9+* - Started: 2008-04-17 (This code is Extension:Treeview5.php with Son of Suckerfish dropdown menus added)
 10+*/
 11+
 12+if (!defined('MEDIAWIKI')) die('Not an entry point.');
 13+
 14+define('TREEANDMENU_VERSION','1.0.0, 2008-04-17');
 15+
 16+# Set any unset images to default titles
 17+if (!isset($wgTreeViewImages) || !is_array($wgTreeViewImages)) $wgTreeViewImages = array();
 18+
 19+$wgTreeMagic = "tree"; # the parser-function name for trees
 20+$wgMenuMagic = "menu"; # the parser-function name for dropdown menus
 21+$wgTreeViewShowLines = false; # whether to render the dotted lines joining nodes
 22+$wgExtensionFunctions[] = 'wfSetupTreeAndMenu';
 23+$wgHooks['LanguageGetMagic'][] = 'wfTreeAndMenuLanguageGetMagic';
 24+
 25+$wgExtensionCredits['parserhook'][] = array(
 26+ 'name' => 'TreeAndMenu',
 27+ 'author' => '[http://www.organicdesign.co.nz/nad Nad], [http://www.organicdesign.co.nz/User:Sven Sven]',
 28+ 'url' => 'http://www.mediawiki.org/wiki/Extension:Treeview',
 29+ 'description' => 'Adds #tree and #menu parser functions which contain bullet-lists to be rendered as collapsible treeview\'s or dropdown menus.
 30+ The treeview\'s use the [http://www.destroydrop.com/javascripts/tree dTree] JavaScript tree menu,
 31+ and the dropdown menu\'s use [http://www.htmldog.com/articles/suckerfish/dropdowns/ Son of Suckerfish]',
 32+ 'version' => TREEANDMENU_VERSION
 33+ );
 34+
 35+class TreeAndMenu {
 36+
 37+ var $version = TREEANDMENU_VERSION;
 38+ var $uniq = ''; # uniq part of all tree id's
 39+ var $uniqname = 'tam'; # input name for uniqid
 40+ var $id = ''; # id for specific tree
 41+ var $baseDir = ''; # internal absolute path to treeview directory
 42+ var $baseUrl = ''; # external URL to treeview directory (relative to domain)
 43+ var $images = ''; # internal JS to update dTree images
 44+ var $useLines = true; # internal variable determining whether to render connector lines
 45+ var $args = array(); # args for each tree
 46+
 47+
 48+ /**
 49+ * Constructor
 50+ */
 51+ function __construct() {
 52+ global $wgOut,$wgHooks,$wgParser,$wgScriptPath,$wgJsMimeType,
 53+ $wgTreeMagic,$wgMenuMagic,$wgTreeViewImages,$wgTreeViewShowLines;
 54+
 55+ # Add hooks
 56+ $wgParser->setFunctionHook($wgTreeMagic,array($this,'expandTree'));
 57+ $wgParser->setFunctionHook($wgMenuMagic,array($this,'expandMenu'));
 58+ $wgHooks['ParserAfterTidy'][] = array($this,'renderTreeAndMenu');
 59+
 60+ # Update general tree paths and properties
 61+ $this->baseDir = dirname(__FILE__);
 62+ $this->baseUrl = preg_replace('|^.+(?=[/\\\\]extensions)|',$wgScriptPath,$this->baseDir);
 63+ $this->useLines = $wgTreeViewShowLines ? 'true' : 'false';
 64+ $this->uniq = uniqid($this->uniqname);
 65+
 66+ # Convert image titles to file paths and store as JS to update dTree
 67+ foreach ($wgTreeViewImages as $k => $v) {
 68+ $title = Title::newFromText($v,NS_IMAGE);
 69+ $image = Image::newFromTitle($title);
 70+ $v = $image && $image->exists() ? $image->getURL() : $wgTreeViewImages[$k];
 71+ $this->images .= "tree.icon['$k'] = '$v';";
 72+ }
 73+
 74+ # Add link to output to load dtree.js script
 75+ $wgOut->addScript("<script type=\"$wgJsMimeType\" src=\"{$this->baseUrl}/dtree.js\"><!-- TreeAndMenu --></script>\n");
 76+ }
 77+
 78+
 79+ /**
 80+ * Expand #tree parser-functions
 81+ */
 82+ public function expandTree() {
 83+ $args = func_get_args();
 84+ return $this->expandTreeAndMenu('tree',$args);
 85+ }
 86+
 87+ /**
 88+ * Expand #menu parser-functions
 89+ */
 90+ public function expandMenu() {
 91+ $args = func_get_args();
 92+ return $this->expandTreeAndMenu('menu',$args);
 93+ }
 94+
 95+ /**
 96+ * Expand either kind of parser-function (reformats tree rows for matching later) and store args
 97+ */
 98+ private function expandTreeAndMenu($magic,$args) {
 99+ $parser = array_shift($args);
 100+
 101+ # Store args for this tree for later use
 102+ foreach ($args as $arg) if (preg_match('/^(\\w+?)\\s*=\\s*(.+)$/s',$arg,$m)) $args[$m[1]] = $m[2]; else $text = $arg;
 103+
 104+ # Create a unique id for this tree or use id supplied in args and store args wrt id
 105+ $this->id = isset($args['id']) ? $args['id'] : uniqid('');
 106+ $args['type'] = $magic;
 107+ $this->args[$this->id] = $args;
 108+
 109+ # Reformat tree rows for matching in ParserAfterStrip
 110+ $text = preg_replace('/(?<=\\*)\\s*\\[\\[Image:(.+?)\\]\\]/',"{$this->uniq}3$1{$this->uniq}4",$text);
 111+ $text = preg_replace_callback('/^(\\*+)(.*?)$/m',array($this,'formatRow'),$text);
 112+
 113+ return $text;
 114+ }
 115+
 116+
 117+ /**
 118+ * Reformat tree bullet structure recording row, depth and id in a format which is not altered by wiki-parsing
 119+ * - format is: 1{uniq}-{id}-{depth}-{item}-2{uniq}
 120+ * - sequences of this format will be matched in ParserAfterTidy and converted into dTree JavaScript
 121+ * - NOTE: we can't encode a unique row-id because if the same tree instranscluded twice a cached version
 122+ * may be used (even if parser-cache disabled) this also means that tree id's may be repeated
 123+ */
 124+ private function formatRow($m) {
 125+ return "\x7f1{$this->uniq}\x7f{$this->id}\x7f".(strlen($m[1])-1)."\x7f$m[2]\x7f2{$this->uniq}";
 126+ }
 127+
 128+
 129+ /**
 130+ * Called after parser has finished (ParserAfterTidy) so all transcluded parts can be assembled into final trees
 131+ */
 132+ public function renderTreeAndMenu(&$parser,&$text) {
 133+ global $wgJsMimeType;
 134+ $u = $this->uniq;
 135+
 136+ # Determine which trees are sub trees
 137+ # - there should be a more robust way to do this,
 138+ # it's just based on the fact that all sub-tree's have a minus preceding their row data
 139+ if (!preg_match_all("/\x7f\x7f1$u\x7f(.+?)\x7f/",$text,$subs)) $subs = array(1 => array());
 140+
 141+ # Extract all the formatted tree rows in the page and if any, replace with dTree JavaScript
 142+ if (preg_match_all("/\x7f1$u\x7f(.+?)\x7f([0-9]+)\x7f({$u}3(.+?){$u}4)?(.*?)(?=\x7f[12]$u)/",$text,$matches,PREG_SET_ORDER)) {
 143+
 144+ # PASS-1: build $rows array containing depth, and tree start/end information
 145+ $rows = array();
 146+ $depths = array('' => 0); # depth of each tree root
 147+ $rootId = ''; # the id of the current root-tree (used as tree id in PASS2)
 148+ $lastId = '';
 149+ $lastDepth = 0;
 150+ foreach ($matches as $match) {
 151+ list(,$id,$depth,,$icon,$item) = $match;
 152+ $start = false;
 153+ if ($id != $lastId) {
 154+ if (!isset($depths[$id])) $depths[$id] = $depths[$lastId]+$lastDepth;
 155+ if ($start = $rootId != $id && !in_array($id,$subs[1])) $depths[$rootId = $id] = 0;
 156+ }
 157+ if ($item) $rows[] = array($rootId,$depth+$depths[$id],$icon,$item,$start);
 158+ $lastId = $id;
 159+ $lastDepth = $depth;
 160+ }
 161+
 162+ # PASS-2: build the JavaScript and replace into $text
 163+ $parents = array(); # parent node for each depth
 164+ $parity = array(); # keep track of odd/even rows for each depth
 165+ $last = -1;
 166+ $nodes = '';
 167+ foreach ($rows as $node => $info) {
 168+ $node++;
 169+ list($id,$depth,$icon,$item,$start) = $info;
 170+ $args = $this->args[$id];
 171+ $type = $args['type'];
 172+ if (!isset($args['root'])) $args['root'] = ''; # tmp - need to handle rootless trees
 173+ $end = $node == count($rows) || $rows[$node][4];
 174+
 175+ # Append node script for this row
 176+ if ($depth > $last) $parents[$depth] = $node-1;
 177+ $parent = $parents[$depth];
 178+ if ($type == 'tree') $nodes .= "{$this->uniqname}$id.add($node,$parent,'".addslashes($item)."');\n";
 179+ else {
 180+ if (!$start) {
 181+ if ($depth < $last) $nodes .= str_repeat('</ul></li>',$last-$depth);
 182+ elseif ($depth > $last) $nodes .= "\n<ul>";
 183+ }
 184+ $parity[$depth] = isset($parity[$depth]) ? $parity[$depth]^1 : 0;
 185+ $class = $parity[$depth] ? 'odd' : 'even';
 186+ $nodes .= "<li class=\"$class\">$item";
 187+ if ($depth >= $rows[$node][1]) $nodes .= "</li>\n";
 188+ }
 189+ $last = $depth;
 190+
 191+ # Last row of current root, surround nodes dtree or menu script and div etc
 192+ if ($end) {
 193+ $class = isset($args['class']) ? $args['class'] : "d$type";
 194+ if ($type == 'tree') {
 195+
 196+ # Finalise a tree
 197+ $add = isset($args['root']) ? "tree.add(0,-1,'".$args['root']."');" : '';
 198+ $top = $bottom = $root = '';
 199+ foreach ($args as $arg => $pos)
 200+ if (($pos == 'top' || $pos == 'bottom' || $pos == 'root') && ($arg == 'open' || $arg == 'close'))
 201+ $$pos .= "<a href=\"javascript: {$this->uniqname}$id.{$arg}All();\">&nbsp;{$arg} all</a>&nbsp;";
 202+ if ($top) $top = "<p>&nbsp;$top</p>";
 203+ if ($bottom) $bottom = "<p>&nbsp;$bottom</p>";
 204+ if ($root) $add = "tree.add(0,-1,'$root');";
 205+ $html = "$top<div class='$class' id='$id'>
 206+ <script type=\"$wgJsMimeType\">
 207+ // TreeAndMenu{$this->version}
 208+ tree = new dTree('{$this->uniqname}$id');
 209+ for (i in tree.icon) tree.icon[i] = '{$this->baseUrl}/'+tree.icon[i];{$this->images}
 210+ tree.config.useLines = {$this->useLines};
 211+ $add
 212+ {$this->uniqname}$id = tree;
 213+ $nodes
 214+ document.getElementById('$id').innerHTML = {$this->uniqname}$id.toString();
 215+ </script>
 216+ </div>$bottom";
 217+ }
 218+ else {
 219+
 220+ # Finalise a menu
 221+ if ($depth > 0) $nodes .= str_repeat('</ul></li>',$depth);
 222+ $nodes = preg_replace("/<(a.*? )title=\".+?\".*?>/","<$1>",$nodes); # IE has problems with title attribute in suckerfish menus
 223+ $html = "
 224+ <ul class='$class' id='$id'>\n$nodes</ul>
 225+ <script type=\"$wgJsMimeType\">
 226+ if (window.attachEvent) {
 227+ var sfEls = document.getElementById('$id').getElementsByTagName('li');
 228+ for (var i=0; i<sfEls.length; i++) {
 229+ sfEls[i].onmouseover=function() { this.className+=' sfhover'; }
 230+ sfEls[i].onmouseout=function() { this.className=this.className.replace(new RegExp(' sfhover *'),''); }
 231+ }
 232+ }
 233+ </script>
 234+ ";
 235+ }
 236+
 237+ $text = preg_replace("/\x7f1$u\x7f$id\x7f.+?$/m",$html,$text,1); # replace first occurence of this trees root-id
 238+ $nodes = '';
 239+ $last = -1;
 240+ }
 241+ }
 242+ }
 243+
 244+ $text = preg_replace("/\x7f1$u\x7f.+?[\\r\\n]+/m",'',$text); # Remove all unreplaced row information
 245+ return true;
 246+ }
 247+
 248+}
 249+
 250+
 251+/**
 252+ * Called from $wgExtensionFunctions array when initialising extensions
 253+ */
 254+function wfSetupTreeAndMenu() {
 255+ global $wgTreeAndMenu;
 256+ $wgTreeAndMenu = new TreeAndMenu();
 257+}
 258+
 259+
 260+/**
 261+ * Needed in MediaWiki >1.8.0 for magic word hooks to work properly
 262+ */
 263+function wfTreeAndMenuLanguageGetMagic(&$magicWords,$langCode = 0) {
 264+ global $wgTreeMagic,$wgMenuMagic;
 265+ $magicWords[$wgTreeMagic] = array($langCode,$wgTreeMagic);
 266+ $magicWords[$wgMenuMagic] = array($langCode,$wgMenuMagic);
 267+ return true;
 268+}
Property changes on: trunk/extensions/TreeAndMenu/TreeAndMenu.php
___________________________________________________________________
Added: svn:eol-style
1269 + native
Added: svn:executable
2270 + *
Index: trunk/extensions/TreeAndMenu/dtree.js
@@ -0,0 +1,693 @@
 2+/*--------------------------------------------------|
 3+
 4+| dTree 2.05 | www.destroydrop.com/javascript/tree/ |
 5+
 6+|---------------------------------------------------|
 7+
 8+| Copyright (c) 2002-2003 Geir Landrö |
 9+
 10+| |
 11+
 12+| This script can be used freely as long as all |
 13+
 14+| copyright messages are intact. |
 15+
 16+| |
 17+
 18+| Updated: 17.04.2003 |
 19+
 20+|--------------------------------------------------*/
 21+
 22+
 23+
 24+// Node object
 25+
 26+function Node(id, pid, name, url, title, target, icon, iconOpen, open) {
 27+
 28+ this.id = id;
 29+
 30+ this.pid = pid;
 31+
 32+ this.name = name;
 33+
 34+ this.url = url;
 35+
 36+ this.title = title;
 37+
 38+ this.target = target;
 39+
 40+ this.icon = icon;
 41+
 42+ this.iconOpen = iconOpen;
 43+
 44+ this._io = open || false;
 45+
 46+ this._is = false;
 47+
 48+ this._ls = false;
 49+
 50+ this._hc = false;
 51+
 52+ this._ai = 0;
 53+
 54+ this._p;
 55+
 56+};
 57+
 58+
 59+
 60+// Tree object
 61+
 62+function dTree(objName) {
 63+
 64+ this.config = {
 65+
 66+ target : null,
 67+
 68+ folderLinks : true,
 69+
 70+ useSelection : true,
 71+
 72+ useCookies : true,
 73+
 74+ useLines : true,
 75+
 76+ useIcons : true,
 77+
 78+ useStatusText : false,
 79+
 80+ closeSameLevel : false,
 81+
 82+ inOrder : false
 83+
 84+ }
 85+
 86+ this.icon = {
 87+
 88+ root : 'img/base.gif',
 89+
 90+ folder : 'img/folder.gif',
 91+
 92+ folderOpen : 'img/folderopen.gif',
 93+
 94+ node : 'img/page.gif',
 95+
 96+ empty : 'img/empty.gif',
 97+
 98+ line : 'img/line.gif',
 99+
 100+ join : 'img/join.gif',
 101+
 102+ joinBottom : 'img/joinbottom.gif',
 103+
 104+ plus : 'img/plus.gif',
 105+
 106+ plusBottom : 'img/plusbottom.gif',
 107+
 108+ minus : 'img/minus.gif',
 109+
 110+ minusBottom : 'img/minusbottom.gif',
 111+
 112+ nlPlus : 'img/nolines_plus.gif',
 113+
 114+ nlMinus : 'img/nolines_minus.gif'
 115+
 116+ };
 117+
 118+ this.obj = objName;
 119+
 120+ this.aNodes = [];
 121+
 122+ this.aIndent = [];
 123+
 124+ this.root = new Node(-1);
 125+
 126+ this.selectedNode = null;
 127+
 128+ this.selectedFound = false;
 129+
 130+ this.completed = false;
 131+
 132+};
 133+
 134+
 135+
 136+// Adds a new node to the node array
 137+
 138+dTree.prototype.add = function(id, pid, name, url, title, target, icon, iconOpen, open) {
 139+
 140+ this.aNodes[this.aNodes.length] = new Node(id, pid, name, url, title, target, icon, iconOpen, open);
 141+
 142+};
 143+
 144+
 145+
 146+// Open/close all nodes
 147+
 148+dTree.prototype.openAll = function() {
 149+
 150+ this.oAll(true);
 151+
 152+};
 153+
 154+dTree.prototype.closeAll = function() {
 155+
 156+ this.oAll(false);
 157+
 158+};
 159+
 160+
 161+
 162+// Outputs the tree to the page
 163+
 164+dTree.prototype.toString = function() {
 165+
 166+ var str = '<div class="dtree">\n';
 167+
 168+ if (document.getElementById) {
 169+
 170+ if (this.config.useCookies) this.selectedNode = this.getSelected();
 171+
 172+ str += this.addNode(this.root);
 173+
 174+ } else str += 'Browser not supported.';
 175+
 176+ str += '</div>';
 177+
 178+ if (!this.selectedFound) this.selectedNode = null;
 179+
 180+ this.completed = true;
 181+
 182+ return str;
 183+
 184+};
 185+
 186+
 187+
 188+// Creates the tree structure
 189+
 190+dTree.prototype.addNode = function(pNode) {
 191+
 192+ var str = '';
 193+
 194+ var n=0;
 195+
 196+ if (this.config.inOrder) n = pNode._ai;
 197+
 198+ for (n; n<this.aNodes.length; n++) {
 199+
 200+ if (this.aNodes[n].pid == pNode.id) {
 201+
 202+ var cn = this.aNodes[n];
 203+
 204+ cn._p = pNode;
 205+
 206+ cn._ai = n;
 207+
 208+ this.setCS(cn);
 209+
 210+ if (!cn.target && this.config.target) cn.target = this.config.target;
 211+
 212+ if (cn._hc && !cn._io && this.config.useCookies) cn._io = this.isOpen(cn.id);
 213+
 214+ if (!this.config.folderLinks && cn._hc) cn.url = null;
 215+
 216+ if (this.config.useSelection && cn.id == this.selectedNode && !this.selectedFound) {
 217+
 218+ cn._is = true;
 219+
 220+ this.selectedNode = n;
 221+
 222+ this.selectedFound = true;
 223+
 224+ }
 225+
 226+ str += this.node(cn, n);
 227+
 228+ if (cn._ls) break;
 229+
 230+ }
 231+
 232+ }
 233+
 234+ return str;
 235+
 236+};
 237+
 238+
 239+
 240+// Creates the node icon, url and text
 241+
 242+dTree.prototype.node = function(node, nodeId) {
 243+
 244+ var str = '<div class="dTreeNode">' + this.indent(node, nodeId);
 245+
 246+ if (this.config.useIcons) {
 247+
 248+ if (!node.icon) node.icon = (this.root.id == node.pid) ? this.icon.root : ((node._hc) ? this.icon.folder : this.icon.node);
 249+
 250+ if (!node.iconOpen) node.iconOpen = (node._hc) ? this.icon.folderOpen : this.icon.node;
 251+
 252+ if (this.root.id == node.pid) {
 253+
 254+ node.icon = this.icon.root;
 255+
 256+ node.iconOpen = this.icon.root;
 257+
 258+ }
 259+
 260+ str += '<img id="i' + this.obj + nodeId + '" src="' + ((node._io) ? node.iconOpen : node.icon) + '" alt="" />';
 261+
 262+ }
 263+
 264+ if (node.url) {
 265+
 266+ str += '<a id="s' + this.obj + nodeId + '" class="' + ((this.config.useSelection) ? ((node._is ? 'nodeSel' : 'node')) : 'node') + '" href="' + node.url + '"';
 267+
 268+ if (node.title) str += ' title="' + node.title + '"';
 269+
 270+ if (node.target) str += ' target="' + node.target + '"';
 271+
 272+ if (this.config.useStatusText) str += ' onmouseover="window.status=\'' + node.name + '\';return true;" onmouseout="window.status=\'\';return true;" ';
 273+
 274+ if (this.config.useSelection && ((node._hc && this.config.folderLinks) || !node._hc))
 275+
 276+ str += ' onclick="javascript: ' + this.obj + '.s(' + nodeId + ');"';
 277+
 278+ str += '>';
 279+
 280+ }
 281+
 282+ else if ((!this.config.folderLinks || !node.url) && node._hc && node.pid != this.root.id)
 283+
 284+ str += '<a href="javascript: ' + this.obj + '.o(' + nodeId + ');" class="node">';
 285+
 286+ str += node.name;
 287+
 288+ if (node.url || ((!this.config.folderLinks || !node.url) && node._hc)) str += '</a>';
 289+
 290+ str += '</div>';
 291+
 292+ if (node._hc) {
 293+
 294+ str += '<div id="d' + this.obj + nodeId + '" class="clip" style="display:' + ((this.root.id == node.pid || node._io) ? 'block' : 'none') + ';">';
 295+
 296+ str += this.addNode(node);
 297+
 298+ str += '</div>';
 299+
 300+ }
 301+
 302+ this.aIndent.pop();
 303+
 304+ return str;
 305+
 306+};
 307+
 308+
 309+
 310+// Adds the empty and line icons
 311+
 312+dTree.prototype.indent = function(node, nodeId) {
 313+
 314+ var str = '';
 315+
 316+ if (this.root.id != node.pid) {
 317+
 318+ for (var n=0; n<this.aIndent.length; n++)
 319+
 320+ str += '<img src="' + ( (this.aIndent[n] == 1 && this.config.useLines) ? this.icon.line : this.icon.empty ) + '" alt="" />';
 321+
 322+ (node._ls) ? this.aIndent.push(0) : this.aIndent.push(1);
 323+
 324+ if (node._hc) {
 325+
 326+ str += '<a href="javascript: ' + this.obj + '.o(' + nodeId + ');"><img id="j' + this.obj + nodeId + '" src="';
 327+
 328+ if (!this.config.useLines) str += (node._io) ? this.icon.nlMinus : this.icon.nlPlus;
 329+
 330+ else str += ( (node._io) ? ((node._ls && this.config.useLines) ? this.icon.minusBottom : this.icon.minus) : ((node._ls && this.config.useLines) ? this.icon.plusBottom : this.icon.plus ) );
 331+
 332+ str += '" alt="" /></a>';
 333+
 334+ } else str += '<img src="' + ( (this.config.useLines) ? ((node._ls) ? this.icon.joinBottom : this.icon.join ) : this.icon.empty) + '" alt="" />';
 335+
 336+ }
 337+
 338+ return str;
 339+
 340+};
 341+
 342+
 343+
 344+// Checks if a node has any children and if it is the last sibling
 345+
 346+dTree.prototype.setCS = function(node) {
 347+
 348+ var lastId;
 349+
 350+ for (var n=0; n<this.aNodes.length; n++) {
 351+
 352+ if (this.aNodes[n].pid == node.id) node._hc = true;
 353+
 354+ if (this.aNodes[n].pid == node.pid) lastId = this.aNodes[n].id;
 355+
 356+ }
 357+
 358+ if (lastId==node.id) node._ls = true;
 359+
 360+};
 361+
 362+
 363+
 364+// Returns the selected node
 365+
 366+dTree.prototype.getSelected = function() {
 367+
 368+ var sn = this.getCookie('cs' + this.obj);
 369+
 370+ return (sn) ? sn : null;
 371+
 372+};
 373+
 374+
 375+
 376+// Highlights the selected node
 377+
 378+dTree.prototype.s = function(id) {
 379+
 380+ if (!this.config.useSelection) return;
 381+
 382+ var cn = this.aNodes[id];
 383+
 384+ if (cn._hc && !this.config.folderLinks) return;
 385+
 386+ if (this.selectedNode != id) {
 387+
 388+ if (this.selectedNode || this.selectedNode==0) {
 389+
 390+ eOld = document.getElementById("s" + this.obj + this.selectedNode);
 391+
 392+ eOld.className = "node";
 393+
 394+ }
 395+
 396+ eNew = document.getElementById("s" + this.obj + id);
 397+
 398+ eNew.className = "nodeSel";
 399+
 400+ this.selectedNode = id;
 401+
 402+ if (this.config.useCookies) this.setCookie('cs' + this.obj, cn.id);
 403+
 404+ }
 405+
 406+};
 407+
 408+
 409+
 410+// Toggle Open or close
 411+
 412+dTree.prototype.o = function(id) {
 413+
 414+ var cn = this.aNodes[id];
 415+
 416+ this.nodeStatus(!cn._io, id, cn._ls);
 417+
 418+ cn._io = !cn._io;
 419+
 420+ if (this.config.closeSameLevel) this.closeLevel(cn);
 421+
 422+ if (this.config.useCookies) this.updateCookie();
 423+
 424+};
 425+
 426+
 427+
 428+// Open or close all nodes
 429+
 430+dTree.prototype.oAll = function(status) {
 431+
 432+ for (var n=0; n<this.aNodes.length; n++) {
 433+
 434+ if (this.aNodes[n]._hc && this.aNodes[n].pid != this.root.id) {
 435+
 436+ this.nodeStatus(status, n, this.aNodes[n]._ls)
 437+
 438+ this.aNodes[n]._io = status;
 439+
 440+ }
 441+
 442+ }
 443+
 444+ if (this.config.useCookies) this.updateCookie();
 445+
 446+};
 447+
 448+
 449+
 450+// Opens the tree to a specific node
 451+
 452+dTree.prototype.openTo = function(nId, bSelect, bFirst) {
 453+
 454+ if (!bFirst) {
 455+
 456+ for (var n=0; n<this.aNodes.length; n++) {
 457+
 458+ if (this.aNodes[n].id == nId) {
 459+
 460+ nId=n;
 461+
 462+ break;
 463+
 464+ }
 465+
 466+ }
 467+
 468+ }
 469+
 470+ var cn=this.aNodes[nId];
 471+
 472+ if (cn.pid==this.root.id || !cn._p) return;
 473+
 474+ cn._io = true;
 475+
 476+ cn._is = bSelect;
 477+
 478+ if (this.completed && cn._hc) this.nodeStatus(true, cn._ai, cn._ls);
 479+
 480+ if (this.completed && bSelect) this.s(cn._ai);
 481+
 482+ else if (bSelect) this._sn=cn._ai;
 483+
 484+ this.openTo(cn._p._ai, false, true);
 485+
 486+};
 487+
 488+
 489+
 490+// Closes all nodes on the same level as certain node
 491+
 492+dTree.prototype.closeLevel = function(node) {
 493+
 494+ for (var n=0; n<this.aNodes.length; n++) {
 495+
 496+ if (this.aNodes[n].pid == node.pid && this.aNodes[n].id != node.id && this.aNodes[n]._hc) {
 497+
 498+ this.nodeStatus(false, n, this.aNodes[n]._ls);
 499+
 500+ this.aNodes[n]._io = false;
 501+
 502+ this.closeAllChildren(this.aNodes[n]);
 503+
 504+ }
 505+
 506+ }
 507+
 508+}
 509+
 510+
 511+
 512+// Closes all children of a node
 513+
 514+dTree.prototype.closeAllChildren = function(node) {
 515+
 516+ for (var n=0; n<this.aNodes.length; n++) {
 517+
 518+ if (this.aNodes[n].pid == node.id && this.aNodes[n]._hc) {
 519+
 520+ if (this.aNodes[n]._io) this.nodeStatus(false, n, this.aNodes[n]._ls);
 521+
 522+ this.aNodes[n]._io = false;
 523+
 524+ this.closeAllChildren(this.aNodes[n]);
 525+
 526+ }
 527+
 528+ }
 529+
 530+}
 531+
 532+
 533+
 534+// Change the status of a node(open or closed)
 535+
 536+dTree.prototype.nodeStatus = function(status, id, bottom) {
 537+
 538+ eDiv = document.getElementById('d' + this.obj + id);
 539+
 540+ eJoin = document.getElementById('j' + this.obj + id);
 541+
 542+ if (this.config.useIcons) {
 543+
 544+ eIcon = document.getElementById('i' + this.obj + id);
 545+
 546+ eIcon.src = (status) ? this.aNodes[id].iconOpen : this.aNodes[id].icon;
 547+
 548+ }
 549+
 550+ eJoin.src = (this.config.useLines)?
 551+
 552+ ((status)?((bottom)?this.icon.minusBottom:this.icon.minus):((bottom)?this.icon.plusBottom:this.icon.plus)):
 553+
 554+ ((status)?this.icon.nlMinus:this.icon.nlPlus);
 555+
 556+ eDiv.style.display = (status) ? 'block': 'none';
 557+
 558+};
 559+
 560+
 561+
 562+
 563+
 564+// [Cookie] Clears a cookie
 565+
 566+dTree.prototype.clearCookie = function() {
 567+
 568+ var now = new Date();
 569+
 570+ var yesterday = new Date(now.getTime() - 1000 * 60 * 60 * 24);
 571+
 572+ this.setCookie('co'+this.obj, 'cookieValue', yesterday);
 573+
 574+ this.setCookie('cs'+this.obj, 'cookieValue', yesterday);
 575+
 576+};
 577+
 578+
 579+
 580+// [Cookie] Sets value in a cookie
 581+
 582+dTree.prototype.setCookie = function(cookieName, cookieValue, expires, path, domain, secure) {
 583+
 584+ document.cookie =
 585+
 586+ escape(cookieName) + '=' + escape(cookieValue)
 587+
 588+ + (expires ? '; expires=' + expires.toGMTString() : '')
 589+
 590+ + (path ? '; path=' + path : '')
 591+
 592+ + (domain ? '; domain=' + domain : '')
 593+
 594+ + (secure ? '; secure' : '');
 595+
 596+};
 597+
 598+
 599+
 600+// [Cookie] Gets a value from a cookie
 601+
 602+dTree.prototype.getCookie = function(cookieName) {
 603+
 604+ var cookieValue = '';
 605+
 606+ var posName = document.cookie.indexOf(escape(cookieName) + '=');
 607+
 608+ if (posName != -1) {
 609+
 610+ var posValue = posName + (escape(cookieName) + '=').length;
 611+
 612+ var endPos = document.cookie.indexOf(';', posValue);
 613+
 614+ if (endPos != -1) cookieValue = unescape(document.cookie.substring(posValue, endPos));
 615+
 616+ else cookieValue = unescape(document.cookie.substring(posValue));
 617+
 618+ }
 619+
 620+ return (cookieValue);
 621+
 622+};
 623+
 624+
 625+
 626+// [Cookie] Returns ids of open nodes as a string
 627+
 628+dTree.prototype.updateCookie = function() {
 629+
 630+ var str = '';
 631+
 632+ for (var n=0; n<this.aNodes.length; n++) {
 633+
 634+ if (this.aNodes[n]._io && this.aNodes[n].pid != this.root.id) {
 635+
 636+ if (str) str += '.';
 637+
 638+ str += this.aNodes[n].id;
 639+
 640+ }
 641+
 642+ }
 643+
 644+ this.setCookie('co' + this.obj, str);
 645+
 646+};
 647+
 648+
 649+
 650+// [Cookie] Checks if a node id is in a cookie
 651+
 652+dTree.prototype.isOpen = function(id) {
 653+
 654+ var aOpen = this.getCookie('co' + this.obj).split('.');
 655+
 656+ for (var n=0; n<aOpen.length; n++)
 657+
 658+ if (aOpen[n] == id) return true;
 659+
 660+ return false;
 661+
 662+};
 663+
 664+
 665+
 666+// If Push and pop is not implemented by the browser
 667+
 668+if (!Array.prototype.push) {
 669+
 670+ Array.prototype.push = function array_push() {
 671+
 672+ for(var i=0;i<arguments.length;i++)
 673+
 674+ this[this.length]=arguments[i];
 675+
 676+ return this.length;
 677+
 678+ }
 679+
 680+};
 681+
 682+if (!Array.prototype.pop) {
 683+
 684+ Array.prototype.pop = function array_pop() {
 685+
 686+ lastElement = this[this.length-1];
 687+
 688+ this.length = Math.max(this.length-1,0);
 689+
 690+ return lastElement;
 691+
 692+ }
 693+
 694+};
Property changes on: trunk/extensions/TreeAndMenu/dtree.js
___________________________________________________________________
Added: svn:executable
1695 + *

Status & tagging log