Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / Resizer.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5   <title>The source code</title>
6   <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
8   <style type="text/css">
9     .highlight { display: block; background-color: #ddd; }
10   </style>
11   <script type="text/javascript">
12     function highlight() {
13       document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
14     }
15   </script>
16 </head>
17 <body onload="prettyPrint(); highlight();">
18   <pre class="prettyprint lang-js"><span id='Ext-resizer-Resizer'>/**
19 </span> * Applies drag handles to an element or component to make it resizable. The drag handles are inserted into the element
20  * (or component's element) and positioned absolute.
21  *
22  * Textarea and img elements will be wrapped with an additional div because these elements do not support child nodes.
23  * The original element can be accessed through the originalTarget property.
24  *
25  * Here is the list of valid resize handles:
26  *
27  *     Value   Description
28  *     ------  -------------------
29  *      'n'     north
30  *      's'     south
31  *      'e'     east
32  *      'w'     west
33  *      'nw'    northwest
34  *      'sw'    southwest
35  *      'se'    southeast
36  *      'ne'    northeast
37  *      'all'   all
38  *
39  * {@img Ext.resizer.Resizer/Ext.resizer.Resizer.png Ext.resizer.Resizer component}
40  *
41  * Here's an example showing the creation of a typical Resizer:
42  *
43  *     Ext.create('Ext.resizer.Resizer', {
44  *         el: 'elToResize',
45  *         handles: 'all',
46  *         minWidth: 200,
47  *         minHeight: 100,
48  *         maxWidth: 500,
49  *         maxHeight: 400,
50  *         pinned: true
51  *     });
52  */
53 Ext.define('Ext.resizer.Resizer', {
54     mixins: {
55         observable: 'Ext.util.Observable'
56     },
57     uses: ['Ext.resizer.ResizeTracker', 'Ext.Component'],
58
59     alternateClassName: 'Ext.Resizable',
60
61     handleCls: Ext.baseCSSPrefix + 'resizable-handle',
62     pinnedCls: Ext.baseCSSPrefix + 'resizable-pinned',
63     overCls:   Ext.baseCSSPrefix + 'resizable-over',
64     wrapCls:   Ext.baseCSSPrefix + 'resizable-wrap',
65
66 <span id='Ext-resizer-Resizer-cfg-dynamic'>    /**
67 </span>     * @cfg {Boolean} dynamic
68      * Specify as true to update the {@link #target} (Element or {@link Ext.Component Component}) dynamically during
69      * dragging. This is `true` by default, but the {@link Ext.Component Component} class passes `false` when it is
70      * configured as {@link Ext.Component#resizable}.
71      *
72      * If specified as `false`, a proxy element is displayed during the resize operation, and the {@link #target} is
73      * updated on mouseup.
74      */
75     dynamic: true,
76
77 <span id='Ext-resizer-Resizer-cfg-handles'>    /**
78 </span>     * @cfg {String} handles
79      * String consisting of the resize handles to display. Defaults to 's e se' for Elements and fixed position
80      * Components. Defaults to 8 point resizing for floating Components (such as Windows). Specify either `'all'` or any
81      * of `'n s e w ne nw se sw'`.
82      */
83     handles: 's e se',
84
85 <span id='Ext-resizer-Resizer-cfg-height'>    /**
86 </span>     * @cfg {Number} height
87      * Optional. The height to set target to in pixels
88      */
89     height : null,
90
91 <span id='Ext-resizer-Resizer-cfg-width'>    /**
92 </span>     * @cfg {Number} width
93      * Optional. The width to set the target to in pixels
94      */
95     width : null,
96
97 <span id='Ext-resizer-Resizer-cfg-heightIncrement'>    /**
98 </span>     * @cfg {Number} heightIncrement
99      * The increment to snap the height resize in pixels.
100      */
101     heightIncrement : 0,
102
103 <span id='Ext-resizer-Resizer-cfg-widthIncrement'>    /**
104 </span>     * @cfg {Number} widthIncrement
105      * The increment to snap the width resize in pixels.
106      */
107     widthIncrement : 0,
108
109 <span id='Ext-resizer-Resizer-cfg-minHeight'>    /**
110 </span>     * @cfg {Number} minHeight
111      * The minimum height for the element
112      */
113     minHeight : 20,
114
115 <span id='Ext-resizer-Resizer-cfg-minWidth'>    /**
116 </span>     * @cfg {Number} minWidth
117      * The minimum width for the element
118      */
119     minWidth : 20,
120
121 <span id='Ext-resizer-Resizer-cfg-maxHeight'>    /**
122 </span>     * @cfg {Number} maxHeight
123      * The maximum height for the element
124      */
125     maxHeight : 10000,
126
127 <span id='Ext-resizer-Resizer-cfg-maxWidth'>    /**
128 </span>     * @cfg {Number} maxWidth
129      * The maximum width for the element
130      */
131     maxWidth : 10000,
132
133 <span id='Ext-resizer-Resizer-cfg-pinned'>    /**
134 </span>     * @cfg {Boolean} pinned
135      * True to ensure that the resize handles are always visible, false indicates resizing by cursor changes only
136      */
137     pinned: false,
138
139 <span id='Ext-resizer-Resizer-cfg-preserveRatio'>    /**
140 </span>     * @cfg {Boolean} preserveRatio
141      * True to preserve the original ratio between height and width during resize
142      */
143     preserveRatio: false,
144
145 <span id='Ext-resizer-Resizer-cfg-transparent'>    /**
146 </span>     * @cfg {Boolean} transparent
147      * True for transparent handles. This is only applied at config time.
148      */
149     transparent: false,
150
151 <span id='Ext-resizer-Resizer-cfg-constrainTo'>    /**
152 </span>     * @cfg {Ext.Element/Ext.util.Region} constrainTo
153      * An element, or a {@link Ext.util.Region Region} into which the resize operation must be constrained.
154      */
155
156     possiblePositions: {
157         n:  'north',
158         s:  'south',
159         e:  'east',
160         w:  'west',
161         se: 'southeast',
162         sw: 'southwest',
163         nw: 'northwest',
164         ne: 'northeast'
165     },
166
167 <span id='Ext-resizer-Resizer-cfg-target'>    /**
168 </span>     * @cfg {Ext.Element/Ext.Component} target
169      * The Element or Component to resize.
170      */
171
172 <span id='Ext-resizer-Resizer-property-el'>    /**
173 </span>     * @property {Ext.Element} el
174      * Outer element for resizing behavior.
175      */
176
177     constructor: function(config) {
178         var me = this,
179             target,
180             tag,
181             handles = me.handles,
182             handleCls,
183             possibles,
184             len,
185             i = 0,
186             pos;
187
188         this.addEvents(
189 <span id='Ext-resizer-Resizer-event-beforeresize'>            /**
190 </span>             * @event beforeresize
191              * Fired before resize is allowed. Return false to cancel resize.
192              * @param {Ext.resizer.Resizer} this
193              * @param {Number} width The start width
194              * @param {Number} height The start height
195              * @param {Ext.EventObject} e The mousedown event
196              */
197             'beforeresize',
198 <span id='Ext-resizer-Resizer-event-resizedrag'>            /**
199 </span>             * @event resizedrag
200              * Fires during resizing. Return false to cancel resize.
201              * @param {Ext.resizer.Resizer} this
202              * @param {Number} width The new width
203              * @param {Number} height The new height
204              * @param {Ext.EventObject} e The mousedown event
205              */
206             'resizedrag',
207 <span id='Ext-resizer-Resizer-event-resize'>            /**
208 </span>             * @event resize
209              * Fired after a resize.
210              * @param {Ext.resizer.Resizer} this
211              * @param {Number} width The new width
212              * @param {Number} height The new height
213              * @param {Ext.EventObject} e The mouseup event
214              */
215             'resize'
216         );
217
218         if (Ext.isString(config) || Ext.isElement(config) || config.dom) {
219             target = config;
220             config = arguments[1] || {};
221             config.target = target;
222         }
223         // will apply config to this
224         me.mixins.observable.constructor.call(me, config);
225
226         // If target is a Component, ensure that we pull the element out.
227         // Resizer must examine the underlying Element.
228         target = me.target;
229         if (target) {
230             if (target.isComponent) {
231                 me.el = target.getEl();
232                 if (target.minWidth) {
233                     me.minWidth = target.minWidth;
234                 }
235                 if (target.minHeight) {
236                     me.minHeight = target.minHeight;
237                 }
238                 if (target.maxWidth) {
239                     me.maxWidth = target.maxWidth;
240                 }
241                 if (target.maxHeight) {
242                     me.maxHeight = target.maxHeight;
243                 }
244                 if (target.floating) {
245                     if (!this.hasOwnProperty('handles')) {
246                         this.handles = 'n ne e se s sw w nw';
247                     }
248                 }
249             } else {
250                 me.el = me.target = Ext.get(target);
251             }
252         }
253         // Backwards compatibility with Ext3.x's Resizable which used el as a config.
254         else {
255             me.target = me.el = Ext.get(me.el);
256         }
257
258         // Tags like textarea and img cannot
259         // have children and therefore must
260         // be wrapped
261         tag = me.el.dom.tagName;
262         if (tag == 'TEXTAREA' || tag == 'IMG') {
263 <span id='Ext-resizer-Resizer-property-originalTarget'>            /**
264 </span>             * @property {Ext.Element/Ext.Component} originalTarget
265              * Reference to the original resize target if the element of the original resize target was an IMG or a
266              * TEXTAREA which must be wrapped in a DIV.
267              */
268             me.originalTarget = me.target;
269             me.target = me.el = me.el.wrap({
270                 cls: me.wrapCls,
271                 id: me.el.id + '-rzwrap'
272             });
273
274             // Transfer originalTarget's positioning/sizing
275             me.el.setPositioning(me.originalTarget.getPositioning());
276             me.originalTarget.clearPositioning();
277             var box = me.originalTarget.getBox();
278             me.el.setBox(box);
279         }
280
281         // Position the element, this enables us to absolute position
282         // the handles within this.el
283         me.el.position();
284         if (me.pinned) {
285             me.el.addCls(me.pinnedCls);
286         }
287
288 <span id='Ext-resizer-Resizer-property-resizeTracker'>        /**
289 </span>         * @property {Ext.resizer.ResizeTracker} resizeTracker
290          */
291         me.resizeTracker = Ext.create('Ext.resizer.ResizeTracker', {
292             disabled: me.disabled,
293             target: me.target,
294             constrainTo: me.constrainTo,
295             overCls: me.overCls,
296             throttle: me.throttle,
297             originalTarget: me.originalTarget,
298             delegate: '.' + me.handleCls,
299             dynamic: me.dynamic,
300             preserveRatio: me.preserveRatio,
301             heightIncrement: me.heightIncrement,
302             widthIncrement: me.widthIncrement,
303             minHeight: me.minHeight,
304             maxHeight: me.maxHeight,
305             minWidth: me.minWidth,
306             maxWidth: me.maxWidth
307         });
308
309         // Relay the ResizeTracker's superclass events as our own resize events
310         me.resizeTracker.on('mousedown', me.onBeforeResize, me);
311         me.resizeTracker.on('drag', me.onResize, me);
312         me.resizeTracker.on('dragend', me.onResizeEnd, me);
313
314         if (me.handles == 'all') {
315             me.handles = 'n s e w ne nw se sw';
316         }
317
318         handles = me.handles = me.handles.split(/ |\s*?[,;]\s*?/);
319         possibles = me.possiblePositions;
320         len = handles.length;
321         handleCls = me.handleCls + ' ' + (this.target.isComponent ? (me.target.baseCls + '-handle ') : '') + me.handleCls + '-';
322
323         for(; i &lt; len; i++){
324             // if specified and possible, create
325             if (handles[i] &amp;&amp; possibles[handles[i]]) {
326                 pos = possibles[handles[i]];
327                 // store a reference in this.east, this.west, etc
328
329                 me[pos] = Ext.create('Ext.Component', {
330                     owner: this,
331                     region: pos,
332                     cls: handleCls + pos,
333                     renderTo: me.el
334                 });
335                 me[pos].el.unselectable();
336                 if (me.transparent) {
337                     me[pos].el.setOpacity(0);
338                 }
339             }
340         }
341
342         // Constrain within configured maxima
343         if (Ext.isNumber(me.width)) {
344             me.width = Ext.Number.constrain(me.width, me.minWidth, me.maxWidth);
345         }
346         if (Ext.isNumber(me.height)) {
347             me.height = Ext.Number.constrain(me.height, me.minHeight, me.maxHeight);
348         }
349
350         // Size the element
351         if (me.width != null || me.height != null) {
352             if (me.originalTarget) {
353                 me.originalTarget.setWidth(me.width);
354                 me.originalTarget.setHeight(me.height);
355             }
356             me.resizeTo(me.width, me.height);
357         }
358
359         me.forceHandlesHeight();
360     },
361
362     disable: function() {
363         this.resizeTracker.disable();
364     },
365
366     enable: function() {
367         this.resizeTracker.enable();
368     },
369
370 <span id='Ext-resizer-Resizer-method-onBeforeResize'>    /**
371 </span>     * @private Relay the Tracker's mousedown event as beforeresize
372      * @param tracker The Resizer
373      * @param e The Event
374      */
375     onBeforeResize: function(tracker, e) {
376         var b = this.target.getBox();
377         return this.fireEvent('beforeresize', this, b.width, b.height, e);
378     },
379
380 <span id='Ext-resizer-Resizer-method-onResize'>    /**
381 </span>     * @private Relay the Tracker's drag event as resizedrag
382      * @param tracker The Resizer
383      * @param e The Event
384      */
385     onResize: function(tracker, e) {
386         var me = this,
387             b = me.target.getBox();
388         me.forceHandlesHeight();
389         return me.fireEvent('resizedrag', me, b.width, b.height, e);
390     },
391
392 <span id='Ext-resizer-Resizer-method-onResizeEnd'>    /**
393 </span>     * @private Relay the Tracker's dragend event as resize
394      * @param tracker The Resizer
395      * @param e The Event
396      */
397     onResizeEnd: function(tracker, e) {
398         var me = this,
399             b = me.target.getBox();
400         me.forceHandlesHeight();
401         return me.fireEvent('resize', me, b.width, b.height, e);
402     },
403
404 <span id='Ext-resizer-Resizer-method-resizeTo'>    /**
405 </span>     * Perform a manual resize and fires the 'resize' event.
406      * @param {Number} width
407      * @param {Number} height
408      */
409     resizeTo : function(width, height){
410         this.target.setSize(width, height);
411         this.fireEvent('resize', this, width, height, null);
412     },
413
414 <span id='Ext-resizer-Resizer-method-getEl'>    /**
415 </span>     * Returns the element that was configured with the el or target config property. If a component was configured with
416      * the target property then this will return the element of this component.
417      *
418      * Textarea and img elements will be wrapped with an additional div because these elements do not support child
419      * nodes. The original element can be accessed through the originalTarget property.
420      * @return {Ext.Element} element
421      */
422     getEl : function() {
423         return this.el;
424     },
425
426 <span id='Ext-resizer-Resizer-method-getTarget'>    /**
427 </span>     * Returns the element or component that was configured with the target config property.
428      *
429      * Textarea and img elements will be wrapped with an additional div because these elements do not support child
430      * nodes. The original element can be accessed through the originalTarget property.
431      * @return {Ext.Element/Ext.Component}
432      */
433     getTarget: function() {
434         return this.target;
435     },
436
437     destroy: function() {
438         var h;
439         for (var i = 0, l = this.handles.length; i &lt; l; i++) {
440             h = this[this.possiblePositions[this.handles[i]]];
441             delete h.owner;
442             Ext.destroy(h);
443         }
444     },
445
446 <span id='Ext-resizer-Resizer-method-forceHandlesHeight'>    /**
447 </span>     * @private
448      * Fix IE6 handle height issue.
449      */
450     forceHandlesHeight : function() {
451         var me = this,
452             handle;
453         if (Ext.isIE6) {
454             handle = me.east;
455             if (handle) {
456                 handle.setHeight(me.el.getHeight());
457             }
458             handle = me.west;
459             if (handle) {
460                 handle.setHeight(me.el.getHeight());
461             }
462             me.el.repaint();
463         }
464     }
465 });
466 </pre>
467 </body>
468 </html>