Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The names of its contributors may NOT be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
===================================================================
dFTree Dynamic Javascript Folder Tree
===================================================================
DFTree is a javascript+css folder tree with dynamic node
insertion/erasing/alteration and other functionalities. It is also very
lightweight and easy to use.
It is CSS 2.1 compliant, although it was developed to be compatible at least
with Internet Explorer version 6+ . It was tested sucessfully on Mozilla
Firefox and Internet Explorer.
To use it:
1. Place in the HEAD section of your HTML document the following tags:
The first one is to load the javascript functions that generate the folder
tree. The second one loads the css styles which the tree are based. Both two
must be included in order to the tree to work.
2. build the tree (inside a javascript section) and draw it.
2.1 To create the tree:
tree = new dTree({name: 'tree'}); //The attribute name must be the object name
2.2 Creating nodes:
n1 = new dNode({id: '1',caption: 'First Node'});
n2 = new dNode({id: '2',caption: 'Second Node'});
n3 = new dNode({id: '3',caption: 'Third Node'});
n4 = new dNode({id: '4',caption: 'Fourth Node'});
2.3 Placing nodes in the tree:
tree.add(n1,'root'); //Places the root; second argument can be anything.
tree.add(n2,'1'); //Adds n2 as son of the node with id='1'
tree.add(n3,'1'); //Adds n3 as son of the node with id='1'
tree.add(n4,'3'); //Adds n3 as son of the node with id='3'
dFTree() //Constructor, sets properties
dFTree.draw() //Draws the tree
dFTree.add(node,pid) //adds node under the tree
dFTree.alter() //Alters a node of the tree (helper method)
dFTree.getNodeById(id) //Returns the node with id
Look at the source for tree and node properties, at their constructors.
-->
<script type="text/javascript">
/* Dynamic Folder Tree
* Generates DHTML tree dynamically (on the fly).
* License: BSD.
* See details at http://www.opensource.org/licenses/bsd-license.php
*
* Copyright (c) 2004, 2005, 2006
* Vinicius Cubas Brand, Raphael Derosso Pereira, Frank Alcantara
* {viniciuscb,raphaelpereira,frankalcantara} at users.sourceforge.net
* All rights reserved.
*/
// NODE
//Usage: a = new dNode({id:2, caption:'tree root', url:'http://www.w3.org'}); function dNode(arrayProps) {
//mandatory fields this.id; //node id this.caption; //node caption
//optional fields this.url; //url to open this.target; //target to open url this.onClick; //javascript to execute onclick this.onOpen; //javascript to execute when a node of the tree opens this.onClose; //javascript to execute when a node of the tree closes this.onFirstOpen; //javascript to execute only on the first open this.iconClosed; //img.src of closed icon this.iconOpen; //img.src of open icon this.runJS = true; //(bool) if true, runs the on* props defined above this.plusSign = true; //(bool) if the plus sign will appear or not this.captionClass = 'l'; //(string) the class for this node's caption
//The parameters below are private this._opened = false; //already opened this._io = false; //is opened
this._children = []; //references to children this._parent; //pointer to parent this._myTree; //pointer to myTree
for (i in arrayProps)
{ if (i.charAt(0) != '_')
{
eval('this.'+i+' = arrayProps[\''+i+'\'];');
}
}
}
//changes node state from open to closed, and vice-versa
dNode.prototype.changeState = function()
{ if (this._io)
{ this.close();
} else
{ this.open();
}
//cons = COokie of Node Status
//setCookie("cons"+this.id,this._io);
}
dNode.prototype.open = function () { if (!this._io)
{ if (!this._opened && this.runJS && this.onFirstOpen != null)
{
eval(this.onFirstOpen);
} else if (this.runJS && this.onOpen != null)
{
eval(this.onOpen);
}
//alter node label and other properties
dNode.prototype.alter = function(arrayProps)
{ for (i in arrayProps)
{ if (i != 'id' && i.charAt(0) != '_')
{
eval('this.'+i+' = arrayProps[\''+i+'\'];');
}
}
}
//css and dhtml refresh part
dNode.prototype._refresh = function() {
var nodeDiv = getObjectById("n"+this.id);
var plusSpan = getObjectById("p"+this.id);
var captionSpan = getObjectById("l"+this.id);
var childrenDiv = getObjectById("ch"+this.id);
if (nodeDiv != null)
{
//Handling open and close: checks this._io and changes class as needed if (!this._io) //just closed
{
childrenDiv.className = "closed";
} else //just opened
{
//prevents IE undesired behaviour when displaying empty DIVs
/* if (this._children.length > 0)
{*/
childrenDiv.className = "opened";
// }
}
plusSpan.innerHTML = this._properPlus();
captionSpan.innerHTML = this.caption;
}
//alter onLoad, etc
}
//gets the proper plus for this moment
dNode.prototype._properPlus = function()
{ if (!this._io)
{ if (this._myTree.useIcons)
{ return (this.plusSign)?imageHTML(this._myTree.icons.plus):"";
} else
{ return (this.plusSign)?"+":"";
}
} else
{ if (this._myTree.useIcons)
{ return (this.plusSign)?imageHTML(this._myTree.icons.minus):"";
} else
{ return (this.plusSign)?"-":"";
}
}
}
//changes node to selected style class. Perform further actions.
dNode.prototype._select = function()
{
var captionSpan;
if (this._myTree._selected)
{ this._myTree._selected._unselect();
} this._myTree._selected = this;
captionSpan = getObjectById("l"+this.id);
//changes class to selected link if (captionSpan)
{
captionSpan.className = 'sl';
}
}
//changes node to unselected style class. Perform further actions.
dNode.prototype._unselect = function()
{
var captionSpan = getObjectById("l"+this.id);
//changes class to selected link if (captionSpan)
{
captionSpan.className = this.captionClass;
}
}
//state can be open or closed
//warning: if drawed node is not child or root, bugs will happen
dNode.prototype._draw = function()
{
var str;
var div;
var myClass = (this._io)? "opened" : "closed";
var myPlus = this._properPlus();
var append = true;
var myPlusOnClick = this._myTree.name+'.getNodeById(\''+this.id+'\').changeState();';
var captionOnClickEvent = "";
// var cook;
var plusEventHandler = function(){
eval(myPlusOnClick);
}
var captionEventHandler = function(){
eval(captionOnClickEvent);
}
/* if (this.myTree.followCookies)
{
this._io = getCookie("cons"+this.id);
}*/
//FIXME put this in a separate function, as this will be necessary in
//various parts
captionOnClickEvent = this._myTree.name+'.getNodeById(\''+this.id+'\')._select(); '; if (this.onClick) //FIXME when onclick && url
{
captionOnClickEvent += this.onClick;
} else if (this.url && this.target)
{
captionOnClickEvent += 'window.open(\''+this.url+'\',\''+this.target+'\')';
} else if (this.url)
{
captionOnClickEvent += 'window.location=\''+this.url+'\'';
}
//The div of this node
divN = document.createElement('div');
divN.id = 'n'+this.id;
divN.className = 'son';
// TREE
//Usage: t = new dFTree({name:t, caption:'tree root', url:'http://www.w3.org'}); function dFTree(arrayProps) {
//mandatory fields this.name; //the value of this must be the name of the object
//optional fields this.is_dynamic = true; //tree is dynamic, i.e. updated on the fly this.followCookies = true;//use previous state (o/c) of nodes this.useIcons = false; //use icons or not
//Recursive function, draws children
dFTree.prototype._drawBranch = function(childrenArray) {
var a=0; for (a;a<childrenArray.length;a++)
{
childrenArray[a]._draw(); this._drawBranch(childrenArray[a]._children);
}
}
//add into a position
dFTree.prototype.add = function(node,pid) {
var auxPos;
var addNode = false; if (typeof (auxPos = this._searchNode(node.id)) != "number")
{
// if parent exists, add node as its child if (typeof (auxPos = this._searchNode(pid)) == "number")
{
node._parent = this._aNodes[auxPos]; this._aNodes[auxPos]._children[this._aNodes[auxPos]._children.length] = node;
addNode = true;
} else //if parent cannot be found and there is a tree root, ignores node
{ if (this._root == null)
{ this._root = node;
addNode = true;
}
} if (addNode)
{ this._aNodes[this._aNodes.length] = node;
node._myTree = this; if (this.is_dynamic)
{
node._draw();
}
}
}
}
//arrayProps: same properties of Node
dFTree.prototype.alter = function(arrayProps) { if (arrayProps['id'])
{ this.getNodeById(arrayProps['id']).alter(arrayProps);
}
}
//Searches for a node in the node array, returning the position of the array 4it
dFTree.prototype._searchNode = function(id) {
var a=0; for (a;a<this._aNodes.length;a++)
{ if (this._aNodes[a].id == id)
{ return a;
}
} return false;
}
//Auxiliar functions
//For multi-browser compatibility function getObjectById(name)
{ if (document.getElementById)
{ return document.getElementById(name);
} else if (document.all)
{ return document.all[name];
} else if (document.layers)
{ return document.layers[name];
} return false;
}
// [Cookie] Clears a cookie function clearCookie(cookieName) {
var now = new Date();
var yesterday = new Date(now.getTime() - 1000 * 60 * 60 * 24); this.setCookie(cookieName, 'cookieValue', yesterday); this.setCookie(cookieName, 'cookieValue', yesterday);
};