Bug 771826: implement Social toolbar button UI, including notification icons, notification panel, and "profile" panel. Styling only for Windows/Mac for the moment, r=gavin
authorShane Caraveo <mixedpuppy@gmail.com>
Sun, 15 Jul 2012 16:12:13 -0700
changeset 99413 934ef44ce5af34ceef2674b51df86d17a6c4c9fa
parent 99412 075af07e9952cff2c1f6adae85a2ed8b688a7164
child 99414 6fdf9985acfe6f939da584b2559464ab22264fe7
push id23130
push usergsharp@mozilla.com
push dateMon, 16 Jul 2012 15:45:40 +0000
treeherdermozilla-central@6fdf9985acfe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgavin
bugs771826
milestone16.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 771826: implement Social toolbar button UI, including notification icons, notification panel, and "profile" panel. Styling only for Windows/Mac for the moment, r=gavin
browser/app/profile/firefox.js
browser/base/content/browser-social.js
browser/base/content/browser.xul
browser/base/content/test/Makefile.in
browser/base/content/test/browser_social_toolbar.js
browser/locales/en-US/chrome/browser/browser.dtd
browser/modules/Social.jsm
browser/themes/pinstripe/browser.css
browser/themes/pinstripe/jar.mn
browser/themes/pinstripe/social/panelarrow-down.png
browser/themes/pinstripe/social/panelarrow-horiz.png
browser/themes/pinstripe/social/panelarrow-up.png
browser/themes/pinstripe/social/social.png
browser/themes/winstripe/browser.css
browser/themes/winstripe/jar.mn
browser/themes/winstripe/social/social.png
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1179,9 +1179,9 @@ pref("pdfjs.previousHandler.preferredAct
 pref("pdfjs.previousHandler.alwaysAskBeforeHandling", false);
 
 // The maximum amount of decoded image data we'll willingly keep around (we
 // might keep around more than this, but we'll try to get down to this value).
 // (This is intentionally on the high side; see bug 746055.)
 pref("image.mem.max_decoded_image_kb", 256000);
 
 // Example social provider
-pref("social.manifest.motown", "{\"origin\":\"https://motown-dev.mozillalabs.com\",\"name\":\"MoTown\",\"workerURL\":\"https://motown-dev.mozillalabs.com/social/worker.js\"}");
+pref("social.manifest.motown", "{\"origin\":\"https://motown-dev.mozillalabs.com\",\"name\":\"MoTown\",\"workerURL\":\"https://motown-dev.mozillalabs.com/social/worker.js\",\"iconURL\":\"https://motown-dev.mozillalabs.com/images/motown-icon.png\"}");
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -1,57 +1,77 @@
 // 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/.
 
 let SocialUI = {
   // Called on delayed startup to initialize UI
   init: function SocialUI_init() {
     Services.obs.addObserver(this, "social:pref-changed", false);
+    Services.obs.addObserver(this, "social:ambient-notification-changed", false);
+    Services.obs.addObserver(this, "social:profile-changed", false);
+
     Social.init(this._providerReady.bind(this));
   },
 
   // Called on window unload
   uninit: function SocialUI_uninit() {
     Services.obs.removeObserver(this, "social:pref-changed");
+    Services.obs.removeObserver(this, "social:ambient-notification-changed");
+    Services.obs.removeObserver(this, "social:profile-changed");
+  },
+
+  showProfile: function SocialUI_showProfile() {
+    if (Social.provider)
+      openUILink(Social.provider.profile.profileURL);
   },
 
-  // Called when the social.enabled pref is changed
-  observe: function SocialUI_observe(aSubject, aTopic, aData) {
-    SocialShareButton.updateButtonEnabledState();
+  observe: function SocialUI_observe(subject, topic, data) {
+    switch (topic) {
+      case "social:pref-changed":
+        SocialShareButton.updateButtonHiddenState();
+        SocialToolbar.updateButtonHiddenState();
+        break;
+      case "social:ambient-notification-changed":
+        SocialToolbar.updateButton();
+        break;
+      case "social:profile-changed":
+        SocialToolbar.updateProfile();
+        break;
+    }
   },
 
   // Called once Social.jsm's provider has been set
   _providerReady: function SocialUI_providerReady() {
+    SocialToolbar.init();
     SocialShareButton.init();
   }
 }
 
 let SocialShareButton = {
   init: function SSB_init() {
     this.sharePopup.hidden = false;
-    this.updateButtonEnabledState();
+    this.updateButtonHiddenState();
   },
 
   get shareButton() {
     return document.getElementById("share-button");
   },
   get sharePopup() {
     return document.getElementById("editSharePopup");
   },
 
   dismissSharePopup: function SSB_dismissSharePopup() {
     this.sharePopup.hidePopup();
   },
 
-  updateButtonEnabledState: function SSB_updateButtonEnabledState() {
+  updateButtonHiddenState: function SSB_updateButtonHiddenState() {
     let shareButton = this.shareButton;
     if (shareButton)
-      shareButton.hidden = !Social.provider || !Social.provider.enabled ||
-                           !Social.provider.port;
+      shareButton.hidden = !Social.uiVisible;
   },
 
   onClick: function SSB_onClick(aEvent) {
     if (aEvent.button != 0)
       return;
 
     // Don't bubble to the textbox, to avoid unwanted selection of the address.
     aEvent.stopPropagation();
@@ -101,8 +121,124 @@ let SocialShareButton = {
       shareButton.setAttribute("shared", "true");
       shareButton.setAttribute("tooltiptext", gNavigatorBundle.getString("social.shareButton.sharedtooltip"));
     } else {
       shareButton.removeAttribute("shared");
       shareButton.setAttribute("tooltiptext", gNavigatorBundle.getString("social.shareButton.tooltip"));
     }
   }
 };
+
+var SocialToolbar = {
+  // Called once, after window load, when the Social.provider object is initialized
+  init: function SocialToolbar_init() {
+    document.getElementById("social-provider-image").setAttribute("image", Social.provider.iconURL);
+    
+    // handle button state
+    document.getElementById("social-statusarea-popup").addEventListener("popupshowing", function(e) {
+      document.getElementById("social-toolbar-button").setAttribute("open", "true");
+    }, false);
+    document.getElementById("social-statusarea-popup").addEventListener("popuphiding", function(e) {
+      document.getElementById("social-toolbar-button").removeAttribute("open");
+    }, false);
+
+    this.updateButton();
+    this.updateProfile();
+  },
+
+  updateButtonHiddenState: function SocialToolbar_updateButtonHiddenState() {
+    let toolbarbutton = document.getElementById("social-toolbar-button");
+    toolbarbutton.hidden = !Social.uiVisible;
+  },
+
+  updateProfile: function SocialToolbar_updateProfile() {
+    // Profile may not have been initialized yet, since it depends on a worker
+    // response. In that case we'll be called again when it's available, via
+    // social:profile-changed
+    let profile = Social.provider.profile || {};
+    let userPortrait = profile.portrait || "chrome://browser/skin/social/social.png";
+    document.getElementById("social-statusarea-user-portrait").setAttribute("src", userPortrait);
+
+    let notLoggedInLabel = document.getElementById("social-statusarea-notloggedin");
+    let userNameBtn = document.getElementById("social-statusarea-username");
+    if (profile.userName) {
+      notLoggedInLabel.hidden = true;
+      userNameBtn.hidden = false;
+      userNameBtn.label = profile.userName;
+    } else {
+      notLoggedInLabel.hidden = false;
+      userNameBtn.hidden = true;
+    }
+  },
+
+  updateButton: function SocialToolbar_updateButton() {
+    this.updateButtonHiddenState();
+
+    let provider = Social.provider;
+    // if there are no ambient icons, we collapse them in the following loop
+    let iconNames = Object.keys(provider.ambientNotificationIcons);
+    let iconBox = document.getElementById("social-status-iconbox");
+    for (var i = 0; i < iconBox.childNodes.length; i++) {
+      let iconContainer = iconBox.childNodes[i];
+      if (i > iconNames.length - 1) {
+        iconContainer.collapsed = true;
+        continue;
+      }
+
+      iconContainer.collapsed = false;
+      let icon = provider.ambientNotificationIcons[iconNames[i]];
+      let iconImage = iconContainer.firstChild;
+      let iconCounter = iconImage.nextSibling;
+
+      iconImage.setAttribute("contentPanel", icon.contentPanel);
+      iconImage.setAttribute("src", icon.iconURL);
+
+      if (iconCounter.firstChild)
+        iconCounter.removeChild(iconCounter.firstChild);
+
+      if (icon.counter) {
+        iconCounter.appendChild(document.createTextNode(icon.counter));
+        iconCounter.collapsed = false;
+      } else {
+        iconCounter.collapsed = true;
+      }
+    }
+  },
+
+  showAmbientPopup: function SocialToolbar_showAmbientPopup(iconContainer) {
+    let iconImage = iconContainer.firstChild;
+    let panel = document.getElementById("social-notification-panel");
+    let notifBrowser = document.getElementById("social-notification-browser");
+
+    panel.hidden = false;
+
+    function sizePanelToContent() {
+      // XXX Maybe we can use nsIDOMWindowUtils.getRootBounds() here?
+      // XXX need to handle dynamic sizing
+      let doc = notifBrowser.contentDocument;
+      // XXX "notif" is an implementation detail that we should get rid of
+      // eventually
+      let body = doc.getElementById("notif") || doc.body.firstChild;
+      if (!body)
+        return;
+      let h = body.scrollHeight > 0 ? body.scrollHeight : 300;
+      notifBrowser.style.width = body.scrollWidth + "px";
+      notifBrowser.style.height = h + "px";
+    }
+
+    notifBrowser.addEventListener("DOMContentLoaded", function onload() {
+      notifBrowser.removeEventListener("DOMContentLoaded", onload);
+      sizePanelToContent();
+    });
+
+    panel.addEventListener("popuphiding", function onpopuphiding() {
+      panel.removeEventListener("popuphiding", onpopuphiding);
+      // unload the panel
+      document.getElementById("social-toolbar-button").removeAttribute("open");
+      notifBrowser.setAttribute("src", "about:blank");
+    });
+
+    notifBrowser.service = Social.provider;
+    notifBrowser.setAttribute("src", iconImage.getAttribute("contentPanel"));
+    document.getElementById("social-toolbar-button").setAttribute("open", "true");
+    panel.openPopup(iconImage, "bottomcenter topleft", 0, 0, false, false);
+  }
+}
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -216,16 +216,20 @@
                 class="editSharePopupBottomButton"
                 label="&social.sharePopup.undo.label;"
                 accesskey="&social.sharePopup.undo.accesskey;"
                 command="Social:UnsharePage"/>
 #endif
       </hbox>
     </panel>
 
+    <panel id="social-notification-panel" type="arrow" hidden="true" noautofocus="true">
+      <browser id="social-notification-browser" type="content" flex="1"/>
+    </panel>
+
     <menupopup id="inspector-node-popup">
       <menuitem id="inspectorHTMLCopyInner"
                 label="&inspectorHTMLCopyInner.label;"
                 accesskey="&inspectorHTMLCopyInner.accesskey;"
                 command="Inspector:CopyInner"/>
       <menuitem id="inspectorHTMLCopyOuter"
                 label="&inspectorHTMLCopyOuter.label;"
                 accesskey="&inspectorHTMLCopyOuter.accesskey;"
@@ -599,16 +603,55 @@
                      label="&homeButton.label;"
                      ondragover="homeButtonObserver.onDragOver(event)"
                      ondragenter="homeButtonObserver.onDragOver(event)"
                      ondrop="homeButtonObserver.onDrop(event)"
                      ondragexit="homeButtonObserver.onDragExit(event)"
                      onclick="BrowserGoHome(event);"
                      aboutHomeOverrideTooltip="&abouthome.pageTitle;"/>
 
+      <toolbaritem id="social-toolbar-button"
+                   class="toolbarbutton-1 chromeclass-toolbar-additional"
+                   removable="false"
+                   title="&socialToolbar.title;"
+                   hidden="true">
+        <hbox id="social-toolbar-button-box" class="social-statusarea-container">
+          <button id="social-provider-image" type="menu">
+            <menupopup id="social-statusarea-popup">
+              <hbox id="social-statusarea-user" pack="left" align="center">
+                <image id="social-statusarea-user-portrait"/>
+                <vbox>
+                  <label id="social-statusarea-notloggedin"
+                         value="&social.notLoggedIn.label;"/>
+                  <button id="social-statusarea-username"
+                          oncommand="SocialUI.showProfile(); document.getElementById('social-statusarea-popup').hidePopup();"/>
+                </vbox>
+              </hbox>
+            </menupopup>
+          </button>
+          <hbox id="social-status-iconbox" flex="1">
+            <box class="social-notification-icon-container" collapsed="true"
+                     onclick="SocialToolbar.showAmbientPopup(this);">
+              <image class="social-notification-icon-image"/>
+              <box class="social-notification-icon-counter" collapsed="true"/>
+            </box>
+            <box class="social-notification-icon-container" collapsed="true"
+                     onclick="SocialToolbar.showAmbientPopup(this);">
+              <image class="social-notification-icon-image"/>
+              <box class="social-notification-icon-counter" collapsed="true"/>
+            </box>
+            <box class="social-notification-icon-container" collapsed="true"
+                     onclick="SocialToolbar.showAmbientPopup(this);">
+              <image class="social-notification-icon-image"/>
+              <box class="social-notification-icon-counter" collapsed="true"/>
+            </box>
+          </hbox>
+        </hbox>
+      </toolbaritem>
+
       <toolbaritem id="bookmarks-menu-button-container"
                    class="chromeclass-toolbar-additional"
                    removable="true"
                    title="&bookmarksMenuButton.label;">
         <toolbarbutton id="bookmarks-menu-button"
                        type="menu"
                        class="toolbarbutton-1"
                        label="&bookmarksMenuButton.label;"
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -251,16 +251,17 @@ endif
                  authenticate.sjs \
                  browser_minimize.js \
                  browser_aboutSyncProgress.js \
                  browser_middleMouse_inherit.js \
                  redirect_bug623155.sjs \
                  browser_tabDrop.js \
                  browser_lastAccessedTab.js \
                  browser_bug734076.js \
+                 browser_social_toolbar.js \
                  $(NULL)
 
 ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 _BROWSER_FILES += \
 		browser_bug462289.js \
 		$(NULL)
 else
 _BROWSER_FILES += \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_social_toolbar.js
@@ -0,0 +1,140 @@
+/* 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/. */
+
+let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
+let gProvider;
+
+function test() {
+  waitForExplicitFinish();
+
+  Services.prefs.setBoolPref("social.enabled", true);
+  registerCleanupFunction(function () {
+    Services.prefs.clearUserPref("social.enabled");
+  });
+
+  let oldProvider;
+  function saveOldProviderAndStartTestWith(provider) {
+    oldProvider = Social.provider;
+    registerCleanupFunction(function () {
+      Social.provider = oldProvider;
+    });
+    Social.provider = gProvider = provider;
+    runTests(tests, undefined, undefined, function () {
+      SocialService.removeProvider(provider.origin, finish);
+    });
+  }
+
+  let manifest = { // normal provider
+    name: "provider 1",
+    origin: "https://example1.com",
+    workerURL: "https://example1.com/worker.js",
+    iconURL: "chrome://branding/content/icon48.png"
+  };
+  SocialService.addProvider(manifest, function(provider) {
+    // If the UI is already active, run the test immediately, otherwise wait
+    // for initialization.
+    if (Social.provider) {
+      saveOldProviderAndStartTestWith(provider);
+    } else {
+      Services.obs.addObserver(function obs() {
+        Services.obs.removeObserver(obs, "test-social-ui-ready");
+        saveOldProviderAndStartTestWith(provider);
+      }, "test-social-ui-ready", false);
+    }
+  });
+}
+
+var tests = {
+  testProfileSet: function(next) {
+    let profile = {
+      portrait: "chrome://branding/content/icon48.png",
+      userName: "trickster",
+      displayName: "Kuma Lisa",
+      profileURL: "http://en.wikipedia.org/wiki/Kuma_Lisa"
+    }
+    gProvider.updateUserProfile(profile);
+    // check dom values
+    let portrait = document.getElementById("social-statusarea-user-portrait").getAttribute("src");
+    is(portrait, profile.portrait, "portrait is set");
+    let userButton = document.getElementById("social-statusarea-username");
+    ok(!userButton.hidden, "username is visible");
+    is(userButton.label, profile.userName, "username is set");
+    next();
+  },
+  testAmbientNotifications: function(next) {
+    let ambience = {
+      name: "testIcon",
+      iconURL: "chrome://branding/content/icon48.png",
+      contentPanel: "about:blank",
+      counter: 42
+    };
+    gProvider.setAmbientNotification(ambience);
+
+    let statusIcons = document.getElementById("social-status-iconbox");
+    ok(!statusIcons.firstChild.collapsed, "status icon is visible");
+    ok(!statusIcons.firstChild.lastChild.collapsed, "status value is visible");
+    is(statusIcons.firstChild.lastChild.textContent, "42", "status value is correct");
+
+    ambience.counter = 0;
+    gProvider.setAmbientNotification(ambience);
+    ok(statusIcons.firstChild.lastChild.collapsed, "status value is not visible");
+    is(statusIcons.firstChild.lastChild.textContent, "", "status value is correct");
+    next();
+  },
+  testProfileUnset: function(next) {
+    gProvider.updateUserProfile({});
+    // check dom values
+    let portrait = document.getElementById("social-statusarea-user-portrait").getAttribute("src");
+    is(portrait, "chrome://browser/skin/social/social.png", "portrait is generic");
+    let userButton = document.getElementById("social-statusarea-username");
+    ok(userButton.hidden, "username is not visible");
+    let ambience = document.getElementById("social-status-iconbox").firstChild;
+    while (ambience) {
+      ok(ambience.collapsed, "ambient icon is collapsed");
+      ambience = ambience.nextSibling;
+    }
+    
+    next();
+  }
+}
+
+function runTests(tests, cbPreTest, cbPostTest, cbFinish) {
+  let testIter = Iterator(tests);
+
+  if (cbPreTest === undefined) {
+    cbPreTest = function(cb) {cb()};
+  }
+  if (cbPostTest === undefined) {
+    cbPostTest = function(cb) {cb()};
+  }
+
+  function runNextTest() {
+    let name, func;
+    try {
+      [name, func] = testIter.next();
+    } catch (err if err instanceof StopIteration) {
+      // out of items:
+      (cbFinish || finish)();
+      return;
+    }
+    // We run on a timeout as the frameworker also makes use of timeouts, so
+    // this helps keep the debug messages sane.
+    executeSoon(function() {
+      function cleanupAndRunNextTest() {
+        info("sub-test " + name + " complete");
+        cbPostTest(runNextTest);
+      }
+      cbPreTest(function() {
+        info("sub-test " + name + " starting");
+        try {
+          func.call(tests, cleanupAndRunNextTest);
+        } catch (ex) {
+          ok(false, "sub-test " + name + " failed: " + ex.toString() +"\n"+ex.stack);
+          cleanupAndRunNextTest();
+        }
+      })
+    });
+  }
+  runNextTest();
+}
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -648,12 +648,15 @@ just addresses the organization to follo
 located in front of the breadcrumbs display in the inspector toolbar. The button
 doesn't display any label, but exposes a label to screen-readers with "aria-label".
 -->
 <!ENTITY markupButton.arialabel          "Markup">
 <!-- LOCALIZATION NOTE (markupButton.accesskey): The key bound to the Markup panel's
 toolbar button -->
 <!ENTITY markupButton.accesskey          "M">
 
+<!ENTITY socialToolbar.title        "Social Toolbar Button">
+<!ENTITY social.notLoggedIn.label   "Not logged in">
+
 <!ENTITY social.sharePopup.undo.label     "Unshare">
 <!ENTITY social.sharePopup.undo.accesskey "U">
 <!ENTITY social.sharePopup.ok.label       "OK">
 <!ENTITY social.sharePopup.ok.accesskey   "O">
--- a/browser/modules/Social.jsm
+++ b/browser/modules/Social.jsm
@@ -33,16 +33,20 @@ let Social = {
       Services.obs.notifyObservers(null, "test-social-ui-ready", "");
     }.bind(this));
   },
 
   get enabled() {
     return SocialService.enabled;
   },
 
+  get uiVisible() {
+    return this.provider && this.provider.enabled && this.provider.port;
+  },
+
   sendWorkerMessage: function Social_sendWorkerMessage(message) {
     // Responses aren't handled yet because there is no actions to perform
     // based on the response from the provider at this point.
     if (this.provider && this.provider.port)
       this.provider.port.postMessage(message);
   },
 
   // Sharing functionality
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -3338,8 +3338,128 @@ stack[anonid=browserStack][responsivemod
 
 #developer-toolbar-webconsole[error-count]:before {
   color: #FDF3DE;
   min-width: 16px;
   text-shadow: none;
   background-image: -moz-linear-gradient(top, #B4211B, #8A1915);
   border-radius: 1px;
 }
+
+/* === social toolbar button === */
+
+/* button icon for the service */
+#social-provider-image {
+  -moz-appearance: none;
+  margin: 0;
+  padding: 2px;
+  min-width: 0;
+  max-height: 20px;
+  list-style-image: url("chrome://browser/skin/social/social.png");
+}
+
+/* hbox that surrounds an image and its counter */
+.social-notification-icon-container {
+  cursor: pointer;
+  padding: 0px;
+  margin: 0px;
+  position: relative;
+}
+
+/* notification counter box */
+.social-notification-icon-counter {
+  background-color: rgb(240,61,37);
+  border: 1px solid rgb(216,55,34);
+  box-shadow: 0px 1px 0px rgba(0,39,121,0.77);
+  padding-right: 1px;
+  padding-left: 1px;
+  color: white;
+  font-size: 9px;
+  font-weight: bold;
+  position: absolute;
+  right: -3px;
+  top: -4px;
+  z-index: 1;
+  text-align: center;
+}
+
+/* notification image */
+.social-notification-icon-image {
+  padding: 2px;
+  margin: 0px;
+  min-width: 20px;
+  max-width: 32px;
+  max-height: 20px;
+  list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
+}
+
+/* === end of social toolbar button === */
+
+/* === social toolbar provider menu  === */
+
+#social-statusarea-user {
+  background-color: white;
+  color: black;
+  cursor: default;
+  font-family: "lucida grande",tahoma,verdana,arial,sans-serif;
+  font-size: 12px;
+}
+
+#social-statusarea-user-portrait {
+  width: 32px;
+  height: 32px;
+  margin: 10px;
+  list-style-image: url("chrome://browser/skin/social/social.png");
+}
+
+#social-statusarea-username {
+  -moz-appearance: none;
+  color: -moz-nativehyperlinktext;
+  cursor: pointer;
+  min-width: 0;
+  margin: 0 6px;
+}
+
+#social-statusarea-username:hover {
+  text-decoration: underline;
+}
+
+/* === end of social toolbar provider menu === */
+
+/* === start of social toolbar panels === */
+
+#social-notification-panel {
+  min-height: 100px;
+  min-width: 240px;
+  max-height: 600px;
+  max-width: 400px;
+}
+
+#social-notification-panel .panel-arrowcontent {
+  margin: -4px 0 0 0;
+  padding: 0;
+  border-radius: 0px;
+}
+
+#social-notification-panel .panel-arrow[side="top"] {
+  list-style-image: url("chrome://browser/skin/social/panelarrow-up.png");
+  margin-top: -4px;
+  margin-bottom: 3px;
+  height: 21px;
+}
+
+#social-notification-panel .panel-arrow[side="bottom"] {
+  list-style-image: url("chrome://browser/skin/social/panelarrow-down.png");
+  margin-top: -5px;
+}
+
+#social-notification-panel .panel-arrow[side="left"] {
+  list-style-image: url("chrome://browser/skin/social/panelarrow-horiz.png");
+  margin-right: -1px;
+  -moz-transform: scaleX(-1);
+}
+
+#social-notification-panel .panel-arrow[side="right"] {
+  list-style-image: url("chrome://browser/skin/social/panelarrow-horiz.png");
+  margin-left: -1px;
+}
+
+/* === end of social toolbar panels === */
--- a/browser/themes/pinstripe/jar.mn
+++ b/browser/themes/pinstripe/jar.mn
@@ -108,16 +108,20 @@ browser.jar:
 #ifdef MOZ_SERVICES_SYNC
   skin/classic/browser/preferences/Options-sync.png         (preferences/Options-sync.png)
 #endif
   skin/classic/browser/preferences/saveFile.png             (preferences/saveFile.png)
 * skin/classic/browser/preferences/preferences.css          (preferences/preferences.css)
 * skin/classic/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
   skin/classic/browser/preferences/applications.css         (preferences/applications.css)
   skin/classic/browser/preferences/aboutPermissions.css     (preferences/aboutPermissions.css)
+  skin/classic/browser/social/social.png                    (social/social.png)
+  skin/classic/browser/social/panelarrow-down.png           (social/panelarrow-down.png)
+  skin/classic/browser/social/panelarrow-horiz.png          (social/panelarrow-horiz.png)
+  skin/classic/browser/social/panelarrow-up.png             (social/panelarrow-up.png)
   skin/classic/browser/tabbrowser/alltabs-box-bkgnd-icon.png             (tabbrowser/alltabs-box-bkgnd-icon.png)
   skin/classic/browser/tabbrowser/newtab.png                             (tabbrowser/newtab.png)
   skin/classic/browser/tabbrowser/connecting.png                         (tabbrowser/connecting.png)
   skin/classic/browser/tabbrowser/loading.png                            (tabbrowser/loading.png)
   skin/classic/browser/tabbrowser/tab-arrow-left.png                     (tabbrowser/tab-arrow-left.png)
   skin/classic/browser/tabbrowser/tab-arrow-right.png                    (tabbrowser/tab-arrow-right.png)
   skin/classic/browser/tabbrowser/tabbar-bottom-bg-active.png            (tabbrowser/tabbar-bottom-bg-active.png)
   skin/classic/browser/tabbrowser/tabbar-bottom-bg-inactive.png          (tabbrowser/tabbar-bottom-bg-inactive.png)
new file mode 100644
index 0000000000000000000000000000000000000000..0224ebdf153bec5d7125f88bb9494d6d36dfbeae
GIT binary patch
literal 2186
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
new file mode 100644
index 0000000000000000000000000000000000000000..ed59312c14252fe9c7f37e902285d652cbb09359
GIT binary patch
literal 2188
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
new file mode 100644
index 0000000000000000000000000000000000000000..451b83b3b9bfde3ffba768feba91566bea92210d
GIT binary patch
literal 2157
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
AwEzGB
new file mode 100644
index 0000000000000000000000000000000000000000..14916fb074c79b18c732f41661110027983c5d03
GIT binary patch
literal 1654
zc%17D@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4(FKV3x~tb`J1#c2)=|%1_J8No8QD
zU~CP!pM5z%<ln8-xf>pKTcrzf+GR}4O9?J<p0h1GeAn5iS7zH4J!UV<jhS^!<!#*t
z_M6@LR!7S}vfKS+=egOOUp<NUm`LJ}H62Pm-;_4bn{DE&9?ZP+`|kTc-&v|Ze-gLg
zXJOQ35q*A<&|v?ghyEOSB69x|W1Nh$_MZ&j?lv(mHFpR8%bP0SZ~n|DcPyvmUH<*m
z|B|oHn#v>iK}KQU6w@P04<i?3##|{8esHbx{ai!SLuY-8BbKvp%BNf8CpSLq=~bSV
zW@73vi}MisQ70?!9S#;VG9P^Ay>YHl<cYf4%1L_NHmhBO^q;1<ZsPg&LB6>8Q~ZV%
zQ(n$q`&^(mcb25z#hR{r@|Lv)J<k}f9<+~_*z34sZb5|E<He?RPG?ot399XV{;ni*
z#@p0c(<3#7RAp55B!#Rq&dGen&D=Tb+2yxi0w!&kZ?fOSIP&x3w*gaGUK<|$`pw(z
z%dWlGZ%>@e{@B!Rx#qQchktv&e=X{IS~=;%>n(D<SHDD0vI@I>`^nj5%7>4X2ih}x
zI5qXjq-Z>t=){vaEBVN(A3kD|N?uDYWtN0gZnC&$tucApTN(F?lkt2z;>5m2Z`$$g
z!S8u@Rj>E$5p6xXeesRJw_6)u?%E_gOS--^ap~f`hvqw<&X&$y&CL<`uj}bXkGRxR
z{!M|`OU<552%i3@l>5BVly|CSLJ>T>)_jQjp_Rks-zt7+`u-~?&fQxpc)Fob$8Pn!
z;Iqfxs9y59^g3n7{;sc1$0UAEFm#TZyHCY;PM77UTLIkaY~@X_pFN7vzs^2y_nFv-
zzjku0)hkl&J0$+qwMOy7KI46M@!Rt|5|`iJcRA(tV#BD{yDv}NwP<72l>Xc5-)#F<
z2}^F;xNl=!7>D+jMafxSn@ju|m{oKArhjIg{9dqyyQX8EZfF1Mr0@y;+FbcFdE%z?
zc&_)jskgzp|1I;j;A^qZGUJOaKWi1dl>U48wVrt>Tb$&9i^Y243ye#jaBirH(|Ij=
zTi#~g_J)bpx0Bb}<|gjywhLQ*yF@Qqj&V2t>Z|k5uey5o`ICC?ip77}Rw{E{JG3y~
z2$*3w3p^r=85p>QL70(Y)*J~21}3@8kcg59UmvUF{9L`nl>DSry^7od1`x2RumUo3
zQ%e#RDspr3imfVamB1>jfNYSkzLEl1NlCV?QiN}Sf^&XRs)C80iJpOy9hZWFf=y9M
znpKdC8&o@xXRDM^Qc_^0uU}qXu2*iXmtT~wZ)j<0sc&GUZ)BtkRH0j3nOBlnp_^B%
z3^4>|j!SBBa#3bMNoIbY0*IfOlwVq6tE2=~0|5|=Qj+2J6qFX_fNe=h)=$kz%}vcK
zDb_dCGt`G04l+L_*{ZlSDJwO(#16$cu*FV^>H5fu^)Xf3=%cxiT$cj_6Yli9VrYB-
zV@AIsu>k0715{@NRa-e1r6!i-7lq{K=h!)dlq-1VCZ?wbr6#6S+UTRJ!0TR!C@{Y4
zxPUrgac{>JuxDWiFgaZDba4!^5ZpS+k*nE2!1eg0&o^3yHs09FE&eET(-v_d@p%gu
zU164NUFp0s<xxlLrACKOm6e_+Dmpm!U#ZM54iq^P6FOCW<Ghk)oAZXJjgFc7GMC2Y
zt32YpWYStWZ)SthN|%EszCzk*{{<zIk6d2zL8Ue7wYBFP$C*dEnpkztS~S^e{EjN{
z7TV&!+%mPVq2=i^{&j^tUYhN-`oH(JyWidvm(ZlqWx&H!_*uP%kGUjvyVni#xElGs
zss@SOGY-79lfE;1v${^ePIjxGr*<;6TgUBVI3k(zKwqXI1(e=BUHx3vIVCg!0Cn%A
AApigX
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -3265,8 +3265,139 @@ stack[anonid=browserStack][responsivemod
 
 #developer-toolbar-webconsole[error-count]:before {
   color: #FDF3DE;
   min-width: 16px;
   text-shadow: none;
   background-image: -moz-linear-gradient(top, #B4211B, #8A1915);
   border-radius: 1px;
 }
+
+
+/* === social toolbar button === */
+
+.social-statusarea-container {
+  -moz-appearance: toolbarbutton;
+  margin: 0 2px;
+  padding: 3px;
+}
+
+.social-statusarea-container {
+  -moz-appearance: none;
+  margin: 2px; /* make sure we have the correct platform spacing*/
+  padding: 1px;
+}
+
+/* aero look for hover */
+#social-toolbar-button[open="true"] > .social-statusarea-container,
+.social-statusarea-container:hover {
+  background-image: -moz-linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
+  border-color: hsla(210,54%,20%,.3) hsla(210,54%,20%,.35) hsla(210,54%,20%,.4);
+  box-shadow: 0 1px hsla(0,0%,100%,.85) inset,
+              0 1px hsla(210,54%,20%,.1),
+              0 0 2px hsla(210,54%,20%,.4);
+}
+
+/* favicon for the service */
+#social-provider-image {
+  width: 20px;
+  height: 20px;
+  max-height: 20px;
+  max-width: 20px;
+  padding: 2px;
+  list-style-image: url("chrome://browser/skin/social/social.png");
+}
+
+/* hbox that hold notification icons */
+#social-status-iconbox {
+  margin: 0px;
+  padding: 0px;
+}
+
+/* hbox that surrounds an image and its counter */
+.social-notification-icon-container {
+  cursor: pointer;
+  padding: 0px;
+  margin: 0px;
+  position: relative;
+}
+
+/* notification counter box */
+.social-notification-icon-counter {
+  background-color: rgb(240,61,37);
+  border: 1px solid rgb(216,55,34);
+  box-shadow: 0px 1px 0px rgba(0,39,121,0.77);
+  padding-right: 1px;
+  padding-left: 1px;
+  color: white;
+  font-size: 9px;
+  font-weight: bold;
+  position: absolute;
+  right: -3px;
+  top: -4px;
+  z-index: 1;
+  text-align: center;
+}
+
+/* notification image */
+.social-notification-icon-image {
+  padding: 2px;
+  margin: 0px;
+  min-width: 20px;
+  max-width: 32px;
+  max-height: 20px;
+  list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
+}
+
+/* === end of social toolbar button === */
+
+/* === social toolbar provider menu  === */
+
+/* popups that hang off our toolbaritem */
+#social-statusarea-popup {
+  margin-top:0px;
+  margin-left: -12px;
+  margin-right: -12px;
+}
+
+#social-statusarea-user {
+  border-bottom:1px solid rgb(221,221,221);
+  background-color:-moz-Dialog;
+  color:black;
+  cursor:default;
+  position:relative;
+  font-family: "lucida grande",tahoma,verdana,arial,sans-serif;
+  font-size:12px;
+}
+
+#social-statusarea-user-portrait {
+  width:32px;
+  height:32px;
+  border-radius:2px;
+  margin:10px;
+  list-style-image: url("chrome://browser/skin/social/social.png");
+}
+
+#social-statusarea-username {
+  -moz-appearance: none;
+  background: transparent;
+  border: none;
+  color: -moz-nativehyperlinktext;
+  cursor: pointer;
+  min-width: 0;
+  margin: 0 6px;
+}
+#social-statusarea-username:hover {
+  text-decoration: underline;
+}
+
+/* === end of social toolbar provider menu === */
+
+/* === end of social toolbar panels === */
+
+#social-notification-panel {
+  min-height: 100px;
+  min-width: 100px;
+  max-height: 600px;
+  max-width: 400px;
+}
+
+/* === end of social toolbar panels === */
--- a/browser/themes/winstripe/jar.mn
+++ b/browser/themes/winstripe/jar.mn
@@ -101,16 +101,17 @@ browser.jar:
 #ifdef MOZ_SERVICES_SYNC
         skin/classic/browser/preferences/Options-sync.png            (preferences/Options-sync.png)
 #endif
         skin/classic/browser/preferences/saveFile.png                (preferences/saveFile.png)
 *       skin/classic/browser/preferences/preferences.css             (preferences/preferences.css)
         skin/classic/browser/preferences/in-content/preferences.css  (preferences/in-content/preferences.css)
         skin/classic/browser/preferences/applications.css            (preferences/applications.css)
         skin/classic/browser/preferences/aboutPermissions.css        (preferences/aboutPermissions.css)
+        skin/classic/browser/social/social.png                       (social/social.png)
         skin/classic/browser/tabbrowser/alltabs.png                  (tabbrowser/alltabs.png)
         skin/classic/browser/tabbrowser/newtab.png                   (tabbrowser/newtab.png)
         skin/classic/browser/tabbrowser/newtab-inverted.png          (tabbrowser/newtab-inverted.png)
         skin/classic/browser/tabbrowser/connecting.png               (tabbrowser/connecting.png)
         skin/classic/browser/tabbrowser/loading.png                  (tabbrowser/loading.png)
         skin/classic/browser/tabbrowser/tab.png                      (tabbrowser/tab.png)
         skin/classic/browser/tabbrowser/tab-arrow-left.png           (tabbrowser/tab-arrow-left.png)
         skin/classic/browser/tabbrowser/tab-arrow-left-inverted.png  (tabbrowser/tab-arrow-left-inverted.png)
@@ -302,16 +303,17 @@ browser.jar:
 #ifdef MOZ_SERVICES_SYNC
         skin/classic/aero/browser/preferences/Options-sync.png       (preferences/Options-sync.png)
 #endif
         skin/classic/aero/browser/preferences/saveFile.png           (preferences/saveFile-aero.png)
 *       skin/classic/aero/browser/preferences/preferences.css        (preferences/preferences.css)
         skin/classic/aero/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
         skin/classic/aero/browser/preferences/applications.css       (preferences/applications.css)
         skin/classic/aero/browser/preferences/aboutPermissions.css   (preferences/aboutPermissions.css)
+        skin/classic/aero/browser/social/social.png                  (social/social.png)
         skin/classic/aero/browser/tabbrowser/alltabs.png             (tabbrowser/alltabs.png)
         skin/classic/aero/browser/tabbrowser/newtab.png              (tabbrowser/newtab.png)
         skin/classic/aero/browser/tabbrowser/newtab-inverted.png     (tabbrowser/newtab-inverted.png)
         skin/classic/aero/browser/tabbrowser/connecting.png          (tabbrowser/connecting.png)
         skin/classic/aero/browser/tabbrowser/loading.png             (tabbrowser/loading.png)
         skin/classic/aero/browser/tabbrowser/tab.png                 (tabbrowser/tab.png)
         skin/classic/aero/browser/tabbrowser/tab-arrow-left.png      (tabbrowser/tab-arrow-left.png)
         skin/classic/aero/browser/tabbrowser/tab-arrow-left-inverted.png (tabbrowser/tab-arrow-left-inverted.png)
new file mode 100644
index 0000000000000000000000000000000000000000..14916fb074c79b18c732f41661110027983c5d03
GIT binary patch
literal 1654
zc%17D@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4(FKV3x~tb`J1#c2)=|%1_J8No8QD
zU~CP!pM5z%<ln8-xf>pKTcrzf+GR}4O9?J<p0h1GeAn5iS7zH4J!UV<jhS^!<!#*t
z_M6@LR!7S}vfKS+=egOOUp<NUm`LJ}H62Pm-;_4bn{DE&9?ZP+`|kTc-&v|Ze-gLg
zXJOQ35q*A<&|v?ghyEOSB69x|W1Nh$_MZ&j?lv(mHFpR8%bP0SZ~n|DcPyvmUH<*m
z|B|oHn#v>iK}KQU6w@P04<i?3##|{8esHbx{ai!SLuY-8BbKvp%BNf8CpSLq=~bSV
zW@73vi}MisQ70?!9S#;VG9P^Ay>YHl<cYf4%1L_NHmhBO^q;1<ZsPg&LB6>8Q~ZV%
zQ(n$q`&^(mcb25z#hR{r@|Lv)J<k}f9<+~_*z34sZb5|E<He?RPG?ot399XV{;ni*
z#@p0c(<3#7RAp55B!#Rq&dGen&D=Tb+2yxi0w!&kZ?fOSIP&x3w*gaGUK<|$`pw(z
z%dWlGZ%>@e{@B!Rx#qQchktv&e=X{IS~=;%>n(D<SHDD0vI@I>`^nj5%7>4X2ih}x
zI5qXjq-Z>t=){vaEBVN(A3kD|N?uDYWtN0gZnC&$tucApTN(F?lkt2z;>5m2Z`$$g
z!S8u@Rj>E$5p6xXeesRJw_6)u?%E_gOS--^ap~f`hvqw<&X&$y&CL<`uj}bXkGRxR
z{!M|`OU<552%i3@l>5BVly|CSLJ>T>)_jQjp_Rks-zt7+`u-~?&fQxpc)Fob$8Pn!
z;Iqfxs9y59^g3n7{;sc1$0UAEFm#TZyHCY;PM77UTLIkaY~@X_pFN7vzs^2y_nFv-
zzjku0)hkl&J0$+qwMOy7KI46M@!Rt|5|`iJcRA(tV#BD{yDv}NwP<72l>Xc5-)#F<
z2}^F;xNl=!7>D+jMafxSn@ju|m{oKArhjIg{9dqyyQX8EZfF1Mr0@y;+FbcFdE%z?
zc&_)jskgzp|1I;j;A^qZGUJOaKWi1dl>U48wVrt>Tb$&9i^Y243ye#jaBirH(|Ij=
zTi#~g_J)bpx0Bb}<|gjywhLQ*yF@Qqj&V2t>Z|k5uey5o`ICC?ip77}Rw{E{JG3y~
z2$*3w3p^r=85p>QL70(Y)*J~21}3@8kcg59UmvUF{9L`nl>DSry^7od1`x2RumUo3
zQ%e#RDspr3imfVamB1>jfNYSkzLEl1NlCV?QiN}Sf^&XRs)C80iJpOy9hZWFf=y9M
znpKdC8&o@xXRDM^Qc_^0uU}qXu2*iXmtT~wZ)j<0sc&GUZ)BtkRH0j3nOBlnp_^B%
z3^4>|j!SBBa#3bMNoIbY0*IfOlwVq6tE2=~0|5|=Qj+2J6qFX_fNe=h)=$kz%}vcK
zDb_dCGt`G04l+L_*{ZlSDJwO(#16$cu*FV^>H5fu^)Xf3=%cxiT$cj_6Yli9VrYB-
zV@AIsu>k0715{@NRa-e1r6!i-7lq{K=h!)dlq-1VCZ?wbr6#6S+UTRJ!0TR!C@{Y4
zxPUrgac{>JuxDWiFgaZDba4!^5ZpS+k*nE2!1eg0&o^3yHs09FE&eET(-v_d@p%gu
zU164NUFp0s<xxlLrACKOm6e_+Dmpm!U#ZM54iq^P6FOCW<Ghk)oAZXJjgFc7GMC2Y
zt32YpWYStWZ)SthN|%EszCzk*{{<zIk6d2zL8Ue7wYBFP$C*dEnpkztS~S^e{EjN{
z7TV&!+%mPVq2=i^{&j^tUYhN-`oH(JyWidvm(ZlqWx&H!_*uP%kGUjvyVni#xElGs
zss@SOGY-79lfE;1v${^ePIjxGr*<;6TgUBVI3k(zKwqXI1(e=BUHx3vIVCg!0Cn%A
AApigX