Upgrade to ExtJS 4.0.2 - Released 06/09/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-heightIncrement'>    /**
100 </span>     * @cfg {Number} heightIncrement The increment to snap the height resize in pixels.
101      * Defaults to &lt;code&gt;0&lt;/code&gt;.
102      */
103     heightIncrement : 0,
104
105 <span id='Ext-resizer-Resizer-cfg-widthIncrement'>    /**
106 </span>     * @cfg {Number} widthIncrement The increment to snap the width resize in pixels
107      * Defaults to &lt;code&gt;0&lt;/code&gt;.
108      */
109     widthIncrement : 0,
110
111 <span id='Ext-resizer-Resizer-cfg-minHeight'>    /**
112 </span>     * @cfg {Number} minHeight The minimum height for the element (defaults to 20)
113      */
114     minHeight : 20,
115
116 <span id='Ext-resizer-Resizer-cfg-minWidth'>    /**
117 </span>     * @cfg {Number} minWidth The minimum width for the element (defaults to 20)
118      */
119     minWidth : 20,
120
121 <span id='Ext-resizer-Resizer-cfg-maxHeight'>    /**
122 </span>     * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
123      */
124     maxHeight : 10000,
125
126 <span id='Ext-resizer-Resizer-cfg-maxWidth'>    /**
127 </span>     * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
128      */
129     maxWidth : 10000,
130
131 <span id='Ext-resizer-Resizer-cfg-pinned'>    /**
132 </span>     * @cfg {Boolean} pinned True to ensure that the resize handles are always
133      * visible, false indicates resizing by cursor changes only (defaults to false)
134      */
135     pinned: false,
136
137 <span id='Ext-resizer-Resizer-cfg-preserveRatio'>    /**
138 </span>     * @cfg {Boolean} preserveRatio True to preserve the original ratio between height
139      * and width during resize (defaults to false)
140      */
141     preserveRatio: false,
142
143 <span id='Ext-resizer-Resizer-cfg-transparent'>    /**
144 </span>     * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
145      */
146     transparent: false,
147
148 <span id='Ext-resizer-Resizer-cfg-constrainTo'>    /**
149 </span>     * @cfg {Mixed} constrainTo Optional. An element, or a {@link Ext.util.Region} into which the resize operation
150      * must be constrained.
151      */
152
153     possiblePositions: {
154         n:  'north',
155         s:  'south',
156         e:  'east',
157         w:  'west',
158         se: 'southeast',
159         sw: 'southwest',
160         nw: 'northwest',
161         ne: 'northeast'
162     },
163
164 <span id='Ext-resizer-Resizer-cfg-target'>    /**
165 </span>     * @cfg {Mixed} target The Element or Component to resize.
166      */
167
168 <span id='Ext-resizer-Resizer-property-el'>    /**
169 </span>     * Outer element for resizing behavior.
170      * @type Ext.core.Element
171      * @property el
172      */
173
174     constructor: function(config) {
175         var me = this,
176             target,
177             tag,
178             handles = me.handles,
179             handleCls,
180             possibles,
181             len,
182             i = 0,
183             pos;
184
185         this.addEvents(
186 <span id='Ext-resizer-Resizer-event-beforeresize'>            /**
187 </span>             * @event beforeresize
188              * Fired before resize is allowed. Return false to cancel resize.
189              * @param {Ext.resizer.Resizer} this
190              * @param {Number} width The start width
191              * @param {Number} height The start height
192              * @param {Ext.EventObject} e The mousedown event
193              */
194             'beforeresize',
195 <span id='Ext-resizer-Resizer-event-resizedrag'>            /**
196 </span>             * @event resizedrag
197              * Fires during resizing. Return false to cancel resize.
198              * @param {Ext.resizer.Resizer} this
199              * @param {Number} width The new width
200              * @param {Number} height The new height
201              * @param {Ext.EventObject} e The mousedown event
202              */
203             'resizedrag',
204 <span id='Ext-resizer-Resizer-event-resize'>            /**
205 </span>             * @event resize
206              * Fired after a resize.
207              * @param {Ext.resizer.Resizer} this
208              * @param {Number} width The new width
209              * @param {Number} height The new height
210              * @param {Ext.EventObject} e The mouseup event
211              */
212             'resize'
213         );
214
215         if (Ext.isString(config) || Ext.isElement(config) || config.dom) {
216             target = config;
217             config = arguments[1] || {};
218             config.target = target;
219         }
220         // will apply config to this
221         me.mixins.observable.constructor.call(me, config);
222
223         // If target is a Component, ensure that we pull the element out.
224         // Resizer must examine the underlying Element.
225         target = me.target;
226         if (target) {
227             if (target.isComponent) {
228                 me.el = target.getEl();
229                 if (target.minWidth) {
230                     me.minWidth = target.minWidth;
231                 }
232                 if (target.minHeight) {
233                     me.minHeight = target.minHeight;
234                 }
235                 if (target.maxWidth) {
236                     me.maxWidth = target.maxWidth;
237                 }
238                 if (target.maxHeight) {
239                     me.maxHeight = target.maxHeight;
240                 }
241                 if (target.floating) {
242                     if (!this.hasOwnProperty('handles')) {
243                         this.handles = 'n ne e se s sw w nw';
244                     }
245                 }
246             } else {
247                 me.el = me.target = Ext.get(target);
248             }
249         }
250         // Backwards compatibility with Ext3.x's Resizable which used el as a config.
251         else {
252             me.target = me.el = Ext.get(me.el);
253         }
254
255         // Tags like textarea and img cannot
256         // have children and therefore must
257         // be wrapped
258         tag = me.el.dom.tagName;
259         if (tag == 'TEXTAREA' || tag == 'IMG') {
260 <span id='Ext-resizer-Resizer-property-originalTarget'>            /**
261 </span>             * Reference to the original resize target if the element of the original
262              * resize target was an IMG or a TEXTAREA which must be wrapped in a DIV.
263              * @type Mixed
264              * @property originalTarget
265              */
266             me.originalTarget = me.target;
267             me.target = me.el = me.el.wrap({
268                 cls: me.wrapCls,
269                 id: me.el.id + '-rzwrap'
270             });
271
272             // Transfer originalTarget's positioning/sizing
273             me.el.setPositioning(me.originalTarget.getPositioning());
274             me.originalTarget.clearPositioning();
275             var box = me.originalTarget.getBox();
276             me.el.setBox(box);
277         }
278
279         // Position the element, this enables us to absolute position
280         // the handles within this.el
281         me.el.position();
282         if (me.pinned) {
283             me.el.addCls(me.pinnedCls);
284         }
285
286 <span id='Ext-resizer-Resizer-property-resizeTracker'>        /**
287 </span>         * @type Ext.resizer.ResizeTracker
288          * @property resizeTracker
289          */
290         me.resizeTracker = Ext.create('Ext.resizer.ResizeTracker', {
291             disabled: me.disabled,
292             target: me.target,
293             constrainTo: me.constrainTo,
294             overCls: me.overCls,
295             throttle: me.throttle,
296             originalTarget: me.originalTarget,
297             delegate: '.' + me.handleCls,
298             dynamic: me.dynamic,
299             preserveRatio: me.preserveRatio,
300             heightIncrement: me.heightIncrement,
301             widthIncrement: me.widthIncrement,
302             minHeight: me.minHeight,
303             maxHeight: me.maxHeight,
304             minWidth: me.minWidth,
305             maxWidth: me.maxWidth
306         });
307
308         // Relay the ResizeTracker's superclass events as our own resize events
309         me.resizeTracker.on('mousedown', me.onBeforeResize, me);
310         me.resizeTracker.on('drag', me.onResize, me);
311         me.resizeTracker.on('dragend', me.onResizeEnd, me);
312
313         if (me.handles == 'all') {
314             me.handles = 'n s e w ne nw se sw';
315         }
316
317         handles = me.handles = me.handles.split(/ |\s*?[,;]\s*?/);
318         possibles = me.possiblePositions;
319         len = handles.length;
320         handleCls = me.handleCls + ' ' + (this.target.isComponent ? (me.target.baseCls + '-handle ') : '') + me.handleCls + '-';
321
322         for(; i &lt; len; i++){
323             // if specified and possible, create
324             if (handles[i] &amp;&amp; possibles[handles[i]]) {
325                 pos = possibles[handles[i]];
326                 // store a reference in this.east, this.west, etc
327
328                 me[pos] = Ext.create('Ext.Component', {
329                     owner: this,
330                     region: pos,
331                     cls: handleCls + pos,
332                     renderTo: me.el
333                 });
334                 me[pos].el.unselectable();
335                 if (me.transparent) {
336                     me[pos].el.setOpacity(0);
337                 }
338             }
339         }
340
341         // Constrain within configured maxima
342         if (Ext.isNumber(me.width)) {
343             me.width = Ext.Number.constrain(me.width, me.minWidth, me.maxWidth);
344         }
345         if (Ext.isNumber(me.height)) {
346             me.height = Ext.Number.constrain(me.height, me.minHeight, me.maxHeight);
347         }
348
349         // Size the element
350         if (me.width != null || me.height != null) {
351             if (me.originalTarget) {
352                 me.originalTarget.setWidth(me.width);
353                 me.originalTarget.setHeight(me.height);
354             }
355             me.resizeTo(me.width, me.height);
356         }
357
358         me.forceHandlesHeight();
359     },
360
361     disable: function() {
362         this.resizeTracker.disable();
363     },
364
365     enable: function() {
366         this.resizeTracker.enable();
367     },
368
369 <span id='Ext-resizer-Resizer-method-onBeforeResize'>    /**
370 </span>     * @private Relay the Tracker's mousedown event as beforeresize
371      * @param tracker The Resizer
372      * @param e The Event
373      */
374     onBeforeResize: function(tracker, e) {
375         var b = this.target.getBox();
376         return this.fireEvent('beforeresize', this, b.width, b.height, e);
377     },
378
379 <span id='Ext-resizer-Resizer-method-onResize'>    /**
380 </span>     * @private Relay the Tracker's drag event as resizedrag
381      * @param tracker The Resizer
382      * @param e The Event
383      */
384     onResize: function(tracker, e) {
385         var me = this,
386             b = me.target.getBox();
387         me.forceHandlesHeight();
388         return me.fireEvent('resizedrag', me, b.width, b.height, e);
389     },
390
391 <span id='Ext-resizer-Resizer-method-onResizeEnd'>    /**
392 </span>     * @private Relay the Tracker's dragend event as resize
393      * @param tracker The Resizer
394      * @param e The Event
395      */
396     onResizeEnd: function(tracker, e) {
397         var me = this,
398             b = me.target.getBox();
399         me.forceHandlesHeight();
400         return me.fireEvent('resize', me, b.width, b.height, e);
401     },
402
403 <span id='Ext-resizer-Resizer-method-resizeTo'>    /**
404 </span>     * Perform a manual resize and fires the 'resize' event.
405      * @param {Number} width
406      * @param {Number} height
407      */
408     resizeTo : function(width, height){
409         this.target.setSize(width, height);
410         this.fireEvent('resize', this, width, height, null);
411     },
412
413 <span id='Ext-resizer-Resizer-method-getEl'>    /**
414 </span>     * &lt;p&gt;Returns the element that was configured with the el or target config property.
415      * If a component was configured with the target property then this will return the
416      * element of this component.&lt;p&gt;
417      * &lt;p&gt;Textarea and img elements will be wrapped with an additional div because
418       * these elements do not support child nodes. The original element can be accessed
419      * through the originalTarget property.&lt;/p&gt;
420      * @return {Element} element
421      */
422     getEl : function() {
423         return this.el;
424     },
425
426 <span id='Ext-resizer-Resizer-method-getTarget'>    /**
427 </span>     * &lt;p&gt;Returns the element or component that was configured with the target config property.&lt;p&gt;
428      * &lt;p&gt;Textarea and img elements will be wrapped with an additional div because
429       * these elements do not support child nodes. The original element can be accessed
430      * through the originalTarget property.&lt;/p&gt;
431      * @return {Element/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>