Type.registerNamespace('Sys.Extended.UI'); Sys.Extended.UI.ResizableControlBehavior = function(element) { Sys.Extended.UI.ResizableControlBehavior.initializeBase(this, [element]); // Properties this._HandleCssClass = ""; this._ResizableCssClass = ""; this._HandleOffsetX = 0; this._HandleOffsetY = 0; this._MinimumWidth = 0; this._MinimumHeight = 0; this._MaximumWidth = 100000; this._MaximumHeight = 100000; // Variables this._frame = null; this._handle = null; this._handleHolder = null; this._lining = null; this._tracking = false; this._lastClientX = 0; this._lastClientY = 0; // Delegates this._onmouseoverDelegate = null; this._onmouseoutDelegate = null; this._onmousedownDelegate = null; this._onmousemoveDelegate = null; this._onmouseupDelegate = null; this._onselectstartDelegate = null; } Sys.Extended.UI.ResizableControlBehavior.prototype = { initialize: function() { Sys.Extended.UI.ResizableControlBehavior.callBaseMethod(this, 'initialize'); this._frame = this.get_element(); var savedSizeString = Sys.Extended.UI.ResizableControlBehavior.callBaseMethod(this, 'get_ClientState'); if(savedSizeString && (-1 != savedSizeString.indexOf(','))) { var savedSize = savedSizeString.split(','); this._frame.style.width = savedSize[0] + 'px'; this._frame.style.height = savedSize[1] + 'px'; } // The this._lining lets us measure the interior of the this._frame easily and // protects the contents of this._frame (when resizing) from interactions // with the mouse (ex: IFRAME grabbing mouse capture in IE or Firefox) this._lining = document.createElement('DIV'); this._lining.style.width = $common.getCurrentStyle(this._frame, 'width'); this._lining.style.height = $common.getCurrentStyle(this._frame, 'height'); this._lining.style.position = 'absolute'; this._lining.style.backgroundColor = 'black'; // Keeps browsers from ignoring the content-free element this._lining.style.opacity = "0"; // Makes the lining invisible this._lining.style.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=0)"; // Ditto, for IE this._lining.style.visibility = 'hidden'; this._frame.insertBefore(this._lining, this._frame.firstChild); // The this._handleHolder provedes a wrapper with absolute positioning // so that this._handle can be absolutely positioned relative to the // this._frame instead of the page this._handleHolder = document.createElement('DIV'); this._handleHolder.style.width = '0px'; this._handleHolder.style.height = '0px'; this._handleHolder.style.position = ((Sys.Browser.agent === Sys.Browser.Opera) ? 'relative' : 'absolute'); this._frame.insertBefore(this._handleHolder, this._frame.firstChild); // The this._handle represents the UI handle for the user to grab with // the mouse this._handle = document.createElement('DIV'); this._handle.className = this._HandleCssClass; this._handle.style.position = 'absolute'; this._handleHolder.appendChild(this._handle); this._onmouseoverDelegate = Function.createDelegate(this, this._onmouseover); $addHandler(this._handle, 'mouseover', this._onmouseoverDelegate); this._onmouseoutDelegate = Function.createDelegate(this, this._onmouseout); $addHandler(this._handle, 'mouseout', this._onmouseoutDelegate); this._onmousedownDelegate = Function.createDelegate(this, this._onmousedown); $addHandler(this._handle, 'mousedown', this._onmousedownDelegate); this._onmousemoveDelegate = Function.createDelegate(this, this._onmousemove); this._onmouseupDelegate = Function.createDelegate(this, this._onmouseup); this._onselectstartDelegate = Function.createDelegate(this, this._onselectstart); this._resizeControl(0, 0, 0, 0); this._rememberSize(); }, dispose: function() { if(this._onmouseoverDelegate) { $removeHandler(this._handle, 'mouseover', this._onmouseoverDelegate); this._onmouseoverDelegate = null; } if(this._onmouseoutDelegate) { $removeHandler(this._handle, 'mouseout', this._onmouseoutDelegate); this._onmouseoutDelegate = null; } if(this._onmousedownDelegate) { $removeHandler(this._handle, 'mousedown', this._onmousedownDelegate); this._onmousedownDelegate = null; } if(this._onmousemoveDelegate) { if(this.tracking) $removeHandler(document, 'mousemove', this._onmousemoveDelegate); this._onmousemoveDelegate = null; } if(this._onmouseupDelegate) { if(this.tracking) $removeHandler(document, 'mouseup', this._onmouseupDelegate); this._onmouseupDelegate = null; } if(this._onselectstartDelegate) { if(this.tracking) { $removeHandler(document, 'selectstart', this._onselectstartDelegate); if(Sys.Browser.agent === Sys.Browser.Opera) $removeHandler(document, 'mousedown', this._onselectstartDelegate); } this._onselectstartDelegate = null; } Sys.Extended.UI.ResizableControlBehavior.callBaseMethod(this, 'dispose'); }, _onmouseover: function() { Sys.UI.DomElement.addCssClass(this._frame, this._ResizableCssClass); }, _onmouseout: function() { if(!this._tracking) Sys.UI.DomElement.removeCssClass(this._frame, this._ResizableCssClass); }, _onmousedown: function(e) { // TODO: Fix for new event model if(!e) e = event; this._onmousedownImplementation(e.clientX, e.clientY); }, _onmousedownImplementation: function(clientX, clientY) { this._tracking = true; this._resizeControl(clientX, clientY, 0, 0); this._lining.style.visibility = 'visible'; // Overlay resizing control to avoid interacting with it (ex: IFRAME) $addHandler(document, 'mousemove', this._onmousemoveDelegate); $addHandler(document, 'mouseup', this._onmouseupDelegate); $addHandler(document, 'selectstart', this._onselectstartDelegate); if(Sys.Browser.agent === Sys.Browser.Opera) $addHandler(document, 'mousedown', this._onselectstartDelegate); this.raiseResizeBegin(); }, _onmousemove: function(e) { // TODO: Fix for new event model if(!e) e = event; this._onmousemoveImplementation(e.clientX, e.clientY); }, _onmousemoveImplementation: function(clientX, clientY) { if(this._tracking) { var deltaX = (clientX - this._lastClientX); var deltaY = (clientY - this._lastClientY); this._resizeControl(clientX, clientY, deltaX, deltaY); } }, _onmouseup: function() { this._tracking = false; this._rememberSize(); this._lining.style.visibility = 'hidden'; $removeHandler(document, 'mousemove', this._onmousemoveDelegate); $removeHandler(document, 'mouseup', this._onmouseupDelegate); $removeHandler(document, 'selectstart', this._onselectstartDelegate); if(Sys.Browser.agent === Sys.Browser.Opera) $removeHandler(document, 'mousedown', this._onselectstartDelegate); Sys.UI.DomElement.removeCssClass(this._frame, this._ResizableCssClass); }, _onselectstart: function(e) { // Don't allow selection during drag e.preventDefault(); return false; }, _resizeControl: function(clientX, clientY, deltaX, deltaY) { // Save last client X/Y this._lastClientX = clientX; this._lastClientY = clientY; // Calculate new lining/frame width/height var _liningWidth = Math.min(Math.max(this._lining.offsetWidth + deltaX, Math.max(this._MinimumWidth, this._handle.offsetWidth)), this._MaximumWidth), _liningHeight = Math.min(Math.max(this._lining.offsetHeight + deltaY, Math.max(this._MinimumHeight, this._handle.offsetHeight)), this._MaximumHeight); // Set new lining/frame width/height this._lining.style.width = _liningWidth + 'px'; this._lining.style.height = _liningHeight + 'px'; this._frame.style.width = _liningWidth + 'px'; this._frame.style.height = _liningHeight + 'px'; // Calculate new handle left/top var _handleLeft = this._lining.offsetWidth - this._handle.offsetWidth + this._HandleOffsetX, _handleTop = this._lining.offsetHeight - this._handle.offsetHeight + this._HandleOffsetY; // Set new handle left/top this._handle.style.left = _handleLeft + 'px'; this._handle.style.top = _handleTop + 'px'; // Raise the resizing event this.raiseResizing(); }, _rememberSize: function() { var size = this.get_Size(); // save the size in ClientState Sys.Extended.UI.ResizableControlBehavior.callBaseMethod(this, 'set_ClientState', [size.width + ',' + size.height]); // Raise the resize event this.raiseResize(); }, _measurementToNumber: function(m) { // Get the magnitude of a measurement // "m" - Measurement // returns - magnitude of a measurement return m.replace('px', ''); }, get_HandleCssClass: function() { return this._HandleCssClass; }, set_HandleCssClass: function(value) { if(this._HandleCssClass) throw String.format(Sys.Extended.UI.Resources.ResizableControlBehavior_CannotChangeProperty, 'HandleCssClass'); this._HandleCssClass = value; this.raisePropertyChanged('HandleCssClass'); }, get_ResizableCssClass: function() { return this._ResizableCssClass; }, set_ResizableCssClass: function(value) { if(this._ResizableCssClass) throw String.format(Sys.Extended.UI.Resources.ResizableControlBehavior_CannotChangeProperty, 'ResizableCssClass'); this._ResizableCssClass = value; this.raisePropertyChanged('ResizableCssClass'); }, get_HandleOffsetX: function() { return this._HandleOffsetX; }, set_HandleOffsetX: function(value) { if(this._HandleOffsetX != value) { this._HandleOffsetX = value; this.raisePropertyChanged('HandleOffsetX'); } }, get_HandleOffsetY: function() { return this._HandleOffsetY; }, set_HandleOffsetY: function(value) { if(this._HandleOffsetY != value) { this._HandleOffsetY = value; this.raisePropertyChanged('HandleOffsetY'); } }, get_MinimumWidth: function() { return this._MinimumWidth; }, set_MinimumWidth: function(value) { if(this._MinimumWidth != value) { this._MinimumWidth = value; this.raisePropertyChanged('MinimumWidth'); } }, get_MinimumHeight: function() { return this._MinimumHeight; }, set_MinimumHeight: function(value) { if(this._MinimumHeight != value) { this._MinimumHeight = value; this.raisePropertyChanged('MinimumHeight'); } }, get_MaximumWidth: function() { return this._MaximumWidth; }, set_MaximumWidth: function(value) { if(this._MaximumWidth != value) { this._MaximumWidth = value; this.raisePropertyChanged('MaximumWidth'); } }, get_MaximumHeight: function() { return this._MaximumHeight; }, set_MaximumHeight: function(value) { if(this._MaximumHeight != value) { this._MaximumHeight = value; this.raisePropertyChanged('MaximumHeight'); } }, add_resizing: function(handler) { this.get_events().addHandler("resizing", handler); }, remove_resizing: function(handler) { this.get_events().removeHandler("resizing", handler); }, raiseResizing: function() { var onResizingHandler = this.get_events().getHandler("resizing"); if(onResizingHandler) onResizingHandler(this, Sys.EventArgs.Empty); }, get_resizing: function() { // Function to invoke on resizing (can a Function, name of a Function, or expression that evaluates to a Function) return this.get_events().getHandler("resizing"); }, set_resizing: function(value) { if(value && (0 < value.length)) { var func = $common.resolveFunction(value); if(func) this.add_resizing(func); else throw Error.argumentType('value', typeof (value), 'Function', String.format(Sys.Extended.UI.Resources.ResizableControlBehavior_InvalidHandler, 'resizing')); } }, add_resize: function(handler) { this.get_events().addHandler("resize", handler); }, remove_resize: function(handler) { this.get_events().removeHandler("resize", handler); }, raiseResize: function() { var onResizeHandler = this.get_events().getHandler("resize"); if(onResizeHandler) onResizeHandler(this, Sys.EventArgs.Empty); }, get_resize: function() { // Function to invoke on resize (can be a Function, name of a Function, or expression that evaluates to a Function) return this.get_events().getHandler("resize"); }, set_resize: function(value) { if(value && (0 < value.length)) { var func = $common.resolveFunction(value); if(func) this.add_resize(func); else throw Error.argumentType('value', typeof (value), 'Function', String.format(Sys.Extended.UI.Resources.ResizableControlBehavior_InvalidHandler, 'resize')); } }, add_resizebegin: function(handler) { this.get_events().addHandler("resizebegin", handler); }, remove_resizebegin: function(handler) { this.get_events().removeHandler("resizebegin", handler); }, raiseResizeBegin: function() { var onresizebeginHandler = this.get_events().getHandler("resizebegin"); if(onresizebeginHandler) onresizebeginHandler(this, Sys.EventArgs.Empty); }, get_resizebegin: function() { // Function to invoke on resizebegin (can be a Function, name of a Function, or expression that evaluates to a Function) return this.get_events().getHandler("resizebegin"); }, set_resizebegin: function(value) { if(value && (0 < value.length)) { var func = $common.resolveFunction(value); if(func) this.add_resizebegin(func); else throw Error.argumentType('value', typeof (value), 'Function', String.format(Sys.Extended.UI.Resources.ResizableControlBehavior_InvalidHandler, 'resizebegin')); } }, get_Size: function() { // Size of the target (of the form {width, height}) return { width: this._measurementToNumber($common.getCurrentStyle(this._lining, 'width')), height: this._measurementToNumber($common.getCurrentStyle(this._lining, 'height')) }; }, set_Size: function(value) { var deltaX = value.width - this._measurementToNumber($common.getCurrentStyle(this._lining, 'width')), deltaY = value.height - this._measurementToNumber($common.getCurrentStyle(this._lining, 'height')); this._resizeControl(0, 0, deltaX, deltaY); this._rememberSize(); this.raisePropertyChanged('Size'); } } Sys.Extended.UI.ResizableControlBehavior.registerClass('Sys.Extended.UI.ResizableControlBehavior', Sys.Extended.UI.BehaviorBase);