// ========================================================================== // Project: SproutCore
- JavaScript Application Framework // Copyright: ©2006-2011 Strobe Inc. and contributors. // Portions ©2008-2011 Apple Inc. All rights reserved. // License: Licensed under MIT license (see license.js) // ==========================================================================
/**
@namespace Provides drag functionality to a pane. If you need to disable dragging at certain times set the property isAnchored to YES and the pane will no longer move. See SC.PalettePane, a simple panel pane with SC.DraggablePaneSupport mixed in.
*/ SC
.DraggablePaneSupport = /** @scope SC
.DraggablePaneSupport.prototype */{
/** Walk like a duck. @type Boolean */ isDraggablePane: YES, /** @type Boolean @default NO */ isAnchored: NO, /** @private */ _drag_cachedMouseX: null, /** @private */ _drag_cachedMouseY: null, /** To provide drag functionality enhance mouseDown, mouseDragged, touchStart, and touchesDragged if they exist. */ initMixin: function() { if (this.mouseDown) { this.mouseDown = SC._enhance(this.mouseDown, function(original, evt) { var ret = this._drag_mouseDown(evt); return original(evt) || ret; }); } else { this.mouseDown = this._drag_mouseDown; } if (this.mouseDragged) { this.mouseDragged = SC._enhance(this.mouseDragged, function(original, evt) { var ret = this._drag_mouseDragged(evt); return original(evt) || ret; }); } else { this.mouseDragged = this._drag_mouseDragged; } if (this.touchStart) { this.touchStart = SC._enhance(this.touchStart, function(original, evt) { var ret = this._drag_touchStart(evt); return original(evt) || ret; }); } else { this.touchStart = this._drag_touchStart; } if (this.touchesDragged) { this.touchesDragged = SC._enhance(this.touchesDragged, function(original, evt) { var ret = this._drag_touchesDragged(evt); return original(evt) || ret; }); } else { this.touchesDragged = this._drag_touchesDragged; } }, /** Returns true if the target view of the event exists and has a truthy isTextSelectable @param evt The event @return {Boolean} */ _drag_targetHasSelectableText: function(evt) { var targetView = SC.RootResponder.responder.targetViewForEvent(evt); return !!(targetView && targetView.isTextSelectable); }, /** Returns true if we should handle a drag. @param evt The event @return {Boolean} */ _drag_shouldHandleDrag: function(evt) { return !this.get('isAnchored') && !this._drag_targetHasSelectableText(evt); }, /** The drag code will modify the existing layout by the difference between each drag event so for the first one store the original mouse down position. @param evt The mouseDown event @return {Boolean} YES */ _drag_mouseDown: function(evt) { this._drag_cachedMouseX = evt.pageX; this._drag_cachedMouseY = evt.pageY; return this._drag_shouldHandleDrag(evt); }, /** Modify the current layout by the movement since the last drag event. @param evt The mouseDrag event @return {Boolean} YES if we moved the view, NO if we didn't due to isAnchored being YES */ _drag_mouseDragged: function(evt) { var xOffset = this._drag_cachedMouseX - evt.pageX, yOffset = this._drag_cachedMouseY - evt.pageY, frame = this.get('frame'), // NOTE: wFrame will be incorrect if this pane is not attached to document.body (e.g. via appendTo). wFrame = SC.RootResponder.responder.computeWindowSize(), oldLayout = SC.clone(this.get('layout')), layout = {}, isPercent = function(num) { return (num < 1 && num > 0); }; //Update the cached coordinates so we can track the change between each drag event this._drag_cachedMouseX = evt.pageX; this._drag_cachedMouseY = evt.pageY; if (!this._drag_shouldHandleDrag(evt)) { return NO; } // If a layout property is in the layout no matter what other layout properties are used we need to modify it the // same way. For the 4 offsets we check if they've been specified as percentages and if so convert them to regular // offsets based on our current frame and the current window. For simplicity's sake, it is assumed that the frame // frame coordinates are in the browser window's coordinates (see above note on wFrame). if (oldLayout.hasOwnProperty('left')) { if (isPercent(oldLayout.left)) { oldLayout.left = frame.x; } layout.left = oldLayout.left - xOffset; } if (oldLayout.hasOwnProperty('right')) { if (isPercent(oldLayout.right)) { oldLayout.right = wFrame.width - (frame.x + frame.width); } layout.right = oldLayout.right + xOffset; } if (oldLayout.hasOwnProperty('centerX')) { layout.centerX = oldLayout.centerX - xOffset; } if (oldLayout.hasOwnProperty('top')) { if (isPercent(oldLayout.top)) { oldLayout.top = frame.y; } layout.top = oldLayout.top - yOffset; } if (oldLayout.hasOwnProperty('bottom')) { if (isPercent(oldLayout.bottom)) { oldLayout.bottom = wFrame.height - (frame.y + frame.height); } layout.bottom = oldLayout.bottom + yOffset; } if (oldLayout.hasOwnProperty('centerY')) { layout.centerY = oldLayout.centerY - yOffset; } this.adjust(layout); return YES; }, /** Forward to our mouseDown handler. */ _drag_touchStart: function(evt) { return this._drag_mouseDown(evt); }, /** Forward to our mouseDragged handler. */ _drag_touchesDragged: function(evt) { return this._drag_mouseDragged(evt); }
};