git-svn-id: https://192.168.0.254/svn/Proyectos.FundacionLQDVI_WebCongresos/trunk@2 94ccb1af-fd9d-d947-8d90-7f70ea60afc8
423 lines
11 KiB
JavaScript
423 lines
11 KiB
JavaScript
/**
|
|
* @version $Id: tree.js 81 2009-06-05 16:31:31Z happynoodleboy $
|
|
* @package JCE
|
|
* @copyright Copyright (C) 2005 - 2009 Ryan Demmer. All rights reserved.
|
|
* @author Ryan Demmer
|
|
* @license GNU/GPL
|
|
* JCE is free software. This version may have been modified pursuant
|
|
* to the GNU General Public License, and as distributed it includes or
|
|
* is derivative of works licensed under the GNU General Public License or
|
|
* other free or open source software licenses.
|
|
*/
|
|
|
|
/*
|
|
Class: Tree
|
|
|
|
Note:
|
|
The Sortables require an XHTML doctype.
|
|
|
|
Arguments:
|
|
container - the container element
|
|
options - an Object, see options below.
|
|
|
|
Options:
|
|
rootName - the root name. Defaults to 'Root'
|
|
rootClass - the root node class. Defaults to 'root'
|
|
collapseTree - collapse all other tree nodes on the same level when one is opened. Defaults to false.
|
|
useLink - Use the link href
|
|
Events:
|
|
onNodeToggle - function executed when a node is toggled
|
|
onNodeClick - function executed when a node is clicked
|
|
onNodeLoad - function executed when a node is loaded
|
|
onNodeCreate - function executed when a node is created
|
|
*/
|
|
var Tree = new Class({
|
|
getOptions : function(){
|
|
return {
|
|
rootName: 'Root',
|
|
rootClass: 'root',
|
|
loaderClass: 'load',
|
|
collapseTree: false,
|
|
charLength: false,
|
|
onInit: Class.empty,
|
|
onNodeClick: Class.empty,
|
|
onNodeLoad: Class.empty,
|
|
onNodeCreate: Class.empty
|
|
};
|
|
},
|
|
initialize : function(container, options){
|
|
this.setOptions(this.getOptions(), options);
|
|
this.container = $(container);
|
|
|
|
this.fireEvent('onInit', function(){
|
|
this.nodeEvents();
|
|
}.bind(this));
|
|
|
|
return this;
|
|
},
|
|
nodeEvents : function(parent){
|
|
if(!parent){
|
|
parent = this.container;
|
|
}
|
|
|
|
$ES('div.tree-row', parent).each(function(el){
|
|
el.addEvent('mouseover', function(){
|
|
el.addClass('hover');
|
|
})
|
|
el.addEvent('mouseout', function(){
|
|
el.removeClass('hover');
|
|
})
|
|
});
|
|
|
|
$ES('div.tree-image', parent).each(function(el){
|
|
var p = this.findParent(el);
|
|
el.addEvent('click', function(e){
|
|
this.toggleNode(e, p);
|
|
}.bind(this))
|
|
if(this.getNode(p)){
|
|
el.addClass('open');
|
|
}
|
|
}.bind(this));
|
|
|
|
$ES('span', this.container).each(function(el){
|
|
if(window.ie){
|
|
el.onselectstart = function(){
|
|
return false;
|
|
}
|
|
}
|
|
if(window.gecko){
|
|
el.setStyle('moz-user-select', 'none');
|
|
}
|
|
if(this.getNode(el.getParent())){
|
|
el.addClass('open');
|
|
}
|
|
}.bind(this));
|
|
|
|
$ES('a', this.container).each(function(el){
|
|
var p = this.findParent(el);
|
|
el.addEvent('click', function(e){
|
|
this.fireEvent('onNodeClick', [e, p]);
|
|
}.bind(this))
|
|
}.bind(this));
|
|
},
|
|
/**
|
|
* Does a parent (ul) have childnodes
|
|
* @param {String} The parent
|
|
* @return {Boolean}.
|
|
*/
|
|
hasNodes : function(parent){
|
|
if($type(parent) == 'string'){
|
|
parent = this.findParent(parent);
|
|
}
|
|
var c = parent.childNodes;
|
|
return c.length > 1 || (c.length == 1 && c[0].className != 'spacer');
|
|
},
|
|
/**
|
|
* Does the node exist?
|
|
* @param {String} The node title
|
|
* @param {String or Element} The parent node
|
|
* @return {Boolean}.
|
|
*/
|
|
isNode : function(id, parent){
|
|
return this.findNode(id, parent) ? true : false;
|
|
},
|
|
/**
|
|
* Does a parent have subnodes?
|
|
* @param {String or Element} The parent node
|
|
* @return {Boolean}.
|
|
*/
|
|
getNode : function(parent){
|
|
if($type(parent) == 'string'){
|
|
parent = this.findParent(parent);
|
|
}
|
|
return $E('ul.tree-node', parent);
|
|
},
|
|
/**
|
|
* Reset all nodes. Set to closed
|
|
*/
|
|
resetNodes : function(){
|
|
$ES('span', this.container).each(function(el){
|
|
el.removeClass('open');
|
|
});
|
|
$ES('div.tree-image', this.container).each(function(el){
|
|
el.removeClass('open');
|
|
});
|
|
},
|
|
/**
|
|
* Rename a node
|
|
* @param {String} The node title
|
|
* @param {String} The new title
|
|
*/
|
|
renameNode : function(id, name){
|
|
var parent = string.dirname(id);
|
|
var node = this.findNode(id, parent);
|
|
// Rename the node
|
|
node.setProperty('id', name);
|
|
// Rename the span
|
|
$E('a', node).setHTML(string.basename(name));
|
|
// Rename each of the child nodes
|
|
$ES('li[id^='+ this._escape(encodeURI(id)) +']', node).each(function(n){
|
|
var nt = n.getProperty('id');
|
|
n.setProperty('id', nt.replace(id, name));
|
|
});
|
|
},
|
|
/**
|
|
* Remove a node
|
|
* @param {String} The node title
|
|
*/
|
|
removeNode : function(id){
|
|
var parent = string.dirname(id);
|
|
var node = this.findNode(id, parent);
|
|
var ul = node.getParent();
|
|
// Remove the node
|
|
node.remove();
|
|
// Remove it if it is now empty
|
|
if(ul && !this.hasNodes(ul)){
|
|
ul.remove();
|
|
}
|
|
},
|
|
/**
|
|
* Create a node <ul></ul>
|
|
* @param {String or Element} The parent node
|
|
* @return {Array} An array of nodes to create.
|
|
*/
|
|
createNode : function(nodes, parent){
|
|
var e, p, h, l, np, i;
|
|
// If parent is not an element, find the parent element
|
|
if(!parent){
|
|
parent = string.dirname(nodes[0].id);
|
|
}
|
|
if($type(parent) == 'string'){
|
|
parent = this.findParent(parent);
|
|
}
|
|
/* Create the nodes from the array
|
|
* <li><div class="tree-row"><div class="tree-image"></div><span><a>node</a></span><div></li>
|
|
*/
|
|
if(nodes && nodes.length){
|
|
// Get parent ul
|
|
var ul = $E('ul.tree-node', parent);
|
|
// Create it if it doesn't exist
|
|
if(!ul){
|
|
ul = new Element('ul').addClass('tree-node').adopt(
|
|
new Element('li').addClass('spacer')
|
|
).injectInside(parent);
|
|
}
|
|
|
|
// Iterate through nodes array
|
|
nodes.each(function(node){
|
|
if(!this.isNode(node.id, parent)){
|
|
// Set default
|
|
if(!node['class']){
|
|
node['class'] = 'folder';
|
|
}
|
|
// title and link html
|
|
t = node.name || node.id;
|
|
// decode
|
|
t = string.decode(t);
|
|
h = t;
|
|
l = this.options.charLength;
|
|
// shorten
|
|
if(l){
|
|
if(h.length > l){
|
|
h = h.substring(0, l) + '...';
|
|
}
|
|
}
|
|
ul.adopt(
|
|
new Element('li', {
|
|
'id': this._escape(encodeURI(node.id))
|
|
}).adopt(
|
|
new Element('div', {
|
|
'class': 'tree-row',
|
|
events: {
|
|
mouseover: function(){
|
|
this.addClass('hover');
|
|
},
|
|
mouseout: function(){
|
|
this.removeClass('hover');
|
|
}
|
|
}
|
|
}).adopt(
|
|
new Element('div', {
|
|
'class': node['class'].contains('folder') ? 'tree-image' : 'tree-noimage',
|
|
events: {
|
|
'click': function(e){
|
|
e = new Event(e);
|
|
p = this.findParent(e.target);
|
|
this.toggleNode(e, p);
|
|
}.bind(this)
|
|
}
|
|
})
|
|
).adopt(
|
|
new Element('span', {
|
|
'class': node['class']
|
|
}).adopt(
|
|
new Element('a', {
|
|
'href': !node.url ? 'javascript:;' : node.url,
|
|
'tabindex': '1',
|
|
'title': t,
|
|
events : {
|
|
'click': function(e){
|
|
e = new Event(e);
|
|
p = this.findParent(e.target);
|
|
this.fireEvent('onNodeClick', [e, p]);
|
|
e.stop();
|
|
}.bind(this)
|
|
}
|
|
}).setHTML(h)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
this.toggleNodeState(parent, 1);
|
|
this.fireEvent('onNodeCreate');
|
|
}else{
|
|
// Node exists, set as open
|
|
this.toggleNodeState(parent, 1);
|
|
}
|
|
}.bind(this))
|
|
}else{
|
|
// No new nodes, set as open
|
|
this.toggleNodeState(parent, 1);
|
|
}
|
|
},
|
|
/**
|
|
* Find the parent node
|
|
* @param {String} The child node id
|
|
* @return {Element} The parent node.
|
|
*/
|
|
findParent : function(el){
|
|
if($type(el) == 'element'){
|
|
n = el.parentNode;
|
|
while (n) {
|
|
if(n.nodeName == 'LI'){
|
|
return n;
|
|
}
|
|
n = n.parentNode;
|
|
}
|
|
}else{
|
|
return $E('li[id='+ this._escape(encodeURI(el)) +']', this.container);
|
|
}
|
|
},
|
|
/**
|
|
* Find a node by id
|
|
* @param {String} The child node title
|
|
* @param {String / Element} The parent node
|
|
* @return {Element} The node.
|
|
*/
|
|
findNode : function(id, parent){
|
|
if(!parent || parent == '/'){
|
|
parent = this.container;
|
|
}
|
|
if($type(parent) == 'string'){
|
|
parent = this.findParent(parent);
|
|
}
|
|
return $E('li[id='+ this._escape(encodeURI(id)) +']', parent) || false;
|
|
},
|
|
/**
|
|
* Toggle the loader class on the node span element
|
|
* @param {Element} The target node
|
|
*/
|
|
toggleLoader : function(node){
|
|
var span = $E('span', node), cls = this.options.loaderClass;
|
|
|
|
if(!span.hasClass(cls)){
|
|
span.$tmp = span.className || '';
|
|
span.className = cls;
|
|
}else{
|
|
span.removeClass(cls).addClass(span.$tmp);
|
|
span.$tmp = null;
|
|
}
|
|
},
|
|
/**
|
|
* Collapse all tree nodes except one excluded
|
|
* @param {Element} The excluded node
|
|
*/
|
|
collapseNodes : function(ex){
|
|
if(!ex) this.resetNodes();
|
|
var parent = ex.getParent();
|
|
|
|
$ES('li', parent).each(function(el){
|
|
if(el != ex){
|
|
if(el.getParent() == parent){
|
|
this.toggleNodeState(el, 0);
|
|
var child = this.getNode(el);
|
|
if(child){
|
|
child.addClass('hide');
|
|
}
|
|
}
|
|
}
|
|
}.bind(this));
|
|
},
|
|
/**
|
|
* Toggle a node's state, open or closed
|
|
* @param {Element} The node
|
|
*/
|
|
toggleNodeState : function(node, state){
|
|
var span = $E('span', node);
|
|
var div = $E('div.tree-image', node);
|
|
|
|
[span, div].each(function(el){
|
|
if(el){
|
|
if(state == 1){
|
|
el.addClass('open');
|
|
}else if(state == 0){
|
|
el.removeClass('open');
|
|
}else{
|
|
el.toggleClass('open');
|
|
}
|
|
}
|
|
});
|
|
if (state == 1) {
|
|
if(node.id == '/'){
|
|
return;
|
|
}
|
|
var c = $E('ul.tree-node', node);
|
|
if (c) {
|
|
if (span.hasClass('open')) {
|
|
c.removeClass('hide');
|
|
}
|
|
else {
|
|
c.addClass('hide');
|
|
}
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* Toggle a node
|
|
* @param {Element} The node
|
|
*/
|
|
toggleNode : function(e, node){
|
|
e = new Event(e);
|
|
// Force reload
|
|
if(e.shift){
|
|
return this.fireEvent('onNodeLoad', node);
|
|
}
|
|
var child = this.getNode(node);
|
|
// No children load or close
|
|
if(!child){
|
|
if($E('div.tree-image', node).hasClass('open')){
|
|
this.toggleNodeState(node);
|
|
}else{
|
|
this.fireEvent('onNodeLoad', node);
|
|
}
|
|
// Hide children, toggle node
|
|
}else{
|
|
child.toggleClass('hide');
|
|
this.toggleNodeState(node);
|
|
}
|
|
// Collpase the all other tree nodes
|
|
if(this.options.collapseTree){
|
|
this.collapseNodes(node);
|
|
}
|
|
},
|
|
/**
|
|
* Private function
|
|
* Escape a string
|
|
* @param {String} The string
|
|
* @return {String} The escaped string
|
|
*/
|
|
_escape : function(s){
|
|
return s.replace(/'/, '%27');
|
|
}
|
|
});
|
|
Tree.implement(new Events, new Options); |