1 /**
  2  * @fileOverview generate proxy drag object,
  3  * @author yiminghe@gmail.com
  4  */
  5 KISSY.add("dd/proxy", function (S, Node, Base, DDM) {
  6     var DESTRUCTOR_ID = "__proxy_destructors",
  7         stamp = S.stamp,
  8         MARKER = S.guid("__dd_proxy");
  9 
 10     /**
 11      * @name Proxy
 12      * @memberOf DD
 13      * @extends Base
 14      * @class
 15      * provide abilities for draggable tp create a proxy drag node,
 16      * instead of dragging the original node.
 17      */
 18     function Proxy() {
 19         var self = this;
 20         Proxy.superclass.constructor.apply(self, arguments);
 21         self[DESTRUCTOR_ID] = {};
 22     }
 23 
 24     Proxy.ATTRS =
 25     /**
 26      * @lends DD.Proxy#
 27      */
 28     {
 29         /**
 30          * how to get the proxy node. default:clone the node itself deeply.
 31          * @type {Function}
 32          */
 33         node:{
 34             value:function (drag) {
 35                 return new Node(drag.get("node").clone(true));
 36             }
 37         },
 38         /**
 39          * destroy the proxy node at the end of this drag. default:false
 40          * @type {Boolean}
 41          */
 42         destroyOnEnd:{
 43             value:false
 44         },
 45 
 46         /**
 47          * move the original node at the end of the drag. default:true
 48          * @type {Boolean}
 49          */
 50         moveOnEnd:{
 51             value:true
 52         },
 53 
 54         /**
 55          * Current proxy node.
 56          * @type {NodeList}
 57          */
 58         proxyNode:{
 59 
 60         }
 61     };
 62 
 63     S.extend(Proxy, Base,
 64         /**
 65          * @lends DD.Proxy#
 66          */
 67         {
 68             /**
 69              * make this draggable object can be proxied.
 70              * @param {DD.Draggable} drag
 71              */
 72             attachDrag:function (drag) {
 73 
 74                 var self = this,
 75                     tag = stamp(drag, 1, MARKER);
 76 
 77                 if (tag && self[DESTRUCTOR_ID][tag]) {
 78                     return;
 79                 }
 80 
 81                 function start() {
 82                     var node = self.get("node"),
 83                         dragNode = drag.get("node");
 84                     // cache proxy node
 85                     if (!self.get("proxyNode")) {
 86                         if (S.isFunction(node)) {
 87                             node = node(drag);
 88                             node.addClass("ks-dd-proxy");
 89                             node.css("position", "absolute");
 90                             self.set("proxyNode", node);
 91                         }
 92                     } else {
 93                         node = self.get("proxyNode");
 94                     }
 95                     node.show();
 96                     dragNode.parent().append(node);
 97                     DDM.cacheWH(node);
 98                     node.offset(dragNode.offset());
 99                     drag.__set("dragNode", dragNode);
100                     drag.__set("node", node);
101                 }
102 
103                 function end() {
104                     var node = self.get("proxyNode");
105                     if (self.get("moveOnEnd")) {
106                         drag.get("dragNode").offset(node.offset());
107                     }
108                     if (self.get("destroyOnEnd")) {
109                         node.remove();
110                         self.set("proxyNode", 0);
111                     } else {
112                         node.hide();
113                     }
114                     drag.__set("node", drag.get("dragNode"));
115                 }
116 
117                 drag.on("dragstart", start);
118                 drag.on("dragend", end);
119 
120                 tag = stamp(drag, 0, MARKER);
121 
122                 self[DESTRUCTOR_ID][tag] = {
123                     drag:drag,
124                     fn:function () {
125                         drag.detach("dragstart", start);
126                         drag.detach("dragend", end);
127                     }
128                 };
129             },
130             /**
131              * make this draggable object unproxied
132              * @param {DD.Draggable} drag
133              */
134             detachDrag:function (drag) {
135                 var self = this,
136                     tag = stamp(drag, 1, MARKER),
137                     destructors = self[DESTRUCTOR_ID];
138                 if (tag && destructors[tag]) {
139                     destructors[tag].fn();
140                     delete destructors[tag];
141                 }
142             },
143 
144             /**
145              * make all draggable object associated with this proxy object unproxied
146              */
147             destroy:function () {
148                 var self = this,
149                     node = self.get("node"),
150                     destructors = self[DESTRUCTOR_ID];
151                 if (node && !S.isFunction(node)) {
152                     node.remove();
153                 }
154                 for (var d in destructors) {
155                     this.detachDrag(destructors[d].drag);
156                 }
157             }
158         });
159 
160     // for compatibility
161     var ProxyPrototype = Proxy.prototype;
162     ProxyPrototype.attach = ProxyPrototype.attachDrag;
163     ProxyPrototype.unAttach = ProxyPrototype.detachDrag;
164 
165     return Proxy;
166 }, {
167     requires:['node', 'base', './ddm']
168 });