1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 * Provide support for drag-and-drop operations in shaped windows. The
8 * standard API doesn't work because no "dragover" events are generated
9 * if the mouse moves outside the window region.
13 /** @suppress {duplicate} */
14 var remoting = remoting || {};
18 * @param {Element} element The element to register for drag and drop.
19 * @param {function(number, number):void} dragUpdate Callback to receive the
20 * X and Y deltas as the element is dragged.
21 * @param {function():void=} opt_dragStart Initiation callback.
22 * @param {function():void=} opt_dragEnd Completion callback.
24 remoting.DragAndDrop = function(element, dragUpdate,
25 opt_dragStart, opt_dragEnd) {
27 this.element_ = element;
30 this.dragUpdate_ = dragUpdate;
33 this.dragStart_ = opt_dragStart;
36 this.dragEnd_ = opt_dragEnd;
38 /** @private {number} */
39 this.previousDeltaX_ = 0;
41 /** @private {number} */
42 this.previousDeltaY_ = 0;
44 /** @type {boolean} */
45 this.seenNonZeroDelta_ = false;
47 /** @private {function(Event):void} */
48 this.callOnMouseUp_ = this.onMouseUp_.bind(this);
50 /** @private {function(Event):void} */
51 this.callOnMouseMove_ = this.onMouseMove_.bind(this);
53 element.addEventListener('mousedown', this.onMouseDown_.bind(this), false);
57 * @param {Event} event
59 remoting.DragAndDrop.prototype.onMouseDown_ = function(event) {
60 if (event.button != 0) {
63 this.previousDeltaX_ = 0;
64 this.previousDeltaY_ = 0;
65 this.seenNonZeroDelta_ = false;
66 this.element_.addEventListener('mousemove', this.callOnMouseMove_, false);
67 this.element_.addEventListener('mouseup', this.callOnMouseUp_, false);
68 this.element_.requestPointerLock();
69 if (this.dragStart_) {
75 * TODO(jamiewalch): Remove the workarounds in this method once the pointer-lock
76 * API is fixed (crbug.com/419562).
78 * @param {Event} event
80 remoting.DragAndDrop.prototype.onMouseMove_ = function(event) {
81 // Ignore the first non-zero delta. A click event will generate a bogus
82 // mousemove event, even if the mouse doesn't move.
83 if (!this.seenNonZeroDelta_ &&
84 (event.movementX != 0 || event.movementY != 0)) {
85 this.seenNonZeroDelta_ = true;
89 * The mouse lock API is buggy when used with shaped windows, and occasionally
90 * generates single, large deltas that must be filtered out.
92 * @param {number} previous
93 * @param {number} current
96 var adjustDelta = function(previous, current) {
97 var THRESHOLD = 100; // Based on observed values.
98 if (Math.abs(previous < THRESHOLD) && Math.abs(current) >= THRESHOLD) {
103 this.previousDeltaX_ = adjustDelta(this.previousDeltaX_, event.movementX);
104 this.previousDeltaY_ = adjustDelta(this.previousDeltaY_, event.movementY);
105 if (this.previousDeltaX_ != 0 || this.previousDeltaY_ != 0) {
106 this.dragUpdate_(this.previousDeltaX_, this.previousDeltaY_);
111 * @param {Event} event
113 remoting.DragAndDrop.prototype.onMouseUp_ = function(event) {
114 this.element_.removeEventListener('mousemove', this.callOnMouseMove_, false);
115 this.element_.removeEventListener('mouseup', this.callOnMouseUp_, false);
116 document.exitPointerLock();