Bug 1101654: First use tour for search UI. r=felipe, a=gavin
authorDave Townsend <dtownsend@oxymoronical.com>
Thu, 20 Nov 2014 15:27:10 -0800
changeset 226111 98c4c4a55139a4db78231835adc8a3077a6ac70c
parent 226110 bc996c1a50f1515da8cfe97d8f221ec99c9233cf
child 226112 9ae0161389d30e0bfea96ebe46241ffb02b1f511
push id4159
push userdtownsend@mozilla.com
push dateThu, 20 Nov 2014 23:28:22 +0000
treeherdermozilla-beta@98c4c4a55139 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfelipe, gavin
bugs1101654
milestone34.0
Bug 1101654: First use tour for search UI. r=felipe, a=gavin
browser/app/profile/firefox.js
browser/base/content/browser.js
browser/base/content/browser.xul
browser/base/content/urlbarBindings.xml
browser/themes/linux/jar.mn
browser/themes/osx/jar.mn
browser/themes/shared/UITour.inc.css
browser/themes/shared/dots.png
browser/themes/shared/dots@2px.png
browser/themes/windows/jar.mn
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -419,16 +419,19 @@ pref("browser.search.suggest.enabled", t
 
 pref("browser.search.showOneOffButtons", false);
 
 #ifdef MOZ_OFFICIAL_BRANDING
 // {moz:official} expands to "official"
 pref("browser.search.official", true);
 #endif
 
+// How many times to show the new search highlight
+pref("browser.search.highlightCount", 5);
+
 pref("browser.sessionhistory.max_entries", 50);
 
 // handle links targeting new windows
 // 1=current window/tab, 2=new window, 3=new tab in most recent window
 pref("browser.link.open_newwindow", 3);
 
 // handle external links (i.e. links opened from a different application)
 // default: use browser.link.open_newwindow
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1283,16 +1283,17 @@ var gBrowserInit = {
         return;
       }
 
       // Enable the Restore Last Session command if needed
       RestoreLastSessionObserver.init();
 
       SocialUI.init();
       TabView.init();
+      SearchHighlight.init();
 
       // Telemetry for master-password - we do this after 5 seconds as it
       // can cause IO if NSS/PSM has not already initialized.
       setTimeout(() => {
         if (window.closed) {
           return;
         }
         let secmodDB = Cc["@mozilla.org/security/pkcs11moduledb;1"]
@@ -3219,16 +3220,135 @@ const BrowserSearch = {
 
     let countId = this._getSearchEngineId(engine) + "." + source;
 
     let count = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS");
     count.add(countId);
   },
 };
 
+const SearchHighlight = {
+  eventsReady: false,
+  // The pref that controls how many times to show the highlight.
+  countPref: "browser.search.highlightCount",
+  // The current highlight to show.
+  currentPos: 0,
+  // Tracks if the popup closed very recently.
+  hideTimer: null,
+
+  // The list of highlights and the items in the panel to anchor them to.
+  highlights: [{
+    id: "SearchHighlight1",
+    anchor: "search-panel-one-offs"
+  }, {
+    id: "SearchHighlight2",
+    anchor: "searchbar-engine",
+  }],
+
+  init: function() {
+    this.panel = document.getElementById("PopupSearchAutoComplete");
+    this.panel.addEventListener("popupshowing", this.searchPanelShown.bind(this), false);
+  },
+
+  initEvents: function() {
+    if (this.eventsReady) {
+      return;
+    }
+
+    this.panel.addEventListener("popuphidden", this.searchPanelHidden.bind(this), false);
+
+    for (let highlight of this.highlights) {
+      highlight.panel = document.getElementById(highlight.id);
+      highlight.panel.addEventListener("popupshowing", this.disablePanelHiding.bind(this), false);
+      highlight.panel.addEventListener("popuphiding", this.enablePanelHiding.bind(this), false);
+
+      highlight.panel.querySelector("button").addEventListener("command", this.highlightButtonClicked.bind(this), false);
+    }
+
+    this.eventsReady = true;
+  },
+
+  get highlightPanel() {
+    return this.highlights[this.currentPos].panel;
+  },
+
+  showHighlight: function() {
+    // Check that all the events are setup.
+    this.initEvents();
+
+    // If a highlight is already showing then do nothing.
+    if (this.highlightPanel.state != "closed") {
+      return;
+    }
+
+    // Show the first highlight.
+    this.currentPos = 0;
+    this.showCurrentHighlight();
+  },
+
+  showCurrentHighlight: function() {
+    let highlight = this.highlights[this.currentPos];
+    let anchor = document.getAnonymousElementByAttribute(this.panel, "anonid", highlight.anchor);
+    highlight.panel.openPopup(anchor, "leftcenter topright");
+  },
+
+  searchPanelShown: function() {
+    // If the panel was only very recently closed re-show the last highlight.
+    if (this.hideTimer) {
+      clearTimeout(this.hideTimer);
+      this.hideTimer = null;
+      this.showCurrentHighlight();
+      return;
+    }
+
+    // If the highlight has already been show the appropriate number of times
+    // do nothing.
+    let count = Services.prefs.getIntPref(this.countPref);
+    if (count <= 0)
+      return;
+
+    this.showHighlight();
+    Services.prefs.setIntPref(this.countPref, count - 1);
+  },
+
+  searchPanelHidden: function() {
+    if (this.highlightPanel.state == "closed") {
+      return;
+    }
+
+    this.highlightPanel.hidePopup();
+
+    // Set a flag when the panel was closed in the last short time.
+    this.hideTimer = setTimeout(() => {
+      this.hideTimer = null;
+    }, 500);
+  },
+
+  highlightButtonClicked: function() {
+    // When the button is clicked close the current highlight and open the next
+    // one.
+    this.highlightPanel.hidePopup();
+    this.currentPos++;
+    if (this.currentPos < this.highlights.length) {
+      this.showCurrentHighlight();
+    } else {
+      Services.prefs.setIntPref(this.countPref, 0);
+      this.currentPos = 0;
+    }
+  },
+
+  disablePanelHiding: function() {
+    this.panel.setAttribute("noautohide", "true");
+  },
+
+  enablePanelHiding: function() {
+    this.panel.setAttribute("noautohide", "false");
+  },
+};
+
 function FillHistoryMenu(aParent) {
   // Lazily add the hover listeners on first showing and never remove them
   if (!aParent.hasStatusListener) {
     // Show history item's uri in the status bar when hovering, and clear on exit
     aParent.addEventListener("DOMMenuItemActive", function(aEvent) {
       // Only the current page should have the checked attribute, so skip it
       if (!aEvent.target.hasAttribute("checked"))
         XULBrowserWindow.setOverLink(aEvent.target.getAttribute("uri"));
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -235,16 +235,49 @@
            hidden="true"
            noautofocus="true"
            noautohide="true"
            flip="none"
            consumeoutsideclicks="false"
            mousethrough="always">
       <box id="UITourHighlight"></box>
     </panel>
+    <!-- Used to highlight the new search experience -->
+    <panel id="SearchHighlight1"
+           class="SearchHighlight"
+           type="arrow"
+           noautofocus="true"
+           noautohide="true"
+           orient="vertical"
+           align="stretch">
+      <label class="SearchHighlightTitle">One Click Searches</label>
+      <description class="SearchHighlightText" flex="1">Looking for something specific? Instantly search on any site using these options!</description>
+      <hbox class="SearchHighlightFooter" align="center">
+        <spacer class="dot filled"/>
+        <spacer class="dot"/>
+        <spacer flex="1"/>
+        <button label="Next"/>
+      </hbox>
+    </panel>
+    <panel id="SearchHighlight2"
+           class="SearchHighlight"
+           type="arrow"
+           noautofocus="true"
+           noautohide="true"
+           orient="vertical"
+           align="stretch">
+      <label class="SearchHighlightTitle">Search Suggestions</label>
+      <description class="SearchHighlightText" flex="1">As-you-type suggestions from your default search engine help you to get to the right results quickly.</description>
+      <hbox class="SearchHighlightFooter" align="center">
+        <spacer class="dot"/>
+        <spacer class="dot filled"/>
+        <spacer flex="1"/>
+        <button label="Thanks!"/>
+      </hbox>
+    </panel>
 
     <panel id="abouthome-search-panel" orient="vertical" type="arrow">
       <hbox id="abouthome-search-panel-manage" class="abouthome-search-panel-item"
             onclick="openPreferences('paneSearch')">
         <label>&cmd_engineManager.label;</label>
       </hbox>
     </panel>
 
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -894,17 +894,17 @@
     </binding>
 
   <!-- Note: this binding is applied to the autocomplete popup used in the Search bar -->
   <binding id="browser-search-autocomplete-result-popup" extends="chrome://browser/content/urlbarBindings.xml#browser-autocomplete-result-popup">
     <resources>
       <stylesheet src="chrome://browser/skin/searchbar.css"/>
     </resources>
     <content ignorekeys="true" level="top" consumeoutsideclicks="false">
-      <xul:hbox xbl:inherits="collapsed=showonlysettings"
+      <xul:hbox xbl:inherits="collapsed=showonlysettings" anonid="searchbar-engine"
                 class="search-panel-header search-panel-current-engine">
         <xul:image class="searchbar-engine-image" xbl:inherits="src"/>
         <xul:label anonid="searchbar-engine-name"/>
       </xul:hbox>
       <xul:tree anonid="tree" flex="1"
                 class="autocomplete-tree plain search-panel-tree"
                 hidecolumnpicker="true" seltype="single">
         <xul:treecols anonid="treecols">
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -19,16 +19,18 @@ browser.jar:
   skin/classic/browser/aboutSyncTabs.css
 #endif
   skin/classic/browser/aboutTabCrashed.css
   skin/classic/browser/actionicon-tab.png
 * skin/classic/browser/browser.css
 * skin/classic/browser/browser-lightweightTheme.css
   skin/classic/browser/click-to-play-warning-stripes.png
 * skin/classic/browser/content-contextmenu.svg
+  skin/classic/browser/dots.png                             (../shared/dots.png)
+  skin/classic/browser/dots@2px.png                         (../shared/dots@2px.png)
 * skin/classic/browser/engineManager.css
   skin/classic/browser/fullscreen-darknoise.png
   skin/classic/browser/Geolocation-16.png
   skin/classic/browser/Geolocation-64.png
   skin/classic/browser/identity.png
   skin/classic/browser/identity-icons-generic.png
   skin/classic/browser/identity-icons-https.png
   skin/classic/browser/identity-icons-https-ev.png
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -19,16 +19,18 @@ browser.jar:
 #endif
   skin/classic/browser/aboutTabCrashed.css
   skin/classic/browser/actionicon-tab.png
   skin/classic/browser/actionicon-tab@2x.png
 * skin/classic/browser/browser.css                          (browser.css)
 * skin/classic/browser/browser-lightweightTheme.css
   skin/classic/browser/click-to-play-warning-stripes.png
 * skin/classic/browser/content-contextmenu.svg
+  skin/classic/browser/dots.png                             (../shared/dots.png)
+  skin/classic/browser/dots@2px.png                         (../shared/dots@2px.png)
 * skin/classic/browser/engineManager.css                    (engineManager.css)
   skin/classic/browser/fullscreen-darknoise.png
   skin/classic/browser/Geolocation-16.png
   skin/classic/browser/Geolocation-16@2x.png
   skin/classic/browser/Geolocation-64.png
   skin/classic/browser/Geolocation-64@2x.png
   skin/classic/browser/identity.png
   skin/classic/browser/identity@2x.png
--- a/browser/themes/shared/UITour.inc.css
+++ b/browser/themes/shared/UITour.inc.css
@@ -142,8 +142,53 @@
   color: white;
   padding-left: 30px;
   padding-right: 30px;
 }
 
 #UITourTooltipButtons > button.button-primary:not(:active):hover {
   background-color: rgb(105,173,61);
 }
+
+.SearchHighlight {
+  -moz-margin-end: 6px;
+  font-size: 110%;
+  width: 225px;
+}
+
+.SearchHighlight label,
+.SearchHighlight description {
+  color: #535353;
+  margin: 0 0 8px 0;
+  padding: 0;
+}
+
+.SearchHighlightTitle {
+  font-weight: bold;
+}
+
+.SearchHighlight .dot {
+  width: 7px;
+  height: 7px;
+  background-image: -moz-image-rect(url("chrome://browser/skin/dots.png"), 0, 100%, 100%, 9);
+  background-size: 7px;
+  background-position: center center;
+  background-repeat: no-repeat;
+  -moz-margin-end: 2px;
+}
+
+.SearchHighlight .dot.filled {
+  background-image: -moz-image-rect(url("chrome://browser/skin/dots.png"), 0, 7, 100%, 0);
+}
+
+.SearchHighlight button {
+  margin: 0;
+}
+
+@media not all and (max-resolution: 1dppx) {
+  .SearchHighlight .dot {
+    background-image: -moz-image-rect(url("chrome://browser/skin/dots@2px.png"), 0, 100%, 100%, 18);
+  }
+
+  .SearchHighlight .dot.filled {
+    background-image: -moz-image-rect(url("chrome://browser/skin/dots@2px.png"), 0, 14, 100%, 0);
+  }
+}
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e856fd0ab2e7f4c36a846c678cd9e539a46c92cf
GIT binary patch
literal 496
zc$@+70T2F(P)<h;3K|Lk000e1NJLTq000mG000LF1^@s60U*sn0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzl1W5CRCwAnkxfeiQ51&HIHTgnFq(t2
z5Er&d(;$Nwh%m@sP!Q;{S_B3DfpXVQD(Vk}%M7I4B`qp~n1y4K3peV@g)$QkgX0V;
zc5c+&+|T!U-*Ya-^E{-}X)cjSoP|Q6)n2dn*=#n?OQn)FpU>fcWV6|YWHNb!Z&vWl
zSG``(Rjbu+IueQa5pWrc#ZCl4SY%mtgQjVrR;xV{A;U1>@pvGU$=sn?O4oIn<G5{~
z&$r%gx1Xs(p>Q1zhjXGRg3INC@puf9Btf^^-Elgd4+KI{)G<P?EX(32lZkG(+gZF*
zOw+6|fk0rBltIM9;Si7vWIq~>w!B{NKVWY#7?cs9V>%!+o|RFXVpLUqce~wd#F>c6
ztSAbg;8oK!_ygRN1lSXnBtUo8;c)DtwnD|@aX&WbA{veE697rkYPD{$v;&Oz3qS$n
z^Z5!oiiTmlp<xQeQn6S(q>*YO{l#XpF}OB5olY5l;Z&AoYdW36Y&Ij2Nm)<Wyrp0;
mxZLmeKkyfh8jXhfBftO<-MX_cvj}zo0000<MNUMnLSTa0irY*8
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5b9089bda016397d100545bbb5564c1255e419c7
GIT binary patch
literal 519
zc$@(T0{H!jP)<h;3K|Lk000e1NJLTq001BW000gM1^@s6PTU@{00001b5ch_0Itp)
z=>Px$!AV3xR5%gERJ(2hF%Yy*JUf&w5*3swQqe~!pFx*L0TmSah!jw9MIK$0uZW`b
zR4JgNLrNFXp#uqLXYpE=bB>6F5=(IQ%-rnSw`-;TdFUX%9*@VDTI&nKPb@bz#ys|V
zy$4#GKp$J~?c)*{jYh}ia`}mZxAR;niPtR4I{kkCBaavCw>|~?qL$#5O2sr94PC3%
zm|8BEYCfME3f_i>z;pV=PQv++X0hFFZ`SMe8_iXzR60wN<Q5zBefR|E*sqAZBf_*=
zEnO@Y@s1mt%|=Zo6C|O@^qM}$y(7Je_z<*MtyZUl!Qj)Q)o?gGs#dG-gw@3-fxv!q
z)oeDu1qY9W!1-Ft!y!J{c^Dj8VBjzpEhj*0E;u=M2*TlUQk<a#Yv$zG^8_BpT1g;J
z`zM$rFhw*JTx@t8Ya=@5P;e2Ri_vnd<pj{@08#BIxNrai2VAtF#^+G&D7a7q44ki(
zdqAgY`eIwepy1@2du^z37j(PbAKOrTC`fJ_5?=Rx3N}l$SO@)yexJ=|7IqH~4h<o(
zI{;$mgU!%xpXpw4CM>WQ8njr;31E(~_Z7O6NB<Ay6Af@M;tOsv1wb2UwcP*!002ov
JPDHLkV1g~k;|c%(
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -21,16 +21,18 @@ browser.jar:
         skin/classic/browser/aboutSyncTabs.css
 #endif
         skin/classic/browser/aboutTabCrashed.css
         skin/classic/browser/actionicon-tab.png
 *       skin/classic/browser/browser.css
 *       skin/classic/browser/browser-lightweightTheme.css
         skin/classic/browser/click-to-play-warning-stripes.png
 *       skin/classic/browser/content-contextmenu.svg
+        skin/classic/browser/dots.png                                (../shared/dots.png)
+        skin/classic/browser/dots@2px.png                            (../shared/dots@2px.png)
 *       skin/classic/browser/engineManager.css
         skin/classic/browser/fullscreen-darknoise.png
         skin/classic/browser/Geolocation-16.png
         skin/classic/browser/Geolocation-64.png
         skin/classic/browser/Info.png
         skin/classic/browser/identity.png
         skin/classic/browser/identity-icons-generic.png
         skin/classic/browser/identity-icons-https.png
@@ -448,16 +450,18 @@ browser.jar:
         skin/classic/aero/browser/aboutTabCrashed.css
         skin/classic/aero/browser/aboutWelcomeBack.css               (../shared/aboutWelcomeBack.css)
         skin/classic/aero/browser/actionicon-tab.png
 *       skin/classic/aero/browser/browser.css                        (browser-aero.css)
 *       skin/classic/aero/browser/browser-lightweightTheme.css
         skin/classic/aero/browser/click-to-play-warning-stripes.png
 *       skin/classic/aero/browser/content-contextmenu.svg
 *       skin/classic/aero/browser/engineManager.css
+        skin/classic/aero/browser/dots.png                           (../shared/dots.png)
+        skin/classic/aero/browser/dots@2px.png                       (../shared/dots@2px.png)
         skin/classic/aero/browser/fullscreen-darknoise.png
         skin/classic/aero/browser/Geolocation-16.png
         skin/classic/aero/browser/Geolocation-64.png
         skin/classic/aero/browser/Info.png                           (Info-aero.png)
         skin/classic/aero/browser/identity.png                       (identity-aero.png)
         skin/classic/aero/browser/identity-icons-generic.png
         skin/classic/aero/browser/identity-icons-https.png
         skin/classic/aero/browser/identity-icons-https-ev.png