node is the object that fired the event. Parameters: The constructor takes two object parameters: config and options. The first, config, contains global settings for the tree control - you can use the configuration options listed below. The second, options, should contain options for the constructor - please refer to the options listed in the documentation. Config: div - a string representing the div Element inside which to build the tree control. mode - optional string, defaults to 'files' - specifies default icon behavior. In 'files' mode, empty nodes have a document icon - whereas, in 'folders' mode, all nodes are displayed as folders (a'la explorer). grid - boolean, defaults to false. If set to true, a grid is drawn to outline the structure of the tree. theme - string, optional, defaults to 'mootree.gif' - specifies the 'theme' GIF to use. loader - optional, an options object for the constructor - defaults to {icon:'mootree_loader.gif', text:'Loading...', color:'a0a0a0'} onExpand - optional function (see Events above) onSelect - optional function (see Events above) */ var MooTreeControl = new Class({ initialize: function(config, options) { options.control = this; // make sure our new MooTreeNode knows who it's owner control is options.div = config.div; // tells the root node which div to insert itself into this.root = new MooTreeNode(options); // create the root node of this tree control this.index = new Object(); // used by the get() method this.enabled = true; // enable visual updates of the control this.theme = config.theme || 'mootree.gif'; this.loader = config.loader || {icon: 'mootree_loader.gif', text: 'Loading...', color: '#a0a0a0'}; this.selected = null; // set the currently selected node to nothing this.mode = config.mode; // mode can be "folders" or "files", and affects the default icons this.grid = config.grid; // grid can be turned on (true) or off (false) this.onExpand = config.onExpand || new Function(); // called when any node in the tree is expanded/collapsed this.onSelect = config.onSelect || new Function(); // called when any node in the tree is selected/deselected this.onClick = config.onClick || new Function(); // called when any node in the tree is clicked this.root.update(true); }, /* Property: insert Creates a new node under the root node of this tree. Parameters: options - an object containing the same options available to the constructor. Returns: A new instance. */ insert: function(options) { options.control = this; return this.root.insert(options); }, /* Property: select Sets the currently selected node. This is called by when a node is selected (e.g. by clicking it's title with the mouse). Parameters: node - the object to select. */ select: function(node) { this.onClick(node); node.onClick(); // fire click events if (this.selected === node) { return; } // already selected if (this.selected) { // deselect previously selected node: this.selected.select(false); this.onSelect(this.selected, false); } // select new node: this.selected = node; node.select(true); this.onSelect(node, true); }, /* Property: expand Expands the entire tree, recursively. */ expand: function() { this.root.toggle(true, true); }, /* Property: collapse Collapses the entire tree, recursively. */ collapse: function() { this.root.toggle(true, false); }, /* Property: get Retrieves the node with the given id - or null, if no node with the given id exists. Parameters: id - a string, the id of the node you wish to retrieve. Note: Node id can be assigned via the constructor, e.g. using the method. */ get: function(id) { return this.index[id] || null; }, /* Property: adopt Adopts a structure of nested ul/li/a elements as tree nodes, then removes the original elements. Parameters: id - a string representing the ul element to be adopted, or an element reference. parentNode - optional, a object under which to import the specified ul element. Defaults to the root node of the parent control. Note: The ul/li structure must be properly nested, and each li-element must contain one a-element, e.g.: > The "href", "target", "title" and "name" attributes of the a-tags are picked up and stored in the data property of the node. CSS-style comments inside a-tags are parsed, and treated as arguments for constructor, e.g. "icon", "openicon", "color", etc. */ adopt: function(id, parentNode) { if (parentNode === undefined) { parentNode = this.root; } this.disable(); this._adopt(id, parentNode); parentNode.update(true); $(id).destroy(); this.enable(); }, _adopt: function(id, parentNode) { /* adopts a structure of ul/li elements into this tree */ e = $(id); var i = 0, c = e.getChildren(); for (i = 0; i < c.length; i++) { if (c[i].nodeName == 'LI') { var con = {text: ''}, comment = '', node = null, subul = null; var n = 0, z = 0, se = null, s = c[i].getChildren(); for (n = 0; n < s.length; n++) { switch (s[n].nodeName) { case 'A': for (z = 0; z < s[n].childNodes.length; z++) { se = s[n].childNodes[z]; switch (se.nodeName) { case '#text': con.text += se.nodeValue; break; case '#comment': comment += se.nodeValue; break; } } con.data = s[n].getProperties('href','target','title','name'); break; case 'UL': subul = s[n]; break; } } if (con.label != '') { con.data.url = con.data['href']; // (for backwards compatibility) if (comment != '') { var bits = comment.split(';'); for (z = 0; z < bits.length; z++) { var pcs = bits[z].trim().split(':'); if (pcs.length == 2) { con[pcs[0].trim()] = pcs[1].trim(); } } } node = parentNode.insert(con); if (subul) { this._adopt(subul, node); } } } } }, /* Property: disable Call this to temporarily disable visual updates -- if you need to insert/remove many nodes at a time, many visual updates would normally occur. By temporarily disabling the control, these visual updates will be skipped. When you're done making changes, call to turn on visual updates again, and automatically repaint all nodes that were changed. */ disable: function() { this.enabled = false; }, /* Property: enable Enables visual updates again after a call to */ enable: function() { this.enabled = true; this.root.update(true, true); } }); /* Class: MooTreeNode This class implements the functionality of a single node in a . Note: You should not manually create objects of this class -- rather, you should use to create nodes in the root of the tree, and then use the similar function to create subnodes. Both insert methods have a similar syntax, and both return the newly created object. Parameters: options - an object. See options below. Options: text - this is the displayed text of the node, and as such as is the only required parameter. id - string, optional - if specified, must be a unique node identifier. Nodes with id can be retrieved using the method. color - string, optional - if specified, must be a six-digit hexadecimal RGB color code. open - boolean value, defaults to false. Use true if you want the node open from the start. icon - use this to customize the icon of the node. The following predefined values may be used: '_open', '_closed' and '_doc'. Alternatively, specify the URL of a GIF or PNG image to use - this should be exactly 18x18 pixels in size. If you have a strip of images, you can specify an image number (e.g. 'my_icons.gif#4' for icon number 4). openicon - use this to customize the icon of the node when it's open. data - an object containing whatever data you wish to associate with this node (such as an url and/or an id, etc.) Events: onExpand - called when the node is expanded or collapsed: function(state) - where state is a boolean meaning true:expanded or false:collapsed. onSelect - called when the node is selected or deselected: function(state) - where state is a boolean meaning true:selected or false:deselected. onClick - called when the node is clicked (no arguments). */ var MooTreeNode = new Class({ initialize: function(options) { this.text = options.text; // the text displayed by this node this.id = options.id || null; // the node's unique id this.nodes = new Array(); // subnodes nested beneath this node (MooTreeNode objects) this.parent = null; // this node's parent node (another MooTreeNode object) this.last = true; // a flag telling whether this node is the last (bottom) node of it's parent this.control = options.control; // owner control of this node's tree this.selected = false; // a flag telling whether this node is the currently selected node in it's tree this.color = options.color || null; // text color of this node this.data = options.data || {}; // optional object containing whatever data you wish to associate with the node (typically an url or an id) this.onExpand = options.onExpand || new Function(); // called when the individual node is expanded/collapsed this.onSelect = options.onSelect || new Function(); // called when the individual node is selected/deselected this.onClick = options.onClick || new Function(); // called when the individual node is clicked this.open = options.open ? true : false; // flag: node open or closed? this.icon = options.icon; this.openicon = options.openicon || this.icon; // add the node to the control's node index: if (this.id) { this.control.index[this.id] = this; } // create the necessary divs: this.div = { main: new Element('div').addClass('mooTree_node'), indent: new Element('div'), gadget: new Element('div'), icon: new Element('div'), text: new Element('div').addClass('mooTree_text'), sub: new Element('div') }; // put the other divs under the main div: this.div.main.adopt(this.div.indent); this.div.main.adopt(this.div.gadget); this.div.main.adopt(this.div.icon); this.div.main.adopt(this.div.text); // put the main and sub divs in the specified parent div: $(options.div).adopt(this.div.main); $(options.div).adopt(this.div.sub); // attach event handler to gadget: this.div.gadget._node = this; this.div.gadget.onclick = this.div.gadget.ondblclick = function() { this._node.toggle(); }; // attach event handler to icon/text: this.div.icon._node = thi