📄 wztree.js
字号:
//@charset "utf-8"; //you could change as gb2312
(function() {if (!window.XTree) window.XTree = {n:1};})();
/**
* @function: tree[edit&&show]
* @filename: tree.js
* @lang[l] : 0:zh_CN; 1:us_EN, ...
* @style[s]: yyyy-MM-dd
* @author : liujy
* @mailto : liujy.mail (at) gmail.com
* @version : v1.0
* @create : 2008-12-12
* @modify : 2008-12-20
* @memo : node name has special char may be a problem ~
*/
var lang = 0;
var datas = '1,0,根结点;2,1,结点2;3,1,结点3;4,2,结点4;5,2,结点5;6,5,结点6;7,5,结点7;20,5,结点20;8,7,结点8;A,7,结点A;9,8,结点9;11,5,结点K;12,11,结点L;13,11,结点Q;15,2,结点U;16,5,结点K;18,15,结点H;19,18,结点X;';
function _$(s) {return document.getElementById(s);}
function _t(s) {return (s?(''+s).replace(/(^\s*)|(\s*$)/g, ""):"");}
function _b(s) {return (s?(''+s).replace(/[\u0391-\uFFE5]/g, "**").length:0);}
function _i(s) {var n=0; try {n=parseInt(_t(s),10); n=(isNaN(n)?0:n);} catch(e){ } return n;}
function _e(s) {return escape(_t(s)).replace(/\%u/gi, "!").replace(/\%/gi, "|"); }
function _u(s) {return unescape(_t(s).replace(/\|/gi, "%").replace(/!/gi, "%u")); }
function WzTree(datas)
{
w = this;
w.n = window.XTree.n++;
var vmaps = window.XTree[w.n] || {};
vmaps.x = w.n;
w.vm = vmaps;
w._xy = function(e)
{
var x = e.offsetLeft;
var y = e.offsetTop;
while(e = e.offsetParent)
{
x += e.offsetLeft;
y += e.offsetTop;
}
return [x, y];
};
w.setTreeAreaWH = function(wh)
{
if (!w.vm.t) return;
w.vm.t.style.width = wh[0];
w.vm.t.style.height = wh[1];
};
w.setTreeLocaXY = function(xy)
{
if (!w.vm.t) return;
w.vm.t.style.left = xy[0];
w.vm.t.style.top = xy[1];
};
w.setTreeLoca = function(obj) {w.setTreeLocaXY(w._xy(obj));};
w.setTreeData = function(str)
{
if (!w.vm.t) return;
var obj = w.vm.t;
w.vm = dataToMap(str||'1,0,根结点');
w.vm.t = obj;
};
w.appendNode = function(vo,mark)
{
if (!vo || _t(vo[2])=='') return ;
if (!w.vm.n) { alert("从哪里添加"); return; }
if (mark && w.vm.n==w.vm.r) { alert("根结点仅能添加下级"); return; }
var nid = _i(w.vm['mxid'])+1;
w.vm['mxid'] = nid+1;
var cid = pni(w.vm.n.id);
var pid,subs;
if (mark)
{
pid = w.vm[cid][1]; //同级
subs = _t(w.vm['s'+pid]).replace(','+cid+',',','+cid+','+nid+',');
}
else
{
pid = cid; //下级
subs = ','+nid+_t(w.vm['s'+pid]);
}
w.vm['s'+nid] = ',';
w.vm['s'+pid] = subs;
var lys = _t(w.vm[pid][3])+pid+'.';
w.vm[nid] = [nid,pid,_t(vo[2]),lys,'0','v4','v5~n'];
var len = w.vm[cid].length;
for (var i=04; i<len; i++) w.vm[nid][i]= _t(vo[i]);
w.vm["nids"] = _t(w.vm["nids"]).replace(','+cid+',',','+cid+','+nid+',');
w.show(); //re-paint tree ~
w.vm.n.style.backgroundColor = 'transparent';
w.vm.n = _$(w.n+'_'+nid);
w.vm.n.style.backgroundColor = '#66c';
};
w.modifyNode = function(vo)
{
if (!w.vm.n) { alert('修改哪个结点'); return; }
var id = pni(w.vm.n.id);
var len = w.vm[id].length;
for (var i=0; i<len; i++) w.vm[id][i]=(_t(vo[i])==''?w.vm[id][i]:_t(vo[i]));
w.vm.n.getElementsByTagName("span")[0].innerHTML = w.vm[id][2];
};
w.deleteNode = function()
{
if (!w.vm.n) { alert('删除哪个结点'); return; }
if (w.vm.r && w.vm.r==w.vm.n) { alert('根结点不能删除'); return; }
var nxt = w.vm.n.nextSibling;
var num = ((nxt && ',has,cls,'.indexOf(nxt.className+',')>0)?nxt.getElementsByTagName("span").length:0);
var msg = '确认要删除选中的结点'+(num>0?'[包括子结点]':'')+'吗?';
if (confirm(msg))
{
var cid = pni(w.vm.n.id);
var pid = w.vm[cid][1];
var subs = w.vm['s'+pid];
w.vm['s'+pid] = subs.replace(','+cid+',', ',');
w.vm['nids'] = rebuildNids(w.vm);
w.show();
}
};
w.treeToDataStr = function()
{
var arr = strToArr(w.vm['nids']);
var kids = '', len = arr.length;
for (var i=0; i<len; i++)
kids += w.vm[arr[i]][0]+','+w.vm[arr[i]][1]+','+w.vm[arr[i]][2]+';';
return kids; //as datas
};
w.treeToData = function()
{
var arr = strToArr(w.vm['nids']);
var kids = '', len = arr.length;
for (var i=0; i<len; i++) kids += _e(w.vm[arr[i]].toString())+';';
return kids;
};
w.nodeToData = function()
{
if (!w.vm.n) return '';
var arr = w.vm[pni(w.vm.n.id)];
return _e(arr.toString());
};
w.shrinkTreeNodeByIds = function(nids)
{
//if (!w.vm.t || !nids) return;
var arr = strToArr(nids);
var len = arr.length;
for (var i=0; i<len; i++)
{
var obj,els=_$(w.n+'_'+arr[i]).getElementsByTagName("span");
obj = (els?els[0].previousSibling:null);
if (obj && obj.className!='fo') obj = obj.previousSibling;
if (obj && obj.className=='fo') iconOnOff(w.vm, obj.previousSibling);
}
};
w.revsTreeNodeByIds = function(nids)
{
//if (!w.vm.t || !nids) return;
var arr = strToArr(nids);
var len = arr.length;
for (var i=0; i<len; i++)
{
var obj,els=_$(w.n+'_'+arr[i]).getElementsByTagName("span");
obj = (els?els[0].previousSibling:null);
if (obj && ',fo,fc,'.indexOf(obj.className+',')<1) obj = obj.previousSibling;
if (obj && ',fo,fc,'.indexOf(obj.className+',')>0) iconOnOff(w.vm, obj.previousSibling);
}
};
w.show = function()
{
if (!w.vm.t) return;
w.vm.t.innerHTML = mapToHtml(w.n,w.vm);
bindNodeEvent(w.vm, w.vm.t);
w.vm.r = _$(w.n+'_'+w.vm["root"]);
w.vm.t.style.display = 'block';
w.vm.x = w.n; //XXX
};
init = function()
{
if (!_$("tree"+w.n))
{
var tree = createDivElement("tree"+w.n, "pane");
document.body.appendChild(tree);
w.vm = dataToMap(datas||'1,0,根结点');
w.vm.t = tree;
}
};
init();
}
function createDivElement(id,cls)
{
var ele = document.createElement("div");
if (id&&id.length>1) ele.setAttribute('id',id);
ele.className = cls;
return ele;
}
//ok~
function rebuildNids(vals, id)
{
var id = _t(vals['root']);
var kids = ','+id+',';
var arr, waits = uniteArr(null, strToArr(vals['s'+id]));
var wl = (waits?waits.length:0);
while (wl>0)
{
id = _t(waits[--wl]);
waits.length = wl;
if (_i(id)>0) kids += id+',';
arr = strToArr(vals['s'+id]);
if (arr.length>0) waits = uniteArr(waits, arr);
wl = waits.length;
}
return kids;
}
// ok ~
function pni(id)
{
//id:km+"_"+id >> peelNodeId --> pni
var pos = (id?id.lastIndexOf('_'):0);
return (pos<1?'':id.substring(pos+1));
}
//ok~
function rowClick(vals, obj)
{
if (vals.n) vals.n.style.backgroundColor="transparent";
vals.n=obj;
obj.style.backgroundColor="#99c";//here add your self method
if (typeof(nodeRowClick)=='function') nodeRowClick([vals[pni(obj.id)],[vals['s'+pni(obj.id)]]]);
}
//ok~
function rowOver(vals, obj)
{
if (vals.n!=obj) obj.style.backgroundColor="#ccc";
}
//ok~
function rowOut(vals, obj)
{
if (vals.n!=obj) obj.style.backgroundColor="transparent";
}
//ok~
function textClick(vals, obj)
{
var id = pni(obj.parentNode.id);
if (typeof(nodeTextClick)=='function') nodeTextClick([vals[id],[vals['s'+id]]]);
}
// ok ~
function bindNodeEvent(vals, obj)
{
if (!obj) return;
var els = obj.getElementsByTagName("span");
var len = (els?els.length:0);
for (var i=0; i<len; i++)
{
var row = els[i].parentNode;
els[i].ondblclick = function() { textClick(vals, this); }
row.onmouseover = function() { rowOver(vals, this); }
row.onmouseout = function() { rowOut(vals, this); }
row.onclick = function() { rowClick(vals, this); }
var dir = els[i].previousSibling;
if (',fo,fc,'.indexOf(dir.className+',')<1) dir = dir.previousSibling;
if (',fo,fc,'.indexOf(dir.className+',')>0)
{
var hub = dir.previousSibling;
hub.onclick = function() { iconOnOff(vals, this); }
dir.ondblclick = function() { iconOnOff(vals, this.previousSibling); };
}
} //end for
if (typeof(customTreeView)=='function') customTreeView(vals.t); //XXX
}
//ok~
function isEnd(vals, lid)
{
var pid = _t(vals[lid][1]);
var subs = strToArr(_t(vals['s'+pid]));
return (lid==_t(subs[subs.length-1]));
}
//ok ~
function calcSeal(vals, id, nid)
{
var seal = '';
var pid = _i(vals[id][1]);
var kpid = _i(vals[nid][1]);
while (pid>0 && pid!=kpid)
{
seal += '</div>';
pid = _i(vals[pid][1]);
}
return seal;
}
//ok ~
function calcGrid(vals, id)
{
var grd='',als=strToArr(_t(vals[id][3]),'.'); //id~lys [1..len-1]
for (var i=1; i<als.length; i++) grd += '<div class="'+(isEnd(vals,_t(als[i]))?'grid':'grdv')+'"></div>';
return grd;
}
//ok ~
function mapToHtml(mk, vals)
{
var htm = '';
var id = _t(vals['root']);
var rec = vals[id] || [];
var subs = strToArr(vals['s'+id]);
//root htm
htm += '<div id="'+mk+'_'+id+'" class="row">';
if (subs.length<1)
{
htm += '<div class="grid"></div><div class="leaf"></div><span>'+_t(rec[2])+'</span></div>';
return htm;
}
htm += '<div class="g2"></div><div class="fo"></div><span>'+_t(rec[2])+'</span></div><div class="has">';
//node htm
var waits = uniteArr(null, subs);
var wl = (waits?waits.length:0);
while (wl>0)
{
id = _t(waits[--wl]);
waits.length = wl;
rec = vals[id] || []; //open pid name lys ...
var tail = isEnd(vals,id);
subs = strToArr(vals['s'+id]);
htm += '<div id="'+mk+'_'+id+'" class="row">';
if (subs.length<1)
{
htm += '<div class="grid"></div>' + calcGrid(vals, id);
htm += '<div class="'+(tail?'g3':'gt')+'"></div><div class="leaf"></div><span>'+_t(rec[2])+"-"+_t(rec[0])+'</span></div>';
if (tail || wl<1) htm += '</div>';
htm += ((!tail || wl<1)?'':calcSeal(vals, vals[id][1], waits[wl-1]));
}
else
{
waits = uniteArr(waits, subs);
htm += '<div class="grid"></div>' + calcGrid(vals, id);
htm += '<div class="'+(tail?'g5':'g7')+'"></div><div class="fo"></div><span>'+_t(rec[2])+"-"+_t(rec[0])+'</span></div><div class="has">';
}
wl = waits.length;
}
return htm;
}
function iconOnOff(vals,obj)
{
var cls = obj.className;
if (',g1,g2,g4,g5,g7,g8,'.indexOf(cls+',')<1) return ;
vals[pni(obj.parentNode.id)][4] = (obj.nextSibling.className=='fo'?'1':'0');
if (cls=='g7')
{
obj.className = 'g8';
obj.nextSibling.className = 'fc';
obj.parentNode.nextSibling.className = 'cls';
}
else if (cls=='g8')
{
obj.className = 'g7';
obj.nextSibling.className = 'fo';
obj.parentNode.nextSibling.className = 'has';
}
else if (cls=='g5')
{
obj.className = 'g4';
obj.nextSibling.className = 'fc';
obj.parentNode.nextSibling.className = 'cls';
}
else if (cls=='g4')
{
obj.className = 'g5';
obj.nextSibling.className = 'fo';
obj.parentNode.nextSibling.className = 'has';
}
else if (cls=='g2')
{
obj.className = 'g1';
obj.nextSibling.className = 'fc';
obj.parentNode.nextSibling.className = 'cls';
}
else if (cls=='g1')
{
obj.className = 'g2';
obj.nextSibling.className = 'fo';
obj.parentNode.nextSibling.className = 'has';
}
}
//ok
function dataToMap(str)
{
var vals={};
var maps={};
var id=0,rid=0,pid=0;
var arr,recs=str.split(";");
var max=0,ids=',',len=recs.length;
for (var i=0; i<len; i++)
{
if (_b(recs[i])<3) continue;
arr = _t(recs[i]).split(',');
id = _i(arr[0]); //here attention ~ isNaN(id)
if (id<1 || ids.indexOf(','+id+',')>-1 || arr.length<3) continue;
max = (max<id?id:max);
ids += id+',';
pid = _i(arr[1]);
vals[''+id] = [_t(arr[0]),_t(arr[1]),_t(arr[2]),null,'0','v4','v5~n']; //arr[4~n]
var subs = vals['s'+pid] || ',';
if (subs.indexOf(','+id+',')<0) vals['s'+pid] = subs+id+',';
maps[''+id] = ''+pid;
}
vals["nids"] = ids;
vals["mxid"] = max;
vals["root"] = _t(vals['s0']).split(',')[1];
arr = ids.split(',');
len = arr.length-1;
for (var i=1; i<len; i++)
{
id = _i(arr[i]);
pid = _i(maps[''+id]);
var lys='.',test=true;
while (test && pid>0)
{
if (vals[''+id][3] || lys.indexOf('.'+pid+'.')>-1) test = false;
lys = (vals[''+id][3]?vals[''+id][3]+lys:'.'+pid+lys);
if (test) pid = _i(maps[''+pid]);
}
vals[''+id][3] = lys;
}
maps = null;
return vals;
}
//ok~
function strToArrLen(str,ch)
{
var s = (str?_t(str):'');
var c = (ch?_t(ch):',');
var p = s.indexOf(c);
if (p==0) s = s.substring(1);
p = s.lastIndexOf(c);
if (p==s.length-1) s = s.substring(0, p);
if (s=='') return [];
return s.split(c).length;
}
//ok~
function strToArr(str,ch)
{
var s = (str?_t(str):'');
var c = (ch?_t(ch):',');
var p = s.indexOf(c);
if (p==0) s = s.substring(1);
p = s.lastIndexOf(c);
if (p==s.length-1) s = s.substring(0, p);
if (s=='') return [];
return s.split(c);
}
//ok~
function uniteArr(arr1, arr2)
{
var arr = (arr1?arr1:[]);
var len = arr2.length-1;
if (!arr2 || len<0) return arr1;
for (var i=len; i>-1; i--) arr[arr.length] = arr2[i];
return arr;
}
//**几种展开状态**
//1.仅根展开
//2.全部展开
//3.某几项展开
//4.仅根合并
//5.除根外全部合并
//6.某几项合并
//**几种编辑状态**
//1.新增[添加同级,添加下级]
//2.修改[名称]
//3.删除[是否允许删除有子结点的点,提供全部可删除]
//4.保存
//考虑: dataToHTML时用字串,减少重整JS数组的时间,或者依次输出
//规定:父结点为零的是根结点,并且只能有一个,避免loop引用 用数组扩展性好一些
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -