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