diff -r 000000000000 -r 6474c204b198 browser/metro/base/content/NavButtonSlider.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/browser/metro/base/content/NavButtonSlider.js Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,217 @@ +/* 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; + } + }, +}; + +