diff --git a/apps/search/index.html b/apps/search/index.html
index 56d50dec2e97..a68bfafdac2b 100644
--- a/apps/search/index.html
+++ b/apps/search/index.html
@@ -22,6 +22,7 @@
+
@@ -44,10 +45,28 @@
+
-
-
-
+
+
+
+
+
+
+
+ Search suggestions are shown as you type. Go to the Homescreen section
+ of Settings to change your search preferences.
+
+
+
+
+
+
+
diff --git a/apps/search/js/search.js b/apps/search/js/search.js
index f8446c738526..d76235b971b5 100644
--- a/apps/search/js/search.js
+++ b/apps/search/js/search.js
@@ -1,10 +1,11 @@
(function() {
'use strict';
+ /* global asyncStorage */
/* global Search */
/* global SearchDedupe */
- /* global UrlHelper */
/* global SettingsListener */
+ /* global UrlHelper */
// timeout before notifying providers
var SEARCH_DELAY = 600;
@@ -28,6 +29,14 @@
suggestionsEnabled: false,
+ /**
+ * Used to display a notice on how to configure the search provider
+ * on first use
+ */
+ suggestionNotice: document.getElementById('suggestions-notice-wrapper'),
+ toShowNotice: false,
+ changeCount: 0,
+
init: function() {
this.dedupe = new SearchDedupe();
@@ -77,6 +86,13 @@
this.suggestionsEnabled = enabled;
}.bind(this));
+ this.initNotice();
+
+ // Fire off a dummy geolocation request so the prompt can be responded
+ // to before the user starts typing
+ if ('geolocation' in navigator) {
+ navigator.geolocation.getCurrentPosition(function(){});
+ }
},
/**
@@ -116,6 +132,7 @@
var input = msg.data.input;
var providers = this.providers;
+ this.maybeShowNotice();
this.clear();
this.changeTimeout = setTimeout(function doSearch() {
@@ -131,6 +148,32 @@
}.bind(this), SEARCH_DELAY);
},
+ /**
+ * Show a notice to the user informaing them of how to configure
+ * search providers, should only be shown once.
+ */
+ initNotice: function() {
+
+ var noticeKey = 'notice-shown';
+ var confirm = document.getElementById('suggestions-notice-confirm');
+
+ confirm.addEventListener('click', function() {
+ this.suggestionNotice.hidden = true;
+ this.toShowNotice = false;
+ asyncStorage.setItem(noticeKey, true);
+ }.bind(this));
+
+ asyncStorage.getItem(noticeKey, function(value) {
+ this.toShowNotice = !value;
+ }.bind(this));
+ },
+
+ maybeShowNotice: function() {
+ if (this.toShowNotice && ++this.changeCount > 2) {
+ this.suggestionNotice.hidden = false;
+ }
+ },
+
/**
* Expands the search experience when the user taps on a suggestion
* or submits a query.
diff --git a/apps/search/locales/search.en-US.properties b/apps/search/locales/search.en-US.properties
index ae55159ae79f..80378d5c4b72 100644
--- a/apps/search/locales/search.en-US.properties
+++ b/apps/search/locales/search.en-US.properties
@@ -6,3 +6,6 @@ suggestions.ariaLabel = Suggestions
contacts.ariaLabel = Contacts
places.ariaLabel = Places
apps.ariaLabel = Apps
+
+suggestions-notice = Search suggestions are shown as you type. Go to the Homescreen section of Settings to change your search preferences.
+ok = Ok
diff --git a/apps/search/style/search.css b/apps/search/style/search.css
index d0b5ca511879..40268ccaf0d5 100644
--- a/apps/search/style/search.css
+++ b/apps/search/style/search.css
@@ -149,4 +149,51 @@ gaia-grid {
.hidden {
display: none;
-}
\ No newline at end of file
+}
+
+#suggestions-wrapper {
+ display: flex;
+}
+
+#suggestions {
+ flex: 1;
+}
+
+#suggestions-notice-wrapper {
+ background: rgba(45, 45, 45, 0.94);
+ z-index: 100;
+ border-radius: 2px;
+ position: absolute;
+ margin: 1rem 1.5rem 0 1.5rem;
+}
+
+#suggestions-notice-wrapper p {
+ padding: 1.5rem;
+ font-size: 1.6rem;
+ font-style: italic;
+}
+
+#suggestions-notice-confirm {
+ display: block;
+ width: 100%;
+ color: #00AACC;
+ background: none;
+ border: none;
+ border-top: 0.1rem solid rgba(255, 255, 255, 0.05);
+ border-radius: 0;
+ padding: 1rem;
+ font-size: 16px;
+ font-style: italic;
+}
+
+#suggestions-notice-wrapper::before {
+ content: ' ';
+ height: 0;
+ width: 0;
+ position: absolute;
+ border: 9px solid transparent;
+ border-left-color: rgba(45, 45, 45, 0.94);
+ top: -0.9rem;
+ left: 0;
+ z-index: -1;
+}
diff --git a/apps/search/test/marionette/app_search_test.js b/apps/search/test/marionette/app_search_test.js
index cbe74bd32853..ad72dc09c408 100644
--- a/apps/search/test/marionette/app_search_test.js
+++ b/apps/search/test/marionette/app_search_test.js
@@ -17,6 +17,9 @@ marionette('Search - App search', function() {
});
test('Search apps from Rocketbar', function() {
+ client.switchToFrame();
+ rocketbar.focus();
+ search.triggerFirstRun(rocketbar);
rocketbar.focus();
rocketbar.enterText('calendar');
search.goToResults();
@@ -26,6 +29,9 @@ marionette('Search - App search', function() {
});
test('Search for app with entry point', function() {
+ client.switchToFrame();
+ rocketbar.focus();
+ search.triggerFirstRun(rocketbar);
rocketbar.focus();
rocketbar.enterText('Phone');
search.goToResults();
diff --git a/apps/search/test/marionette/lib/search.js b/apps/search/test/marionette/lib/search.js
index 4ee99cdc5fef..180153539f1a 100644
--- a/apps/search/test/marionette/lib/search.js
+++ b/apps/search/test/marionette/lib/search.js
@@ -23,7 +23,8 @@ Search.Selectors = {
firstContact: '#contacts div',
firstContactContainer: '#contacts',
firstPlace: '#places div .title',
- firstPlaceContainer: '#places'
+ firstPlaceContainer: '#places',
+ firstRunConfirm: '#suggestions-notice-confirm'
};
Search.prototype = {
@@ -83,6 +84,20 @@ Search.prototype = {
}, [Search.URL]);
},
+ /**
+ * On first run a warning is shown to users on Search app configuration
+ * trigger this notice and confirm it.
+ */
+ triggerFirstRun: function(rocketbar) {
+ rocketbar.enterText('abc');
+ this.goToResults();
+ this.client.helper
+ .waitForElement(Search.Selectors.firstRunConfirm)
+ .click();
+ this.client.switchToFrame();
+ rocketbar.enterText('');
+ },
+
/**
* Navigates to a specific app/entry point
* Waits for the body to be loaded
diff --git a/apps/search/test/marionette/places_search_test.js b/apps/search/test/marionette/places_search_test.js
index bb8db744d2e2..f57c667395fa 100644
--- a/apps/search/test/marionette/places_search_test.js
+++ b/apps/search/test/marionette/places_search_test.js
@@ -33,6 +33,7 @@ marionette('Places tests', function() {
test('Search for previously visited URL', function() {
var url = server.url('sample.html');
+ search.triggerFirstRun(rocketbar);
rocketbar.focus();
rocketbar.enterText(url + '\uE006');
rocketbar.waitForBrowserFrame();
@@ -45,6 +46,7 @@ marionette('Places tests', function() {
test('Search for a string that doesnt match visited url', function() {
var url = server.url('sample.html');
+ search.triggerFirstRun(rocketbar);
rocketbar.focus();
rocketbar.enterText(url + '\uE006');
rocketbar.waitForBrowserFrame();
@@ -57,6 +59,7 @@ marionette('Places tests', function() {
test('Ensures urls visited twice only show in results once', function() {
var url = server.url('sample.html');
+ search.triggerFirstRun(rocketbar);
rocketbar.focus();
rocketbar.enterText(url + '\uE006');
rocketbar.waitForBrowserFrame();
@@ -80,6 +83,7 @@ marionette('Places tests', function() {
test('Ensure favicon is loaded', function() {
var url = server.url('favicon.html');
+ search.triggerFirstRun(rocketbar);
rocketbar.focus();
rocketbar.enterText(url + '\uE006');
rocketbar.waitForBrowserFrame();
diff --git a/apps/search/test/unit/search_test.js b/apps/search/test/unit/search_test.js
index a4ac0b7575c3..0d466be4c6be 100644
--- a/apps/search/test/unit/search_test.js
+++ b/apps/search/test/unit/search_test.js
@@ -1,16 +1,17 @@
'use strict';
/* global MockNavigatormozApps, MockNavigatormozSetMessageHandler,
- MockMozActivity, Search, MockProvider */
+ MockMozActivity, Search, MockProvider, MockasyncStorage */
require('/shared/test/unit/mocks/mock_navigator_moz_apps.js');
require('/shared/test/unit/mocks/mock_navigator_moz_set_message_handler.js');
require('/shared/test/unit/mocks/mock_moz_activity.js');
require('/shared/js/url_helper.js');
require('/shared/js/dedupe.js');
+require('/shared/test/unit/mocks/mock_async_storage.js');
requireApp('search/test/unit/mock_provider.js');
-
suite('search/search', function() {
+ var realAsyncStorage;
var realMozApps;
var realMozActivity;
var realSetMessageHandler;
@@ -25,6 +26,9 @@ suite('search/search', function() {
realMozActivity = window.MozActivity;
window.MozActivity = MockMozActivity;
+
+ realAsyncStorage = window.asyncStorage;
+ window.asyncStorage = MockasyncStorage;
window.SettingsListener = {
observe: function() {}
@@ -39,6 +43,7 @@ suite('search/search', function() {
navigator.mozSetMessageHandler = realSetMessageHandler;
navigator.mozApps = realMozApps;
window.MozActivity = realMozActivity;
+ window.asyncStorage = realAsyncStorage;
clock.restore();
delete window.SettingsListener;
});
@@ -56,7 +61,12 @@ suite('search/search', function() {
suite('init', function() {
test('will call provider init method', function() {
+
var initCalled;
+ var fakeElement = document.createElement('div');
+ var confirmStub = this.sinon.stub(document, 'getElementById')
+ .returns(fakeElement);
+
Search.providers = [{
init: function() {
initCalled = true;
@@ -72,6 +82,7 @@ suite('search/search', function() {
MockNavigatormozApps.mLastConnectionCallback([]);
assert.ok(initCalled);
Search.providers = [];
+ confirmStub.restore();
});
});
diff --git a/apps/verticalhome/test/marionette/search_test.js b/apps/verticalhome/test/marionette/search_test.js
index b7d9cff056d7..c9294bbb74eb 100644
--- a/apps/verticalhome/test/marionette/search_test.js
+++ b/apps/verticalhome/test/marionette/search_test.js
@@ -27,6 +27,7 @@ marionette('Vertical - Search', function() {
client.helper.waitForElement(Home2.Selectors.search).tap();
client.switchToFrame();
+ search.triggerFirstRun(rocketbar);
rocketbar.enterText('Phone');
search.goToResults();
@@ -40,6 +41,7 @@ marionette('Vertical - Search', function() {
home.waitForLaunch();
client.helper.waitForElement(Home2.Selectors.search).tap();
client.switchToFrame();
+ search.triggerFirstRun(rocketbar);
rocketbar.enterText('Phone');
search.goToResults();