1 /**
  2  * @fileOverview checkable tree node
  3  * @author yiminghe@gmail.com
  4  */
  5 KISSY.add("tree/checknode", function (S, Node, BaseNode, CheckNodeRender) {
  6     var $ = Node.all,
  7         PARTIAL_CHECK = 2,
  8         CHECK = 1,
  9         EMPTY = 0;
 10 
 11     /**
 12      * @name CheckNode
 13      * @memberOf Tree
 14      * @class
 15      * Checked tree node.
 16      * xclass: 'tree-check-item'.
 17      * @extends Tree.Node
 18      */
 19     var CheckNode = BaseNode.extend(
 20         /**
 21          * @lends Tree.CheckNode#
 22          */
 23         {
 24 
 25             /**
 26              * See {@link Tree.Node#expandAll}
 27              */
 28             expandAll:function () {
 29                 return CheckNode.superclass.expandAll.apply(this, arguments);
 30             },
 31 
 32             performActionInternal:function (e) {
 33                 var self = this;
 34                 // 需要通知 tree 获得焦点
 35                 self.get("tree").get("el")[0].focus();
 36                 var target = $(e.target),
 37                     view = self.get("view"),
 38                     tree = self.get("tree");
 39 
 40                 if (e.type == "dblclick") {
 41                     // 双击在 +- 号上无效
 42                     if (target.equals(view.get("expandIconEl"))) {
 43                         return;
 44                     }
 45                     // 双击在 checkbox 上无效
 46                     if (target.equals(view.get("checkEl"))) {
 47                         return;
 48                     }
 49                     // 双击在字或者图标上,切换 expand 装tai
 50                     self.set("expanded", !self.get("expanded"));
 51                 }
 52 
 53                 // 点击在 +- 号,切换状态
 54                 if (target.equals(view.get("expandIconEl"))) {
 55                     self.set("expanded", !self.get("expanded"));
 56                     return;
 57                 }
 58 
 59                 // 单击任何其他地方都切换 check 状态
 60                 var checkState = self.get("checkState");
 61                 if (checkState == CHECK) {
 62                     checkState = EMPTY;
 63                 } else {
 64                     checkState = CHECK;
 65                 }
 66                 self.set("checkState", checkState);
 67                 tree.fire("click", {
 68                     target:self
 69                 });
 70             },
 71 
 72             _uiSetCheckState:function (s) {
 73                 var self = this;
 74                 if (s == CHECK || s == EMPTY) {
 75                     S.each(self.get("children"), function (c) {
 76                         c.set("checkState", s);
 77                     });
 78                 }
 79                 // 每次状态变化都通知 parent 沿链检查,一层层向上通知
 80                 // 效率不高,但是结构清晰
 81                 var parent = self.get("parent");
 82                 if (parent) {
 83                     var checkCount = 0;
 84                     var cs = parent.get("children");
 85                     for (var i = 0; i < cs.length; i++) {
 86                         var c = cs[i], cState = c.get("checkState");
 87                         // 一个是部分选,父亲必定是部分选,立即结束
 88                         if (cState == PARTIAL_CHECK) {
 89                             parent.set("checkState", PARTIAL_CHECK);
 90                             return;
 91                         } else if (cState == CHECK) {
 92                             checkCount++;
 93                         }
 94                     }
 95 
 96                     // 儿子全都选了,父亲也全选
 97                     if (checkCount == cs.length) {
 98                         parent.set("checkState", CHECK);
 99                     }
100                     // 儿子都没选,父亲也不选
101                     else if (checkCount === 0) {
102                         parent.set("checkState", EMPTY);
103                     }
104                     // 有的儿子选了,有的没选,父亲部分选
105                     else {
106                         parent.set("checkState", PARTIAL_CHECK);
107                     }
108                 }
109             }
110         }, {
111             ATTRS:/**
112              * @lends Tree.CheckNode#
113              */
114             {
115 
116                 /**
117                  * Enums for check states.
118                  * CheckNode.PARTIAL_CHECK: checked partly.
119                  * CheckNode.CHECK: checked completely.
120                  * CheckNode.EMPTY: not checked.
121                  * @type Number
122                  */
123                 checkState:{
124                     view:1
125                 },
126 
127                 xrender:{
128                     value:CheckNodeRender
129                 }
130             }
131         }, {
132             xclass:"tree-check-item",
133             priority:20
134         });
135 
136     S.mix(CheckNode,
137         /**
138          * @lends Tree.CheckNode
139          */
140         {
141             /**
142              * checked partly.
143              */
144             PARTIAL_CHECK:PARTIAL_CHECK,
145             /**
146              * checked completely.
147              */
148             CHECK:CHECK,
149             /**
150              * not checked at all.
151              */
152             EMPTY:EMPTY
153         })
154 
155     return CheckNode;
156 }, {
157     requires:['node', './basenode', './checknodeRender']
158 });