You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
721 lines
18 KiB
JavaScript
721 lines
18 KiB
JavaScript
/**
|
|
* 页面 JS Tree 的实现
|
|
* Copyright (c) 2009 YaoYiLang
|
|
* @email redrainyi@gmail.com
|
|
* @datetime 2009-10-01 12:11:08
|
|
* @version 2.2
|
|
*/
|
|
|
|
getUniqueID = function(){
|
|
return ('_' + (new Date().getTime()) + '_' + parseInt(Math.random()*10000));
|
|
}
|
|
|
|
TreePanel = function(config){
|
|
this.nodeHash = {};
|
|
this.root = null;
|
|
this._id = getUniqueID();
|
|
this.iconPath = 'img/';
|
|
this.clickListeners = [];
|
|
this.element = document.createElement('div');
|
|
this.element.className='TreePanel';
|
|
this.container = null;
|
|
this.focusNode = null;
|
|
this.on=this.addListener;
|
|
this.initialize.apply(this, arguments);
|
|
};
|
|
|
|
TreePanel.prototype={
|
|
initialize : function(config){
|
|
var renderTo = config['renderTo'];
|
|
this.container = (String.isInstance(renderTo) ? document.getElementById(renderTo) : renderTo ) || document.body;
|
|
var handler= config['handler'];
|
|
if(Function.isInstance(handler)){
|
|
this.addListener('click',handler);
|
|
}
|
|
var iconPath = config['iconPath'];
|
|
if(String.isInstance(iconPath)){
|
|
this.iconPath = iconPath;
|
|
}
|
|
|
|
var node = new TreeNode(config.root);
|
|
this.setRootNode(node);
|
|
},
|
|
pathSeparator: "/",
|
|
getRootNode : function(){
|
|
return this.root;
|
|
},
|
|
setRootNode : function(node){
|
|
this.root = node;
|
|
node.ownerTree = this;
|
|
this.registerNode(node);
|
|
node.cascade((function(node){
|
|
this.registerNode(node);
|
|
}),this);
|
|
},
|
|
getNodeById : function(id){
|
|
return this.nodeHash[id];
|
|
},
|
|
registerNode : function(node){
|
|
this.nodeHash[node.id] = node;
|
|
},
|
|
unregisterNode : function(node){
|
|
delete this.nodeHash[node.id];
|
|
},
|
|
render : function(){
|
|
this.element.innerHTML = ''
|
|
this.root.render();
|
|
if(this.container){
|
|
this.container.appendChild(this.element);
|
|
}
|
|
this.initEvent();
|
|
},
|
|
getIcon : function(icontype){
|
|
return this.iconPath + this.icon[icontype]
|
|
},
|
|
getIconByType : function(type){
|
|
return type;
|
|
},
|
|
initEvent : function(){
|
|
var _this = this;
|
|
this.element.onclick=function(event){
|
|
var event = event || window.event;
|
|
var elem=(event.srcElement || event.target);
|
|
var _type = elem['_type_'];
|
|
if(typeof(_type) === undefined){
|
|
return;
|
|
}
|
|
elem = elem.parentNode || elem.parentElement;
|
|
if(_type == 'clip'){
|
|
if(elem.indexId!=null){
|
|
var node = _this.nodeHash[ elem.indexId ];
|
|
if(node.isExpand){
|
|
node.collapse();
|
|
}else{
|
|
node.expand();
|
|
}
|
|
}
|
|
}else if(_type == 'icon' || _type == 'text'){
|
|
var node = _this.nodeHash[elem.indexId];
|
|
for(var i=0; i < _this.clickListeners.length; i++){
|
|
_this.clickListeners[i](node);
|
|
}
|
|
_this.setFocusNode(node);
|
|
}else if(_type == 'checked'){
|
|
var node = _this.nodeHash[elem.indexId];
|
|
node.onCheck();
|
|
}
|
|
};
|
|
},
|
|
|
|
getChecked : function(name){
|
|
var checkeds = [];
|
|
name = name||'id';
|
|
for(var k in this.nodeHash){
|
|
var node = this.nodeHash[k];
|
|
if(node.checked==1){
|
|
var value = node.attributes[name]
|
|
if(value != null){
|
|
checkeds.push(value);
|
|
}
|
|
}
|
|
}
|
|
return checkeds;
|
|
},
|
|
addListener : function(type,handler){
|
|
if(Function.isInstance(type)){
|
|
handler=type;
|
|
type === 'click'
|
|
}
|
|
this.clickListeners.push(handler);
|
|
},
|
|
setFocusNode : function(node){
|
|
if(this.focusNode){
|
|
this.focusNode.unselect();
|
|
}
|
|
this.focusNode = node;
|
|
if(node.parentNode){
|
|
node.parentNode.expand();
|
|
}
|
|
node.select();
|
|
},
|
|
toString : function(){
|
|
return "[Tree"+(this.id?" "+this.id:"")+"]";
|
|
},
|
|
collapseAll : function(){
|
|
if(this.root){
|
|
this.root.collapseChildNodes(true);
|
|
}
|
|
},
|
|
expandAll : function(){
|
|
if(this.root){
|
|
this.root.expand(true);
|
|
}
|
|
}
|
|
};
|
|
|
|
TreePanel.prototype.icon = {
|
|
root : 'root.gif',
|
|
folder : 'folder.gif',
|
|
folderOpen : 'folderopen.gif',
|
|
node : 'page.gif',
|
|
empty : 'empty.gif',
|
|
line : 'line.gif',
|
|
join : 'join.gif',
|
|
joinBottom : 'joinbottom.gif',
|
|
plus : 'plus.gif',
|
|
plusBottom : 'plusbottom.gif',
|
|
minus : 'minus.gif',
|
|
minusBottom : 'minusbottom.gif',
|
|
nlPlus : 'nolines_plus.gif',
|
|
nlMinus : 'nolines_minus.gif',
|
|
checkbox0 : 'checkbox_0.gif',
|
|
checkbox1 : 'checkbox_1.gif',
|
|
checkbox2 : 'checkbox_2.gif',
|
|
org : 'org.gif',
|
|
edp : 'edp.gif',
|
|
emp : 'emp.gif'
|
|
};
|
|
|
|
|
|
TreeNode=function(attributes) {
|
|
this['attributes'] = attributes || {};
|
|
this['html-element'] = false;//null
|
|
if(!attributes.id){
|
|
attributes.id = getUniqueID();
|
|
}
|
|
this.id = attributes.id;
|
|
this.parentNode = null;
|
|
this.childNodes = [];
|
|
this.parentNode = null;
|
|
this.lastChild = null;
|
|
this.firstChild = null;
|
|
this.previousSibling = null;
|
|
this.nextSibling = null;
|
|
this.childrenRendered = false
|
|
this.isExpand = false;
|
|
|
|
this.checked = this['attributes']['checked'];
|
|
this.checked = this.checked==null ? false : this.checked;
|
|
|
|
this.leaf = this.attributes.leaf;
|
|
var children = attributes.children || [];
|
|
for(var i=0,j=children.length;i<j;i++){
|
|
var node = new TreeNode(children[i]);
|
|
this.appendChild(node);
|
|
}
|
|
}
|
|
|
|
TreeNode.prototype={
|
|
initEl : function(){
|
|
this['html-element']={};
|
|
this['html-element']['element'] = document.createElement('div');
|
|
this['html-element']['line'] = document.createElement('span');
|
|
this['html-element']['clip'] = document.createElement('img');
|
|
this['html-element']['icon'] = document.createElement('img');
|
|
this['html-element']['text'] = document.createElement('span');
|
|
this['html-element']['checkbox'] = document.createElement('img');
|
|
this['html-element']['child'] = document.createElement('div');
|
|
this['html-element']['element'].appendChild(this['html-element']['line']);
|
|
this['html-element']['element'].appendChild(this['html-element']['clip']);
|
|
this['html-element']['element'].appendChild(this['html-element']['icon']);
|
|
this['html-element']['element'].appendChild(this['html-element']['checkbox']);
|
|
this['html-element']['element'].appendChild(this['html-element']['text']);
|
|
this['html-element']['element'].appendChild(this['html-element']['child']);
|
|
this['html-element']['text'].className='TreeNode'
|
|
this['html-element']['element'].noWrap='true';
|
|
this['html-element']['line']['_type_'] ='line';
|
|
this['html-element']['clip']['_type_'] ='clip';
|
|
this['html-element']['icon']['_type_'] ='icon';
|
|
this['html-element']['text']['_type_'] ='text';
|
|
this['html-element']['checkbox']['_type_'] ='checked';
|
|
this['html-element']['child'].style.display='none';
|
|
if(this.checked===false){
|
|
this['html-element']['checkbox'].style.display='none';
|
|
}
|
|
},
|
|
render : function(){
|
|
if(!this['html-element']){
|
|
this.initEl();
|
|
}
|
|
if(this.isRoot()){
|
|
this.ownerTree.element.appendChild(this['html-element']['element']);
|
|
this.expand();
|
|
}else{
|
|
this.parentNode['html-element']['child'].appendChild(this['html-element']['element']);
|
|
}
|
|
this.paintPrefix();
|
|
this['html-element']['element'].indexId = this.id;
|
|
},
|
|
paintPrefix : function(){
|
|
this.paintLine();
|
|
this.paintClipIcoImg();
|
|
this.paintCheckboxImg();
|
|
this.paintIconImg();
|
|
this.paintText();
|
|
},
|
|
paintLine : function(){
|
|
var ownerTree = this.getOwnerTree();
|
|
this['html-element']['line'].innerHTML = '';
|
|
var pathNodes = this.getPathNodes();
|
|
for(var i = 1 ,count = pathNodes.length-1 ; i < count ; i++){
|
|
var node = pathNodes[i];
|
|
var img = document.createElement('img');
|
|
if( node.isLast()){
|
|
img.src = ownerTree.getIcon('empty');
|
|
}else{
|
|
img.src = ownerTree.getIcon('line');
|
|
}
|
|
this['html-element']['line'].appendChild(img);
|
|
}
|
|
},
|
|
paintClipIcoImg : function(){
|
|
if(this.isRoot()){
|
|
this['html-element']['clip'].style.display='none';//不显示根节点的clip
|
|
return;
|
|
}
|
|
var ownerTree = this.getOwnerTree();
|
|
var icon = 'empty';
|
|
if(this.isRoot()){
|
|
icon = this.isExpand ? 'nlMinus':'nlPlus';
|
|
}else{
|
|
if(this.isLeaf()){ //是叶节点
|
|
if(this.isLast()){
|
|
icon = 'joinBottom';
|
|
}else{
|
|
icon = 'join';
|
|
}
|
|
}else{ //非叶节点
|
|
if(this.isExpand){ //展开
|
|
if(this.isLast()){
|
|
icon = 'minusBottom';
|
|
}else{
|
|
icon = 'minus';
|
|
}
|
|
}else{ //折叠
|
|
if(this.isLast()){
|
|
icon = 'plusBottom';
|
|
}else{
|
|
icon = 'plus';
|
|
}
|
|
}
|
|
}
|
|
};
|
|
this['html-element']['clip'].src = ownerTree.getIcon(icon);
|
|
},
|
|
paintIconImg : function(){
|
|
var ownerTree = this.getOwnerTree();
|
|
var icon = this['attributes']['icon'];
|
|
if(!icon){
|
|
var type = this['attributes']['type']
|
|
if(type){
|
|
icon = ownerTree.getIconByType(type);
|
|
}
|
|
if(!icon){
|
|
if(this.isRoot()){
|
|
icon = 'root';
|
|
}else if(this.isLeaf()){
|
|
icon = 'node';
|
|
}else if(this.isExpand){
|
|
icon = 'folderOpen';
|
|
}else{
|
|
icon = 'folder';
|
|
}
|
|
}
|
|
}
|
|
this['html-element']['icon'].src = ownerTree.getIcon(icon);
|
|
},
|
|
paintCheckboxImg : function(){
|
|
var ownerTree = this.getOwnerTree();
|
|
var checked = this.checked;
|
|
if(this['html-element']){
|
|
this['html-element']['checkbox'].src = ownerTree.getIcon(((checked==2)?'checkbox2':(checked==1)?'checkbox1':'checkbox0'));
|
|
}
|
|
},
|
|
paintText : function(){
|
|
var text = this['attributes']['text'];
|
|
this['html-element']['text'].style.cursor='hand'
|
|
this['html-element']['text'].title=text;
|
|
this['html-element']['text'].innerText=text;
|
|
this['html-element']['text'].textContent=text;
|
|
},
|
|
paintChildren : function(){
|
|
if(!this.childrenRendered){
|
|
this['html-element']['child'].innerHTML = '';
|
|
this.childrenRendered = true;
|
|
var childNodes = this.childNodes;
|
|
for(var i=0;i < childNodes.length;i++){
|
|
childNodes[i].render();
|
|
}
|
|
};
|
|
},
|
|
collapse : function(deep){
|
|
this.isExpand=false;
|
|
this['html-element']['child'].style.display='none';
|
|
this.paintIconImg();
|
|
this.paintClipIcoImg();
|
|
if(deep){
|
|
this.collapseChildNodes(deep);
|
|
}
|
|
},
|
|
collapseChildNodes : function(deep){
|
|
var cs = this.childNodes;
|
|
for(var i = 0, len = cs.length; i < len; i++) {
|
|
cs[i].collapse(deep);
|
|
}
|
|
},
|
|
expand : function(deep){
|
|
if(!this.isLeaf()&&this.childNodes.length>0){
|
|
this.isExpand=true;
|
|
this.paintChildren();
|
|
this['html-element']['child'].style.display='block';
|
|
}
|
|
this.paintIconImg();
|
|
this.paintClipIcoImg();
|
|
if(deep){
|
|
this.expandChildNodes(deep);
|
|
}
|
|
},
|
|
expandChildNodes : function(deep){
|
|
var cs = this.childNodes;
|
|
for(var i = 0, len = cs.length; i < len; i++) {
|
|
cs[i].expand(deep);
|
|
}
|
|
},
|
|
select : function(){
|
|
this.isSelect = true;
|
|
this['html-element']['text'].style.backgroundColor='#CCCCFF';
|
|
},
|
|
unselect : function(){
|
|
this.isSelect = false;
|
|
this['html-element']['text'].style.backgroundColor='';
|
|
},
|
|
getEl : function(){
|
|
return this['html-element'];
|
|
},
|
|
setCheck : function(checked){
|
|
if(checked==2||checked==3){
|
|
var childNodes = this.childNodes;
|
|
var count = childNodes.length;
|
|
if(count==0){
|
|
this.checked=checked==2?0:1;
|
|
}else{
|
|
var checked1 = 0;
|
|
var checked2 = 0;
|
|
for(var i=0;i<count;i++){
|
|
var checked = childNodes[i].checked;
|
|
if(checked==1){
|
|
checked1++;
|
|
}else if(checked==2){
|
|
checked2++;
|
|
}
|
|
}
|
|
this.checked = (childNodes.length==checked1) ? 1 : (checked1>0||checked2>0) ? 2 : 0;
|
|
}
|
|
}else{
|
|
this.checked=checked;
|
|
}
|
|
this.paintCheckboxImg();
|
|
},
|
|
onCheck : function(){
|
|
if(this.checked!==false){
|
|
if(this.checked==1){
|
|
this.cascade((function(checked){
|
|
this.setCheck(checked);
|
|
}),null,0);
|
|
this.bubble((function(checked){
|
|
this.setCheck(checked);
|
|
}),null,2);
|
|
}else{
|
|
this.cascade((function(checked){
|
|
this.setCheck(checked);
|
|
}),null,1);
|
|
this.bubble((function(checked){
|
|
this.setCheck(checked);
|
|
}),null,3);
|
|
}
|
|
}
|
|
},
|
|
|
|
isRoot : function(){
|
|
return (this.ownerTree!=null) && (this.ownerTree.root === this);
|
|
},
|
|
isLeaf : function(){
|
|
return this.childNodes.length===0;
|
|
//return this.leaf === true;
|
|
},
|
|
isLast : function(){
|
|
return (!this.parentNode ? true : this.parentNode.lastChild == this);
|
|
},
|
|
isFirst : function(){
|
|
return (!this.parentNode ? true : this.parentNode.firstChild == this);
|
|
},
|
|
hasChildNodes : function(){
|
|
return !this.isLeaf() && this.childNodes.length > 0;
|
|
},
|
|
// private
|
|
setFirstChild : function(node){
|
|
this.firstChild = node;
|
|
},
|
|
//private
|
|
setLastChild : function(node){
|
|
this.lastChild = node;
|
|
},
|
|
appendChild : function(node){
|
|
var multi = false;
|
|
if(Array.isInstance(node)){
|
|
multi = node;
|
|
}else if(arguments.length > 1){
|
|
multi = arguments;
|
|
}
|
|
if(multi){
|
|
for(var i = 0, len = multi.length; i < len; i++) {
|
|
this.appendChild(multi[i]);
|
|
}
|
|
}else{
|
|
//>>beforeappend
|
|
var oldParent = node.parentNode;
|
|
//>>beforemove
|
|
if(oldParent){
|
|
oldParent.removeChild(node);
|
|
}
|
|
var index = this.childNodes.length;
|
|
if(index == 0){
|
|
this.setFirstChild(node);
|
|
}
|
|
this.childNodes.push(node);
|
|
node.parentNode = this;
|
|
//
|
|
var ps = this.childNodes[index-1];
|
|
if(ps){
|
|
node.previousSibling = ps;
|
|
ps.nextSibling = node;
|
|
}else{
|
|
node.previousSibling = null;
|
|
}
|
|
node.nextSibling = null;
|
|
this.setLastChild(node);
|
|
node.setOwnerTree(this.getOwnerTree());
|
|
//>>append
|
|
//if(oldParent) >>move
|
|
|
|
if(node && this.childrenRendered){
|
|
node.render();
|
|
if(node.previousSibling){
|
|
node.previousSibling.paintPrefix();//paintLine();
|
|
}
|
|
}
|
|
if(this['html-element']){
|
|
this.paintPrefix();
|
|
}
|
|
return node;//true
|
|
}
|
|
},
|
|
removeChild : function(node){
|
|
var index = this.childNodes.indexOf(node);
|
|
if(index == -1){
|
|
return false;
|
|
}
|
|
//>>beforeremove
|
|
this.childNodes.splice(index, 1);
|
|
if(node.previousSibling){
|
|
node.previousSibling.nextSibling = node.nextSibling;
|
|
}
|
|
if(node.nextSibling){
|
|
node.nextSibling.previousSibling = node.previousSibling;
|
|
}
|
|
if(this.firstChild == node){
|
|
this.setFirstChild(node.nextSibling);
|
|
}
|
|
if(this.lastChild == node){
|
|
this.setLastChild(node.previousSibling);
|
|
}
|
|
node.setOwnerTree(null);
|
|
//clear
|
|
node.parentNode = null;
|
|
node.previousSibling = null;
|
|
node.nextSibling = null;
|
|
//>>remove UI
|
|
if(this.childrenRendered){
|
|
if(node['html-element']&&node['html-element']['element']){
|
|
this['html-element']['child'].removeChild(node['html-element']['element'])
|
|
}
|
|
if(this.childNodes.length==0){
|
|
this.collapse();
|
|
}
|
|
}
|
|
if(this['html-element']){
|
|
this.paintPrefix();
|
|
}
|
|
return node;
|
|
},
|
|
insertBefore : function(node, refNode){
|
|
if(!refNode){
|
|
return this.appendChild(node);
|
|
}
|
|
//移动位置是自身位置(不需要移动)
|
|
if(node == refNode){
|
|
return false;
|
|
}
|
|
var index = this.childNodes.indexOf(refNode);
|
|
var oldParent = node.parentNode;
|
|
var refIndex = index;
|
|
//是子节点,并且是向后移动
|
|
if(oldParent == this && this.childNodes.indexOf(node) < index){
|
|
refIndex--;
|
|
}
|
|
if(oldParent){
|
|
oldParent.removeChild(node);
|
|
}
|
|
//设置节点间关系
|
|
if(refIndex == 0){
|
|
this.setFirstChild(node);
|
|
}
|
|
this.childNodes.splice(refIndex, 0, node);
|
|
node.parentNode = this;
|
|
var ps = this.childNodes[refIndex-1];
|
|
if(ps){
|
|
node.previousSibling = ps;
|
|
ps.nextSibling = node;
|
|
}else{
|
|
node.previousSibling = null;
|
|
}
|
|
node.nextSibling = refNode;
|
|
refNode.previousSibling = node;
|
|
node.setOwnerTree(this.getOwnerTree());
|
|
return node;
|
|
},
|
|
replaceChild : function(newChild, oldChild){
|
|
this.insertBefore(newChild, oldChild);
|
|
this.removeChild(oldChild);
|
|
return oldChild;
|
|
},
|
|
indexOf : function(child){
|
|
return this.childNodes.indexOf(child);
|
|
},
|
|
getOwnerTree : function(){
|
|
if(!this.ownerTree){
|
|
var p = this;
|
|
while(p){
|
|
if(p.ownerTree){
|
|
this.ownerTree = p.ownerTree;
|
|
break;
|
|
}
|
|
p = p.parentNode;
|
|
}
|
|
}
|
|
return this.ownerTree;
|
|
},
|
|
//获得节点深度
|
|
getDepth : function(){
|
|
var depth = 0;
|
|
var p = this;
|
|
while(p.parentNode){
|
|
depth++;
|
|
p = p.parentNode;
|
|
}
|
|
return depth;
|
|
},
|
|
//private
|
|
setOwnerTree : function(tree){
|
|
if(tree != this.ownerTree){
|
|
if(this.ownerTree){
|
|
this.ownerTree.unregisterNode(this);
|
|
}
|
|
this.ownerTree = tree;
|
|
var cs = this.childNodes;
|
|
for(var i = 0, len = cs.length; i < len; i++) {
|
|
cs[i].setOwnerTree(tree);
|
|
}
|
|
if(tree){
|
|
tree.registerNode(this);
|
|
}
|
|
}
|
|
},
|
|
getPathNodes : function(){
|
|
var nodes = [];
|
|
for(var parent=this; parent!=null; parent=parent.parentNode){nodes.push(parent);};
|
|
return nodes.reverse();
|
|
},
|
|
getPath : function(attr){
|
|
attr = attr || "id";
|
|
var p = this.parentNode;
|
|
var b = [this['attributes'][attr]];
|
|
while(p){
|
|
b.unshift(p.attributes[attr]);
|
|
p = p.parentNode;
|
|
}
|
|
var sep = this.getOwnerTree().pathSeparator;
|
|
return sep + b.join(sep);
|
|
},
|
|
//冒泡(遍历所有父节点)
|
|
bubble : function(fn, scope, args){
|
|
var p = this;
|
|
while(p){
|
|
if(fn.call(scope || p, (args==null)?p:args) === false){
|
|
break;
|
|
}
|
|
p = p.parentNode;
|
|
}
|
|
},
|
|
//瀑布(遍历所有子节点)
|
|
cascade : function(fn, scope, args){
|
|
if(fn.call(scope || this, (args==null)?this:args) !== false){
|
|
var cs = this.childNodes;
|
|
for(var i = 0, len = cs.length; i < len; i++) {
|
|
cs[i].cascade(fn, scope, args);
|
|
}
|
|
}
|
|
},
|
|
//查找
|
|
findChild : function(attribute, value){
|
|
var cs = this.childNodes;
|
|
for(var i = 0, len = cs.length; i < len; i++) {
|
|
if(cs[i].attributes[attribute] == value){
|
|
return cs[i];
|
|
}
|
|
}
|
|
return null;
|
|
},
|
|
findChildBy : function(fn, scope){
|
|
var cs = this.childNodes;
|
|
for(var i = 0, len = cs.length; i < len; i++) {
|
|
if(fn.call(scope||cs[i], cs[i]) === true){
|
|
return cs[i];
|
|
}
|
|
}
|
|
return null;
|
|
},
|
|
//该方法未完全实现
|
|
sort : function(fn, scope){
|
|
var cs = this.childNodes;
|
|
var len = cs.length;
|
|
if(len > 0){
|
|
var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
|
|
cs.sort(sortFn);
|
|
for(var i = 0; i < len; i++){
|
|
var n = cs[i];
|
|
n.previousSibling = cs[i-1];
|
|
n.nextSibling = cs[i+1];
|
|
if(i == 0){
|
|
this.setFirstChild(n);
|
|
}
|
|
if(i == len-1){
|
|
this.setLastChild(n);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
contains : function(node){
|
|
var p = node.parentNode;
|
|
while(p){
|
|
if(p == this){
|
|
return true;
|
|
}
|
|
p = p.parentNode;
|
|
}
|
|
return false;
|
|
},
|
|
toString : function(){
|
|
return "[Node"+(this.id?" "+this.id:"")+"]";
|
|
}
|
|
}; |