diff --git a/apps/devhub/templates/devhub/devhub_search.html b/apps/devhub/templates/devhub/devhub_search.html
new file mode 100644
index 0000000000..a72bbcf1ee
--- /dev/null
+++ b/apps/devhub/templates/devhub/devhub_search.html
@@ -0,0 +1,29 @@
+{% extends 'devhub/base_impala.html' %}
+
+{% if query %}
+ {% set title = _('{0} :: Search')|f(query) %}
+{% else %}
+ {% set title = _('Search') %}
+{% endif %}
+{% block title %}{{ dev_page_title(title) }}{% endblock %}
+
+{% block content %}
+{{ docs_breadcrumbs(items=[(None, _('Search Results'))]) }}
+{% if query %}
+
{{ _('Search Results for "{0}"')|f(query) }}
+{% else %}
+{{ _('Search Results') }}
+{% endif %}
+
+
+
{{ _('Please enter some search terms.') }}
+
+
{{ _('Loading results…') }}
+
+
+{% endblock %}
+{% block js_extras %}
+
+
+
+{% endblock %}
diff --git a/apps/devhub/tests/test_views.py b/apps/devhub/tests/test_views.py
index 8cd747d3f3..966dafee9f 100644
--- a/apps/devhub/tests/test_views.py
+++ b/apps/devhub/tests/test_views.py
@@ -3573,3 +3573,16 @@ class TestRemoveLocale(amo.tests.TestCase):
doc = pq(res.content)
# There's 2 fields, one for en-us, one for init.
eq_(len(doc('div.trans textarea')), 2)
+
+
+class TestSearch(amo.tests.TestCase):
+
+ def test_search_titles(self):
+ r = self.client.get(reverse('devhub.search'), {'q': 'davor'})
+ self.assertContains(r, '"davor"')
+ self.assertContains(r, 'davor :: Search ::')
+
+ def test_search_titles_default(self):
+ r = self.client.get(reverse('devhub.search'))
+ self.assertContains(r, 'Search ::')
+ self.assertContains(r, 'Search Results
')
diff --git a/apps/devhub/urls.py b/apps/devhub/urls.py
index 4c991ed75d..e788e8971a 100644
--- a/apps/devhub/urls.py
+++ b/apps/devhub/urls.py
@@ -169,6 +169,7 @@ redirect_patterns = patterns('',
('^versions/validate/(\d+)', views.validator_redirect),
)
+
urlpatterns = decorate(write, patterns('',
url('^$', views.index, name='devhub.index'),
url('', include(redirect_patterns)),
@@ -256,4 +257,6 @@ urlpatterns = decorate(write, patterns('',
# PayPal Checker
url('^check_paypal$', views.check_paypal, name='devhub.check_paypal'),
+ # Search
+ url(r'^search$', views.search, name='devhub.search'),
))
diff --git a/apps/devhub/views.py b/apps/devhub/views.py
index 9a2eb8dffc..91170c5654 100644
--- a/apps/devhub/views.py
+++ b/apps/devhub/views.py
@@ -1776,3 +1776,8 @@ def check_paypal(request):
return {'valid': bool(paykey and valid_paypal), 'message': message}
+
+def search(request):
+ query = request.GET.get('q', '')
+ return jingo.render(request, 'devhub/devhub_search.html', {'query': query})
+
diff --git a/media/css/devhub/search.less b/media/css/devhub/search.less
new file mode 100644
index 0000000000..b6cefb06a8
--- /dev/null
+++ b/media/css/devhub/search.less
@@ -0,0 +1,135 @@
+@import '../impala/lib';
+
+#search-results {
+ // Outer row
+ .gsc-webResult {
+ color: @note-gray;
+ padding: 0;
+ width: 100%;
+
+ // Inner row
+ .gs-result {
+ padding: 20px 1em;
+ &:hover {
+ background-color: @faded-blue;
+ }
+ .gs-title {
+ font-size: 16px;
+ font-weight: bold;
+ line-height: 18px;
+ text-decoration: none;
+ a {
+ color: @link;
+ text-decoration: none;
+ b {
+ color: @orange;
+ }
+ &:hover {
+ text-decoration: underline;
+ }
+ * {
+ text-decoration: none;
+ }
+ }
+ }
+ .gs-title, .gs-snippet {
+ margin-bottom: 5px;
+ }
+ .gs-snippet {
+ color: @medium-gray;
+ margin-top: .5em;
+ font-size: 12px;
+ line-height: 1.3em;
+ }
+ .gs-per-result-labels {
+ margin-top: 5px;
+ font-size: 11px;
+ a {
+ color: @medium-gray;
+ font-weight: bold;
+ text-decoration: none;
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+ }
+ .gs-visibleUrl {
+ color: @green;
+ }
+ }
+ .gsc-result {
+ border-bottom: 1px dotted @border-blue;
+ }
+ }
+ .gsc-result-info {
+ padding: .5em 0 1em 0;
+ font-size: 11px;
+ border-bottom: 1px dotted @border-blue;
+ }
+ .gsc-tabHeader {
+ border: 0;
+ font-size: 11px;
+ margin-right: 0;
+ &.gsc-tabhActive, &.gsc-tabhInactive {
+ border: 0;
+ border-left: 1px solid @light-gray;
+ &:first-child {
+ border-left: 0;
+ }
+ }
+ &.gsc-tabhActive {
+ color: @orange;
+ font-weight: bold;
+ }
+ &.gsc-tabhInactive {
+ background: transparent;
+ color: @link;
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+ &:first-child {
+ padding-left: 0;
+ }
+ }
+ .gsc-cursor-box {
+ margin-top: 1em;
+ }
+ .gsc-cursor-page {
+ color: @dark-gray;
+ text-decoration: none;
+ margin: 0 8px 0 0;
+ padding: 5px;
+ &.gsc-cursor-current-page {
+ color: @orange;
+ }
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+ .gsc-result .gs-title {
+ height: auto;
+ }
+ .gsc-tabsArea {
+ margin-bottom: .5em;
+ .gs-spacer {
+ display: none;
+ }
+ }
+}
+.html-rtl #search-results {
+ .gsc-cursor-page {
+ margin: 0 0 0 8px;
+ }
+ .gsc-tabHeader {
+ margin-left: 0;
+ &.gsc-tabhActive, &.gsc-tabhInactive {
+ border-left: 0;
+ border-right: 1px solid @light-gray;
+ }
+ }
+ .gsc-tabsArea div .gsc-tabHeader:first-child {
+ border-right: 0 !important;
+ padding: 0 0 0 6px;
+ }
+}
\ No newline at end of file
diff --git a/media/js/zamboni/devhub_search.js b/media/js/zamboni/devhub_search.js
new file mode 100644
index 0000000000..6ebc7308fc
--- /dev/null
+++ b/media/js/zamboni/devhub_search.js
@@ -0,0 +1,37 @@
+google.load('search', '1', {'language' : $('html').attr('lang')});
+google.setOnLoadCallback(function() {
+ var qry = $('.header-search input[name="q"]'),
+ opt = new google.search.DrawOptions();
+
+ opt.setInput(qry.get(0));
+ sc = new google.search.CustomSearchControl('007182852441266509516:fnsg3w7luc4');
+ sc.setNoResultsString(gettext('No results found.'));
+ sc.setSearchStartingCallback(null, function(sc, searcher, qry) {
+ sc.maxResultCount = 0;
+ });
+
+ sc.setSearchCompleteCallback(null, function(sc, searcher) {
+ if (searcher.results.length) {
+ var cur = searcher.cursor,
+ total = parseInt(cur.estimatedResultCount, 10);
+ if (total > sc.maxResultCount) {
+ sc.maxResultCount = total;
+ $('#cse').show();
+ window.scroll(0, 0);
+ }
+ } else {
+ $('#resultcount').hide();
+ }
+ });
+
+ $('#cse').hide();
+ sc.draw('cse', opt);
+
+ if (!qry.val()) {
+ $('#resultcount').show();
+ }
+
+ $('#searchbox').submit(_pd(function(e) {
+ sc.execute();
+ }));
+}, true);
diff --git a/settings.py b/settings.py
index 43cba5c5bf..186b935e83 100644
--- a/settings.py
+++ b/settings.py
@@ -517,6 +517,7 @@ MINIFY_BUNDLES = {
'css/devhub/dashboard.less',
'css/devhub/forms.less',
'css/devhub/submission.less',
+ 'css/devhub/search.less',
),
'zamboni/editors': (
'css/zamboni/editors.css',