Upgrade to ExtJS 3.3.1 - Released 11/30/2010
[extjs.git] / docs / source / Resizable.html
1 <html>
2 <head>
3   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />    
4   <title>The source code</title>
5     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
6     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
7 </head>
8 <body  onload="prettyPrint();">
9     <pre class="prettyprint lang-js">/*!
10  * Ext JS Library 3.3.1
11  * Copyright(c) 2006-2010 Sencha Inc.
12  * licensing@sencha.com
13  * http://www.sencha.com/license
14  */
15 <div id="cls-Ext.Resizable"></div>/**
16  * @class Ext.Resizable
17  * @extends Ext.util.Observable
18  * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
19  * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
20  * the textarea in a div and set 'resizeChild' to true (or to the id of the element), <b>or</b> set wrap:true in your config and
21  * the element will be wrapped for you automatically.</p>
22  * <p>Here is the list of valid resize handles:</p>
23  * <pre>
24 Value   Description
25 ------  -------------------
26  'n'     north
27  's'     south
28  'e'     east
29  'w'     west
30  'nw'    northwest
31  'sw'    southwest
32  'se'    southeast
33  'ne'    northeast
34  'all'   all
35 </pre>
36  * <p>Here's an example showing the creation of a typical Resizable:</p>
37  * <pre><code>
38 var resizer = new Ext.Resizable('element-id', {
39     handles: 'all',
40     minWidth: 200,
41     minHeight: 100,
42     maxWidth: 500,
43     maxHeight: 400,
44     pinned: true
45 });
46 resizer.on('resize', myHandler);
47 </code></pre>
48  * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
49  * resizer.east.setDisplayed(false);</p>
50  * @constructor
51  * Create a new resizable component
52  * @param {Mixed} el The id or element to resize
53  * @param {Object} config configuration options
54   */
55 Ext.Resizable = Ext.extend(Ext.util.Observable, {
56
57     constructor: function(el, config){
58         this.el = Ext.get(el);
59         if(config && config.wrap){
60             config.resizeChild = this.el;
61             this.el = this.el.wrap(typeof config.wrap == 'object' ? config.wrap : {cls:'xresizable-wrap'});
62             this.el.id = this.el.dom.id = config.resizeChild.id + '-rzwrap';
63             this.el.setStyle('overflow', 'hidden');
64             this.el.setPositioning(config.resizeChild.getPositioning());
65             config.resizeChild.clearPositioning();
66             if(!config.width || !config.height){
67                 var csize = config.resizeChild.getSize();
68                 this.el.setSize(csize.width, csize.height);
69             }
70             if(config.pinned && !config.adjustments){
71                 config.adjustments = 'auto';
72             }
73         }
74
75         <div id="prop-Ext.Resizable-proxy"></div>/**
76          * The proxy Element that is resized in place of the real Element during the resize operation.
77          * This may be queried using {@link Ext.Element#getBox} to provide the new area to resize to.
78          * Read only.
79          * @type Ext.Element.
80          * @property proxy
81          */
82         this.proxy = this.el.createProxy({tag: 'div', cls: 'x-resizable-proxy', id: this.el.id + '-rzproxy'}, Ext.getBody());
83         this.proxy.unselectable();
84         this.proxy.enableDisplayMode('block');
85
86         Ext.apply(this, config);
87
88         if(this.pinned){
89             this.disableTrackOver = true;
90             this.el.addClass('x-resizable-pinned');
91         }
92         // if the element isn't positioned, make it relative
93         var position = this.el.getStyle('position');
94         if(position != 'absolute' && position != 'fixed'){
95             this.el.setStyle('position', 'relative');
96         }
97         if(!this.handles){ // no handles passed, must be legacy style
98             this.handles = 's,e,se';
99             if(this.multiDirectional){
100                 this.handles += ',n,w';
101             }
102         }
103         if(this.handles == 'all'){
104             this.handles = 'n s e w ne nw se sw';
105         }
106         var hs = this.handles.split(/\s*?[,;]\s*?| /);
107         var ps = Ext.Resizable.positions;
108         for(var i = 0, len = hs.length; i < len; i++){
109             if(hs[i] && ps[hs[i]]){
110                 var pos = ps[hs[i]];
111                 this[pos] = new Ext.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent, this.handleCls);
112             }
113         }
114         // legacy
115         this.corner = this.southeast;
116
117         if(this.handles.indexOf('n') != -1 || this.handles.indexOf('w') != -1){
118             this.updateBox = true;
119         }
120
121         this.activeHandle = null;
122
123         if(this.resizeChild){
124             if(typeof this.resizeChild == 'boolean'){
125                 this.resizeChild = Ext.get(this.el.dom.firstChild, true);
126             }else{
127                 this.resizeChild = Ext.get(this.resizeChild, true);
128             }
129         }
130
131         if(this.adjustments == 'auto'){
132             var rc = this.resizeChild;
133             var hw = this.west, he = this.east, hn = this.north, hs = this.south;
134             if(rc && (hw || hn)){
135                 rc.position('relative');
136                 rc.setLeft(hw ? hw.el.getWidth() : 0);
137                 rc.setTop(hn ? hn.el.getHeight() : 0);
138             }
139             this.adjustments = [
140                 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
141                 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
142             ];
143         }
144
145         if(this.draggable){
146             this.dd = this.dynamic ?
147                 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
148             this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
149             if(this.constrainTo){
150                 this.dd.constrainTo(this.constrainTo);
151             }
152         }
153
154         this.addEvents(
155             <div id="event-Ext.Resizable-beforeresize"></div>/**
156              * @event beforeresize
157              * Fired before resize is allowed. Set {@link #enabled} to false to cancel resize.
158              * @param {Ext.Resizable} this
159              * @param {Ext.EventObject} e The mousedown event
160              */
161             'beforeresize',
162             <div id="event-Ext.Resizable-resize"></div>/**
163              * @event resize
164              * Fired after a resize.
165              * @param {Ext.Resizable} this
166              * @param {Number} width The new width
167              * @param {Number} height The new height
168              * @param {Ext.EventObject} e The mouseup event
169              */
170             'resize'
171         );
172
173         if(this.width !== null && this.height !== null){
174             this.resizeTo(this.width, this.height);
175         }else{
176             this.updateChildSize();
177         }
178         if(Ext.isIE){
179             this.el.dom.style.zoom = 1;
180         }
181         Ext.Resizable.superclass.constructor.call(this);
182     },
183
184     <div id="cfg-Ext.Resizable-adjustments"></div>/**
185      * @cfg {Array/String} adjustments String 'auto' or an array [width, height] with values to be <b>added</b> to the
186      * resize operation's new size (defaults to <tt>[0, 0]</tt>)
187      */
188     adjustments : [0, 0],
189     <div id="cfg-Ext.Resizable-animate"></div>/**
190      * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
191      */
192     animate : false,
193     <div id="cfg-Ext.Resizable-constrainTo"></div>/**
194      * @cfg {Mixed} constrainTo Constrain the resize to a particular element
195      */
196     <div id="cfg-Ext.Resizable-disableTrackOver"></div>/**
197      * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
198      */
199     disableTrackOver : false,
200     <div id="cfg-Ext.Resizable-draggable"></div>/**
201      * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
202      */
203     draggable: false,
204     <div id="cfg-Ext.Resizable-duration"></div>/**
205      * @cfg {Number} duration Animation duration if animate = true (defaults to 0.35)
206      */
207     duration : 0.35,
208     <div id="cfg-Ext.Resizable-dynamic"></div>/**
209      * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
210      */
211     dynamic : false,
212     <div id="cfg-Ext.Resizable-easing"></div>/**
213      * @cfg {String} easing Animation easing if animate = true (defaults to <tt>'easingOutStrong'</tt>)
214      */
215     easing : 'easeOutStrong',
216     <div id="cfg-Ext.Resizable-enabled"></div>/**
217      * @cfg {Boolean} enabled False to disable resizing (defaults to true)
218      */
219     enabled : true,
220     <div id="prop-Ext.Resizable-enabled"></div>/**
221      * @property enabled Writable. False if resizing is disabled.
222      * @type Boolean
223      */
224     <div id="cfg-Ext.Resizable-handles"></div>/**
225      * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined).
226      * Specify either <tt>'all'</tt> or any of <tt>'n s e w ne nw se sw'</tt>.
227      */
228     handles : false,
229     <div id="cfg-Ext.Resizable-multiDirectional"></div>/**
230      * @cfg {Boolean} multiDirectional <b>Deprecated</b>.  Deprecated style of adding multi-direction resize handles.
231      */
232     multiDirectional : false,
233     <div id="cfg-Ext.Resizable-height"></div>/**
234      * @cfg {Number} height The height of the element in pixels (defaults to null)
235      */
236     height : null,
237     <div id="cfg-Ext.Resizable-width"></div>/**
238      * @cfg {Number} width The width of the element in pixels (defaults to null)
239      */
240     width : null,
241     <div id="cfg-Ext.Resizable-heightIncrement"></div>/**
242      * @cfg {Number} heightIncrement The increment to snap the height resize in pixels
243      * (only applies if <code>{@link #dynamic}==true</code>). Defaults to <tt>0</tt>.
244      */
245     heightIncrement : 0,
246     <div id="cfg-Ext.Resizable-widthIncrement"></div>/**
247      * @cfg {Number} widthIncrement The increment to snap the width resize in pixels
248      * (only applies if <code>{@link #dynamic}==true</code>). Defaults to <tt>0</tt>.
249      */
250     widthIncrement : 0,
251     <div id="cfg-Ext.Resizable-minHeight"></div>/**
252      * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
253      */
254     minHeight : 5,
255     <div id="cfg-Ext.Resizable-minWidth"></div>/**
256      * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
257      */
258     minWidth : 5,
259     <div id="cfg-Ext.Resizable-maxHeight"></div>/**
260      * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
261      */
262     maxHeight : 10000,
263     <div id="cfg-Ext.Resizable-maxWidth"></div>/**
264      * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
265      */
266     maxWidth : 10000,
267     <div id="cfg-Ext.Resizable-minX"></div>/**
268      * @cfg {Number} minX The minimum x for the element (defaults to 0)
269      */
270     minX: 0,
271     <div id="cfg-Ext.Resizable-minY"></div>/**
272      * @cfg {Number} minY The minimum x for the element (defaults to 0)
273      */
274     minY: 0,
275     <div id="cfg-Ext.Resizable-pinned"></div>/**
276      * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
277      * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
278      */
279     pinned : false,
280     <div id="cfg-Ext.Resizable-preserveRatio"></div>/**
281      * @cfg {Boolean} preserveRatio True to preserve the original ratio between height
282      * and width during resize (defaults to false)
283      */
284     preserveRatio : false,
285     <div id="cfg-Ext.Resizable-resizeChild"></div>/**
286      * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
287      */
288     resizeChild : false,
289     <div id="cfg-Ext.Resizable-transparent"></div>/**
290      * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
291      */
292     transparent: false,
293     <div id="cfg-Ext.Resizable-resizeRegion"></div>/**
294      * @cfg {Ext.lib.Region} resizeRegion Constrain the resize to a particular region
295      */
296     <div id="cfg-Ext.Resizable-wrap"></div>/**
297      * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
298      * in favor of the handles config option (defaults to false)
299      */
300     <div id="cfg-Ext.Resizable-handleCls"></div>/**
301      * @cfg {String} handleCls A css class to add to each handle. Defaults to <tt>''</tt>.
302      */
303
304
305     <div id="method-Ext.Resizable-resizeTo"></div>/**
306      * Perform a manual resize and fires the 'resize' event.
307      * @param {Number} width
308      * @param {Number} height
309      */
310     resizeTo : function(width, height){
311         this.el.setSize(width, height);
312         this.updateChildSize();
313         this.fireEvent('resize', this, width, height, null);
314     },
315
316     // private
317     startSizing : function(e, handle){
318         this.fireEvent('beforeresize', this, e);
319         if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
320
321             if(!this.overlay){
322                 this.overlay = this.el.createProxy({tag: 'div', cls: 'x-resizable-overlay', html: '&#160;'}, Ext.getBody());
323                 this.overlay.unselectable();
324                 this.overlay.enableDisplayMode('block');
325                 this.overlay.on({
326                     scope: this,
327                     mousemove: this.onMouseMove,
328                     mouseup: this.onMouseUp
329                 });
330             }
331             this.overlay.setStyle('cursor', handle.el.getStyle('cursor'));
332
333             this.resizing = true;
334             this.startBox = this.el.getBox();
335             this.startPoint = e.getXY();
336             this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
337                             (this.startBox.y + this.startBox.height) - this.startPoint[1]];
338
339             this.overlay.setSize(Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true));
340             this.overlay.show();
341
342             if(this.constrainTo) {
343                 var ct = Ext.get(this.constrainTo);
344                 this.resizeRegion = ct.getRegion().adjust(
345                     ct.getFrameWidth('t'),
346                     ct.getFrameWidth('l'),
347                     -ct.getFrameWidth('b'),
348                     -ct.getFrameWidth('r')
349                 );
350             }
351
352             this.proxy.setStyle('visibility', 'hidden'); // workaround display none
353             this.proxy.show();
354             this.proxy.setBox(this.startBox);
355             if(!this.dynamic){
356                 this.proxy.setStyle('visibility', 'visible');
357             }
358         }
359     },
360
361     // private
362     onMouseDown : function(handle, e){
363         if(this.enabled){
364             e.stopEvent();
365             this.activeHandle = handle;
366             this.startSizing(e, handle);
367         }
368     },
369
370     // private
371     onMouseUp : function(e){
372         this.activeHandle = null;
373         var size = this.resizeElement();
374         this.resizing = false;
375         this.handleOut();
376         this.overlay.hide();
377         this.proxy.hide();
378         this.fireEvent('resize', this, size.width, size.height, e);
379     },
380
381     // private
382     updateChildSize : function(){
383         if(this.resizeChild){
384             var el = this.el;
385             var child = this.resizeChild;
386             var adj = this.adjustments;
387             if(el.dom.offsetWidth){
388                 var b = el.getSize(true);
389                 child.setSize(b.width+adj[0], b.height+adj[1]);
390             }
391             // Second call here for IE
392             // The first call enables instant resizing and
393             // the second call corrects scroll bars if they
394             // exist
395             if(Ext.isIE){
396                 setTimeout(function(){
397                     if(el.dom.offsetWidth){
398                         var b = el.getSize(true);
399                         child.setSize(b.width+adj[0], b.height+adj[1]);
400                     }
401                 }, 10);
402             }
403         }
404     },
405
406     // private
407     snap : function(value, inc, min){
408         if(!inc || !value){
409             return value;
410         }
411         var newValue = value;
412         var m = value % inc;
413         if(m > 0){
414             if(m > (inc/2)){
415                 newValue = value + (inc-m);
416             }else{
417                 newValue = value - m;
418             }
419         }
420         return Math.max(min, newValue);
421     },
422
423     <div id="method-Ext.Resizable-resizeElement"></div>/**
424      * <p>Performs resizing of the associated Element. This method is called internally by this
425      * class, and should not be called by user code.</p>
426      * <p>If a Resizable is being used to resize an Element which encapsulates a more complex UI
427      * component such as a Panel, this method may be overridden by specifying an implementation
428      * as a config option to provide appropriate behaviour at the end of the resize operation on
429      * mouseup, for example resizing the Panel, and relaying the Panel's content.</p>
430      * <p>The new area to be resized to is available by examining the state of the {@link #proxy}
431      * Element. Example:
432 <pre><code>
433 new Ext.Panel({
434     title: 'Resize me',
435     x: 100,
436     y: 100,
437     renderTo: Ext.getBody(),
438     floating: true,
439     frame: true,
440     width: 400,
441     height: 200,
442     listeners: {
443         render: function(p) {
444             new Ext.Resizable(p.getEl(), {
445                 handles: 'all',
446                 pinned: true,
447                 transparent: true,
448                 resizeElement: function() {
449                     var box = this.proxy.getBox();
450                     p.updateBox(box);
451                     if (p.layout) {
452                         p.doLayout();
453                     }
454                     return box;
455                 }
456            });
457        }
458     }
459 }).show();
460 </code></pre>
461      */
462     resizeElement : function(){
463         var box = this.proxy.getBox();
464         if(this.updateBox){
465             this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
466         }else{
467             this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
468         }
469         this.updateChildSize();
470         if(!this.dynamic){
471             this.proxy.hide();
472         }
473         if(this.draggable && this.constrainTo){
474             this.dd.resetConstraints();
475             this.dd.constrainTo(this.constrainTo);
476         }
477         return box;
478     },
479
480     // private
481     constrain : function(v, diff, m, mx){
482         if(v - diff < m){
483             diff = v - m;
484         }else if(v - diff > mx){
485             diff = v - mx;
486         }
487         return diff;
488     },
489
490     // private
491     onMouseMove : function(e){
492         if(this.enabled && this.activeHandle){
493             try{// try catch so if something goes wrong the user doesn't get hung
494
495             if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
496                 return;
497             }
498
499             //var curXY = this.startPoint;
500             var curSize = this.curSize || this.startBox,
501                 x = this.startBox.x, y = this.startBox.y,
502                 ox = x,
503                 oy = y,
504                 w = curSize.width,
505                 h = curSize.height,
506                 ow = w,
507                 oh = h,
508                 mw = this.minWidth,
509                 mh = this.minHeight,
510                 mxw = this.maxWidth,
511                 mxh = this.maxHeight,
512                 wi = this.widthIncrement,
513                 hi = this.heightIncrement,
514                 eventXY = e.getXY(),
515                 diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0])),
516                 diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1])),
517                 pos = this.activeHandle.position,
518                 tw,
519                 th;
520
521             switch(pos){
522                 case 'east':
523                     w += diffX;
524                     w = Math.min(Math.max(mw, w), mxw);
525                     break;
526                 case 'south':
527                     h += diffY;
528                     h = Math.min(Math.max(mh, h), mxh);
529                     break;
530                 case 'southeast':
531                     w += diffX;
532                     h += diffY;
533                     w = Math.min(Math.max(mw, w), mxw);
534                     h = Math.min(Math.max(mh, h), mxh);
535                     break;
536                 case 'north':
537                     diffY = this.constrain(h, diffY, mh, mxh);
538                     y += diffY;
539                     h -= diffY;
540                     break;
541                 case 'west':
542                     diffX = this.constrain(w, diffX, mw, mxw);
543                     x += diffX;
544                     w -= diffX;
545                     break;
546                 case 'northeast':
547                     w += diffX;
548                     w = Math.min(Math.max(mw, w), mxw);
549                     diffY = this.constrain(h, diffY, mh, mxh);
550                     y += diffY;
551                     h -= diffY;
552                     break;
553                 case 'northwest':
554                     diffX = this.constrain(w, diffX, mw, mxw);
555                     diffY = this.constrain(h, diffY, mh, mxh);
556                     y += diffY;
557                     h -= diffY;
558                     x += diffX;
559                     w -= diffX;
560                     break;
561                case 'southwest':
562                     diffX = this.constrain(w, diffX, mw, mxw);
563                     h += diffY;
564                     h = Math.min(Math.max(mh, h), mxh);
565                     x += diffX;
566                     w -= diffX;
567                     break;
568             }
569
570             var sw = this.snap(w, wi, mw);
571             var sh = this.snap(h, hi, mh);
572             if(sw != w || sh != h){
573                 switch(pos){
574                     case 'northeast':
575                         y -= sh - h;
576                     break;
577                     case 'north':
578                         y -= sh - h;
579                         break;
580                     case 'southwest':
581                         x -= sw - w;
582                     break;
583                     case 'west':
584                         x -= sw - w;
585                         break;
586                     case 'northwest':
587                         x -= sw - w;
588                         y -= sh - h;
589                     break;
590                 }
591                 w = sw;
592                 h = sh;
593             }
594
595             if(this.preserveRatio){
596                 switch(pos){
597                     case 'southeast':
598                     case 'east':
599                         h = oh * (w/ow);
600                         h = Math.min(Math.max(mh, h), mxh);
601                         w = ow * (h/oh);
602                        break;
603                     case 'south':
604                         w = ow * (h/oh);
605                         w = Math.min(Math.max(mw, w), mxw);
606                         h = oh * (w/ow);
607                         break;
608                     case 'northeast':
609                         w = ow * (h/oh);
610                         w = Math.min(Math.max(mw, w), mxw);
611                         h = oh * (w/ow);
612                     break;
613                     case 'north':
614                         tw = w;
615                         w = ow * (h/oh);
616                         w = Math.min(Math.max(mw, w), mxw);
617                         h = oh * (w/ow);
618                         x += (tw - w) / 2;
619                         break;
620                     case 'southwest':
621                         h = oh * (w/ow);
622                         h = Math.min(Math.max(mh, h), mxh);
623                         tw = w;
624                         w = ow * (h/oh);
625                         x += tw - w;
626                         break;
627                     case 'west':
628                         th = h;
629                         h = oh * (w/ow);
630                         h = Math.min(Math.max(mh, h), mxh);
631                         y += (th - h) / 2;
632                         tw = w;
633                         w = ow * (h/oh);
634                         x += tw - w;
635                        break;
636                     case 'northwest':
637                         tw = w;
638                         th = h;
639                         h = oh * (w/ow);
640                         h = Math.min(Math.max(mh, h), mxh);
641                         w = ow * (h/oh);
642                         y += th - h;
643                         x += tw - w;
644                         break;
645
646                 }
647             }
648             this.proxy.setBounds(x, y, w, h);
649             if(this.dynamic){
650                 this.resizeElement();
651             }
652             }catch(ex){}
653         }
654     },
655
656     // private
657     handleOver : function(){
658         if(this.enabled){
659             this.el.addClass('x-resizable-over');
660         }
661     },
662
663     // private
664     handleOut : function(){
665         if(!this.resizing){
666             this.el.removeClass('x-resizable-over');
667         }
668     },
669
670     <div id="method-Ext.Resizable-getEl"></div>/**
671      * Returns the element this component is bound to.
672      * @return {Ext.Element}
673      */
674     getEl : function(){
675         return this.el;
676     },
677
678     <div id="method-Ext.Resizable-getResizeChild"></div>/**
679      * Returns the resizeChild element (or null).
680      * @return {Ext.Element}
681      */
682     getResizeChild : function(){
683         return this.resizeChild;
684     },
685
686     <div id="method-Ext.Resizable-destroy"></div>/**
687      * Destroys this resizable. If the element was wrapped and
688      * removeEl is not true then the element remains.
689      * @param {Boolean} removeEl (optional) true to remove the element from the DOM
690      */
691     destroy : function(removeEl){
692         Ext.destroy(this.dd, this.overlay, this.proxy);
693         this.overlay = null;
694         this.proxy = null;
695
696         var ps = Ext.Resizable.positions;
697         for(var k in ps){
698             if(typeof ps[k] != 'function' && this[ps[k]]){
699                 this[ps[k]].destroy();
700             }
701         }
702         if(removeEl){
703             this.el.update('');
704             Ext.destroy(this.el);
705             this.el = null;
706         }
707         this.purgeListeners();
708     },
709
710     syncHandleHeight : function(){
711         var h = this.el.getHeight(true);
712         if(this.west){
713             this.west.el.setHeight(h);
714         }
715         if(this.east){
716             this.east.el.setHeight(h);
717         }
718     }
719 });
720
721 // private
722 // hash to map config positions to true positions
723 Ext.Resizable.positions = {
724     n: 'north', s: 'south', e: 'east', w: 'west', se: 'southeast', sw: 'southwest', nw: 'northwest', ne: 'northeast'
725 };
726
727 Ext.Resizable.Handle = Ext.extend(Object, {
728     constructor : function(rz, pos, disableTrackOver, transparent, cls){
729        if(!this.tpl){
730             // only initialize the template if resizable is used
731             var tpl = Ext.DomHelper.createTemplate(
732                 {tag: 'div', cls: 'x-resizable-handle x-resizable-handle-{0}'}
733             );
734             tpl.compile();
735             Ext.Resizable.Handle.prototype.tpl = tpl;
736         }
737         this.position = pos;
738         this.rz = rz;
739         this.el = this.tpl.append(rz.el.dom, [this.position], true);
740         this.el.unselectable();
741         if(transparent){
742             this.el.setOpacity(0);
743         }
744         if(!Ext.isEmpty(cls)){
745             this.el.addClass(cls);
746         }
747         this.el.on('mousedown', this.onMouseDown, this);
748         if(!disableTrackOver){
749             this.el.on({
750                 scope: this,
751                 mouseover: this.onMouseOver,
752                 mouseout: this.onMouseOut
753             });
754         }
755     },
756
757     // private
758     afterResize : function(rz){
759         // do nothing
760     },
761     // private
762     onMouseDown : function(e){
763         this.rz.onMouseDown(this, e);
764     },
765     // private
766     onMouseOver : function(e){
767         this.rz.handleOver(this, e);
768     },
769     // private
770     onMouseOut : function(e){
771         this.rz.handleOut(this, e);
772     },
773     // private
774     destroy : function(){
775         Ext.destroy(this.el);
776         this.el = null;
777     }
778 });
779 </pre>    
780 </body>
781 </html>