3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * Applies drag handles to an element or component to make it resizable. The drag handles are inserted into the element
17 * (or component's element) and positioned absolute.
19 * Textarea and img elements will be wrapped with an additional div because these elements do not support child nodes.
20 * The original element can be accessed through the originalTarget property.
22 * Here is the list of valid resize handles:
25 * ------ -------------------
36 * {@img Ext.resizer.Resizer/Ext.resizer.Resizer.png Ext.resizer.Resizer component}
38 * Here's an example showing the creation of a typical Resizer:
40 * Ext.create('Ext.resizer.Resizer', {
50 Ext.define('Ext.resizer.Resizer', {
52 observable: 'Ext.util.Observable'
54 uses: ['Ext.resizer.ResizeTracker', 'Ext.Component'],
56 alternateClassName: 'Ext.Resizable',
58 handleCls: Ext.baseCSSPrefix + 'resizable-handle',
59 pinnedCls: Ext.baseCSSPrefix + 'resizable-pinned',
60 overCls: Ext.baseCSSPrefix + 'resizable-over',
61 wrapCls: Ext.baseCSSPrefix + 'resizable-wrap',
64 * @cfg {Boolean} dynamic
65 * Specify as true to update the {@link #target} (Element or {@link Ext.Component Component}) dynamically during
66 * dragging. This is `true` by default, but the {@link Ext.Component Component} class passes `false` when it is
67 * configured as {@link Ext.Component#resizable}.
69 * If specified as `false`, a proxy element is displayed during the resize operation, and the {@link #target} is
75 * @cfg {String} handles
76 * String consisting of the resize handles to display. Defaults to 's e se' for Elements and fixed position
77 * Components. Defaults to 8 point resizing for floating Components (such as Windows). Specify either `'all'` or any
78 * of `'n s e w ne nw se sw'`.
83 * @cfg {Number} height
84 * Optional. The height to set target to in pixels
90 * Optional. The width to set the target to in pixels
95 * @cfg {Number} heightIncrement
96 * The increment to snap the height resize in pixels.
101 * @cfg {Number} widthIncrement
102 * The increment to snap the width resize in pixels.
107 * @cfg {Number} minHeight
108 * The minimum height for the element
113 * @cfg {Number} minWidth
114 * The minimum width for the element
119 * @cfg {Number} maxHeight
120 * The maximum height for the element
125 * @cfg {Number} maxWidth
126 * The maximum width for the element
131 * @cfg {Boolean} pinned
132 * True to ensure that the resize handles are always visible, false indicates resizing by cursor changes only
137 * @cfg {Boolean} preserveRatio
138 * True to preserve the original ratio between height and width during resize
140 preserveRatio: false,
143 * @cfg {Boolean} transparent
144 * True for transparent handles. This is only applied at config time.
149 * @cfg {Ext.Element/Ext.util.Region} constrainTo
150 * An element, or a {@link Ext.util.Region Region} into which the resize operation must be constrained.
165 * @cfg {Ext.Element/Ext.Component} target
166 * The Element or Component to resize.
170 * @property {Ext.Element} el
171 * Outer element for resizing behavior.
174 constructor: function(config) {
178 handles = me.handles,
187 * @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
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
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
215 if (Ext.isString(config) || Ext.isElement(config) || config.dom) {
217 config = arguments[1] || {};
218 config.target = target;
220 // will apply config to this
221 me.mixins.observable.constructor.call(me, config);
223 // If target is a Component, ensure that we pull the element out.
224 // Resizer must examine the underlying Element.
227 if (target.isComponent) {
228 me.el = target.getEl();
229 if (target.minWidth) {
230 me.minWidth = target.minWidth;
232 if (target.minHeight) {
233 me.minHeight = target.minHeight;
235 if (target.maxWidth) {
236 me.maxWidth = target.maxWidth;
238 if (target.maxHeight) {
239 me.maxHeight = target.maxHeight;
241 if (target.floating) {
242 if (!this.hasOwnProperty('handles')) {
243 this.handles = 'n ne e se s sw w nw';
247 me.el = me.target = Ext.get(target);
250 // Backwards compatibility with Ext3.x's Resizable which used el as a config.
252 me.target = me.el = Ext.get(me.el);
255 // Tags like textarea and img cannot
256 // have children and therefore must
258 tag = me.el.dom.tagName;
259 if (tag == 'TEXTAREA' || tag == 'IMG') {
261 * @property {Ext.Element/Ext.Component} originalTarget
262 * Reference to the original resize target if the element of the original resize target was an IMG or a
263 * TEXTAREA which must be wrapped in a DIV.
265 me.originalTarget = me.target;
266 me.target = me.el = me.el.wrap({
268 id: me.el.id + '-rzwrap'
271 // Transfer originalTarget's positioning/sizing
272 me.el.setPositioning(me.originalTarget.getPositioning());
273 me.originalTarget.clearPositioning();
274 var box = me.originalTarget.getBox();
278 // Position the element, this enables us to absolute position
279 // the handles within this.el
282 me.el.addCls(me.pinnedCls);
286 * @property {Ext.resizer.ResizeTracker} resizeTracker
288 me.resizeTracker = Ext.create('Ext.resizer.ResizeTracker', {
289 disabled: me.disabled,
291 constrainTo: me.constrainTo,
293 throttle: me.throttle,
294 originalTarget: me.originalTarget,
295 delegate: '.' + me.handleCls,
297 preserveRatio: me.preserveRatio,
298 heightIncrement: me.heightIncrement,
299 widthIncrement: me.widthIncrement,
300 minHeight: me.minHeight,
301 maxHeight: me.maxHeight,
302 minWidth: me.minWidth,
303 maxWidth: me.maxWidth
306 // Relay the ResizeTracker's superclass events as our own resize events
307 me.resizeTracker.on('mousedown', me.onBeforeResize, me);
308 me.resizeTracker.on('drag', me.onResize, me);
309 me.resizeTracker.on('dragend', me.onResizeEnd, me);
311 if (me.handles == 'all') {
312 me.handles = 'n s e w ne nw se sw';
315 handles = me.handles = me.handles.split(/ |\s*?[,;]\s*?/);
316 possibles = me.possiblePositions;
317 len = handles.length;
318 handleCls = me.handleCls + ' ' + (this.target.isComponent ? (me.target.baseCls + '-handle ') : '') + me.handleCls + '-';
321 // if specified and possible, create
322 if (handles[i] && possibles[handles[i]]) {
323 pos = possibles[handles[i]];
324 // store a reference in this.east, this.west, etc
326 me[pos] = Ext.create('Ext.Component', {
329 cls: handleCls + pos,
332 me[pos].el.unselectable();
333 if (me.transparent) {
334 me[pos].el.setOpacity(0);
339 // Constrain within configured maxima
340 if (Ext.isNumber(me.width)) {
341 me.width = Ext.Number.constrain(me.width, me.minWidth, me.maxWidth);
343 if (Ext.isNumber(me.height)) {
344 me.height = Ext.Number.constrain(me.height, me.minHeight, me.maxHeight);
348 if (me.width != null || me.height != null) {
349 if (me.originalTarget) {
350 me.originalTarget.setWidth(me.width);
351 me.originalTarget.setHeight(me.height);
353 me.resizeTo(me.width, me.height);
356 me.forceHandlesHeight();
359 disable: function() {
360 this.resizeTracker.disable();
364 this.resizeTracker.enable();
368 * @private Relay the Tracker's mousedown event as beforeresize
369 * @param tracker The Resizer
372 onBeforeResize: function(tracker, e) {
373 var b = this.target.getBox();
374 return this.fireEvent('beforeresize', this, b.width, b.height, e);
378 * @private Relay the Tracker's drag event as resizedrag
379 * @param tracker The Resizer
382 onResize: function(tracker, e) {
384 b = me.target.getBox();
385 me.forceHandlesHeight();
386 return me.fireEvent('resizedrag', me, b.width, b.height, e);
390 * @private Relay the Tracker's dragend event as resize
391 * @param tracker The Resizer
394 onResizeEnd: function(tracker, e) {
396 b = me.target.getBox();
397 me.forceHandlesHeight();
398 return me.fireEvent('resize', me, b.width, b.height, e);
402 * Perform a manual resize and fires the 'resize' event.
403 * @param {Number} width
404 * @param {Number} height
406 resizeTo : function(width, height){
407 this.target.setSize(width, height);
408 this.fireEvent('resize', this, width, height, null);
412 * Returns the element that was configured with the el or target config property. If a component was configured with
413 * the target property then this will return the element of this component.
415 * Textarea and img elements will be wrapped with an additional div because these elements do not support child
416 * nodes. The original element can be accessed through the originalTarget property.
417 * @return {Ext.Element} element
424 * Returns the element or component that was configured with the target config property.
426 * Textarea and img elements will be wrapped with an additional div because these elements do not support child
427 * nodes. The original element can be accessed through the originalTarget property.
428 * @return {Ext.Element/Ext.Component}
430 getTarget: function() {
434 destroy: function() {
436 for (var i = 0, l = this.handles.length; i < l; i++) {
437 h = this[this.possiblePositions[this.handles[i]]];
445 * Fix IE6 handle height issue.
447 forceHandlesHeight : function() {
453 handle.setHeight(me.el.getHeight());
457 handle.setHeight(me.el.getHeight());