/** * tree - jQuery EasyUI * * Licensed under the GPL: * http://www.gnu.org/licenses/gpl.txt * * Copyright 2010 stworthy [ stworthy@gmail.com ] * * Node is a javascript object which contains following properties: * 1 id: An identity value bind to the node. * 2 text: Text to be showed. * 3 checked: Indicate whether the node is checked selected. * 3 attributes: Custom attributes bind to the node. * 4 target: Target DOM object. */ /** * 首先要明白,tree控件包装的理念,tree包装结构是: * 节点(<li><div></div><ul>其他节点(li)</ul>) * 所以一个节点就是一个节点li,一个li会有两个内容,第一个是由div本节点包装的基本信息,另一个是由ul子节点标签包装信息 * 树级别之间的缩进是用一个个小方格划分的,每个节点的高度是18px,每个小方格的尺寸是16*18 */ (($) { /** * wrap the <ul> tag as a tree and then return it. * 包装tree外层标签,默认tree一个外层标签ul,其实不使用tree不依赖控制ul */ wrapTree(target) { //target为dom对象 tree = $(target);
//首先给外层标签添加类tree tree.addClass();
//包装这个最外层的dom对象,并说明深度为0 wrapNode(tree, 0);
/** * 包装指定的节点,如果depth为0表示包装的是一个树节点的外层,这个ul很像是节点的ul标签 */ wrapNode(ul, depth) {
//找到这个最外层节点的下级li标签,如果depth为0那么就是在寻找所有的根节点 $(, ul).each(() {
//如果找到了根节点,就直接向这个根节点里面加入一个div标签(这个标签封装了这个节点的信息) node = $().($());
//找到这个根节点下的下级span标签,将这些span标签添加到新创建的div标签后获取其内容 text = $(, ).addClass().(node).();
//给这个节点(div标签)绑定'tree-node'数据,绑定的数据中记录了这个节点的值 $.data(node[0], , {
: text
});
//找到这个根节点下的所有ul标签 subTree = $(, );
(subTree.) {
//如果找到了ul标签,那么就认为这个节点有子节点,然后就把文件打开的span标签添加到这个节点的最前方 $().(node);
//把这个节点的展开信息添加到这个节点的最前方 $().(node);
//递归调用,将这个ul标签传递进去,并说明深度加了1 wrapNode(subTree, depth + 1);
} {
$().(node);
$().(node);
}
//最后处理由于深度问题引起的行缩进问题 (i = 0; i < depth; i++) {
$().(node);
}
});
}
tree;
}
expandNode(target, node) {
//展开节点 opts = $.data(target, ).;
hit = $(, node);
(hit.== 0) ; // is a leaf node (hit.hasClass()) {
hit.removeClass().addClass();
hit.().addClass();
ul = $(node).();
(ul.) {
(opts.) {
ul.();
} {
ul.(, );
}
} {
id = $.data($(node)[0], ).;
subul = $().(node);
request(target, subul, {
: id}); // request children nodes data }
}
}
collapseNode(target, node) {
//折叠节点 opts = $.data(target, ).;
hit = $(, node);
(hit.== 0) ; // is a leaf node (hit.hasClass()) {
hit.removeClass().addClass();
hit.().removeClass();
(opts.) {
$(node).().();
} {
$(node).().(, );
}
}
}
toggleNode(target, node) {
//展开或折叠节点 hit = $(, node);
//如果没有加减号就代表是子节点 (hit.== 0) ; // is a leaf node (hit.hasClass()) {
//如果是展开的就关闭子节点 collapseNode(target, node);
} {
//如果是折叠的就展开子节点 expandNode(target, node);
}
}
/** * 给树控件绑定事件,包括节点的鼠标划入划出,单击、双击,奇怪的是这里没有看到右击事件 * target */ bindTreeEvents(target) {
opts = $.data(target, ).;
tree = $.data(target, ).tree;
//给整体节点绑定单击、双击、鼠标划入划出事件,注意绑定事件前先把同类型的事件移除掉,注意这些绑定的事件的返回值大部分都是false,这是要阻止事件冒泡 $(, tree).unbind().bind(, () {
//双击树节点,从源代码上看,单击和双击都是选中节点,然后再去调用用户绑定的方法,其他的并没有什么不同 $(, tree).removeClass();
$().addClass();
(opts.onDblClick) {
target = ; // the target HTML DIV element data = $.data(, );
opts.onDblClick.call(, {
: data.,
: data.,
: data.,
: target
});
}
}).bind(, () {
//点击树节点,代表选中该节点 $(, tree).removeClass();
$().addClass();
(opts.onClick) {
target = ; // the target HTML DIV element data = $.data(, );
opts.onClick.call(, {
: data.,
: data.,
: data.,
: target
});
}
// return false; }).bind(, () {
//鼠标滑进去节点(说的是div标签,不是li标签) $().addClass();
;
}).bind(, () {
//鼠标滑出来 $().removeClass();
;
});
//给节点的加减号绑定事件 $(, tree).unbind().bind(, () {
//单击加减号,切换展开或折叠效果 node = $().();
toggleNode(target, node);
;
}).bind(, () {
($().hasClass()) {
$().addClass();
} {
$().addClass();
}
}).bind(, () {
($().hasClass()) {
$().removeClass();
} {
$().removeClass();
}
});
//给复选框绑定事件 $(, tree).unbind().bind(, () {
($().hasClass()) {
$().removeClass().addClass();
} ($().hasClass()) {
$().removeClass().addClass();
} ($().hasClass()) {
$().removeClass().addClass();
}
//设置父节点是否选中 setParentCheckbox($().());
//设置子节点是否选中 setChildCheckbox($().());
;
});
setChildCheckbox(node) {
//选中子节点 childck = node.().find();
childck.removeClass()
(node.find().hasClass()) {
childck.addClass();
} {
childck.addClass();
}
}
setParentCheckbox(node) {
//设置父节点是否展开,需要递归调用 pnode = getParentNode(target, node[0]);
(pnode) {
ck = $(pnode.).find();
ck.removeClass();
(isAllSelected(node)) {
ck.addClass();
} (isAllNull(node)) {
ck.addClass();
} {
ck.addClass();
}
setParentCheckbox($(pnode.));
}
//是否全部被选中 isAllSelected(n) {
ck = n.find();
(ck.hasClass() || ck.hasClass()) ;
b = ;
n.().siblings().each(() {
(!$().find().hasClass()) {
b = ;
}
});
b;
}
isAllNull(n) {
ck = n.find();
(ck.hasClass() || ck.hasClass()) ;
b = ;
n.().siblings().each(() {
(!$().find().hasClass()) {
b = ;
}
});
b;
}
}
}
//加载数据 loadData(target, ul, data) {
// clear the tree when loading to the root //加载之前,直接将树的根节点的html标签全部清空 (target == ul) {
$(target).empty();
}
opts = $.data(target, ).;
appendNodes(ul, children, depth) {
(i = 0; i < children.; i++) {
//首先给每一个节点先创建li标签 li = $().(ul);
item = children[i];
// the node state has only 'open' or 'closed' attribute (item.!= && item.!= ) {
item.= ;
}
//给每个节点创建主要展示区div标签,并设置node-id属性值 node = $().(li);
node.attr(, item.);
//存储这个节点绑定的数据模型,方面后面事件的调用 // store node attributes $.data(node[0], , {
: item.,
: item.,
: item.});
//这里先把节点显示的文本信息添加进去,其他的内容"加减号"、"复选框"、"文件夹"后面根据条件插入到前面去 $().(item.).(node);
//如果设置了复选框,就将现将复选框插入到最左 (opts.) {
(item.) {
$().(node);
} {
$().(node);
}
}
//如果这个节点有子节点,就添加子节点的容器ul标签 (item.) {
subul = $().(li);
//如果当前节点是展开的,就将文件夹打开的图标和减号添加到树节点的展示区 (item.== ) {
$().addClass(item.).(node);
$().(node);
} {
$().addClass(item.).(node);
$().(node);
subul.(, );
}
//如果存在子节点就递归调用 appendNodes(subul, item., depth + 1);
} {
//如果没有子节点 (item.== ) {
$().addClass(item.).(node);
$().(node);
} {
// $('<input type="checkbox" style="vertical-align:bottom;margin:0;height:18px;">').prependTo(node); $().addClass(item.).(node);
$().(node);
}
}
(j = 0; j < depth; j++) {
$().(node);
}
}
}
depth = $(ul).().find().;
appendNodes(ul, data, depth);
}
/** * request remote data and then load nodes in the <ul> tag. */ request(target, ul, param) {
//首