1 /** 2 * @fileOverview abstraction of tree node ,root and other node will extend it 3 * @author yiminghe@gmail.com 4 */ 5 KISSY.add("tree/basenode", function (S, Node, Component, BaseNodeRender) { 6 var $ = Node.all, 7 KeyCodes = Node.KeyCodes; 8 9 10 /** 11 * @class 12 * Tree Node. 13 * xclass: 'tree-item'. 14 * @name Node 15 * @memberOf Tree 16 * @extends Component.Controller 17 */ 18 var BaseNode = Component.Controller.extend( 19 /* 20 * 可多继承从某个子节点开始装饰儿子组件 21 */ 22 [Component.DecorateChild], 23 /** 24 * @lends Tree.Node# 25 */ 26 { 27 _keyNav:function (e) { 28 var self = this, 29 processed = true, 30 n, 31 children = self.get("children"), 32 keyCode = e.keyCode; 33 34 // 顺序统统为前序遍历顺序 35 switch (keyCode) { 36 // home 37 // 移到树的顶层节点 38 case KeyCodes.HOME: 39 n = self.get("tree"); 40 break; 41 42 // end 43 // 移到最后一个可视节点 44 case KeyCodes.END: 45 n = self.get("tree").getLastVisibleDescendant(); 46 break; 47 48 // 上 49 // 当前节点的上一个兄弟节点的最后一个可显示节点 50 case KeyCodes.UP: 51 n = self.getPreviousVisibleNode(); 52 break; 53 54 // 下 55 // 当前节点的下一个可显示节点 56 case KeyCodes.DOWN: 57 n = self.getNextVisibleNode(); 58 break; 59 60 // 左 61 // 选择父节点或 collapse 当前节点 62 case KeyCodes.LEFT: 63 if (self.get("expanded") && (children.length || self.get("isLeaf") === false)) { 64 self.set("expanded", false); 65 } else { 66 n = self.get("parent"); 67 } 68 break; 69 70 // 右 71 // expand 当前节点 72 case KeyCodes.RIGHT: 73 if (children.length || self.get("isLeaf") === false) { 74 if (!self.get("expanded")) { 75 self.set("expanded", true); 76 } else { 77 children[0].select(); 78 } 79 } 80 break; 81 82 default: 83 processed = false; 84 break; 85 86 } 87 if (n) { 88 n.select(); 89 } 90 return processed; 91 }, 92 93 getLastVisibleDescendant:function () { 94 var self = this, children = self.get("children"); 95 // 没有展开或者根本没有儿子节点,可视的只有自己 96 if (!self.get("expanded") || !children.length) { 97 return self; 98 } 99 // 可视的最后一个子孙 100 return children[children.length - 1].getLastVisibleDescendant(); 101 }, 102 103 getNextVisibleNode:function () { 104 var self = this, 105 children = self.get("children"), 106 parent = self.get("parent"); 107 if (self.get("expanded") && children.length) { 108 return children[0]; 109 } 110 // 没有展开或者根本没有儿子节点 111 // 深度遍历的下一个 112 var n = self.next(); 113 while (parent && !n) { 114 n = parent.next(); 115 parent = parent.get("parent"); 116 } 117 return n; 118 }, 119 120 getPreviousVisibleNode:function () { 121 var self = this, prev = self.prev(); 122 if (!prev) { 123 prev = self.get("parent"); 124 } else { 125 prev = prev.getLastVisibleDescendant(); 126 } 127 return prev; 128 }, 129 130 next:function () { 131 var self = this, parent = self.get("parent"); 132 if (!parent) { 133 return null; 134 } 135 var siblings = parent.get('children'); 136 var index = S.indexOf(self, siblings); 137 if (index == siblings.length - 1) { 138 return null; 139 } 140 return siblings[index + 1]; 141 }, 142 143 prev:function () { 144 var self = this, parent = self.get("parent"); 145 if (!parent) { 146 return null; 147 } 148 var siblings = parent.get('children'); 149 var index = S.indexOf(self, siblings); 150 if (index === 0) { 151 return null; 152 } 153 return siblings[index - 1]; 154 }, 155 156 /** 157 * Select current tree node. 158 */ 159 select:function () { 160 var self = this; 161 self.get("tree").set("selectedItem", self); 162 }, 163 164 performActionInternal:function (e) { 165 var self = this, 166 target = $(e.target), 167 tree = self.get("tree"), 168 view = self.get("view"); 169 tree.get("el")[0].focus(); 170 if (target.equals(view.get("expandIconEl"))) { 171 // 忽略双击 172 if (e.type != 'dblclick') { 173 self.set("expanded", !self.get("expanded")); 174 } 175 } else if (e.type == 'dblclick') { 176 self.set("expanded", !self.get("expanded")); 177 } 178 else { 179 self.select(); 180 tree.fire("click", { 181 target:self 182 }); 183 } 184 }, 185 186 // 默认 addChild,这里需要设置 tree 属性 187 decorateChildrenInternal:function (ui, c) { 188 var self = this; 189 self.addChild(new ui({ 190 srcNode:c, 191 tree:self.get("tree"), 192 prefixCls:self.get("prefixCls") 193 })); 194 }, 195 196 addChild:function (c) { 197 var self = this, tree = self.get("tree"); 198 c.__set("tree", tree); 199 c.__set("depth", self.get('depth') + 1); 200 BaseNode.superclass.addChild.call(self, c); 201 self._updateRecursive(); 202 tree._register(c); 203 S.each(c.get("children"), function (cc) { 204 tree._register(cc); 205 }); 206 }, 207 208 /* 209 每次添加/删除节点,都检查自己以及自己子孙 class 210 每次 expand/collapse,都检查 211 */ 212 _computeClass:function (cause) { 213 var self = this, view = self.get("view"); 214 view._computeClass(self.get('children'), self.get("parent"), cause); 215 }, 216 217 _updateRecursive:function () { 218 var self = this, 219 len = self.get('children').length; 220 self._computeClass("_updateRecursive"); 221 S.each(self.get("children"), function (c, index) { 222 c._computeClass("_updateRecursive_children"); 223 c.get("view").set("ariaPosInSet", index + 1); 224 c.get("view").set("ariaSize", len); 225 }); 226 }, 227 228 removeChild:function (c) { 229 var self = this, 230 tree = self.get("tree"); 231 tree._unRegister(c); 232 S.each(c.get("children"), function (cc) { 233 tree._unRegister(cc); 234 }); 235 BaseNode.superclass.removeChild.apply(self, S.makeArray(arguments)); 236 self._updateRecursive(); 237 }, 238 239 _uiSetExpanded:function (v) { 240 var self = this, 241 tree = self.get("tree"); 242 self._computeClass("expanded-" + v); 243 if (v) { 244 tree.fire("expand", { 245 target:self 246 }); 247 } else { 248 tree.fire("collapse", { 249 target:self 250 }); 251 } 252 }, 253 254 /** 255 * Expand all descend nodes of current node 256 */ 257 expandAll:function () { 258 var self = this; 259 self.set("expanded", true); 260 S.each(self.get("children"), function (c) { 261 c.expandAll(); 262 }); 263 }, 264 265 /** 266 * Collapse all descend nodes of current node 267 */ 268 collapseAll:function () { 269 var self = this; 270 self.set("expanded", false); 271 S.each(self.get("children"), function (c) { 272 c.collapseAll(); 273 }); 274 } 275 }, 276 277 { 278 ATTRS:/** 279 * @lends Tree.Node# 280 */ 281 { 282 xrender:{ 283 value:BaseNodeRender 284 }, 285 // 事件代理 286 handleMouseEvents:{ 287 value:false 288 }, 289 290 /** 291 * Only For Config. 292 * Whether to force current tree node as a leaf. 293 * Default:false. 294 * It will change as children are added. 295 * @type Boolean 296 */ 297 isLeaf:{ 298 view:1 299 }, 300 301 /** 302 * Element for expand icon. 303 * @type {NodeList} 304 */ 305 expandIconEl:{ 306 view:1 307 }, 308 309 /** 310 * Element for icon. 311 * @type {NodeList} 312 */ 313 iconEl:{ 314 view:1 315 }, 316 317 /** 318 * Whether current tree node is selected. 319 * @type Boolean 320 */ 321 selected:{ 322 view:1 323 }, 324 325 /** 326 * Whether current tree node is expanded. 327 */ 328 expanded:{ 329 view:1 330 }, 331 332 /** 333 * Html title for current tree node. 334 * @type String 335 */ 336 tooltip:{ 337 view:1 338 }, 339 340 /** 341 * Tree instance current tree node belongs to. 342 * @type Tree 343 */ 344 tree:{ 345 }, 346 347 /** 348 * depth of node. 349 * @type Number 350 */ 351 depth:{ 352 view:1 353 }, 354 focusable:{ 355 value:false 356 }, 357 decorateChildCls:{ 358 value:"ks-tree-children" 359 } 360 } 361 }, { 362 xclass:'tree-item', 363 priority:10 364 }); 365 366 return BaseNode; 367 368 }, { 369 requires:['node', 'component', './basenodeRender'] 370 });