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