| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| /** |
| * @fileoverview This class implements a mouse-drag event. It registers for |
| * mousedown events, and when it sees one, starts capturing mousemove events |
| * until it gets a mousup event. It manufactures three drag events: the |
| * DRAG_START, DRAG and DRAG_END. |
| */ |
| |
| // Requires bind |
| |
| /** |
| * Constructor for the Dragger. Register for mousedown events that happen on |
| * |opt_target|. If |opt_target| is null or undefined, then this object |
| * observes mousedown on the whole document. |
| * @param {?Element} opt_target The event target. Defaults to the whole |
| * document. |
| * @constructor |
| */ |
| tumbler.Dragger = function(opt_target) { |
| /** |
| * The event target. |
| * @type {Element} |
| * @private |
| */ |
| this.target_ = opt_target || document; |
| |
| /** |
| * The array of objects that get notified of drag events. Each object in |
| * this array get sent a handleStartDrag(), handleDrag() and handleEndDrag() |
| * message. |
| * @type {Array.<Object>} |
| * @private |
| */ |
| this.listeners_ = []; |
| |
| /** |
| * Flag to indicate whether the object is in a drag sequence or not. |
| * @type {boolean} |
| * @private |
| */ |
| this.isDragging_ = false; |
| |
| /** |
| * The function objects that get attached as event handlers. These are |
| * cached so that they can be removed on mouse up. |
| * @type {function} |
| * @private |
| */ |
| this.boundMouseMove_ = null; |
| this.boundMouseUp_ = null; |
| |
| this.target_.addEventListener('mousedown', |
| this.onMouseDown.bind(this), |
| false); |
| } |
| |
| /** |
| * The ids used for drag event types. |
| * @enum {string} |
| */ |
| tumbler.Dragger.DragEvents = { |
| DRAG_START: 'dragstart', // Start a drag sequence |
| DRAG: 'drag', // Mouse moved during a drag sequence. |
| DRAG_END: 'dragend' // End a drag sewquence. |
| }; |
| |
| /** |
| * Add a drag listener. Each listener should respond to thhree methods: |
| * handleStartDrag(), handleDrag() and handleEndDrag(). This method assumes |
| * that |listener| does not already exist in the array of listeners. |
| * @param {!Object} listener The object that will listen to drag events. |
| */ |
| tumbler.Dragger.prototype.addDragListener = function(listener) { |
| this.listeners_.push(listener); |
| } |
| |
| /** |
| * Handle a mousedown event: register for mousemove and mouseup, then tell |
| * the target that is has a DRAG_START event. |
| * @param {Event} event The mousedown event that triggered this method. |
| */ |
| tumbler.Dragger.prototype.onMouseDown = function(event) { |
| this.boundMouseMove_ = this.onMouseMove.bind(this); |
| this.boundMouseUp_ = this.onMouseUp.bind(this); |
| this.target_.addEventListener('mousemove', this.boundMouseMove_); |
| this.target_.addEventListener('mouseup', this.boundMouseUp_); |
| this.isDragging_ = true; |
| var dragStartEvent = { type: tumbler.Dragger.DragEvents.DRAG_START, |
| clientX: event.offsetX, |
| clientY: event.offsetY }; |
| var i; |
| for (i = 0; i < this.listeners_.length; ++i) { |
| this.listeners_[i].handleStartDrag(this.target_, dragStartEvent); |
| } |
| } |
| |
| /** |
| * Handle a mousemove event: tell the target that is has a DRAG event. |
| * @param {Event} event The mousemove event that triggered this method. |
| */ |
| tumbler.Dragger.prototype.onMouseMove = function(event) { |
| if (!this.isDragging_) |
| return; |
| var dragEvent = { type: tumbler.Dragger.DragEvents.DRAG, |
| clientX: event.offsetX, |
| clientY: event.offsetY}; |
| var i; |
| for (i = 0; i < this.listeners_.length; ++i) { |
| this.listeners_[i].handleDrag(this.target_, dragEvent); |
| } |
| } |
| |
| /** |
| * Handle a mouseup event: un-register for mousemove and mouseup, then tell |
| * the target that is has a DRAG_END event. |
| * @param {Event} event The mouseup event that triggered this method. |
| */ |
| tumbler.Dragger.prototype.onMouseUp = function(event) { |
| this.target_.removeEventListener('mouseup', this.boundMouseUp_, false); |
| this.target_.removeEventListener('mousemove', this.boundMouseMove_, false); |
| this.boundMouseUp_ = null; |
| this.boundMouseMove_ = null; |
| this.isDragging_ = false; |
| var dragEndEvent = { type: tumbler.Dragger.DragEvents.DRAG_END, |
| clientX: event.offsetX, |
| clientY: event.offsetY}; |
| var i; |
| for (i = 0; i < this.listeners_.length; ++i) { |
| this.listeners_[i].handleEndDrag(this.target_, dragEndEvent); |
| } |
| } |