1 /**
  2  * @fileOverview delegate all draggable nodes to one draggable object
  3  * @author yiminghe@gmail.com
  4  */
  5 KISSY.add("dd/draggable-delegate", function (S, DDM, Draggable, DOM, Node) {
  6 
  7     var PREFIX_CLS = DDM.PREFIX_CLS;
  8 
  9     /**
 10      * @name DraggableDelegate
 11      * @extends DD.Draggable
 12      * @memberOf DD
 13      * @class
 14      * drag multiple nodes under a container element
 15      * using only one draggable instance as a delegate.
 16      */
 17     function DraggableDelegate() {
 18         DraggableDelegate.superclass.constructor.apply(this, arguments);
 19     }
 20 
 21 
 22     /**
 23      * 父容器监听 mousedown,找到合适的拖动 handlers 以及拖动节点
 24      * @param ev
 25      */
 26     function handleMouseDown(ev) {
 27         var self = this,
 28             handler,
 29             node;
 30 
 31         if (!self._checkMouseDown(ev)) {
 32             return;
 33         }
 34 
 35         var handlers = self.get("handlers"),
 36             target = new Node(ev.target);
 37 
 38         // 不需要像 Draggble 一样,判断 target 是否在 handler 内
 39         // 委托时,直接从 target 开始往上找 handler
 40         if (handlers.length) {
 41             handler = self._getHandler(target);
 42         } else {
 43             handler = target;
 44         }
 45 
 46         if (handler) {
 47             node = self._getNode(handler);
 48         }
 49 
 50         // can not find handler or can not find matched node from handler
 51         // just return !
 52         if (!node) {
 53             return;
 54         }
 55 
 56         self.__set("activeHandler", handler);
 57 
 58         // 找到 handler 确定 委托的 node ,就算成功了
 59         self.__set("node", node);
 60         self.__set("dragNode", node);
 61         self._prepare(ev);
 62     }
 63 
 64     S.extend(DraggableDelegate, Draggable, {
 65 
 66             _uiSetDisabledChange:function (d) {
 67                 this.get("container")[d ? 'addClass' :
 68                     'removeClass'](PREFIX_CLS + '-disabled');
 69             },
 70 
 71             _init:function () {
 72                 var self = this,
 73                     node = self.get('container');
 74                 node.on('mousedown', handleMouseDown, self)
 75                     .on('dragstart', self._fixDragStart);
 76             },
 77 
 78             /**
 79              * 得到适合 handler,从这里开始启动拖放,对于 handlers 选择器字符串数组
 80              * @param target
 81              */
 82             _getHandler:function (target) {
 83                 var self = this,
 84                     ret = undefined,
 85                     node = self.get("container"),
 86                     handlers = self.get('handlers');
 87                 while (target && target[0] !== node[0]) {
 88                     S.each(handlers, function (h) {
 89                         if (DOM.test(target[0], h)) {
 90                             ret = target;
 91                             return false;
 92                         }
 93                     });
 94                     if (ret) {
 95                         break;
 96                     }
 97                     target = target.parent();
 98                 }
 99                 return ret;
100             },
101 
102             /**
103              * 找到真正应该移动的节点,对应 selector 属性选择器字符串
104              * @param h
105              */
106             _getNode:function (h) {
107                 return h.closest(this.get("selector"), this.get("container"));
108             },
109 
110             destroy:function () {
111                 var self = this;
112                 self.get("container")
113                     .detach('mousedown',
114                     handleMouseDown,
115                     self)
116                     .detach('dragstart', self._fixDragStart);
117                 self.detach();
118             }
119         },
120         {
121             ATTRS:/**
122              * @lends DD.DraggableDelegate#
123              */
124             {
125                 /**
126                  * a selector query to get the container to listen for mousedown events on.
127                  * All "draggable selector" should be a child of this container
128                  * @type {HTMLElement|String}
129                  */
130                 container:{
131                     setter:function (v) {
132                         return Node.one(v);
133                     }
134                 },
135 
136                 /**
137                  * a selector query to get the children of container to make draggable elements from.
138                  * usually as for tag.cls.
139                  * @type {String}
140                  */
141                 selector:{
142                 },
143 
144                 /**
145                  * handlers to initiate drag operation.
146                  * can only be as form of tag.cls.
147                  * default:[selector]
148                  * @type {String[]}
149                  **/
150                 handlers:{
151                     value:[],
152                     // 覆盖父类的 getter ,这里 normalize 成节点
153                     getter:0
154                 }
155             }
156         });
157 
158     return DraggableDelegate;
159 }, {
160     requires:['./ddm', './draggable', 'dom', 'node']
161 });