Index: t3lib/class.t3lib_tceforms.php =================================================================== --- t3lib/class.t3lib_tceforms.php (revision 5812) +++ t3lib/class.t3lib_tceforms.php (working copy) @@ -5220,7 +5220,9 @@ $GLOBALS['SOBE']->doc->loadPrototype(); $GLOBALS['SOBE']->doc->loadExtJS(); + $GLOBALS['SOBE']->doc->addStyleSheet('ext.resizable', $this->backPath . '../t3lib/js/extjs/ux/resize.css'); $this->loadJavascriptLib('../t3lib/jsfunc.evalfield.js'); + $this->loadJavascriptLib('../t3lib/js/extjs/ux/ext.resizable.js'); // @TODO: Change to loadJavascriptLib(), but fix "TS = new typoScript()" issue first - see bug #9494 $jsFile[] = ''; Index: t3lib/js/extjs/tceforms.js =================================================================== --- t3lib/js/extjs/tceforms.js (revision 5812) +++ t3lib/js/extjs/tceforms.js (working copy) @@ -34,6 +34,7 @@ Ext.QuickTips.init(); this.convertDateFieldsToDatePicker(); + this.convertTextareasResizable(); }, convertDateFieldsToDatePicker: function() { @@ -69,6 +70,17 @@ menu.show(datepicker); }); }); + }, + + convertTextareasResizable: function() { + var textAreas = Ext.select("*[id^=tceforms-textarea-]"); + textAreas.each(function(element) { + var dwrapped = new Ext.Resizable(element.dom.id, { + minWidth:200, + minHeight: 50, + dynamic: true + }); + }); } } Ext.onReady(TYPO3.TCEFORMS.init, TYPO3.TCEFORMS); \ No newline at end of file Index: t3lib/js/extjs/ux/ext.resizable.js =================================================================== --- t3lib/js/extjs/ux/ext.resizable.js (revision 0) +++ t3lib/js/extjs/ux/ext.resizable.js (revision 0) @@ -0,0 +1,924 @@ +/** + * @class Ext.ux.EventZone + *

This class implements a "virtual element" at a relative size and position + * within an existing element. It provides mouse events from a zone of an element of + * defined dimensions.

+ *

The zone is defined using top, right, bottom, + * left, width and height options which specify + * the bounds of the zone in a similar manner to the CSS style properties of those names.

+ * @cfg {String|HtmlElement} el The element in which to create the zone. + * @cfg {Array} points An Array of points within the element defining the event zone. + * @cfg {Number} top The top of the zone. If negative means an offset from the bottom. + * @cfg {Number} right The right of the zone. If negative means an offset from the right. + * @cfg {Number} left The left of the zone. If negative means an offset from the right. + * @cfg {Number} bottom The bottom of the zone. If negative means an offset from the bottom. + * @cfg {Number} width The width of the zone. + * @cfg {Number} height The height of the zone. + * @constructor + * Create a new EventZone + * @param {Object} config The config object. + */ +Ext.ux.EventZone = Ext.extend(Ext.util.Observable, { + + constructor: function(config) { + this.initialConfig = config; + this.addEvents( + /** + * @event mouseenter + * This event fires when the mouse enters the zone. + * @param {EventObject} e the underlying mouse event. + * @param {EventZone} this + */ + 'mouseenter', + /** + * @event mousedown + * This event fires when the mouse button is depressed within the zone. + * @param {EventObject} e the underlying mouse event. + * @param {EventZone} this + */ + 'mousedown', + /** + * @event mousemove + * This event fires when the mouse moves within the zone. + * @param {EventObject} e the underlying mouse event. + * @param {EventZone} this + */ + 'mousemove', + /** + * @event mouseup + * This event fires when the mouse button is released within the zone. + * @param {EventObject} e the underlying mouse event. + * @param {EventZone} this + */ + 'mouseup', + /** + * @event mouseenter + * This event fires when the mouse is clicked within the zone. + * @param {EventObject} e the underlying mouse event. + * @param {EventZone} this + */ + 'click', + /** + * @event mouseleave + * This event fires when the mouse leaves the zone. + * @param {EventObject} e the underlying mouse event. + * @param {EventZone} this + */ + 'mouseleave' + ); + Ext.apply(this, config); + this.el = Ext.get(this.el); + +// If a polygon within the element is specified... + if (this.points) { + this.polygon = new Ext.lib.Polygon(this.points); + this.points = this.polygon.points; + } + + Ext.ux.EventZone.superclass.constructor.call(this); + this.el.on({ + mouseenter: this.handleMouseEvent, + mousedown: this.handleMouseEvent, + mousemove: this.handleMouseEvent, + mouseup: this.handleMouseEvent, + click: this.handleMouseEvent, + mouseleave: this.handleMouseEvent, + scope: this + }); + }, + + handleMouseEvent: function(e) { + var r = this.polygon ? this.getPolygon() : this.getRegion(); + var inBounds = r.contains(e.getPoint()); + + switch (e.type) { + // mouseenter fires this + case 'mouseover': + if (inBounds) { + this.mouseIn = true; + this.fireEvent('mouseenter', e, this); + } + break; + // mouseleave fires this + case 'mouseout': + this.mouseIn = false; + this.fireEvent('mouseleave', e, this); + break; + case 'mousemove': + if (inBounds) { + if (this.mouseIn) { + this.fireEvent('mousemove', e, this); + } else { + this.mouseIn = true; + this.fireEvent('mouseenter', e, this); + } + } else { + if (this.mouseIn) { + this.mouseIn = false; + this.fireEvent('mouseleave', e, this); + } + } + break; + default: + if (inBounds) { + this.fireEvent(e.type, e, this); + } + } + }, + + getPolygon: function() { + var xy = this.el.getXY(); + return this.polygon.translate(xy[0], xy[1]); + }, + + getRegion: function() { + var r = this.el.getRegion(); + +// Adjust left boundary of region + if (Ext.isNumber(this.left)) { + if (this.left < 0) { + r.left = r.right + this.left; + } else { + r.left += this.left; + } + } + +// Adjust right boundary of region + if (Ext.isNumber(this.width)) { + r.right = r.left + this.width; + } else if (Ext.isNumber(this.right)) { + r.right = (this.right < 0) ? r.right + this.right : r.left + this.right; + } + +// Adjust top boundary of region + if (Ext.isNumber(this.top)) { + if (this.top < 0) { + r.top = r.bottom + this.top; + } else { + r.top += this.top; + } + } + +// Adjust bottom boundary of region + if (Ext.isNumber(this.height)) { + r.bottom = r.top + this.height; + } else if (Ext.isNumber(this.bottom)) { + r.bottom = (this.bottom < 0) ? r.bottom + this.bottom : r.top + this.bottom; + } + + return r; + } +}); + +/** + * @class Ext.lib.Polygon + *

This class encapsulates an absolute area of the document bounded by a list of points.

+ * @constructor + * Create a new Polygon + * @param {Object} points An Array of [n,n] point specification Arrays, or + * an Array of Ext.lib.Points, or an HtmlElement, or an Ext.lib.Region. + */ +Ext.lib.Polygon = Ext.extend(Ext.lib.Region, { + constructor: function(points) { + var i, l, el; + if (l = points.length) { + if (points[0].x) { + for (i = 0; i < l; i++) { + points[i] = [ points[i].x, points[i].y ]; + } + } + this.points = points; + } else { + if (el = Ext.get(points)) { + points = Ext.lib.Region.getRegion(el.dom); + } + if (points instanceof Ext.lib.Region) { + this.points = [ + [points.left, points.top], + [points.right, points.top], + [points.right, points.bottom], + [points.left, points.bottom] + ]; + } + } + }, + + /** + * Returns a new Polygon translated by the specified X and Y increments. + * @param xDelta {Number} The X translation increment. + * @param xDelta {Number} The Y translation increment. + * @return {Polygon} The resulting Polygon. + */ + translate: function(xDelta, yDelta) { + var r = [], p = this.points, l = p.length, i; + for (i = 0; i < l; i++) { + r[i] = [ p[i][0] + xDelta, p[i][1] + yDelta ]; + } + return new Ext.lib.Polygon(r); + }, + + /** + * Returns the area of this Polygon. + */ + getArea: function() { + var p = this.points, l = p.length, area = 0, i, j = 0; + for (i = 0; i < l; i++) { + j++; + if (j == l) { + j = 0; + } + area += (p[i][0] + p[j][0]) * (p[i][1] - p[j][1]); + } + return area * 0.5; + }, + + /** + * Returns true if this Polygon contains the specified point. Thanks + * to http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html for the algorithm. + * @param pt {Point|Number} Either an Ext.lib.Point object, or the X coordinate to test. + * @param py {Number} Optional. If the first parameter was an X coordinate, this is the Y coordinate. + */ + contains: function(pt, py) { + var f = (arguments.length == 1), + testX = f ? pt.x : pt, + testY = f ? pt.y : py, + p = this.points, + nvert = p.length, + j = nvert - 1, + i, j, c = false; + for (i = 0; i < nvert; j = i++) { + if ( ((p[i][1] > testY) != (p[j][1] > testY)) && + (testX < (p[j][0]-p[i][0]) * (testY-p[i][1]) / (p[j][1]-p[i][1]) + p[i][0])) { + c = !c; + } + } + return c; + } +}); + +/** + * @class Ext.Resizable + * @extends Ext.util.Observable + *

Applies virtual drag handles to an element to make it resizable.

+ *

Here is the list of valid resize handles:

+ *
+Value   Description
+------  -------------------
+ 'n'     north
+ 's'     south
+ 'e'     east
+ 'w'     west
+ 'nw'    northwest
+ 'sw'    southwest
+ 'se'    southeast
+ 'ne'    northeast
+ 'all'   all
+
+ *

Here's an example showing the creation of a typical Resizable:

+ *

+var resizer = new Ext.Resizable('element-id', {
+    handles: 'all',
+    minWidth: 200,
+    minHeight: 100,
+    maxWidth: 500,
+    maxHeight: 400,
+    pinned: true
+});
+resizer.on('resize', myHandler);
+
+ *

To hide a particular handle, set its display to none in CSS, or through script:
+ * resizer.east.setDisplayed(false);

+ * @constructor + * Create a new resizable component + * @param {Mixed} el The id or element to resize + * @param {Object} config configuration options + */ +Ext.Resizable = function(el, config){ + this.el = Ext.get(el); + + /** + * The proxy Element that is resized in place of the real Element during the resize operation. + * This may be queried using {@link Ext.Element#getBox} to provide the new area to resize to. + * Read only. + * @type Ext.Element. + * @property proxy + */ + this.proxy = this.el.createProxy({tag: 'div', cls: 'x-resizable-proxy', id: this.el.id + '-rzproxy'}, Ext.getBody()); + this.proxy.unselectable(); + this.proxy.enableDisplayMode('block'); + + Ext.apply(this, config); + + if(this.pinned){ + this.disableTrackOver = true; + this.el.addClass('x-resizable-pinned'); + } + // if the element isn't positioned, make it relative + var position = this.el.getStyle('position'); + if(position != 'absolute' && position != 'fixed'){ + this.el.setStyle('position', 'relative'); + } + if(!this.handles){ // no handles passed, must be legacy style + this.handles = 's,e,se'; + if(this.multiDirectional){ + this.handles += ',n,w'; + } + } + if(this.handles == 'all'){ + this.handles = 'n s e w ne nw se sw'; + } + var hs = this.handles.split(/\s*?[,;]\s*?| /); + var ps = Ext.Resizable.positions; + for(var i = 0, len = hs.length; i < len; i++){ + if(hs[i] && ps[hs[i]]){ + var pos = ps[hs[i]]; + this[pos] = new Ext.Resizable.Handle(this, pos); + } + } + // legacy + this.corner = this.southeast; + + if(this.handles.indexOf('n') != -1 || this.handles.indexOf('w') != -1){ + this.updateBox = true; + } + this.activeHandle = null; + + if(this.adjustments == 'auto'){ + var hw = this.west, he = this.east, hn = this.north, hs = this.south; + this.adjustments = [ + (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0), + (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1 + ]; + } + + if(this.draggable){ + this.dd = this.dynamic ? + this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id}); + this.dd.setHandleElId(this.el.id); + } + + this.addEvents( + /** + * @event beforeresize + * Fired before resize is allowed. Set {@link #enabled} to false to cancel resize. + * @param {Ext.Resizable} this + * @param {Ext.EventObject} e The mousedown event + */ + 'beforeresize', + /** + * @event resize + * Fired after a resize. + * @param {Ext.Resizable} this + * @param {Number} width The new width + * @param {Number} height The new height + * @param {Ext.EventObject} e The mouseup event + */ + 'resize' + ); + + if(this.width !== null && this.height !== null){ + this.resizeTo(this.width, this.height); + } + if(Ext.isIE){ + this.el.dom.style.zoom = 1; + } + Ext.Resizable.superclass.constructor.call(this); +}; + +Ext.extend(Ext.Resizable, Ext.util.Observable, { + + /** + * @cfg {Array/String} adjustments String 'auto' or an array [width, height] with values to be added to the + * resize operation's new size (defaults to [0, 0]) + */ + adjustments : [0, 0], + /** + * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false) + */ + animate : false, + /** + * @cfg {Mixed} constrainTo Constrain the resize to a particular element + */ + /** + * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false) + */ + draggable: false, + /** + * @cfg {Number} duration Animation duration if animate = true (defaults to 0.35) + */ + duration : 0.35, + /** + * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false) + */ + dynamic : false, + /** + * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong') + */ + easing : 'easeOutStrong', + /** + * @cfg {Boolean} enabled False to disable resizing (defaults to true) + */ + enabled : true, + /** + * @property enabled Writable. False if resizing is disabled. + * @type Boolean + */ + /** + * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined). + * Specify either 'all' or any of 'n s e w ne nw se sw'. + */ + handles : false, + /** + * @cfg {Boolean} multiDirectional Deprecated. Deprecated style of adding multi-direction resize handles. + */ + multiDirectional : false, + /** + * @cfg {Number} height The height of the element in pixels (defaults to null) + */ + height : null, + /** + * @cfg {Number} width The width of the element in pixels (defaults to null) + */ + width : null, + /** + * @cfg {Number} heightIncrement The increment to snap the height resize in pixels + * (only applies if {@link #dynamic}==true). Defaults to 0. + */ + heightIncrement : 0, + /** + * @cfg {Number} widthIncrement The increment to snap the width resize in pixels + * (only applies if {@link #dynamic}==true). Defaults to 0. + */ + widthIncrement : 0, + /** + * @cfg {Number} minHeight The minimum height for the element (defaults to 5) + */ + minHeight : 5, + /** + * @cfg {Number} minWidth The minimum width for the element (defaults to 5) + */ + minWidth : 5, + /** + * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000) + */ + maxHeight : 10000, + /** + * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000) + */ + maxWidth : 10000, + /** + * @cfg {Number} minX The minimum x for the element (defaults to 0) + */ + minX: 0, + /** + * @cfg {Number} minY The minimum x for the element (defaults to 0) + */ + minY: 0, + /** + * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the + * user mouses over the resizable borders. This is only applied at config time. (defaults to false) + */ + pinned : false, + /** + * @cfg {Boolean} preserveRatio True to preserve the original ratio between height + * and width during resize (defaults to false) + */ + preserveRatio : false, + /** + * @cfg {Ext.lib.Region} resizeRegion Constrain the resize to a particular region + */ + + + /** + * Perform a manual resize and fires the 'resize' event. + * @param {Number} width + * @param {Number} height + */ + resizeTo : function(width, height){ + this.el.setSize(width, height); + this.fireEvent('resize', this, width, height, null); + }, + + // private + startSizing : function(e, handle){ + this.fireEvent('beforeresize', this, e); + if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler + e.stopEvent(); + + Ext.getDoc().on({ + scope: this, + mousemove: this.onMouseMove, + mouseup: { + fn: this.onMouseUp, + single: true, + scope: this + } + }); + Ext.getBody().addClass('ux-resizable-handle-' + handle.position); + + this.resizing = true; + this.startBox = this.el.getBox(); + this.startPoint = e.getXY(); + this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0], + (this.startBox.y + this.startBox.height) - this.startPoint[1]]; + + if(this.constrainTo) { + var ct = Ext.get(this.constrainTo); + this.resizeRegion = ct.getRegion().adjust( + ct.getFrameWidth('t'), + ct.getFrameWidth('l'), + -ct.getFrameWidth('b'), + -ct.getFrameWidth('r') + ); + } + + this.proxy.setStyle('visibility', 'hidden'); // workaround display none + this.proxy.show(); + this.proxy.setBox(this.startBox); + if(!this.dynamic){ + this.proxy.setStyle('visibility', 'visible'); + } + } + }, + + // private + onMouseDown : function(handle, e){ + if(this.enabled && !this.activeHandle){ + e.stopEvent(); + this.activeHandle = handle; + this.startSizing(e, handle); + } + }, + + // private + onMouseUp : function(e){ + Ext.getBody().removeClass('ux-resizable-handle-' + this.activeHandle.position) + .un('mousemove', this.onMouseMove, this); + var size = this.resizeElement(); + this.resizing = false; + this.handleOut(this.activeHandle); + this.proxy.hide(); + this.fireEvent('resize', this, size.width, size.height, e); + this.activeHandle = null; + }, + + // private + snap : function(value, inc, min){ + if(!inc || !value){ + return value; + } + var newValue = value; + var m = value % inc; + if(m > 0){ + if(m > (inc/2)){ + newValue = value + (inc-m); + }else{ + newValue = value - m; + } + } + return Math.max(min, newValue); + }, + + /** + *

Performs resizing of the associated Element. This method is called internally by this + * class, and should not be called by user code.

+ *

If a Resizable is being used to resize an Element which encapsulates a more complex UI + * component such as a Panel, this method may be overridden by specifying an implementation + * as a config option to provide appropriate behaviour at the end of the resize operation on + * mouseup, for example resizing the Panel, and relaying the Panel's content.

+ *

The new area to be resized to is available by examining the state of the {@link #proxy} + * Element. Example: +


+new Ext.Panel({
+    title: 'Resize me',
+    x: 100,
+    y: 100,
+    renderTo: Ext.getBody(),
+    floating: true,
+    frame: true,
+    width: 400,
+    height: 200,
+    listeners: {
+        render: function(p) {
+            new Ext.Resizable(p.getEl(), {
+                handles: 'all',
+                pinned: true,
+                transparent: true,
+                resizeElement: function() {
+                    var box = this.proxy.getBox();
+                    p.updateBox(box);
+                    if (p.layout) {
+                        p.doLayout();
+                    }
+                    return box;
+                }
+           });
+       }
+    }
+}).show();
+
+ */ + resizeElement : function(){ + var box = this.proxy.getBox(); + if(this.updateBox){ + this.el.setBox(box, false, this.animate, this.duration, null, this.easing); + }else{ + this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing); + } + if(!this.dynamic){ + this.proxy.hide(); + } + return box; + }, + + // private + constrain : function(v, diff, m, mx){ + if(v - diff < m){ + diff = v - m; + }else if(v - diff > mx){ + diff = v - mx; + } + return diff; + }, + + // private + onMouseMove : function(e){ + if(this.enabled && this.activeHandle){ + try{// try catch so if something goes wrong the user doesn't get hung + + if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) { + return; + } + + //var curXY = this.startPoint; + var curSize = this.curSize || this.startBox, + x = this.startBox.x, y = this.startBox.y, + ox = x, + oy = y, + w = curSize.width, + h = curSize.height, + ow = w, + oh = h, + mw = this.minWidth, + mh = this.minHeight, + mxw = this.maxWidth, + mxh = this.maxHeight, + wi = this.widthIncrement, + hi = this.heightIncrement, + eventXY = e.getXY(), + diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0])), + diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1])), + pos = this.activeHandle.position, + tw, + th; + + switch(pos){ + case 'east': + w += diffX; + w = Math.min(Math.max(mw, w), mxw); + break; + case 'south': + h += diffY; + h = Math.min(Math.max(mh, h), mxh); + break; + case 'southeast': + w += diffX; + h += diffY; + w = Math.min(Math.max(mw, w), mxw); + h = Math.min(Math.max(mh, h), mxh); + break; + case 'north': + diffY = this.constrain(h, diffY, mh, mxh); + y += diffY; + h -= diffY; + break; + case 'west': + diffX = this.constrain(w, diffX, mw, mxw); + x += diffX; + w -= diffX; + break; + case 'northeast': + w += diffX; + w = Math.min(Math.max(mw, w), mxw); + diffY = this.constrain(h, diffY, mh, mxh); + y += diffY; + h -= diffY; + break; + case 'northwest': + diffX = this.constrain(w, diffX, mw, mxw); + diffY = this.constrain(h, diffY, mh, mxh); + y += diffY; + h -= diffY; + x += diffX; + w -= diffX; + break; + case 'southwest': + diffX = this.constrain(w, diffX, mw, mxw); + h += diffY; + h = Math.min(Math.max(mh, h), mxh); + x += diffX; + w -= diffX; + break; + } + + var sw = this.snap(w, wi, mw); + var sh = this.snap(h, hi, mh); + if(sw != w || sh != h){ + switch(pos){ + case 'northeast': + y -= sh - h; + break; + case 'north': + y -= sh - h; + break; + case 'southwest': + x -= sw - w; + break; + case 'west': + x -= sw - w; + break; + case 'northwest': + x -= sw - w; + y -= sh - h; + break; + } + w = sw; + h = sh; + } + + if(this.preserveRatio){ + switch(pos){ + case 'southeast': + case 'east': + h = oh * (w/ow); + h = Math.min(Math.max(mh, h), mxh); + w = ow * (h/oh); + break; + case 'south': + w = ow * (h/oh); + w = Math.min(Math.max(mw, w), mxw); + h = oh * (w/ow); + break; + case 'northeast': + w = ow * (h/oh); + w = Math.min(Math.max(mw, w), mxw); + h = oh * (w/ow); + break; + case 'north': + tw = w; + w = ow * (h/oh); + w = Math.min(Math.max(mw, w), mxw); + h = oh * (w/ow); + x += (tw - w) / 2; + break; + case 'southwest': + h = oh * (w/ow); + h = Math.min(Math.max(mh, h), mxh); + tw = w; + w = ow * (h/oh); + x += tw - w; + break; + case 'west': + th = h; + h = oh * (w/ow); + h = Math.min(Math.max(mh, h), mxh); + y += (th - h) / 2; + tw = w; + w = ow * (h/oh); + x += tw - w; + break; + case 'northwest': + tw = w; + th = h; + h = oh * (w/ow); + h = Math.min(Math.max(mh, h), mxh); + w = ow * (h/oh); + y += th - h; + x += tw - w; + break; + + } + } + this.proxy.setBounds(x, y, w, h); + if(this.dynamic){ + this.resizeElement(); + } + }catch(ex){} + } + }, + + // private + handleOver : function(handle){ + if(this.enabled){ + Ext.getBody().addClass('ux-resizable-handle-' + handle.position); + } + }, + + // private + handleOut : function(handle){ + if(!this.resizing){ + Ext.getBody().removeClass('ux-resizable-handle-' + handle.position); + } + }, + + /** + * Returns the element this component is bound to. + * @return {Ext.Element} + */ + getEl : function(){ + return this.el; + }, + + /** + * Destroys this resizable. If the element was wrapped and + * removeEl is not true then the element remains. + * @param {Boolean} removeEl (optional) true to remove the element from the DOM + */ + destroy : function(removeEl){ + Ext.destroy(this.dd, this.proxy); + this.proxy = null; + + var ps = Ext.Resizable.positions; + for(var k in ps){ + if(typeof ps[k] != 'function' && this[ps[k]]){ + this[ps[k]].destroy(); + } + } + if(removeEl){ + this.el.update(''); + Ext.destroy(this.el); + this.el = null; + } + this.purgeListeners(); + }, + + syncHandleHeight : function(){ + var h = this.el.getHeight(true); + if(this.west){ + this.west.el.setHeight(h); + } + if(this.east){ + this.east.el.setHeight(h); + } + } +}); + +// private +// hash to map config positions to true positions +Ext.Resizable.positions = { + n: 'north', s: 'south', e: 'east', w: 'west', se: 'southeast', sw: 'southwest', nw: 'northwest', ne: 'northeast' +}; +Ext.Resizable.cfg = { + north: {left: 7, right: -7, height: 7}, + south: {left: 7, right: -7, top: -7}, + east: {top: 7, bottom: -7, left: -7}, + west: {top: 7, bottom: -7, width: 7}, + southeast: {top: -7, left: -7}, + southwest: {top: -7, width: 7}, + northwest: {height: 7, width: 7}, + northeast: {left: -7, height: 7} +}; + +// private +Ext.Resizable.Handle = function(rz, pos){ + this.position = pos; + this.rz = rz; + var cfg = Ext.Resizable.cfg[pos] || Ext.Resizable.cfg[Ext.Resizable.positions[pos]]; + this.ez = new Ext.ux.EventZone(Ext.apply({ + position: pos, + el: rz.el + }, cfg)); + this.ez.on({ + mousedown: this.onMouseDown, + mouseenter: this.onMouseOver, + mouseleave: this.onMouseOut, + scope: this + }); +}; + +// private +Ext.Resizable.Handle.prototype = { + cursor: 'move', + + // private + afterResize : function(rz){ + // do nothing + }, + // private + onMouseDown : function(e){ + this.rz.onMouseDown(this, e); + }, + // private + onMouseOver : function(e){ + this.rz.handleOver(this, e); + }, + // private + onMouseOut : function(e){ + this.rz.handleOut(this, e); + }, + // private + destroy : function(){ + Ext.destroy(this.el); + this.el = null; + } +}; Index: t3lib/js/extjs/ux/resize.css =================================================================== --- t3lib/js/extjs/ux/resize.css (revision 0) +++ t3lib/js/extjs/ux/resize.css (revision 0) @@ -0,0 +1,62 @@ +.ux-resizable-handle-east, .ux-resizable-handle-east textarea { + cursor: e-resize; +} + +.ux-resizable-handle-south, .ux-resizable-handle-south textarea { + cursor: s-resize; +} + +.ux-resizable-handle-west, .ux-resizable-handle-west textarea { + cursor: w-resize; +} + +.ux-resizable-handle-north, .ux-resizable-handle-north textarea { + cursor: n-resize; +} + +.ux-resizable-handle-southeast, .ux-resizable-handle-southeast textarea { + cursor: se-resize; +} + +.ux-resizable-handle-northwest, .ux-resizable-handle-northwest textarea { + cursor: nw-resize; +} + +.ux-resizable-handle-northeast, .ux-resizable-handle-northeast textarea { + cursor: ne-resize; +} + +.ux-resizable-handle-southwest, .ux-resizable-handle-southwest textarea { + cursor: sw-resize; +} +.ux-resizable-handle-east, .ux-resizable-handle-east textarea { + cursor: e-resize; +} + +.ux-resizable-handle-south, .ux-resizable-handle-south textarea { + cursor: s-resize; +} + +.ux-resizable-handle-west, .ux-resizable-handle-west textarea { + cursor: w-resize; +} + +.ux-resizable-handle-north, .ux-resizable-handle-north textarea { + cursor: n-resize; +} + +.ux-resizable-handle-southeast, .ux-resizable-handle-southeast textarea { + cursor: se-resize; +} + +.ux-resizable-handle-northwest, .ux-resizable-handle-northwest textarea { + cursor: nw-resize; +} + +.ux-resizable-handle-northeast, .ux-resizable-handle-northeast textarea { + cursor: ne-resize; +} + +.ux-resizable-handle-southwest, .ux-resizable-handle-southwest textarea { + cursor: sw-resize; +} \ No newline at end of file