Bug 1393565 - De-duplicate the JS code and CSS that sets the bookmark and pocket library animation. r=Gijs
authorJared Wein <jwein@mozilla.com>
Wed, 30 Aug 2017 15:58:24 -0400
changeset 428440 bf39016f88787bc08d62f69d6391374978bfcee6
parent 428439 1320c22e21796cb54f02d1712e28b78066fad6c0
child 428441 1559cabac7b6dc8638cbe8422b14d1371ccba3f2
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersGijs
bugs1393565
milestone57.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 1393565 - De-duplicate the JS code and CSS that sets the bookmark and pocket library animation. r=Gijs MozReview-Commit-ID: Z1kIdrY2Um
browser/base/content/browser-places.js
browser/extensions/pocket/bootstrap.js
browser/extensions/pocket/skin/shared/pocket.css
browser/themes/shared/toolbarbutton-icons.inc.css
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -73,31 +73,16 @@ var StarUI = {
         elt.removeAttribute("disabled");
       elt.removeAttribute("wasDisabled");
     });
   },
 
   // nsIDOMEventListener
   handleEvent(aEvent) {
     switch (aEvent.type) {
-      case "animationend": {
-        let animatableBox = document.getElementById("library-animatable-box");
-        if (aEvent.animationName.startsWith("library-bookmark-animation")) {
-          animatableBox.setAttribute("fade", "true");
-        } else if (aEvent.animationName == "library-bookmark-fade") {
-          animatableBox.removeEventListener("animationend", this);
-          animatableBox.removeAttribute("animate");
-          animatableBox.removeAttribute("fade");
-          let libraryButton = document.getElementById("library-button");
-          // Put the 'fill' back in the normal icon.
-          libraryButton.removeAttribute("animate");
-          gNavToolbox.removeAttribute("animate");
-        }
-        break;
-      }
       case "mousemove":
         clearTimeout(this._autoCloseTimer);
         // The autoclose timer is not disabled on generic mouseout
         // because the user may not have actually interacted with the popup.
         break;
       case "popuphidden": {
         clearTimeout(this._autoCloseTimer);
         if (aEvent.originalTarget == this.panel) {
@@ -115,17 +100,16 @@ var StarUI = {
           let guidsForRemoval = this._itemGuids;
           this._itemGuids = null;
           this._itemIdsMap = null;
 
           if (this._batching) {
             this.endBatch();
           }
 
-          let libraryButton;
           if (removeBookmarksOnPopupHidden && guidsForRemoval) {
             if (this._isNewBookmark) {
               if (!PlacesUIUtils.useAsyncTransactions) {
                 PlacesUtils.transactionManager.undoTransaction();
                 break;
               }
               PlacesTransactions.undo().catch(Cu.reportError);
               break;
@@ -139,42 +123,18 @@ var StarUI = {
                   PlacesUtils.transactionManager.doTransaction(txn);
                 }
               }
               break;
             }
 
             PlacesTransactions.Remove(guidsForRemoval)
                               .transact().catch(Cu.reportError);
-          } else if (this._isNewBookmark &&
-                     Services.prefs.getBoolPref("toolkit.cosmeticAnimations.enabled") &&
-                     (libraryButton = document.getElementById("library-button")) &&
-                     libraryButton.getAttribute("cui-areatype") != "menu-panel" &&
-                     libraryButton.getAttribute("overflowedItem") != "true" &&
-                     libraryButton.closest("#nav-bar")) {
-            let animatableBox = document.getElementById("library-animatable-box");
-            let navBar = document.getElementById("nav-bar");
-            let libraryIcon = document.getAnonymousElementByAttribute(libraryButton, "class", "toolbarbutton-icon");
-            let dwu = window.getInterface(Ci.nsIDOMWindowUtils);
-            let iconBounds = dwu.getBoundsWithoutFlushing(libraryIcon);
-            let libraryBounds = dwu.getBoundsWithoutFlushing(libraryButton);
-
-            animatableBox.style.setProperty("--library-button-y", libraryBounds.y + "px");
-            animatableBox.style.setProperty("--library-button-height", libraryBounds.height + "px");
-            animatableBox.style.setProperty("--library-icon-x", iconBounds.x + "px");
-            if (navBar.hasAttribute("brighttext")) {
-              animatableBox.setAttribute("brighttext", "true");
-            } else {
-              animatableBox.removeAttribute("brighttext");
-            }
-            animatableBox.removeAttribute("fade");
-            gNavToolbox.setAttribute("animate", "bookmark");
-            libraryButton.setAttribute("animate", "bookmark");
-            animatableBox.setAttribute("animate", "bookmark");
-            animatableBox.addEventListener("animationend", this);
+          } else if (this._isNewBookmark) {
+            LibraryUI.triggerLibraryAnimation("bookmark");
           }
         }
         break;
       }
       case "keypress":
         clearTimeout(this._autoCloseTimer);
         this._autoCloseTimerEnabled = false;
 
@@ -1537,16 +1497,78 @@ var RecentBookmarksMenuUI = {
   onEndUpdateBatch() {},
   onItemAdded() {},
   onItemChanged() {},
   onItemVisited() {},
   onItemMoved() {},
 }
 
 /**
+ * Handles the Library button in the toolbar.
+ */
+var LibraryUI = {
+  triggerLibraryAnimation(animation) {
+    if (!this.hasOwnProperty("COSMETIC_ANIMATIONS_ENABLED")) {
+      XPCOMUtils.defineLazyPreferenceGetter(this, "COSMETIC_ANIMATIONS_ENABLED",
+        "toolkit.cosmeticAnimations.enabled", true);
+    }
+
+    let libraryButton = document.getElementById("library-button");
+    if (!libraryButton ||
+        libraryButton.getAttribute("cui-areatype") == "menu-panel" ||
+        libraryButton.getAttribute("overflowedItem") == "true" ||
+        !libraryButton.closest("#nav-bar") ||
+        !this.COSMETIC_ANIMATIONS_ENABLED) {
+      return;
+    }
+    let animatableBox = document.getElementById("library-animatable-box");
+    let navBar = document.getElementById("nav-bar");
+    let libraryIcon = document.getAnonymousElementByAttribute(libraryButton, "class", "toolbarbutton-icon");
+    let dwu = window.getInterface(Ci.nsIDOMWindowUtils);
+    let iconBounds = dwu.getBoundsWithoutFlushing(libraryIcon);
+    let libraryBounds = dwu.getBoundsWithoutFlushing(libraryButton);
+
+    animatableBox.style.setProperty("--library-button-y", libraryBounds.y + "px");
+    animatableBox.style.setProperty("--library-button-height", libraryBounds.height + "px");
+    animatableBox.style.setProperty("--library-icon-x", iconBounds.x + "px");
+    if (navBar.hasAttribute("brighttext")) {
+      animatableBox.setAttribute("brighttext", "true");
+    } else {
+      animatableBox.removeAttribute("brighttext");
+    }
+    animatableBox.removeAttribute("fade");
+    gNavToolbox.setAttribute("animate", animation);
+    libraryButton.setAttribute("animate", animation);
+    animatableBox.setAttribute("animate", animation);
+    if (!this._libraryButtonAnimationEndListeners[animation]) {
+      this._libraryButtonAnimationEndListeners[animation] = event => {
+        this._libraryButtonAnimationEndListener(event, animation);
+      }
+    }
+    animatableBox.addEventListener("animationend", this._libraryButtonAnimationEndListeners[animation]);
+  },
+
+  _libraryButtonAnimationEndListeners: {},
+  _libraryButtonAnimationEndListener(aEvent, animation) {
+    let animatableBox = document.getElementById("library-animatable-box");
+    if (aEvent.animationName.startsWith(`library-${animation}-animation`)) {
+      animatableBox.setAttribute("fade", "true");
+    } else if (aEvent.animationName == `library-${animation}-fade`) {
+      animatableBox.removeEventListener("animationend", LibraryUI._libraryButtonAnimationEndListeners[animation]);
+      animatableBox.removeAttribute("animate");
+      animatableBox.removeAttribute("fade");
+      let libraryButton = document.getElementById("library-button");
+      // Put the 'fill' back in the normal icon.
+      libraryButton.removeAttribute("animate");
+      gNavToolbox.removeAttribute("animate");
+    }
+  },
+};
+
+/**
  * Handles the bookmarks menu-button in the toolbar.
  */
 
 var BookmarkingUI = {
   STAR_ID: "star-button",
   BOOKMARK_BUTTON_ID: "bookmarks-menu-button",
   BOOKMARK_BUTTON_SHORTCUT: "addBookmarkAsKb",
   get button() {
--- a/browser/extensions/pocket/bootstrap.js
+++ b/browser/extensions/pocket/bootstrap.js
@@ -160,17 +160,17 @@ var PocketPageAction = {
           PocketPageAction.urlbarNode = urlbarNode;
           PocketPageAction.urlbarNode.setAttribute("open", "true");
           if (Services.prefs.getBoolPref("toolkit.cosmeticAnimations.enabled")) {
             PocketPageAction.urlbarNode.setAttribute("animate", "true");
           }
         },
         onIframeHiding(iframe, panel) {
           if (iframe.getAttribute("itemAdded") == "true") {
-            PocketPageAction.startLibraryAnimation(iframe.ownerDocument);
+            iframe.ownerGlobal.LibraryUI.triggerLibraryAnimation("pocket");
           }
         },
         onIframeHidden(iframe, panel) {
           if (!PocketPageAction.urlbarNode) {
             return;
           }
           PocketPageAction.urlbarNode.removeAttribute("animate");
           PocketPageAction.urlbarNode.removeAttribute("open");
@@ -192,64 +192,16 @@ var PocketPageAction = {
       if (pocketButtonBox) {
         pocketButtonBox.remove();
       }
     }
 
     this.pageAction.remove();
     this.pageAction = null;
   },
-
-  startLibraryAnimation(doc) {
-    let libraryButton = doc.getElementById("library-button");
-    if (!Services.prefs.getBoolPref("toolkit.cosmeticAnimations.enabled") ||
-        !libraryButton ||
-        libraryButton.getAttribute("cui-areatype") == "menu-panel" ||
-        libraryButton.getAttribute("overflowedItem") == "true" ||
-        !libraryButton.closest("#nav-bar")) {
-      return;
-    }
-
-    let animatableBox = doc.getElementById("library-animatable-box");
-    let navBar = doc.getElementById("nav-bar");
-    let libraryIcon = doc.getAnonymousElementByAttribute(libraryButton, "class", "toolbarbutton-icon");
-    let dwu = doc.defaultView.getInterface(Ci.nsIDOMWindowUtils);
-    let iconBounds = dwu.getBoundsWithoutFlushing(libraryIcon);
-    let libraryBounds = dwu.getBoundsWithoutFlushing(libraryButton);
-
-    animatableBox.style.setProperty("--library-button-y", libraryBounds.y + "px");
-    animatableBox.style.setProperty("--library-button-height", libraryBounds.height + "px");
-    animatableBox.style.setProperty("--library-icon-x", iconBounds.x + "px");
-    if (navBar.hasAttribute("brighttext")) {
-      animatableBox.setAttribute("brighttext", "true");
-    } else {
-      animatableBox.removeAttribute("brighttext");
-    }
-    animatableBox.removeAttribute("fade");
-    doc.defaultView.gNavToolbox.setAttribute("animate", "pocket");
-    libraryButton.setAttribute("animate", "pocket");
-    animatableBox.setAttribute("animate", "pocket");
-    animatableBox.addEventListener("animationend", PocketPageAction.onLibraryButtonAnimationEnd);
-  },
-
-  onLibraryButtonAnimationEnd(event) {
-    let doc = event.target.ownerDocument;
-    let libraryButton = doc.getElementById("library-button");
-    let animatableBox = doc.getElementById("library-animatable-box");
-    if (event.animationName.startsWith("library-pocket-animation")) {
-      animatableBox.setAttribute("fade", "true");
-    } else if (event.animationName == "library-pocket-fade") {
-      animatableBox.removeEventListener("animationend", PocketPageAction.onLibraryButtonAnimationEnd);
-      // Put the 'fill' back in the normal icon.
-      libraryButton.removeAttribute("animate");
-      animatableBox.removeAttribute("animate");
-      animatableBox.removeAttribute("fade");
-      event.target.ownerGlobal.gNavToolbox.removeAttribute("animate");
-    }
-  },
 };
 
 // PocketContextMenu
 // When the context menu is opened check if we need to build and enable pocket UI.
 var PocketContextMenu = {
   init() {
     Services.obs.addObserver(this, "on-build-contextmenu");
   },
--- a/browser/extensions/pocket/skin/shared/pocket.css
+++ b/browser/extensions/pocket/skin/shared/pocket.css
@@ -95,20 +95,16 @@
   width: 260px;
 }
 
 #pocket-button-box[animate="true"]:-moz-locale-dir(rtl) > #pocket-animatable-box > #pocket-animatable-image,
 #pocket-button[open="true"][animationsenabled][cui-areatype="toolbar"]:not([overflowedItem="true"]):-moz-locale-dir(rtl) > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
   animation-name: pocket-animation-rtl;
 }
 
-#library-button[animate="pocket"] > .toolbarbutton-icon {
-  fill: transparent;
-}
-
 @keyframes library-pocket-animation {
   from {
     transform: translateX(0);
     fill: inherit;
   }
   25% {
     fill: inherit;
   }
@@ -146,46 +142,16 @@
   from {
     fill: #ef4056;
   }
   to {
     fill: inherit;
   }
 }
 
-.toolbarbutton-animatable-box[animate="pocket"] {
-  position: absolute;
-  overflow: hidden;
-  /* Position the sprite at the y-position of the library-button, then adjust
-     based on the size difference between half of the button height and half
-     of the sprite height. */
-  top: calc(var(--library-button-y) + var(--library-button-height) / 2 - 27px);
-  /* Since .toolbarbutton-icon uses a different width than the animatable box,
-     we need to set a margin relative to the difference in widths.
-     margin-left is used here even in RTL because the item is positioned using `left` */
-  left: calc(var(--library-icon-x) + (16px + 2 * var(--toolbarbutton-inner-padding) - 22px) / 2);
-  /* Set the min- and max- width and height of the box equal to that
-     of each frame of the SVG sprite. Setting the width and height via
-     the `width` and `height` CSS properties causes an assertion for
-     `inline-size less than zero: 'aContainingBlockISize >= 0'` (bug 1379332). */
-  min-width: 22px;
-  max-width: 22px;
-  /* Height of each frame within the SVG sprite. The sprite must have equal amount
-     of space above and below the icon to allow it to vertically center with the
-     sprite's icon on top of the toolbar icon when using position:absolute;. */
-  min-height: 54px;
-  max-height: 54px;
-  z-index: 2;
-}
-
-.toolbarbutton-animatable-box[animate="pocket"] > .toolbarbutton-animatable-image {
-  height: var(--toolbarbutton-height); /* Height must be equal to height of toolbarbutton padding-box */
-  min-height: 54px; /* Minimum height must be equal to the height of the SVG sprite */
-}
-
 .toolbarbutton-animatable-box[animate="pocket"] > .toolbarbutton-animatable-image {
   background-image: url("chrome://pocket-shared/skin/library-pocket-animation.svg");
   width: 1078px;
   animation-name: library-pocket-animation;
   animation-duration: 800ms;
   animation-timing-function: steps(48);
 }
 
--- a/browser/themes/shared/toolbarbutton-icons.inc.css
+++ b/browser/themes/shared/toolbarbutton-icons.inc.css
@@ -453,21 +453,21 @@ toolbar[brighttext] .toolbarbutton-1 {
   from {
     fill: var(--toolbarbutton-icon-fill-attention);
   }
   to {
     fill: inherit;
   }
 }
 
-#library-button[animate="bookmark"] > .toolbarbutton-icon {
+#library-button[animate] > .toolbarbutton-icon {
   fill: transparent;
 }
 
-.toolbarbutton-animatable-box[animate="bookmark"] {
+.toolbarbutton-animatable-box[animate] {
   position: absolute;
   overflow: hidden;
   /* Position the sprite at the y-position of the library-button, then adjust
      based on the size difference between half of the button height and half
      of the sprite height. */
   top: calc(var(--library-button-y) + var(--library-button-height) / 2 - 27px);
   /* Set a margin relative to the difference in widths of the .toolbarbutton-icon
      and the .toolbar-animatable-box. This is correct even in RTL because the item
@@ -477,19 +477,22 @@ toolbar[brighttext] .toolbarbutton-1 {
      of each frame of the SVG sprite (must use min- and max- due to bug 1379332). */
   min-width: 22px;
   max-width: 22px;
   min-height: 54px;
   max-height: 54px;
   z-index: 2;
 }
 
-.toolbarbutton-animatable-box[animate="bookmark"] > .toolbarbutton-animatable-image {
+.toolbarbutton-animatable-box[animate] > .toolbarbutton-animatable-image {
   height: var(--toolbarbutton-height);
   min-height: 54px; /* Minimum height must be equal to the height of the SVG sprite */
+}
+
+.toolbarbutton-animatable-box[animate="bookmark"] > .toolbarbutton-animatable-image {
   background-image: url("chrome://browser/skin/library-bookmark-animation.svg");
   width: 1078px;
   animation-name: library-bookmark-animation;
   animation-duration: 800ms;
   animation-timing-function: steps(48);
   -moz-context-properties: fill, stroke;
   stroke: var(--toolbarbutton-icon-fill-attention);
 }