gecko-dev/browser/metro/base/content/NavButtonSlider.js

218 lines
5.9 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Handles nav overlay button positioning.
*/
// minimum amount of movement using the mouse after which we cancel the button click handlers
const kOnClickMargin = 3;
const kNavButtonPref = "browser.display.overlaynavbuttons";
var NavButtonSlider = {
_back: document.getElementById("overlay-back"),
_plus: document.getElementById("overlay-plus"),
_mouseMoveStarted: false,
_mouseDown: false,
_yPos: -1,
get back() {
return this._back;
},
get plus() {
return this._plus;
},
/*
* custom dragger, see input.js
*/
freeDrag: function freeDrag() {
return true;
},
isDraggable: function isDraggable(aTarget, aContent) {
return { x: false, y: true };
},
dragStart: function dragStart(aX, aY, aTarget, aScroller) {
return true;
},
dragStop: function dragStop(aDx, aDy, aScroller) {
return true;
},
dragMove: function dragMove(aDx, aDy, aScroller, aIsKenetic, aClientX, aClientY) {
// Note if aIsKenetic is true this is synthetic movement,
// we don't want that so return false.
if (aIsKenetic) {
return false;
}
this._updatePosition(aClientY);
// return true if we moved, false otherwise. The result
// is used in deciding if we should repaint between drags.
return true;
},
/*
* logic
*/
init: function init() {
// Touch drag support provided by input.js
this._back.customDragger = this;
this._plus.customDragger = this;
Elements.browsers.addEventListener("ContentSizeChanged", this, true);
let events = ["mousedown", "mouseup", "mousemove", "click", "touchstart", "touchmove", "touchend"];
events.forEach(function (value) {
this._back.addEventListener(value, this, true);
this._plus.addEventListener(value, this, true);
}, this);
this._updateStops();
this._updateVisibility();
Services.prefs.addObserver(kNavButtonPref, this, false);
},
observe: function (aSubject, aTopic, aData) {
if (aTopic == "nsPref:changed" && aData == kNavButtonPref) {
this._updateVisibility();
}
},
_updateVisibility: function () {
if (Services.prefs.getBoolPref(kNavButtonPref)) {
this._back.removeAttribute("hidden");
this._plus.removeAttribute("hidden");
} else {
this._back.setAttribute("hidden", true);
this._plus.setAttribute("hidden", true);
}
},
_updateStops: function () {
this._contentHeight = ContentAreaObserver.contentHeight;
this._imageHeight = 118;
this._topStop = this._imageHeight * .7;
this._bottomStop = this._contentHeight - (this._imageHeight * .7);
// Check to see if we need to move the slider into view
if (this._yPos != -1 &&
(this._topStop > this._yPos || this._bottomStop < this._yPos)) {
this._back.style.top = "50%";
this._plus.style.top = "50%";
}
},
_getPosition: function _getPosition() {
this._yPos = parseInt(getComputedStyle(this._back).top);
},
_setPosition: function _setPosition() {
this._back.style.top = this._yPos + "px";
this._plus.style.top = this._yPos + "px";
},
_updatePosition: function (aClientY) {
if (this._topStop > aClientY || this._bottomStop < aClientY)
return;
this._yPos = aClientY;
this._setPosition();
},
_updateOffset: function (aOffset) {
let newPos = this._yPos + aOffset;
if (this._topStop > newPos || this._bottomStop < newPos)
return;
this._yPos = newPos;
this._setPosition();
},
/*
* Events
*/
handleEvent: function handleEvent(aEvent) {
switch (aEvent.type) {
case "ContentSizeChanged":
this._updateStops();
break;
case "touchstart":
if (aEvent.touches.length != 1)
break;
aEvent.preventDefault();
aEvent = aEvent.touches[0];
case "mousedown":
this._getPosition();
this._mouseDown = true;
this._mouseMoveStarted = false;
this._mouseY = aEvent.clientY;
if (aEvent.originalTarget)
aEvent.originalTarget.setCapture();
this._back.setAttribute("mousedrag", true);
this._plus.setAttribute("mousedrag", true);
break;
case "touchend":
if (aEvent.touches.length != 0)
break;
this._mouseDown = false;
this._back.removeAttribute("mousedrag");
this._plus.removeAttribute("mousedrag");
if (!this._mouseMoveStarted) {
if (aEvent.originalTarget == this._back) {
CommandUpdater.doCommand('cmd_back');
} else {
CommandUpdater.doCommand('cmd_newTab');
}
}
break;
case "mouseup":
this._mouseDown = false;
this._back.removeAttribute("mousedrag");
this._plus.removeAttribute("mousedrag");
break;
case "touchmove":
if (aEvent.touches.length != 1)
break;
aEvent = aEvent.touches[0];
case "mousemove":
// Check to be sure this is a drag operation
if (!this._mouseDown) {
return;
}
// Don't start a drag until we've passed a threshold
let dy = aEvent.clientY - this._mouseY;
if (!this._mouseMoveStarted && Math.abs(dy) < kOnClickMargin) {
return;
}
// Start dragging via the mouse
this._mouseMoveStarted = true;
this._mouseY = aEvent.clientY;
this._updateOffset(dy);
break;
case "click":
// Don't invoke the click action if we've moved the buttons via the mouse.
if (this._mouseMoveStarted) {
return;
}
if (aEvent.originalTarget == this._back) {
CommandUpdater.doCommand('cmd_back');
} else {
CommandUpdater.doCommand('cmd_newTab');
}
break;
}
},
};