1 /**
  2  * @fileOverview resizable support for kissy
  3  * @author yiminghe@gmail.com
  4  */
  5 KISSY.add("resizable", function (S, Node, Base, D, undefined) {
  6 
  7     var $ = Node.all,
  8         i,
  9         j,
 10         Draggable = D.Draggable,
 11         CLS_PREFIX = "ks-resizable-handler",
 12         horizontal = ["l", "r"],
 13         vertical = ["t", "b"],
 14         hcNormal = {
 15             t:function (minW, maxW, minH, maxH, ot, ol, ow, oh, diffT) {
 16                 var h = getBoundValue(minH, maxH, oh - diffT),
 17                     t = ot + oh - h;
 18                 return [0, h, t, 0]
 19             },
 20             b:function (minW, maxW, minH, maxH, ot, ol, ow, oh, diffT) {
 21                 var h = getBoundValue(minH, maxH, oh + diffT);
 22                 return [0, h, 0, 0];
 23             },
 24             r:function (minW, maxW, minH, maxH, ot, ol, ow, oh, diffT, diffL) {
 25                 var w = getBoundValue(minW, maxW, ow + diffL);
 26                 return [w, 0, 0, 0];
 27             },
 28             l:function (minW, maxW, minH, maxH, ot, ol, ow, oh, diffT, diffL) {
 29                 var w = getBoundValue(minW, maxW, ow - diffL),
 30                     l = ol + ow - w;
 31                 return [w, 0, 0, l]
 32             }
 33         };
 34 
 35 
 36     for (i = 0; i < horizontal.length; i++) {
 37         for (j = 0; j < vertical.length; j++) {
 38             (function (h, v) {
 39                 hcNormal[ h + v] = hcNormal[ v + h] = function () {
 40                     return merge(hcNormal[h].apply(this, arguments),
 41                         hcNormal[v].apply(this, arguments));
 42                 };
 43             })(horizontal[i], vertical[j]);
 44         }
 45     }
 46     function merge(a1, a2) {
 47         var a = [];
 48         for (i = 0; i < a1.length; i++) {
 49             a[i] = a1[i] || a2[i];
 50         }
 51         return a;
 52     }
 53 
 54     function getBoundValue(min, max, v) {
 55         return Math.min(Math.max(min, v), max);
 56     }
 57 
 58     function _uiSetHandlers(e) {
 59         var self = this,
 60             v = e.newVal,
 61             dds = self.dds,
 62             node = self.get("node");
 63         self.destroy();
 64         for (i = 0; i < v.length; i++) {
 65             var hc = v[i],
 66                 el = $("<div class='" +
 67                     CLS_PREFIX +
 68                     " " + CLS_PREFIX +
 69                     "-" + hc +
 70                     "'></div>")
 71                     .prependTo(node, undefined),
 72                 dd = dds[hc] = new Draggable({
 73                     node:el,
 74                     cursor:null
 75                 });
 76             dd.on("drag", _drag, self);
 77             dd.on("dragstart", _dragStart, self);
 78         }
 79     }
 80 
 81     function _dragStart() {
 82         var self = this,
 83             node = self.get("node");
 84         self._width = node.width();
 85         self._top = parseInt(node.css("top"));
 86         self._left = parseInt(node.css("left"));
 87         self._height = node.height();
 88     }
 89 
 90     function _drag(ev) {
 91         var self = this,
 92             node = self.get("node"),
 93             dd = ev.target,
 94             hc = _getHandlerC(self, dd),
 95             ow = self._width,
 96             oh = self._height,
 97             minW = self.get("minWidth"),
 98             maxW = self.get("maxWidth"),
 99             minH = self.get("minHeight"),
100             maxH = self.get("maxHeight"),
101             diffT = ev.top - dd.startNodePos.top,
102             diffL = ev.left - dd.startNodePos.left,
103             ot = self._top,
104             ol = self._left,
105             pos = hcNormal[hc](minW, maxW, minH, maxH, ot, ol, ow, oh, diffT, diffL),
106             attr = ["width", "height", "top", "left"];
107         for (i = 0; i < attr.length; i++) {
108             if (pos[i]) {
109                 node.css(attr[i], pos[i]);
110             }
111         }
112     }
113 
114     function _getHandlerC(self, dd) {
115         var dds = self.dds;
116         for (var d in dds) {
117             if (dds[d] == dd) {
118                 return d;
119             }
120         }
121         return 0;
122     }
123 
124     /**
125      * @class
126      * Make a element resizable.
127      * @extends Base
128      * @name Resizable
129      */
130     function Resizable(cfg) {
131         var self = this,
132             node;
133         Resizable.superclass.constructor.apply(self, arguments);
134         self.on("afterHandlersChange", _uiSetHandlers, self);
135         node = self.get("node");
136         self.dds = {};
137         if (node.css("position") == "static") {
138             node.css("position", "relative");
139         }
140         _uiSetHandlers.call(self, {
141             newVal:self.get("handlers")
142         });
143     }
144 
145     S.extend(Resizable, Base,
146         /**
147          * @lends Resizable#
148          */
149         {
150             /**
151              * make current resizable 's node not resizable.
152              */
153             destroy:function () {
154                 var self = this,
155                     dds = self.dds;
156                 for (var d in dds) {
157                     if (dds.hasOwnProperty(d)) {
158                         dds[d].destroy();
159                         dds[d].get("node").remove();
160                         delete dds[d];
161                     }
162                 }
163             }
164         }, {
165             ATTRS:/**
166              * @lends Resizable#
167              */
168             {
169                 /**
170                  * KISSY Node to be resizable.
171                  * @type Node
172                  */
173                 node:{
174                     setter:function (v) {
175                         return $(v);
176                     }
177                 },
178                 /**
179                  * Minimum width can current node resize to.
180                  * @type Number
181                  */
182                 minWidth:{
183                     value:0
184                 },
185                 /**
186                  * Minimum height can current node resize to.
187                  * @type Number
188                  */
189                 minHeight:{
190                     value:0
191                 },
192                 /**
193                  * Maximum width can current node resize to.
194                  * @type Number
195                  */
196                 maxWidth:{
197                     value:Number.MAX_VALUE
198                 },
199                 /**
200                  * Maximum height can current node resize to.
201                  * @type Number
202                  */
203                 maxHeight:{
204                     value:Number.MAX_VALUE
205                 },
206                 /**
207                  * Enumeration of directions can current node resize to.
208                  * Directions:
209                  * "t": top.
210                  * "tr": top-right.
211                  * "r": right.
212                  * "b": bottom.
213                  * "l": left.
214                  * "tl": top-left.
215                  * "bl": bottom-left.
216                  * "br": bottom-right.
217                  * @type String[]
218                  */
219                 handlers:{
220                     // t,tr,r,br,b,bl,l,tl
221                     value:[]
222                 }
223             }
224         });
225 
226     return Resizable;
227 
228 }, { requires:["node", "base", "dd"] });
229