Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 /*
6 * Handles nav overlay button positioning.
7 */
9 // minimum amount of movement using the mouse after which we cancel the button click handlers
10 const kOnClickMargin = 3;
12 const kNavButtonPref = "browser.display.overlaynavbuttons";
14 var NavButtonSlider = {
15 _back: document.getElementById("overlay-back"),
16 _plus: document.getElementById("overlay-plus"),
17 _mouseMoveStarted: false,
18 _mouseDown: false,
19 _yPos: -1,
21 get back() {
22 return this._back;
23 },
25 get plus() {
26 return this._plus;
27 },
29 /*
30 * custom dragger, see input.js
31 */
33 freeDrag: function freeDrag() {
34 return true;
35 },
37 isDraggable: function isDraggable(aTarget, aContent) {
38 return { x: false, y: true };
39 },
41 dragStart: function dragStart(aX, aY, aTarget, aScroller) {
42 return true;
43 },
45 dragStop: function dragStop(aDx, aDy, aScroller) {
46 return true;
47 },
49 dragMove: function dragMove(aDx, aDy, aScroller, aIsKenetic, aClientX, aClientY) {
50 // Note if aIsKenetic is true this is synthetic movement,
51 // we don't want that so return false.
52 if (aIsKenetic) {
53 return false;
54 }
56 this._updatePosition(aClientY);
58 // return true if we moved, false otherwise. The result
59 // is used in deciding if we should repaint between drags.
60 return true;
61 },
63 /*
64 * logic
65 */
67 init: function init() {
68 // Touch drag support provided by input.js
69 this._back.customDragger = this;
70 this._plus.customDragger = this;
71 Elements.browsers.addEventListener("ContentSizeChanged", this, true);
72 let events = ["mousedown", "mouseup", "mousemove", "click", "touchstart", "touchmove", "touchend"];
73 events.forEach(function (value) {
74 this._back.addEventListener(value, this, true);
75 this._plus.addEventListener(value, this, true);
76 }, this);
78 this._updateStops();
79 this._updateVisibility();
80 Services.prefs.addObserver(kNavButtonPref, this, false);
81 },
83 observe: function (aSubject, aTopic, aData) {
84 if (aTopic == "nsPref:changed" && aData == kNavButtonPref) {
85 this._updateVisibility();
86 }
87 },
89 _updateVisibility: function () {
90 if (Services.prefs.getBoolPref(kNavButtonPref)) {
91 this._back.removeAttribute("hidden");
92 this._plus.removeAttribute("hidden");
93 } else {
94 this._back.setAttribute("hidden", true);
95 this._plus.setAttribute("hidden", true);
96 }
97 },
99 _updateStops: function () {
100 this._contentHeight = ContentAreaObserver.contentHeight;
101 this._imageHeight = 118;
102 this._topStop = this._imageHeight * .7;
103 this._bottomStop = this._contentHeight - (this._imageHeight * .7);
105 // Check to see if we need to move the slider into view
106 if (this._yPos != -1 &&
107 (this._topStop > this._yPos || this._bottomStop < this._yPos)) {
108 this._back.style.top = "50%";
109 this._plus.style.top = "50%";
110 }
111 },
113 _getPosition: function _getPosition() {
114 this._yPos = parseInt(getComputedStyle(this._back).top);
115 },
117 _setPosition: function _setPosition() {
118 this._back.style.top = this._yPos + "px";
119 this._plus.style.top = this._yPos + "px";
120 },
122 _updatePosition: function (aClientY) {
123 if (this._topStop > aClientY || this._bottomStop < aClientY)
124 return;
125 this._yPos = aClientY;
126 this._setPosition();
127 },
129 _updateOffset: function (aOffset) {
130 let newPos = this._yPos + aOffset;
131 if (this._topStop > newPos || this._bottomStop < newPos)
132 return;
133 this._yPos = newPos;
134 this._setPosition();
135 },
137 /*
138 * Events
139 */
141 handleEvent: function handleEvent(aEvent) {
142 switch (aEvent.type) {
143 case "ContentSizeChanged":
144 this._updateStops();
145 break;
147 case "touchstart":
148 if (aEvent.touches.length != 1)
149 break;
150 aEvent.preventDefault();
151 aEvent = aEvent.touches[0];
152 case "mousedown":
153 this._getPosition();
154 this._mouseDown = true;
155 this._mouseMoveStarted = false;
156 this._mouseY = aEvent.clientY;
157 if (aEvent.originalTarget)
158 aEvent.originalTarget.setCapture();
159 this._back.setAttribute("mousedrag", true);
160 this._plus.setAttribute("mousedrag", true);
161 break;
163 case "touchend":
164 if (aEvent.touches.length != 0)
165 break;
166 this._mouseDown = false;
167 this._back.removeAttribute("mousedrag");
168 this._plus.removeAttribute("mousedrag");
169 if (!this._mouseMoveStarted) {
170 if (aEvent.originalTarget == this._back) {
171 CommandUpdater.doCommand('cmd_back');
172 } else {
173 CommandUpdater.doCommand('cmd_newTab');
174 }
175 }
176 break;
177 case "mouseup":
178 this._mouseDown = false;
179 this._back.removeAttribute("mousedrag");
180 this._plus.removeAttribute("mousedrag");
181 break;
183 case "touchmove":
184 if (aEvent.touches.length != 1)
185 break;
186 aEvent = aEvent.touches[0];
187 case "mousemove":
188 // Check to be sure this is a drag operation
189 if (!this._mouseDown) {
190 return;
191 }
192 // Don't start a drag until we've passed a threshold
193 let dy = aEvent.clientY - this._mouseY;
194 if (!this._mouseMoveStarted && Math.abs(dy) < kOnClickMargin) {
195 return;
196 }
197 // Start dragging via the mouse
198 this._mouseMoveStarted = true;
199 this._mouseY = aEvent.clientY;
200 this._updateOffset(dy);
201 break;
202 case "click":
203 // Don't invoke the click action if we've moved the buttons via the mouse.
204 if (this._mouseMoveStarted) {
205 return;
206 }
207 if (aEvent.originalTarget == this._back) {
208 CommandUpdater.doCommand('cmd_back');
209 } else {
210 CommandUpdater.doCommand('cmd_newTab');
211 }
212 break;
213 }
214 },
215 };