Bug 695569 - Add scroll indicators for web content [r=mfinkle]
authorKartikaya Gupta <kgupta@mozilla.com>
Mon, 31 Oct 2011 16:25:21 -0400
changeset 83334 0aeaa4995892103d4b92db4b381682b19703a3e1
parent 83333 06bee407d000cfad697b92af754d8fcd58f9fd2e
child 83335 e968742b325d1b2f1e4c477863451d03053951ef
push id519
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 00:38:35 +0000
treeherdermozilla-beta@788ea1ef610b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmfinkle
bugs695569
milestone10.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 695569 - Add scroll indicators for web content [r=mfinkle] Add horizontal and vertical scrollbars that appear while the user is scrolling the top-level content. They disappear once scrolling has ceased.
mobile/chrome/content/browser.js
mobile/chrome/content/browser.xul
--- a/mobile/chrome/content/browser.js
+++ b/mobile/chrome/content/browser.js
@@ -115,22 +115,26 @@ var Strings = {};
   });
 });
 
 var BrowserApp = {
   _tabs: [],
   _selectedTab: null,
 
   deck: null,
+  vertScroller: null,
+  horizScroller: null,
 
   startup: function startup() {
     window.QueryInterface(Ci.nsIDOMChromeWindow).browserDOMWindow = new nsBrowserAccess();
     dump("zerdatime " + Date.now() + " - browser chrome startup finished.");
 
     this.deck = document.getElementById("browsers");
+    this.vertScroller = document.getElementById("vertical-scroller");
+    this.horizScroller = document.getElementById("horizontal-scroller");
     BrowserEventHandler.init();
 
     Services.obs.addObserver(this, "Tab:Add", false);
     Services.obs.addObserver(this, "Tab:Load", false);
     Services.obs.addObserver(this, "Tab:Select", false);
     Services.obs.addObserver(this, "Tab:Close", false);
     Services.obs.addObserver(this, "Session:Back", false);
     Services.obs.addObserver(this, "Session:Forward", false);
@@ -450,16 +454,56 @@ var BrowserApp = {
     let doc = aBrowser.contentDocument;
     if (!doc)
       return;
     let focused = doc.activeElement;
     if ((focused instanceof HTMLInputElement && focused.mozIsTextField(false)) || (focused instanceof HTMLTextAreaElement))
       focused.scrollIntoView(false);
   },
 
+  updateScrollbarsFor: function(aElement) {
+    // only draw the scrollbars if we're scrolling the root content element
+    let doc = this.selectedBrowser.contentDocument;
+    if (aElement != doc.documentElement && aElement != doc.body)
+      return;
+
+    // draw the vertical scrollbar as needed
+    let scrollMax = aElement.scrollHeight;
+    let viewSize = aElement.clientHeight;
+    if (scrollMax > viewSize) {
+      let scrollPos = aElement.scrollTop;
+      let scrollerSize = this.selectedBrowser.clientHeight;
+      // scrollerSize may not equal viewSize if the user has zoomed
+      let barStart = Math.round(scrollerSize * scrollPos / scrollMax);
+      let barEnd = Math.round(scrollerSize * (scrollPos + viewSize) / scrollMax);
+      this.vertScroller.height = (barEnd - barStart);
+      this.vertScroller.style.MozTransform = "translateY(" + barStart + "px)";
+      this.vertScroller.setAttribute("panning", "true");
+    }
+
+    // draw the horizontal scrollbar as needed
+    scrollMax = aElement.scrollWidth;
+    viewSize = aElement.clientWidth;
+    if (scrollMax > viewSize) {
+      let scrollPos = aElement.scrollLeft;
+      let scrollerSize = this.selectedBrowser.clientWidth;
+      // scrollerSize may not equal viewSize if the user has zoomed
+      let barStart = Math.round(scrollerSize * scrollPos / scrollMax);
+      let barEnd = Math.round(scrollerSize * (scrollPos + viewSize) / scrollMax);
+      this.horizScroller.width = (barEnd - barStart);
+      this.horizScroller.style.MozTransform = "translateX(" + barStart + "px)";
+      this.horizScroller.setAttribute("panning", "true");
+    }
+  },
+
+  hideScrollbars: function() {
+    this.vertScroller.setAttribute("panning", "");
+    this.horizScroller.setAttribute("panning", "");
+  },
+
   observe: function(aSubject, aTopic, aData) {
     let browser = this.selectedBrowser;
     if (!browser)
       return;
 
     if (aTopic == "Session:Back") {
       browser.goBack();
     } else if (aTopic == "Session:Forward") {
@@ -994,16 +1038,21 @@ var BrowserEventHandler = {
         break;
 
       case "mouseup":
         if (!this.panning)
           break;
 
         this.panning = false;
 
+        // hide the scrollbars in case we're done scrolling. if the
+        // kinetic scrolling kicks in, it will re-enable the scrollbars
+        // anyway by calling _scrollElementBy below
+        BrowserApp.hideScrollbars();
+
         if (Math.abs(aEvent.clientX - this.startX) > kDragThreshold ||
             Math.abs(aEvent.clientY - this.startY) > kDragThreshold) {
           this.blockClick = true;
           aEvent.stopPropagation();
           aEvent.preventDefault();
 
           // Calculate a regression line for the last few motion events in
           // the same direction to estimate the velocity. This ought to do a
@@ -1153,17 +1202,19 @@ var BrowserEventHandler = {
                   self.panAccumulatedDeltaY -= ady;
               }
 
               self._scrollElementBy(panElement, -dx, -dy);
 
               if (Math.abs(self.panX) >= kMinKineticSpeed ||
                   Math.abs(self.panY) >= kMinKineticSpeed)
                 window.mozRequestAnimationFrame(this);
-              }
+              else
+                BrowserApp.hideScrollbars();
+            }
           };
 
           // If one axis is moving a lot slower than the other, lock it.
           if (Math.abs(this.panX) < Math.abs(this.panY) / kAxisLockRatio)
             this.panX = 0;
           else if (Math.abs(this.panY) < Math.abs(this.panX) / kAxisLockRatio)
             this.panY = 0;
 
@@ -1290,16 +1341,17 @@ var BrowserEventHandler = {
       return null;
 
     return elem;
   },
 
   _scrollElementBy: function(elem, x, y) {
     elem.scrollTop = elem.scrollTop + y;
     elem.scrollLeft = elem.scrollLeft + x;
+    BrowserApp.updateScrollbarsFor(elem);
   },
 
   _elementCanScroll: function(elem, x, y) {
     let scrollX = true;
     let scrollY = true;
 
     if (x < 0) {
       if (elem.scrollLeft <= 0) {
--- a/mobile/chrome/content/browser.xul
+++ b/mobile/chrome/content/browser.xul
@@ -1,15 +1,21 @@
 <?xml version="1.0"?>
 
+<?xml-stylesheet href="chrome://browser/skin/browser.css" type="text/css"?>
+
 <window id="main-window"
         onload="BrowserApp.startup();"
         windowtype="navigator:browser"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <script type="application/javascript" src="chrome://browser/content/browser.js"/>
   <script type="application/javascript" src="chrome://browser/content/downloads.js"/>
   <script type="application/javascript" src="chrome://browser/content/exceptions.js"/>
   <script type="application/javascript" src="chrome://browser/content/sanitize.js"/>
 
-  <deck id="browsers" flex="1"/>
+  <stack flex="1">
+    <deck id="browsers" flex="1"/>
+    <box id="vertical-scroller" class="scroller" orient="vertical" end="2" top="0"/>
+    <box id="horizontal-scroller" class="scroller" orient="horizontal" left="0" bottom="2"/>
+  </stack>
 
 </window>