]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - jssource/src_files/include/javascript/yui3/build/resize/resize.js
Release 6.5.0
[Github/sugarcrm.git] / jssource / src_files / include / javascript / yui3 / build / resize / resize.js
1 /*
2 Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
5 version: 3.3.0
6 build: 3167
7 */
8 YUI.add('resize-base', function(Y) {
9
10 /**
11  * The Resize Utility allows you to make an HTML element resizable.
12  *
13  * @module resize
14  */
15
16 var Lang = Y.Lang,
17         isArray = Lang.isArray,
18         isBoolean = Lang.isBoolean,
19         isNumber = Lang.isNumber,
20         isString = Lang.isString,
21
22         YArray  = Y.Array,
23         trim = Lang.trim,
24         indexOf = YArray.indexOf,
25
26         COMMA = ',',
27         DOT = '.',
28         EMPTY_STR = '',
29         HANDLE_SUB = '{handle}',
30         SPACE = ' ',
31
32         ACTIVE = 'active',
33         ACTIVE_HANDLE = 'activeHandle',
34         ACTIVE_HANDLE_NODE = 'activeHandleNode',
35         ALL = 'all',
36         AUTO_HIDE = 'autoHide',
37         BORDER = 'border',
38         BOTTOM = 'bottom',
39         CLASS_NAME = 'className',
40         COLOR = 'color',
41         DEF_MIN_HEIGHT = 'defMinHeight',
42         DEF_MIN_WIDTH = 'defMinWidth',
43         HANDLE = 'handle',
44         HANDLES = 'handles',
45         HIDDEN = 'hidden',
46         INNER = 'inner',
47         LEFT = 'left',
48         MARGIN = 'margin',
49         NODE = 'node',
50         NODE_NAME = 'nodeName',
51         NONE = 'none',
52         OFFSET_HEIGHT = 'offsetHeight',
53         OFFSET_WIDTH = 'offsetWidth',
54         PADDING = 'padding',
55         PARENT_NODE = 'parentNode',
56         POSITION = 'position',
57         RELATIVE = 'relative',
58         RESIZE = 'resize',
59         RESIZING = 'resizing',
60         RIGHT = 'right',
61         STATIC = 'static',
62         STYLE = 'style',
63         TOP = 'top',
64         WIDTH = 'width',
65         WRAP = 'wrap',
66         WRAPPER = 'wrapper',
67         WRAP_TYPES = 'wrapTypes',
68
69         EV_MOUSE_UP = 'resize:mouseUp',
70         EV_RESIZE = 'resize:resize',
71         EV_RESIZE_ALIGN = 'resize:align',
72         EV_RESIZE_END = 'resize:end',
73         EV_RESIZE_START = 'resize:start',
74
75         T = 't',
76         TR = 'tr',
77         R = 'r',
78         BR = 'br',
79         B = 'b',
80         BL = 'bl',
81         L = 'l',
82         TL = 'tl',
83
84         concat = function() {
85                 return Array.prototype.slice.call(arguments).join(SPACE);
86         },
87
88         // round the passed number to get rid of pixel-flickering
89         toRoundNumber = function(num) {
90                 return Math.round(parseFloat(num)) || 0;
91         },
92
93         getCompStyle = function(node, val) {
94                 return node.getComputedStyle(val);
95         },
96
97         handleAttrName = function(handle) {
98                 return HANDLE + handle.toUpperCase();
99         },
100
101         isNode = function(v) {
102                 return (v instanceof Y.Node);
103         },
104
105         toInitialCap = Y.cached(
106                 function(str) {
107                         return str.substring(0, 1).toUpperCase() + str.substring(1);
108                 }
109         ),
110
111         capitalize = Y.cached(function() {
112                 var out = [],
113                         args = YArray(arguments, 0, true);
114
115                 YArray.each(args, function(part, i) {
116                         if (i > 0) {
117                                 part = toInitialCap(part);
118                         }
119                         out.push(part);
120                 });
121
122                 return out.join(EMPTY_STR);
123         }),
124
125         getCN = Y.ClassNameManager.getClassName,
126
127         CSS_RESIZE = getCN(RESIZE),
128         CSS_RESIZE_HANDLE = getCN(RESIZE, HANDLE),
129         CSS_RESIZE_HANDLE_ACTIVE = getCN(RESIZE, HANDLE, ACTIVE),
130         CSS_RESIZE_HANDLE_INNER = getCN(RESIZE, HANDLE, INNER),
131         CSS_RESIZE_HANDLE_INNER_PLACEHOLDER = getCN(RESIZE, HANDLE, INNER, HANDLE_SUB),
132         CSS_RESIZE_HANDLE_PLACEHOLDER = getCN(RESIZE, HANDLE, HANDLE_SUB),
133         CSS_RESIZE_HIDDEN_HANDLES = getCN(RESIZE, HIDDEN, HANDLES),
134         CSS_RESIZE_WRAPPER = getCN(RESIZE, WRAPPER);
135
136 /**
137  * A base class for Resize, providing:
138  * <ul>
139  *    <li>Basic Lifecycle (initializer, renderUI, bindUI, syncUI, destructor)</li>
140  *    <li>Applies drag handles to an element to make it resizable</li>
141  *    <li>Here is the list of valid resize handles:
142  *        <code>[ 't', 'tr', 'r', 'br', 'b', 'bl', 'l', 'tl' ]</code>. You can
143  *        read this list as top, top-right, right, bottom-right, bottom,
144  *        bottom-left, left, top-left.</li>
145  *    <li>The drag handles are inserted into the element and positioned
146  *        absolute. Some elements, such as a textarea or image, don't support
147  *        children. To overcome that, set wrap:true in your config and the
148  *        element willbe wrapped for you automatically.</li>
149  * </ul>
150  *
151  * Quick Example:
152  *
153  * <pre><code>var instance = new Y.Resize({
154  *  node: '#resize1',
155  *  preserveRatio: true,
156  *  wrap: true,
157  *  maxHeight: 170,
158  *  maxWidth: 400,
159  *  handles: 't, tr, r, br, b, bl, l, tl'
160  * });
161  * </code></pre>
162  *
163  * Check the list of <a href="Resize.html#configattributes">Configuration Attributes</a> available for
164  * Resize.
165  *
166  * @class Resize
167  * @param config {Object} Object literal specifying widget configuration properties.
168  * @constructor
169  * @extends Base
170  */
171 function Resize() {
172     Resize.superclass.constructor.apply(this, arguments);
173 }
174
175 Y.mix(Resize, {
176         /**
177          * Static property provides a string to identify the class.
178          *
179          * @property Resize.NAME
180          * @type String
181          * @static
182          */
183         NAME: RESIZE,
184
185         /**
186          * Static property used to define the default attribute
187          * configuration for the Resize.
188          *
189          * @property Resize.ATTRS
190          * @type Object
191          * @static
192          */
193         ATTRS: {
194                 /**
195                  * Stores the active handle during the resize.
196                  *
197                  * @attribute activeHandle
198                  * @default null
199                  * @private
200                  * @type String
201                  */
202                 activeHandle: {
203                         value: null,
204                         validator: function(v) {
205                 return Y.Lang.isString(v) || Y.Lang.isNull(v);
206             }
207                 },
208
209                 /**
210                  * Stores the active handle element during the resize.
211                  *
212                  * @attribute activeHandleNode
213                  * @default null
214                  * @private
215                  * @type Node
216                  */
217                 activeHandleNode: {
218                         value: null,
219                         validator: isNode
220                 },
221
222                 /**
223          * False to ensure that the resize handles are always visible, true to
224          * display them only when the user mouses over the resizable borders.
225                  *
226                  * @attribute autoHide
227                  * @default false
228                  * @type boolean
229                  */
230                 autoHide: {
231                         value: false,
232                         validator: isBoolean
233                 },
234
235                 /**
236          * The default minimum height of the element. Only used when
237                  * ResizeConstrained is not plugged.
238          *
239          * @attribute defMinHeight
240          * @default 15
241          * @type Number
242          */
243                 defMinHeight: {
244                         value: 15,
245                         validator: isNumber
246                 },
247
248                 /**
249          * The default minimum width of the element. Only used when
250                  * ResizeConstrained is not plugged.
251          *
252          * @attribute defMinWidth
253          * @default 15
254          * @type Number
255          */
256                 defMinWidth: {
257                         value: 15,
258                         validator: isNumber
259                 },
260
261         /**
262          * The handles to use (any combination of): 't', 'b', 'r', 'l', 'bl',
263          * 'br', 'tl', 'tr'. Can use a shortcut of All.
264          *
265          * @attribute handles
266          * @default all
267          * @type Array | String
268          */
269                 handles: {
270                         setter: '_setHandles',
271                         value: ALL
272                 },
273
274                 /**
275          * The selector or element to resize. Required.
276          *
277          * @attribute node
278          * @type Node
279          */
280                 node: {
281                         setter: Y.one
282                 },
283
284                 /**
285          * True when the element is being Resized.
286          *
287          * @attribute resizing
288          * @default false
289          * @type boolean
290          */
291                 resizing: {
292                         value: false,
293                         validator: isBoolean
294                 },
295
296                 /**
297                  * True to wrap an element with a div if needed (required for textareas
298          * and images, defaults to false) in favor of the handles config option.
299          * The wrapper element type (default div) could be over-riden passing the
300          * <code>wrapper</code> attribute.
301                  *
302                  * @attribute wrap
303                  * @default false
304                  * @type boolean
305                  */
306                 wrap: {
307                         setter: '_setWrap',
308                         value: false,
309                         validator: isBoolean
310                 },
311
312                 /**
313                  * Elements that requires a wrapper by default. Normally are elements
314          * which cannot have children elements.
315                  *
316                  * @attribute wrapTypes
317                  * @default /canvas|textarea|input|select|button|img/i
318                  * @readOnly
319                  * @type Regex
320                  */
321                 wrapTypes: {
322                         readOnly: true,
323                         value: /^canvas|textarea|input|select|button|img|iframe|table|embed$/i
324                 },
325
326                 /**
327                  * Element to wrap the <code>wrapTypes</code>. This element will house
328          * the handles elements.
329                  *
330                  * @attribute wrapper
331                  * @default div
332                  * @type String | Node
333                  * @writeOnce
334                  */
335                 wrapper: {
336                         readOnly: true,
337                         valueFn: '_valueWrapper',
338                         writeOnce: true
339                 }
340         },
341
342         RULES: {
343                 b: function(instance, dx, dy) {
344                         var info = instance.info,
345                                 originalInfo = instance.originalInfo;
346
347                         info.offsetHeight = originalInfo.offsetHeight + dy;
348                 },
349
350                 l: function(instance, dx, dy) {
351                         var info = instance.info,
352                                 originalInfo = instance.originalInfo;
353
354                         info.left = originalInfo.left + dx;
355                         info.offsetWidth = originalInfo.offsetWidth - dx;
356                 },
357
358                 r: function(instance, dx, dy) {
359                         var info = instance.info,
360                                 originalInfo = instance.originalInfo;
361
362                         info.offsetWidth = originalInfo.offsetWidth + dx;
363                 },
364
365                 t: function(instance, dx, dy) {
366                         var info = instance.info,
367                                 originalInfo = instance.originalInfo;
368
369                         info.top = originalInfo.top + dy;
370                         info.offsetHeight = originalInfo.offsetHeight - dy;
371                 },
372
373                 tr: function(instance, dx, dy) {
374                         this.t.apply(this, arguments);
375                         this.r.apply(this, arguments);
376                 },
377
378                 bl: function(instance, dx, dy) {
379                         this.b.apply(this, arguments);
380                         this.l.apply(this, arguments);
381                 },
382
383                 br: function(instance, dx, dy) {
384                         this.b.apply(this, arguments);
385                         this.r.apply(this, arguments);
386                 },
387
388                 tl: function(instance, dx, dy) {
389                         this.t.apply(this, arguments);
390                         this.l.apply(this, arguments);
391                 }
392         },
393
394         capitalize: capitalize
395 });
396
397 Y.Resize = Y.extend(
398         Resize,
399         Y.Base,
400         {
401                 /**
402              * Array containing all possible resizable handles.
403              *
404              * @property ALL_HANDLES
405              * @type {String}
406              */
407                 ALL_HANDLES: [ T, TR, R, BR, B, BL, L, TL ],
408
409                 /**
410              * Regex which matches with the handles that could change the height of
411                  * the resizable element.
412              *
413              * @property REGEX_CHANGE_HEIGHT
414              * @type {String}
415              */
416                 REGEX_CHANGE_HEIGHT: /^(t|tr|b|bl|br|tl)$/i,
417
418                 /**
419              * Regex which matches with the handles that could change the left of
420                  * the resizable element.
421              *
422              * @property REGEX_CHANGE_LEFT
423              * @type {String}
424              */
425                 REGEX_CHANGE_LEFT: /^(tl|l|bl)$/i,
426
427                 /**
428              * Regex which matches with the handles that could change the top of
429                  * the resizable element.
430              *
431              * @property REGEX_CHANGE_TOP
432              * @type {String}
433              */
434                 REGEX_CHANGE_TOP: /^(tl|t|tr)$/i,
435
436                 /**
437              * Regex which matches with the handles that could change the width of
438                  * the resizable element.
439              *
440              * @property REGEX_CHANGE_WIDTH
441              * @type {String}
442              */
443                 REGEX_CHANGE_WIDTH: /^(bl|br|l|r|tl|tr)$/i,
444
445                 /**
446              * Template used to create the resize wrapper node when needed.
447              *
448              * @property WRAP_TEMPLATE
449              * @type {String}
450              */
451                 WRAP_TEMPLATE: '<div class="'+CSS_RESIZE_WRAPPER+'"></div>',
452
453                 /**
454              * Template used to create each resize handle.
455              *
456              * @property HANDLE_TEMPLATE
457              * @type {String}
458              */
459                 HANDLE_TEMPLATE: '<div class="'+concat(CSS_RESIZE_HANDLE, CSS_RESIZE_HANDLE_PLACEHOLDER)+'">' +
460                                                         '<div class="'+concat(CSS_RESIZE_HANDLE_INNER, CSS_RESIZE_HANDLE_INNER_PLACEHOLDER)+'">&nbsp;</div>' +
461                                                 '</div>',
462
463
464                 /**
465                  * Each box has a content area and optional surrounding padding and
466                  * border areas. This property stores the sum of all horizontal
467                  * surrounding * information needed to adjust the node height.
468                  *
469                  * @property totalHSurrounding
470                  * @default 0
471                  * @type number
472                  */
473                 totalHSurrounding: 0,
474
475                 /**
476                  * Each box has a content area and optional surrounding padding and
477                  * border areas. This property stores the sum of all vertical
478                  * surrounding * information needed to adjust the node height.
479                  *
480                  * @property totalVSurrounding
481                  * @default 0
482                  * @type number
483                  */
484                 totalVSurrounding: 0,
485
486                 /**
487                  * Stores the <a href="Resize.html#config_node">node</a>
488                  * surrounding information retrieved from
489                  * <a href="Resize.html#method__getBoxSurroundingInfo">_getBoxSurroundingInfo</a>.
490                  *
491                  * @property nodeSurrounding
492                  * @type Object
493                  * @default null
494                  */
495                 nodeSurrounding: null,
496
497                 /**
498                  * Stores the <a href="Resize.html#config_wrapper">wrapper</a>
499                  * surrounding information retrieved from
500                  * <a href="Resize.html#method__getBoxSurroundingInfo">_getBoxSurroundingInfo</a>.
501                  *
502                  * @property wrapperSurrounding
503                  * @type Object
504                  * @default null
505                  */
506                 wrapperSurrounding: null,
507
508                 /**
509                  * Whether the handle being dragged can change the height.
510                  *
511                  * @property changeHeightHandles
512                  * @default false
513                  * @type boolean
514                  */
515                 changeHeightHandles: false,
516
517                 /**
518                  * Whether the handle being dragged can change the left.
519                  *
520                  * @property changeLeftHandles
521                  * @default false
522                  * @type boolean
523                  */
524                 changeLeftHandles: false,
525
526                 /**
527                  * Whether the handle being dragged can change the top.
528                  *
529                  * @property changeTopHandles
530                  * @default false
531                  * @type boolean
532                  */
533                 changeTopHandles: false,
534
535                 /**
536                  * Whether the handle being dragged can change the width.
537                  *
538                  * @property changeWidthHandles
539                  * @default false
540                  * @type boolean
541                  */
542                 changeWidthHandles: false,
543
544                 /**
545                  * Store DD.Delegate reference for the respective Resize instance.
546                  *
547                  * @property delegate
548                  * @default null
549                  * @type Object
550                  */
551                 delegate: null,
552
553             /**
554              * Stores the current values for the height, width, top and left. You are
555              * able to manipulate these values on resize in order to change the resize
556              * behavior.
557              *
558              * @property info
559              * @type Object
560              * @protected
561              */
562                 info: null,
563
564                 /**
565              * Stores the last values for the height, width, top and left.
566              *
567              * @property lastInfo
568              * @type Object
569              * @protected
570              */
571                 lastInfo: null,
572
573             /**
574              * Stores the original values for the height, width, top and left, stored
575              * on resize start.
576              *
577              * @property originalInfo
578              * @type Object
579              * @protected
580              */
581                 originalInfo: null,
582
583             /**
584              * Construction logic executed during Resize instantiation. Lifecycle.
585              *
586              * @method initializer
587              * @protected
588              */
589                 initializer: function() {
590                         this.renderer();
591                 },
592
593             /**
594              * Create the DOM structure for the Resize. Lifecycle.
595              *
596              * @method renderUI
597              * @protected
598              */
599                 renderUI: function() {
600                         var instance = this;
601
602                         instance._renderHandles();
603                 },
604
605             /**
606              * Bind the events on the Resize UI. Lifecycle.
607              *
608              * @method bindUI
609              * @protected
610              */
611                 bindUI: function() {
612                         var instance = this;
613
614                         instance._createEvents();
615                         instance._bindDD();
616                         instance._bindHandle();
617                 },
618
619             /**
620              * Sync the Resize UI.
621              *
622              * @method syncUI
623              * @protected
624              */
625                 syncUI: function() {
626                         var instance = this;
627
628                         this.get(NODE).addClass(CSS_RESIZE);
629
630                         // hide handles if AUTO_HIDE is true
631                         instance._setHideHandlesUI(
632                                 instance.get(AUTO_HIDE)
633                         );
634                 },
635
636             /**
637              * Descructor lifecycle implementation for the Resize class. Purges events attached
638              * to the node (and all child nodes) and removes the Resize handles.
639              *
640              * @method destructor
641              * @protected
642              */
643                 destructor: function() {
644                         var instance = this,
645                                 node = instance.get(NODE),
646                                 wrapper = instance.get(WRAPPER),
647                                 pNode = wrapper.get(PARENT_NODE);
648
649                         // purgeElements on boundingBox
650                         Y.Event.purgeElement(wrapper, true);
651
652                         // destroy handles dd and remove them from the dom
653                         instance.eachHandle(function(handleEl) {
654                                 instance.delegate.dd.destroy();
655
656                                 // remove handle
657                                 handleEl.remove(true);
658                         });
659
660                         // unwrap node
661                         if (instance.get(WRAP)) {
662                                 instance._copyStyles(wrapper, node);
663
664                                 if (pNode) {
665                                         pNode.insertBefore(node, wrapper);
666                                 }
667
668                                 wrapper.remove(true);
669                         }
670
671                         node.removeClass(CSS_RESIZE);
672                         node.removeClass(CSS_RESIZE_HIDDEN_HANDLES);
673                 },
674
675             /**
676              * Creates DOM (or manipulates DOM for progressive enhancement)
677              * This method is invoked by initializer(). It's chained automatically for
678              * subclasses if required.
679              *
680              * @method renderer
681              * @protected
682              */
683             renderer: function() {
684                 this.renderUI();
685                 this.bindUI();
686                 this.syncUI();
687             },
688
689             /**
690              * <p>Loop through each handle which is being used and executes a callback.</p>
691              * <p>Example:</p>
692              * <pre><code>instance.eachHandle(
693                  *      function(handleName, index) { ... }
694                  *  );</code></pre>
695              *
696              * @method eachHandle
697              * @param {function} fn Callback function to be executed for each handle.
698              */
699                 eachHandle: function(fn) {
700                         var instance = this;
701
702                         Y.each(
703                                 instance.get(HANDLES),
704                                 function(handle, i) {
705                                         var handleEl = instance.get(
706                                                 handleAttrName(handle)
707                                         );
708
709                                         fn.apply(instance, [handleEl, handle, i]);
710                                 }
711                         );
712                 },
713
714             /**
715              * Bind the handles DragDrop events to the Resize instance.
716              *
717              * @method _bindDD
718              * @private
719              */
720                 _bindDD: function() {
721                         var instance = this;
722
723                         instance.delegate = new Y.DD.Delegate(
724                                 {
725                                         bubbleTargets: instance,
726                                         container: instance.get(WRAPPER),
727                                         dragConfig: {
728                                                 clickPixelThresh: 0,
729                                                 clickTimeThresh: 0,
730                                                 useShim: true,
731                                                 move: false
732                                         },
733                                         nodes: DOT+CSS_RESIZE_HANDLE,
734                                         target: false
735                                 }
736                         );
737
738                         instance.on('drag:drag', instance._handleResizeEvent);
739                         instance.on('drag:dropmiss', instance._handleMouseUpEvent);
740                         instance.on('drag:end', instance._handleResizeEndEvent);
741                         instance.on('drag:start', instance._handleResizeStartEvent);
742                 },
743
744             /**
745              * Bind the events related to the handles (_onHandleMouseEnter, _onHandleMouseLeave).
746              *
747              * @method _bindHandle
748              * @private
749              */
750                 _bindHandle: function() {
751                         var instance = this,
752                                 wrapper = instance.get(WRAPPER);
753
754                         wrapper.on('mouseenter', Y.bind(instance._onWrapperMouseEnter, instance));
755                         wrapper.on('mouseleave', Y.bind(instance._onWrapperMouseLeave, instance));
756                         wrapper.delegate('mouseenter', Y.bind(instance._onHandleMouseEnter, instance), DOT+CSS_RESIZE_HANDLE);
757                         wrapper.delegate('mouseleave', Y.bind(instance._onHandleMouseLeave, instance), DOT+CSS_RESIZE_HANDLE);
758                 },
759
760             /**
761              * Create the custom events used on the Resize.
762              *
763              * @method _createEvents
764              * @private
765              */
766                 _createEvents: function() {
767                         var instance = this,
768                                 // create publish function for kweight optimization
769                                 publish = function(name, fn) {
770                                         instance.publish(name, {
771                                                 defaultFn: fn,
772                                                 queuable: false,
773                                                 emitFacade: true,
774                                                 bubbles: true,
775                                                 prefix: RESIZE
776                                         });
777                                 };
778
779                         /**
780                          * Handles the resize start event. Fired when a handle starts to be
781                  * dragged.
782                          *
783                  * @event resize:start
784                  * @preventable _defResizeStartFn
785                  * @param {Event.Facade} event The resize start event.
786                  * @bubbles Resize
787                  * @type {Event.Custom}
788                  */
789                         publish(EV_RESIZE_START, this._defResizeStartFn);
790
791                         /**
792                          * Handles the resize event. Fired on each pixel when the handle is
793                  * being dragged.
794                          *
795                  * @event resize:resize
796                  * @preventable _defResizeFn
797                  * @param {Event.Facade} event The resize event.
798                  * @bubbles Resize
799                  * @type {Event.Custom}
800                  */
801                         publish(EV_RESIZE, this._defResizeFn);
802
803                         /**
804                          * Handles the resize align event.
805                          *
806                  * @event resize:align
807                  * @preventable _defResizeAlignFn
808                  * @param {Event.Facade} event The resize align event.
809                  * @bubbles Resize
810                  * @type {Event.Custom}
811                  */
812                         publish(EV_RESIZE_ALIGN, this._defResizeAlignFn);
813
814                         /**
815                          * Handles the resize end event. Fired when a handle stop to be
816                  * dragged.
817                          *
818                  * @event resize:end
819                  * @preventable _defResizeEndFn
820                  * @param {Event.Facade} event The resize end event.
821                  * @bubbles Resize
822                  * @type {Event.Custom}
823                  */
824                         publish(EV_RESIZE_END, this._defResizeEndFn);
825
826                         /**
827                          * Handles the resize mouseUp event. Fired when a mouseUp event happens on a
828                  * handle.
829                          *
830                  * @event resize:mouseUp
831                  * @preventable _defMouseUpFn
832                  * @param {Event.Facade} event The resize mouseUp event.
833                  * @bubbles Resize
834                  * @type {Event.Custom}
835                  */
836                         publish(EV_MOUSE_UP, this._defMouseUpFn);
837                 },
838
839             /**
840               * Responsible for loop each handle element and append to the wrapper.
841               *
842               * @method _renderHandles
843               * @protected
844               */
845                 _renderHandles: function() {
846                         var instance = this,
847                                 wrapper = instance.get(WRAPPER);
848
849                         instance.eachHandle(function(handleEl) {
850                                 wrapper.append(handleEl);
851                         });
852                 },
853
854             /**
855              * Creates the handle element based on the handle name and initialize the
856              * DragDrop on it.
857              *
858              * @method _buildHandle
859              * @param {String} handle Handle name ('t', 'tr', 'b', ...).
860              * @protected
861              */
862                 _buildHandle: function(handle) {
863                         var instance = this;
864
865                         return Y.Node.create(
866                                 Y.substitute(instance.HANDLE_TEMPLATE, {
867                                         handle: handle
868                                 })
869                         );
870                 },
871
872             /**
873              * Basic resize calculations.
874              *
875              * @method _calcResize
876              * @protected
877              */
878                 _calcResize: function() {
879                         var instance = this,
880                                 handle = instance.handle,
881                                 info = instance.info,
882                                 originalInfo = instance.originalInfo,
883
884                                 dx = info.actXY[0] - originalInfo.actXY[0],
885                                 dy = info.actXY[1] - originalInfo.actXY[1];
886
887             if (handle && Y.Resize.RULES[handle]) {
888                             Y.Resize.RULES[handle](instance, dx, dy);
889             }
890                         else {
891                         }
892                 },
893
894                 /**
895              * Helper method to update the current size value on
896              * <a href="Resize.html#property_info">info</a> to respect the
897              * min/max values and fix the top/left calculations.
898                  *
899                  * @method _checkSize
900                  * @param {String} offset 'offsetHeight' or 'offsetWidth'
901                  * @param {number} size Size to restrict the offset
902                  * @protected
903                  */
904                 _checkSize: function(offset, size) {
905                         var instance = this,
906                                 info = instance.info,
907                                 originalInfo = instance.originalInfo,
908                                 axis = (offset == OFFSET_HEIGHT) ? TOP : LEFT;
909
910                         // forcing the offsetHeight/offsetWidth to be the passed size
911                         info[offset] = size;
912
913                         // predicting, based on the original information, the last left valid in case of reach the min/max dimension
914                         // this calculation avoid browser event leaks when user interact very fast
915                         if (((axis == LEFT) && instance.changeLeftHandles) ||
916                                 ((axis == TOP) && instance.changeTopHandles)) {
917
918                                 info[axis] = originalInfo[axis] + originalInfo[offset] - size;
919                         }
920                 },
921
922             /**
923              * Copy relevant styles of the <a href="Resize.html#config_node">node</a>
924              * to the <a href="Resize.html#config_wrapper">wrapper</a>.
925              *
926              * @method _copyStyles
927              * @param {Node} node Node from.
928              * @param {Node} wrapper Node to.
929              * @protected
930              */
931                 _copyStyles: function(node, wrapper) {
932                         var position = node.getStyle(POSITION).toLowerCase(),
933                                 surrounding = this._getBoxSurroundingInfo(node),
934                                 wrapperStyle;
935
936                         // resizable wrapper should be positioned
937                         if (position == STATIC) {
938                                 position = RELATIVE;
939                         }
940
941                         wrapperStyle = {
942                                 position: position,
943                                 left: getCompStyle(node, LEFT),
944                                 top: getCompStyle(node, TOP)
945                         };
946
947                         Y.mix(wrapperStyle, surrounding.margin);
948                         Y.mix(wrapperStyle, surrounding.border);
949
950                         wrapper.setStyles(wrapperStyle);
951
952                         // remove margin and border from the internal node
953                         node.setStyles({ border: 0, margin: 0 });
954
955                         wrapper.sizeTo(
956                                 node.get(OFFSET_WIDTH) + surrounding.totalHBorder,
957                                 node.get(OFFSET_HEIGHT) + surrounding.totalVBorder
958                         );
959                 },
960
961                 // extract handle name from a string
962                 // using Y.cached to memoize the function for performance
963                 _extractHandleName: Y.cached(
964                         function(node) {
965                                 var className = node.get(CLASS_NAME),
966
967                                         match = className.match(
968                                                 new RegExp(
969                                                         getCN(RESIZE, HANDLE, '(\\w{1,2})\\b')
970                                                 )
971                                         );
972
973                                 return match ? match[1] : null;
974                         }
975                 ),
976
977             /**
978              * <p>Generates metadata to the <a href="Resize.html#property_info">info</a>
979              * and <a href="Resize.html#property_originalInfo">originalInfo</a></p>
980              * <pre><code>bottom, actXY, left, top, offsetHeight, offsetWidth, right</code></pre>
981              *
982              * @method _getInfo
983              * @param {Node} node
984              * @param {EventFacade} event
985              * @private
986              */
987                 _getInfo: function(node, event) {
988                         var actXY = [0,0],
989                                 drag = event.dragEvent.target,
990                                 nodeXY = node.getXY(),
991                                 nodeX = nodeXY[0],
992                                 nodeY = nodeXY[1],
993                                 offsetHeight = node.get(OFFSET_HEIGHT),
994                                 offsetWidth = node.get(OFFSET_WIDTH);
995
996                         if (event) {
997                                 // the xy that the node will be set to. Changing this will alter the position as it's dragged.
998                                 actXY = (drag.actXY.length ? drag.actXY : drag.lastXY);
999                         }
1000
1001                         return {
1002                                 actXY: actXY,
1003                                 bottom: (nodeY + offsetHeight),
1004                                 left: nodeX,
1005                                 offsetHeight: offsetHeight,
1006                                 offsetWidth: offsetWidth,
1007                                 right: (nodeX + offsetWidth),
1008                                 top: nodeY
1009                         };
1010                 },
1011
1012                 /**
1013                  * Each box has a content area and optional surrounding margin,
1014                  * padding and * border areas. This method get all this information from
1015                  * the passed node. For more reference see
1016                  * <a href="http://www.w3.org/TR/CSS21/box.html#box-dimensions">
1017                  * http://www.w3.org/TR/CSS21/box.html#box-dimensions</a>.
1018                  *
1019                  * @method _getBoxSurroundingInfo
1020                  * @param {Node} node
1021                  * @private
1022                  * @return {Object}
1023                  */
1024                 _getBoxSurroundingInfo: function(node) {
1025                         var     info = {
1026                                 padding: {},
1027                                 margin: {},
1028                                 border: {}
1029                         };
1030
1031                         if (isNode(node)) {
1032                                 Y.each([ TOP, RIGHT, BOTTOM, LEFT ], function(dir) {
1033                                         var paddingProperty = capitalize(PADDING, dir),
1034                                                 marginProperty = capitalize(MARGIN, dir),
1035                                                 borderWidthProperty = capitalize(BORDER, dir, WIDTH),
1036                                                 borderColorProperty = capitalize(BORDER, dir, COLOR),
1037                                                 borderStyleProperty = capitalize(BORDER, dir, STYLE);
1038
1039                                         info.border[borderColorProperty] = getCompStyle(node, borderColorProperty);
1040                                         info.border[borderStyleProperty] = getCompStyle(node, borderStyleProperty);
1041                                         info.border[borderWidthProperty] = getCompStyle(node, borderWidthProperty);
1042                                         info.margin[marginProperty] = getCompStyle(node, marginProperty);
1043                                         info.padding[paddingProperty] = getCompStyle(node, paddingProperty);
1044                                 });
1045                         }
1046
1047                         info.totalHBorder = (toRoundNumber(info.border.borderLeftWidth) + toRoundNumber(info.border.borderRightWidth));
1048                         info.totalHPadding = (toRoundNumber(info.padding.paddingLeft) + toRoundNumber(info.padding.paddingRight));
1049                         info.totalVBorder = (toRoundNumber(info.border.borderBottomWidth) + toRoundNumber(info.border.borderTopWidth));
1050                         info.totalVPadding = (toRoundNumber(info.padding.paddingBottom) + toRoundNumber(info.padding.paddingTop));
1051
1052                         return info;
1053                 },
1054
1055                 /**
1056              * Sync the Resize UI with internal values from
1057              * <a href="Resize.html#property_info">info</a>.
1058              *
1059              * @method _syncUI
1060              * @protected
1061              */
1062                 _syncUI: function() {
1063                         var instance = this,
1064                                 info = instance.info,
1065                                 wrapperSurrounding = instance.wrapperSurrounding,
1066                                 wrapper = instance.get(WRAPPER),
1067                                 node = instance.get(NODE);
1068
1069                         wrapper.sizeTo(info.offsetWidth, info.offsetHeight);
1070
1071                         if (instance.changeLeftHandles || instance.changeTopHandles) {
1072                                 wrapper.setXY([info.left, info.top]);
1073                         }
1074
1075                         // if a wrap node is being used
1076                         if (!wrapper.compareTo(node)) {
1077                                 // the original internal node borders were copied to the wrapper on _copyStyles, to compensate that subtract the borders from the internal node
1078                                 node.sizeTo(
1079                                         info.offsetWidth - wrapperSurrounding.totalHBorder,
1080                                         info.offsetHeight - wrapperSurrounding.totalVBorder
1081                                 );
1082                         }
1083
1084                         // prevent webkit textarea resize
1085                         if (Y.UA.webkit) {
1086                                 node.setStyle(RESIZE, NONE);
1087                         }
1088                 },
1089
1090                 /**
1091              * Update <code>instance.changeHeightHandles,
1092                  * instance.changeLeftHandles, instance.changeTopHandles,
1093                  * instance.changeWidthHandles</code> information.
1094              *
1095              * @method _updateChangeHandleInfo
1096              * @private
1097              */
1098                 _updateChangeHandleInfo: function(handle) {
1099                         var instance = this;
1100
1101                         instance.changeHeightHandles = instance.REGEX_CHANGE_HEIGHT.test(handle);
1102                         instance.changeLeftHandles = instance.REGEX_CHANGE_LEFT.test(handle);
1103                         instance.changeTopHandles = instance.REGEX_CHANGE_TOP.test(handle);
1104                         instance.changeWidthHandles = instance.REGEX_CHANGE_WIDTH.test(handle);
1105                 },
1106
1107                 /**
1108              * Update <a href="Resize.html#property_info">info</a> values (bottom, actXY, left, top, offsetHeight, offsetWidth, right).
1109              *
1110              * @method _updateInfo
1111              * @private
1112              */
1113                 _updateInfo: function(event) {
1114                         var instance = this;
1115
1116                         instance.info = instance._getInfo(instance.get(WRAPPER), event);
1117                 },
1118
1119                 /**
1120              * Update properties
1121              * <a href="Resize.html#property_nodeSurrounding">nodeSurrounding</a>,
1122              * <a href="Resize.html#property_nodeSurrounding">wrapperSurrounding</a>,
1123              * <a href="Resize.html#property_nodeSurrounding">totalVSurrounding</a>,
1124              * <a href="Resize.html#property_nodeSurrounding">totalHSurrounding</a>.
1125              *
1126              * @method _updateSurroundingInfo
1127              * @private
1128              */
1129                 _updateSurroundingInfo: function() {
1130                         var instance = this,
1131                                 node = instance.get(NODE),
1132                                 wrapper = instance.get(WRAPPER),
1133                                 nodeSurrounding = instance._getBoxSurroundingInfo(node),
1134                                 wrapperSurrounding = instance._getBoxSurroundingInfo(wrapper);
1135
1136                         instance.nodeSurrounding = nodeSurrounding;
1137                         instance.wrapperSurrounding = wrapperSurrounding;
1138
1139                         instance.totalVSurrounding = (nodeSurrounding.totalVPadding + wrapperSurrounding.totalVBorder);
1140                         instance.totalHSurrounding = (nodeSurrounding.totalHPadding + wrapperSurrounding.totalHBorder);
1141                 },
1142
1143             /**
1144              * Set the active state of the handles.
1145              *
1146              * @method _setActiveHandlesUI
1147              * @param {boolean} val True to activate the handles, false to deactivate.
1148              * @protected
1149              */
1150                 _setActiveHandlesUI: function(val) {
1151                         var instance = this,
1152                                 activeHandleNode = instance.get(ACTIVE_HANDLE_NODE);
1153
1154                         if (activeHandleNode) {
1155                                 if (val) {
1156                                         // remove CSS_RESIZE_HANDLE_ACTIVE from all handles before addClass on the active
1157                                         instance.eachHandle(
1158                                                 function(handleEl) {
1159                                                         handleEl.removeClass(CSS_RESIZE_HANDLE_ACTIVE);
1160                                                 }
1161                                         );
1162
1163                                         activeHandleNode.addClass(CSS_RESIZE_HANDLE_ACTIVE);
1164                                 }
1165                                 else {
1166                                         activeHandleNode.removeClass(CSS_RESIZE_HANDLE_ACTIVE);
1167                                 }
1168                         }
1169                 },
1170
1171             /**
1172              * Setter for the handles attribute
1173              *
1174              * @method _setHandles
1175              * @protected
1176              * @param {String} val
1177              */
1178                 _setHandles: function(val) {
1179                         var instance = this,
1180                                 handles = [];
1181
1182                         // handles attr accepts both array or string
1183                         if (isArray(val)) {
1184                                 handles = val;
1185                         }
1186                         else if (isString(val)) {
1187                                 // if the handles attr passed in is an ALL string...
1188                                 if (val.toLowerCase() == ALL) {
1189                                         handles = instance.ALL_HANDLES;
1190                                 }
1191                                 // otherwise, split the string to extract the handles
1192                                 else {
1193                                         Y.each(
1194                                                 val.split(COMMA),
1195                                                 function(node, i) {
1196                                                         var handle = trim(node);
1197
1198                                                         // if its a valid handle, add it to the handles output
1199                                                         if (indexOf(instance.ALL_HANDLES, handle) > -1) {
1200                                                                 handles.push(handle);
1201                                                         }
1202                                                 }
1203                                         );
1204                                 }
1205                         }
1206
1207                         return handles;
1208                 },
1209
1210             /**
1211              * Set the visibility of the handles.
1212              *
1213              * @method _setHideHandlesUI
1214              * @param {boolean} val True to hide the handles, false to show.
1215              * @protected
1216              */
1217                 _setHideHandlesUI: function(val) {
1218                         var instance = this,
1219                                 wrapper = instance.get(WRAPPER);
1220
1221                         if (!instance.get(RESIZING)) {
1222                                 if (val) {
1223                                         wrapper.addClass(CSS_RESIZE_HIDDEN_HANDLES);
1224                                 }
1225                                 else {
1226                                         wrapper.removeClass(CSS_RESIZE_HIDDEN_HANDLES);
1227                                 }
1228                         }
1229                 },
1230
1231             /**
1232              * Setter for the wrap attribute
1233              *
1234              * @method _setWrap
1235              * @protected
1236              * @param {boolean} val
1237              */
1238                 _setWrap: function(val) {
1239                         var instance = this,
1240                                 node = instance.get(NODE),
1241                                 nodeName = node.get(NODE_NAME),
1242                                 typeRegex = instance.get(WRAP_TYPES);
1243
1244                         // if nodeName is listed on WRAP_TYPES force use the wrapper
1245                         if (typeRegex.test(nodeName)) {
1246                                 val = true;
1247                         }
1248
1249                         return val;
1250                 },
1251
1252             /**
1253              * Default resize:mouseUp handler
1254              *
1255              * @method _defMouseUpFn
1256              * @param {EventFacade} event The Event object
1257              * @protected
1258              */
1259                 _defMouseUpFn: function(event) {
1260                         var instance = this;
1261
1262                         instance.set(RESIZING, false);
1263                 },
1264
1265             /**
1266              * Default resize:resize handler
1267              *
1268              * @method _defResizeFn
1269              * @param {EventFacade} event The Event object
1270              * @protected
1271              */
1272                 _defResizeFn: function(event) {
1273                         var instance = this;
1274
1275                         instance._resize(event);
1276                 },
1277
1278                 /**
1279              * Logic method for _defResizeFn. Allow AOP.
1280              *
1281              * @method _resize
1282              * @param {EventFacade} event The Event object
1283              * @protected
1284              */
1285                 _resize: function(event) {
1286                         var instance = this;
1287
1288                         instance._handleResizeAlignEvent(event.dragEvent);
1289
1290                         // _syncUI of the wrapper, not using proxy
1291                         instance._syncUI();
1292                 },
1293
1294                 /**
1295              * Default resize:align handler
1296              *
1297              * @method _defResizeAlignFn
1298              * @param {EventFacade} event The Event object
1299              * @protected
1300              */
1301                 _defResizeAlignFn: function(event) {
1302                         var instance = this;
1303
1304                         instance._resizeAlign(event);
1305                 },
1306
1307                 /**
1308              * Logic method for _defResizeAlignFn. Allow AOP.
1309              *
1310              * @method _resizeAlign
1311              * @param {EventFacade} event The Event object
1312              * @protected
1313              */
1314                 _resizeAlign: function(event) {
1315                         var instance = this,
1316                                 info,
1317                                 defMinHeight,
1318                                 defMinWidth;
1319
1320                         instance.lastInfo = instance.info;
1321
1322                         // update the instance.info values
1323                         instance._updateInfo(event);
1324
1325                         info = instance.info;
1326
1327                         // basic resize calculations
1328                         instance._calcResize();
1329
1330                         // if Y.Plugin.ResizeConstrained is not plugged, check for min dimension
1331                         if (!instance.con) {
1332                                 defMinHeight = (instance.get(DEF_MIN_HEIGHT) + instance.totalVSurrounding);
1333                                 defMinWidth = (instance.get(DEF_MIN_WIDTH) + instance.totalHSurrounding);
1334
1335                                 if (info.offsetHeight <= defMinHeight) {
1336                                         instance._checkSize(OFFSET_HEIGHT, defMinHeight);
1337                                 }
1338
1339                                 if (info.offsetWidth <= defMinWidth) {
1340                                         instance._checkSize(OFFSET_WIDTH, defMinWidth);
1341                                 }
1342                         }
1343                 },
1344
1345             /**
1346              * Default resize:end handler
1347              *
1348              * @method _defResizeEndFn
1349              * @param {EventFacade} event The Event object
1350              * @protected
1351              */
1352                 _defResizeEndFn: function(event) {
1353                         var instance = this;
1354
1355                         instance._resizeEnd(event);
1356                 },
1357
1358                 /**
1359              * Logic method for _defResizeEndFn. Allow AOP.
1360              *
1361              * @method _resizeEnd
1362              * @param {EventFacade} event The Event object
1363              * @protected
1364              */
1365                 _resizeEnd: function(event) {
1366                         var instance = this,
1367                                 drag = event.dragEvent.target;
1368
1369                         // reseting actXY from drag when drag end
1370                         drag.actXY = [];
1371
1372                         // syncUI when resize end
1373                         instance._syncUI();
1374
1375                         instance._setActiveHandlesUI(false);
1376
1377                         instance.set(ACTIVE_HANDLE, null);
1378                         instance.set(ACTIVE_HANDLE_NODE, null);
1379
1380                         instance.handle = null;
1381                 },
1382
1383             /**
1384              * Default resize:start handler
1385              *
1386              * @method _defResizeStartFn
1387              * @param {EventFacade} event The Event object
1388              * @protected
1389              */
1390                 _defResizeStartFn: function(event) {
1391                         var instance = this;
1392
1393                         instance._resizeStart(event);
1394                 },
1395
1396                 /**
1397              * Logic method for _defResizeStartFn. Allow AOP.
1398              *
1399              * @method _resizeStart
1400              * @param {EventFacade} event The Event object
1401              * @protected
1402              */
1403                 _resizeStart: function(event) {
1404                         var instance = this,
1405                                 wrapper = instance.get(WRAPPER);
1406
1407                         instance.handle = instance.get(ACTIVE_HANDLE);
1408
1409                         instance.set(RESIZING, true);
1410
1411                         instance._updateSurroundingInfo();
1412
1413                         // create an originalInfo information for reference
1414                         instance.originalInfo = instance._getInfo(wrapper, event);
1415
1416                         instance._updateInfo(event);
1417                 },
1418
1419             /**
1420              * Fires the resize:mouseUp event.
1421              *
1422              * @method _handleMouseUpEvent
1423              * @param {EventFacade} event resize:mouseUp event facade
1424              * @protected
1425              */
1426                 _handleMouseUpEvent: function(event) {
1427                         this.fire(EV_MOUSE_UP, { dragEvent: event, info: this.info });
1428                 },
1429
1430             /**
1431              * Fires the resize:resize event.
1432              *
1433              * @method _handleResizeEvent
1434              * @param {EventFacade} event resize:resize event facade
1435              * @protected
1436              */
1437                 _handleResizeEvent: function(event) {
1438                         this.fire(EV_RESIZE, { dragEvent: event, info: this.info });
1439                 },
1440
1441             /**
1442              * Fires the resize:align event.
1443              *
1444              * @method _handleResizeAlignEvent
1445              * @param {EventFacade} event resize:resize event facade
1446              * @protected
1447              */
1448                 _handleResizeAlignEvent: function(event) {
1449                         this.fire(EV_RESIZE_ALIGN, { dragEvent: event, info: this.info });
1450                 },
1451
1452             /**
1453              * Fires the resize:end event.
1454              *
1455              * @method _handleResizeEndEvent
1456              * @param {EventFacade} event resize:end event facade
1457              * @protected
1458              */
1459                 _handleResizeEndEvent: function(event) {
1460                         this.fire(EV_RESIZE_END, { dragEvent: event, info: this.info });
1461                 },
1462
1463             /**
1464              * Fires the resize:start event.
1465              *
1466              * @method _handleResizeStartEvent
1467              * @param {EventFacade} event resize:start event facade
1468              * @protected
1469              */
1470                 _handleResizeStartEvent: function(event) {
1471             if (!this.get(ACTIVE_HANDLE)) {
1472                 //This handles the "touch" case
1473                             this._setHandleFromNode(event.target.get('node'));
1474             }
1475                         this.fire(EV_RESIZE_START, { dragEvent: event, info: this.info });
1476                 },
1477
1478                 /**
1479                  * Mouseenter event handler for the <a href="Resize.html#config_wrapper">wrapper</a>.
1480                  *
1481                  * @method _onWrapperMouseEnter
1482              * @param {EventFacade} event
1483                  * @protected
1484                  */
1485                 _onWrapperMouseEnter: function(event) {
1486                         var instance = this;
1487
1488                         if (instance.get(AUTO_HIDE)) {
1489                                 instance._setHideHandlesUI(false);
1490                         }
1491                 },
1492
1493                 /**
1494                  * Mouseleave event handler for the <a href="Resize.html#config_wrapper">wrapper</a>.
1495                  *
1496                  * @method _onWrapperMouseLeave
1497              * @param {EventFacade} event
1498                  * @protected
1499                  */
1500                 _onWrapperMouseLeave: function(event) {
1501                         var instance = this;
1502
1503                         if (instance.get(AUTO_HIDE)) {
1504                                 instance._setHideHandlesUI(true);
1505                         }
1506                 },
1507
1508                 /**
1509                  * Handles setting the activeHandle from a node, used from startDrag (for touch) and mouseenter (for mouse).
1510                  *
1511                  * @method _setHandleFromNode
1512              * @param {Node} node
1513                  * @protected
1514                  */
1515         _setHandleFromNode: function(node) {
1516                         var instance = this,
1517                                 handle = instance._extractHandleName(node);
1518
1519                         if (!instance.get(RESIZING)) {
1520                                 instance.set(ACTIVE_HANDLE, handle);
1521                                 instance.set(ACTIVE_HANDLE_NODE, node);
1522
1523                                 instance._setActiveHandlesUI(true);
1524                                 instance._updateChangeHandleInfo(handle);
1525                         }
1526         },
1527
1528                 /**
1529                  * Mouseenter event handler for the handles.
1530                  *
1531                  * @method _onHandleMouseEnter
1532              * @param {EventFacade} event
1533                  * @protected
1534                  */
1535                 _onHandleMouseEnter: function(event) {
1536                         this._setHandleFromNode(event.currentTarget);
1537                 },
1538
1539                 /**
1540                  * Mouseout event handler for the handles.
1541                  *
1542                  * @method _onHandleMouseLeave
1543              * @param {EventFacade} event
1544                  * @protected
1545                  */
1546                 _onHandleMouseLeave: function(event) {
1547                         var instance = this;
1548
1549                         if (!instance.get(RESIZING)) {
1550                                 instance._setActiveHandlesUI(false);
1551                         }
1552                 },
1553
1554                 /**
1555              * Default value for the wrapper attribute
1556              *
1557              * @method _valueWrapper
1558              * @protected
1559              * @readOnly
1560              */
1561                 _valueWrapper: function() {
1562                         var instance = this,
1563                                 node = instance.get(NODE),
1564                                 pNode = node.get(PARENT_NODE),
1565                                 // by deafult the wrapper is always the node
1566                                 wrapper = node;
1567
1568                         // if the node is listed on the wrapTypes or wrap is set to true, create another wrapper
1569                         if (instance.get(WRAP)) {
1570                                 wrapper = Y.Node.create(instance.WRAP_TEMPLATE);
1571
1572                                 if (pNode) {
1573                                         pNode.insertBefore(wrapper, node);
1574                                 }
1575
1576                                 wrapper.append(node);
1577
1578                                 instance._copyStyles(node, wrapper);
1579
1580                                 // remove positioning of wrapped node, the WRAPPER take care about positioning
1581                                 node.setStyles({
1582                                         position: STATIC,
1583                                         left: 0,
1584                                         top: 0
1585                                 });
1586                         }
1587
1588                         return wrapper;
1589                 }
1590         }
1591 );
1592
1593 Y.each(Y.Resize.prototype.ALL_HANDLES, function(handle, i) {
1594         // creating ATTRS with the handles elements
1595         Y.Resize.ATTRS[handleAttrName(handle)] = {
1596                 setter: function() {
1597                         return this._buildHandle(handle);
1598                 },
1599                 value: null,
1600                 writeOnce: true
1601         };
1602 });
1603
1604
1605 }, '3.3.0' ,{requires:['base', 'widget', 'substitute', 'event', 'oop', 'dd-drag', 'dd-delegate', 'dd-drop'], skinnable:true});
1606 YUI.add('resize-proxy', function(Y) {
1607
1608 var ACTIVE_HANDLE_NODE = 'activeHandleNode',
1609         CURSOR = 'cursor',
1610         DRAG_CURSOR = 'dragCursor',
1611         HOST = 'host',
1612         PARENT_NODE = 'parentNode',
1613         PROXY = 'proxy',
1614         PROXY_NODE = 'proxyNode',
1615         RESIZE = 'resize',
1616         RESIZE_PROXY = 'resize-proxy',
1617         WRAPPER = 'wrapper',
1618
1619         getCN = Y.ClassNameManager.getClassName,
1620
1621         CSS_RESIZE_PROXY = getCN(RESIZE, PROXY);
1622
1623 function ResizeProxy() {
1624         ResizeProxy.superclass.constructor.apply(this, arguments);
1625 }
1626
1627 Y.mix(ResizeProxy, {
1628         NAME: RESIZE_PROXY,
1629
1630         NS: PROXY,
1631
1632         ATTRS: {
1633                 /**
1634          * The Resize proxy element.
1635          *
1636          * @attribute proxyNode
1637          * @default Generated using an internal HTML markup
1638          * @type String | Node
1639          */
1640                 proxyNode: {
1641                         setter: Y.one,
1642                         valueFn: function() {
1643                                 return Y.Node.create(this.PROXY_TEMPLATE);
1644                         }
1645                 }
1646         }
1647 });
1648
1649 Y.extend(ResizeProxy, Y.Plugin.Base, {
1650         /**
1651      * Template used to create the resize proxy.
1652      *
1653      * @property PROXY_TEMPLATE
1654      * @type {String}
1655      */
1656         PROXY_TEMPLATE: '<div class="'+CSS_RESIZE_PROXY+'"></div>',
1657
1658         initializer: function() {
1659                 var instance = this;
1660
1661                 instance.afterHostEvent('resize:start', instance._afterResizeStart);
1662                 instance.beforeHostMethod('_resize', instance._beforeHostResize);
1663                 instance.afterHostMethod('_resizeEnd', instance._afterHostResizeEnd);
1664         },
1665
1666         destructor: function() {
1667                 var instance = this;
1668
1669                 instance.get(PROXY_NODE).remove(true);
1670         },
1671
1672         _afterHostResizeEnd: function(event) {
1673                 var instance = this,
1674                         drag = event.dragEvent.target;
1675
1676                 // reseting actXY from drag when drag end
1677                 drag.actXY = [];
1678
1679                 // if proxy is true, hide it on resize end
1680                 instance._syncProxyUI();
1681
1682                 instance.get(PROXY_NODE).hide();
1683         },
1684
1685         _afterResizeStart: function(event) {
1686                 var instance = this;
1687
1688                 instance._renderProxy();
1689         },
1690
1691         _beforeHostResize: function(event) {
1692                 var instance = this,
1693                         host = this.get(HOST);
1694
1695                 host._handleResizeAlignEvent(event.dragEvent);
1696
1697                 // if proxy is true _syncProxyUI instead of _syncUI
1698                 instance._syncProxyUI();
1699
1700                 return new Y.Do.Prevent();
1701         },
1702
1703     /**
1704       * Render the <a href="ResizeProxy.html#config_proxyNode">proxyNode</a> element and
1705       * make it sibling of the <a href="Resize.html#config_node">node</a>.
1706       *
1707       * @method _renderProxy
1708       * @protected
1709       */
1710         _renderProxy: function() {
1711                 var instance = this,
1712                         host = this.get(HOST),
1713                         proxyNode = instance.get(PROXY_NODE);
1714
1715                 if (!proxyNode.inDoc()) {
1716                         host.get(WRAPPER).get(PARENT_NODE).append(
1717                                 proxyNode.hide()
1718                         );
1719                 }
1720         },
1721
1722         /**
1723      * Sync the proxy UI with internal values from
1724      * <a href="ResizeProxy.html#property_info">info</a>.
1725      *
1726      * @method _syncProxyUI
1727      * @protected
1728      */
1729         _syncProxyUI: function() {
1730                 var instance = this,
1731                         host = this.get(HOST),
1732                         info = host.info,
1733                         activeHandleNode = host.get(ACTIVE_HANDLE_NODE),
1734                         proxyNode = instance.get(PROXY_NODE),
1735                         cursor = activeHandleNode.getStyle(CURSOR);
1736
1737                 proxyNode.show().setStyle(CURSOR, cursor);
1738
1739                 host.delegate.dd.set(DRAG_CURSOR, cursor);
1740
1741                 proxyNode.sizeTo(info.offsetWidth, info.offsetHeight);
1742
1743                 proxyNode.setXY([ info.left, info.top ]);
1744         }
1745 });
1746
1747 Y.namespace('Plugin');
1748 Y.Plugin.ResizeProxy = ResizeProxy;
1749
1750
1751 }, '3.3.0' ,{requires:['resize-base', 'plugin'], skinnable:false});
1752 YUI.add('resize-constrain', function(Y) {
1753
1754 var Lang = Y.Lang,
1755         isBoolean = Lang.isBoolean,
1756         isNumber = Lang.isNumber,
1757         isString = Lang.isString,
1758         capitalize = Y.Resize.capitalize,
1759
1760         isNode = function(v) {
1761                 return (v instanceof Y.Node);
1762         },
1763
1764         toNumber = function(num) {
1765                 return parseFloat(num) || 0;
1766         },
1767
1768         BORDER_BOTTOM_WIDTH = 'borderBottomWidth',
1769         BORDER_LEFT_WIDTH = 'borderLeftWidth',
1770         BORDER_RIGHT_WIDTH = 'borderRightWidth',
1771         BORDER_TOP_WIDTH = 'borderTopWidth',
1772         BORDER = 'border',
1773         BOTTOM = 'bottom',
1774         CON = 'con',
1775         CONSTRAIN = 'constrain',
1776         HOST = 'host',
1777         LEFT = 'left',
1778         MAX_HEIGHT = 'maxHeight',
1779         MAX_WIDTH = 'maxWidth',
1780         MIN_HEIGHT = 'minHeight',
1781         MIN_WIDTH = 'minWidth',
1782         NODE = 'node',
1783         OFFSET_HEIGHT = 'offsetHeight',
1784         OFFSET_WIDTH = 'offsetWidth',
1785         PRESEVE_RATIO = 'preserveRatio',
1786         REGION = 'region',
1787         RESIZE_CONTRAINED = 'resizeConstrained',
1788         RIGHT = 'right',
1789         TICK_X = 'tickX',
1790         TICK_Y = 'tickY',
1791         TOP = 'top',
1792         WIDTH = 'width',
1793         VIEW = 'view',
1794         VIEWPORT_REGION = 'viewportRegion';
1795
1796 function ResizeConstrained() {
1797         ResizeConstrained.superclass.constructor.apply(this, arguments);
1798 }
1799
1800 Y.mix(ResizeConstrained, {
1801         NAME: RESIZE_CONTRAINED,
1802
1803         NS: CON,
1804
1805         ATTRS: {
1806         /**
1807         * Will attempt to constrain the resize node to the boundaries. Arguments:<br>
1808         * 'view': Contrain to Viewport<br>
1809         * '#selector_string': Constrain to this node<br>
1810         * '{Region Object}': An Object Literal containing a valid region (top, right, bottom, left) of page positions
1811         *
1812         * @attribute constrain
1813         * @type {String/Object/Node}
1814         */
1815                 constrain: {
1816                         setter: function(v) {
1817                                 if (v && (isNode(v) || isString(v) || v.nodeType)) {
1818                                         v = Y.one(v);
1819                                 }
1820
1821                                 return v;
1822                         }
1823                 },
1824
1825         /**
1826          * The minimum height of the element
1827          *
1828          * @attribute minHeight
1829          * @default 15
1830          * @type Number
1831          */
1832                 minHeight: {
1833                         value: 15,
1834                         validator: isNumber
1835                 },
1836
1837         /**
1838          * The minimum width of the element
1839          *
1840          * @attribute minWidth
1841          * @default 15
1842          * @type Number
1843          */
1844                 minWidth: {
1845                         value: 15,
1846                         validator: isNumber
1847                 },
1848
1849         /**
1850          * The maximum height of the element
1851          *
1852          * @attribute maxHeight
1853          * @default Infinity
1854          * @type Number
1855          */
1856                 maxHeight: {
1857                         value: Infinity,
1858                         validator: isNumber
1859                 },
1860
1861         /**
1862          * The maximum width of the element
1863          *
1864          * @attribute maxWidth
1865          * @default Infinity
1866          * @type Number
1867          */
1868                 maxWidth: {
1869                         value: Infinity,
1870                         validator: isNumber
1871                 },
1872
1873                 /**
1874          * Maintain the element's ratio when resizing.
1875          *
1876          * @attribute preserveRatio
1877          * @default false
1878          * @type boolean
1879          */
1880                 preserveRatio: {
1881                         value: false,
1882                         validator: isBoolean
1883                 },
1884
1885                 /**
1886          * The number of x ticks to span the resize to.
1887          *
1888          * @attribute tickX
1889          * @default false
1890          * @type Number | false
1891          */
1892                 tickX: {
1893                         value: false
1894                 },
1895
1896         /**
1897          * The number of y ticks to span the resize to.
1898          *
1899          * @attribute tickY
1900          * @default false
1901          * @type Number | false
1902          */
1903                 tickY: {
1904                         value: false
1905                 }
1906         }
1907 });
1908
1909 Y.extend(ResizeConstrained, Y.Plugin.Base, {
1910         /**
1911          * Stores the <code>constrain</code>
1912          * surrounding information retrieved from
1913          * <a href="Resize.html#method__getBoxSurroundingInfo">_getBoxSurroundingInfo</a>.
1914          *
1915          * @property constrainSurrounding
1916          * @type Object
1917          * @default null
1918          */
1919         constrainSurrounding: null,
1920
1921         initializer: function() {
1922                 var instance = this,
1923                         host = instance.get(HOST);
1924
1925                 host.delegate.dd.plug(
1926                         Y.Plugin.DDConstrained,
1927                         {
1928                                 tickX: instance.get(TICK_X),
1929                                 tickY: instance.get(TICK_Y)
1930                         }
1931                 );
1932
1933                 host.after('resize:align', Y.bind(instance._handleResizeAlignEvent, instance));
1934                 host.on('resize:start', Y.bind(instance._handleResizeStartEvent, instance));
1935         },
1936
1937         /**
1938      * Helper method to update the current values on
1939      * <a href="Resize.html#property_info">info</a> to respect the
1940      * constrain node.
1941          *
1942          * @method _checkConstrain
1943          * @param {String} axis 'top' or 'left'
1944          * @param {String} axisConstrain 'bottom' or 'right'
1945          * @param {String} offset 'offsetHeight' or 'offsetWidth'
1946          * @protected
1947          */
1948         _checkConstrain: function(axis, axisConstrain, offset) {
1949                 var instance = this,
1950                         point1,
1951                         point1Constrain,
1952                         point2,
1953                         point2Constrain,
1954                         host = instance.get(HOST),
1955                         info = host.info,
1956                         constrainBorders = instance.constrainSurrounding.border,
1957                         region = instance._getConstrainRegion();
1958
1959                 if (region) {
1960                         point1 = info[axis] + info[offset];
1961                         point1Constrain = region[axisConstrain] - toNumber(constrainBorders[capitalize(BORDER, axisConstrain, WIDTH)]);
1962
1963                         if (point1 >= point1Constrain) {
1964                                 info[offset] -= (point1 - point1Constrain);
1965                         }
1966
1967                         point2 = info[axis];
1968                         point2Constrain = region[axis] + toNumber(constrainBorders[capitalize(BORDER, axis, WIDTH)]);
1969
1970                         if (point2 <= point2Constrain) {
1971                                 info[axis] += (point2Constrain - point2);
1972                                 info[offset] -= (point2Constrain - point2);
1973                         }
1974                 }
1975         },
1976
1977     /**
1978      * Update the current values on <a href="Resize.html#property_info">info</a>
1979      * to respect the maxHeight and minHeight.
1980      *
1981      * @method _checkHeight
1982      * @protected
1983      */
1984         _checkHeight: function() {
1985                 var instance = this,
1986                         host = instance.get(HOST),
1987                         info = host.info,
1988                         maxHeight = (instance.get(MAX_HEIGHT) + host.totalVSurrounding),
1989                         minHeight = (instance.get(MIN_HEIGHT) + host.totalVSurrounding);
1990
1991                 instance._checkConstrain(TOP, BOTTOM, OFFSET_HEIGHT);
1992
1993                 if (info.offsetHeight > maxHeight) {
1994                         host._checkSize(OFFSET_HEIGHT, maxHeight);
1995                 }
1996
1997                 if (info.offsetHeight < minHeight) {
1998                         host._checkSize(OFFSET_HEIGHT, minHeight);
1999                 }
2000         },
2001
2002     /**
2003      * Update the current values on <a href="Resize.html#property_info">info</a>
2004      * calculating the correct ratio for the other values.
2005      *
2006      * @method _checkRatio
2007      * @protected
2008      */
2009         _checkRatio: function() {
2010                 var instance = this,
2011                         host = instance.get(HOST),
2012                         info = host.info,
2013                         originalInfo = host.originalInfo,
2014                         oWidth = originalInfo.offsetWidth,
2015                         oHeight = originalInfo.offsetHeight,
2016                         oTop = originalInfo.top,
2017                         oLeft = originalInfo.left,
2018                         oBottom = originalInfo.bottom,
2019                         oRight = originalInfo.right,
2020                         // wRatio/hRatio functions keep the ratio information always synced with the current info information
2021                         // RETURN: percentage how much width/height has changed from the original width/height
2022                         wRatio = function() {
2023                                 return (info.offsetWidth/oWidth);
2024                         },
2025                         hRatio = function() {
2026                                 return (info.offsetHeight/oHeight);
2027                         },
2028                         isClosestToHeight = host.changeHeightHandles,
2029                         bottomDiff,
2030                         constrainBorders,
2031                         constrainRegion,
2032                         leftDiff,
2033                         rightDiff,
2034                         topDiff;
2035
2036                 // check whether the resizable node is closest to height or not
2037                 if (instance.get(CONSTRAIN) && host.changeHeightHandles && host.changeWidthHandles) {
2038                         constrainRegion = instance._getConstrainRegion();
2039                         constrainBorders = instance.constrainSurrounding.border;
2040                         bottomDiff = (constrainRegion.bottom - toNumber(constrainBorders[BORDER_BOTTOM_WIDTH])) - oBottom;
2041                         leftDiff = oLeft - (constrainRegion.left + toNumber(constrainBorders[BORDER_LEFT_WIDTH]));
2042                         rightDiff = (constrainRegion.right - toNumber(constrainBorders[BORDER_RIGHT_WIDTH])) - oRight;
2043                         topDiff = oTop - (constrainRegion.top + toNumber(constrainBorders[BORDER_TOP_WIDTH]));
2044
2045                         if (host.changeLeftHandles && host.changeTopHandles) {
2046                                 isClosestToHeight = (topDiff < leftDiff);
2047                         }
2048                         else if (host.changeLeftHandles) {
2049                                 isClosestToHeight = (bottomDiff < leftDiff);
2050                         }
2051                         else if (host.changeTopHandles) {
2052                                 isClosestToHeight = (topDiff < rightDiff);
2053                         }
2054                         else {
2055                                 isClosestToHeight = (bottomDiff < rightDiff);
2056                         }
2057                 }
2058
2059                 // when the height of the resizable element touch the border of the constrain first
2060                 // force the offsetWidth to be calculated based on the height ratio
2061                 if (isClosestToHeight) {
2062                         info.offsetWidth = oWidth*hRatio();
2063                         instance._checkWidth();
2064                         info.offsetHeight = oHeight*wRatio();
2065                 }
2066                 else {
2067                         info.offsetHeight = oHeight*wRatio();
2068                         instance._checkHeight();
2069                         info.offsetWidth = oWidth*hRatio();
2070                 }
2071
2072                 // fixing the top on handles which are able to change top
2073                 // the idea here is change the top based on how much the height has changed instead of follow the dy
2074                 if (host.changeTopHandles) {
2075                         info.top = oTop + (oHeight - info.offsetHeight);
2076                 }
2077
2078                 // fixing the left on handles which are able to change left
2079                 // the idea here is change the left based on how much the width has changed instead of follow the dx
2080                 if (host.changeLeftHandles) {
2081                         info.left = oLeft + (oWidth - info.offsetWidth);
2082                 }
2083
2084                 // rounding values to avoid pixel jumpings
2085                 Y.each(info, function(value, key) {
2086                         if (isNumber(value)) {
2087                                 info[key] = Math.round(value);
2088                         }
2089                 });
2090         },
2091
2092         /**
2093          * Check whether the resizable node is inside the constrain region.
2094          *
2095          * @method _checkRegion
2096          * @protected
2097          * @return {boolean}
2098          */
2099         _checkRegion: function() {
2100                 var instance = this,
2101                         host = instance.get(HOST),
2102                         region = instance._getConstrainRegion();
2103
2104                 return Y.DOM.inRegion(null, region, true, host.info);
2105         },
2106
2107     /**
2108      * Update the current values on <a href="Resize.html#property_info">info</a>
2109      * to respect the maxWidth and minWidth.
2110      *
2111      * @method _checkWidth
2112      * @protected
2113      */
2114         _checkWidth: function() {
2115                 var instance = this,
2116                         host = instance.get(HOST),
2117                         info = host.info,
2118                         maxWidth = (instance.get(MAX_WIDTH) + host.totalHSurrounding),
2119                         minWidth = (instance.get(MIN_WIDTH) + host.totalHSurrounding);
2120
2121                 instance._checkConstrain(LEFT, RIGHT, OFFSET_WIDTH);
2122
2123                 if (info.offsetWidth < minWidth) {
2124                         host._checkSize(OFFSET_WIDTH, minWidth);
2125                 }
2126
2127                 if (info.offsetWidth > maxWidth) {
2128                         host._checkSize(OFFSET_WIDTH, maxWidth);
2129                 }
2130         },
2131
2132         /**
2133          * Get the constrain region based on the <code>constrain</code>
2134      * attribute.
2135          *
2136          * @method _getConstrainRegion
2137          * @protected
2138          * @return {Object Region}
2139          */
2140         _getConstrainRegion: function() {
2141                 var instance = this,
2142                         host = instance.get(HOST),
2143                         node = host.get(NODE),
2144                         constrain = instance.get(CONSTRAIN),
2145                         region = null;
2146
2147                 if (constrain) {
2148                         if (constrain == VIEW) {
2149                                 region = node.get(VIEWPORT_REGION);
2150                         }
2151                         else if (isNode(constrain)) {
2152                                 region = constrain.get(REGION);
2153                         }
2154                         else {
2155                                 region = constrain;
2156                         }
2157                 }
2158
2159                 return region;
2160         },
2161
2162         _handleResizeAlignEvent: function(event) {
2163                 var instance = this,
2164                         host = instance.get(HOST);
2165
2166                 // check the max/min height and locking top when these values are reach
2167                 instance._checkHeight();
2168
2169                 // check the max/min width and locking left when these values are reach
2170                 instance._checkWidth();
2171
2172                 // calculating the ratio, for proportionally resizing
2173                 if (instance.get(PRESEVE_RATIO)) {
2174                         instance._checkRatio();
2175                 }
2176
2177                 if (instance.get(CONSTRAIN) && !instance._checkRegion()) {
2178                         host.info = host.lastInfo;
2179                 }
2180         },
2181
2182         _handleResizeStartEvent: function(event) {
2183                 var instance = this,
2184                         constrain = instance.get(CONSTRAIN),
2185                         host = instance.get(HOST);
2186
2187                 instance.constrainSurrounding = host._getBoxSurroundingInfo(constrain);
2188         }
2189 });
2190
2191 Y.namespace('Plugin');
2192 Y.Plugin.ResizeConstrained = ResizeConstrained;
2193
2194
2195 }, '3.3.0' ,{requires:['resize-base', 'plugin'], skinnable:false});
2196
2197
2198 YUI.add('resize', function(Y){}, '3.3.0' ,{use:['resize-base', 'resize-proxy', 'resize-constrain']});
2199