Skip to content
This repository has been archived by the owner on Dec 8, 2017. It is now read-only.

add client-side search #80

Merged
merged 32 commits into from
Feb 5, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
63e9e58
switch to pages api gem
afeld Jan 25, 2015
dc6fb06
add super-simple search with angular
afeld Jan 25, 2015
4ced1cc
hide the page contents when searching
afeld Jan 25, 2015
c77de82
don't escape search result titles
afeld Jan 25, 2015
833eae5
only show search results when at least two characters are entered
afeld Jan 25, 2015
5e53b0f
add space above the search box
afeld Jan 26, 2015
0faf218
simplify search code
afeld Jan 26, 2015
688bb41
simplify bower.json
afeld Jan 26, 2015
a3fca59
search using lunrjs
afeld Jan 26, 2015
ca160f5
simplify pages promise
afeld Jan 26, 2015
2ff2495
limit search to 20 results
afeld Jan 26, 2015
a0b2aef
use decoded html entities from pages api generator
afeld Jan 26, 2015
38e1c0c
use LiveSearch plugin
afeld Jan 26, 2015
ca72e5c
move limiting of results into directive
afeld Jan 26, 2015
449ba9e
pressing enter with a result highlighted takes you to that page
afeld Jan 26, 2015
1e7d11e
use jekyll_pages_api from github
afeld Jan 26, 2015
8c3ad82
move all bower components under assets/
afeld Jan 26, 2015
a0b396f
handle baseurl for search
afeld Jan 26, 2015
56796d4
don't lowercase the titles
afeld Jan 26, 2015
b0d1ec5
handle missing titles
afeld Jan 26, 2015
24caedf
add keyboard shortcut to search
afeld Jan 26, 2015
6c3db2d
refactor the search shortcut
afeld Jan 26, 2015
a4b9493
create a service for the search UI
afeld Jan 26, 2015
d1d1142
Merge remote-tracking branch 'origin/master' into lunr-search
afeld Jan 28, 2015
c62da21
remove unnecessary files from bower
afeld Jan 28, 2015
a2508a5
fix references to search scripts
afeld Jan 31, 2015
d7c8e9f
remove need for the search javascript file to be processed by jekyll
afeld Jan 31, 2015
2af3979
split out search methods
afeld Jan 31, 2015
3a7421d
Merge remote-tracking branch 'origin/master' into lunr-search
afeld Jan 31, 2015
fc37050
bundle search scripts using jekyll-assets
afeld Jan 31, 2015
deb6027
Merge branch 'master' of github.com:18F/hub into lunr-search
Feb 5, 2015
6daf8f4
Update gems
Feb 5, 2015
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ gem 'team_hub'
gem 'weekly_snippets'

group :jekyll_plugins do
gem 'jekyll_pages_api', git: 'https://github.com/18F/jekyll_pages_api.git'
gem 'jekyll-assets'
gem 'jekyll_pages_api'
end

group :test do
Expand Down
41 changes: 30 additions & 11 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
GIT
remote: https://github.com/18F/jekyll_pages_api.git
revision: ebe34affd93282a1f8fe7e36c1730d59932298f2
specs:
jekyll_pages_api (0.1.0)
htmlentities (~> 4.3)
jekyll (~> 2.0)

GEM
remote: https://rubygems.org/
specs:
RedCloth (4.2.9)
addressable (2.3.7)
blankslate (2.1.2.4)
bourbon (4.1.1)
sass (~> 3.3)
Expand All @@ -26,11 +19,14 @@ GEM
coffee-script-source (1.9.0)
colorator (0.1)
docile (1.1.5)
execjs (2.2.2)
execjs (2.3.0)
fast-stemmer (1.0.2)
fastimage (1.6.6)
addressable (~> 2.3, >= 2.3.5)
ffi (1.9.6)
hash-joiner (0.0.3)
safe_yaml
hike (1.2.3)
hitimes (1.2.2)
htmlentities (4.3.3)
jekyll (2.5.3)
Expand All @@ -48,15 +44,25 @@ GEM
redcarpet (~> 3.1)
safe_yaml (~> 1.0)
toml (~> 0.1.0)
jekyll-assets (0.13.0)
fastimage (~> 1.6)
jekyll (~> 2.0)
sass (~> 3.2)
sprockets (~> 2.10)
sprockets-helpers
sprockets-sass
jekyll-coffeescript (1.0.1)
coffee-script (~> 2.2)
jekyll-gist (1.1.0)
jekyll-paginate (1.1.0)
jekyll-sass-converter (1.3.0)
sass (~> 3.2)
jekyll-sitemap (0.7.0)
jekyll-sitemap (0.8.0)
jekyll-watch (1.2.1)
listen (~> 2.7)
jekyll_pages_api (0.1.0)
htmlentities (~> 4.3)
jekyll (~> 2.0)
kramdown (1.5.0)
liquid (2.6.2)
listen (2.8.5)
Expand All @@ -72,6 +78,7 @@ GEM
pygments.rb (0.6.2)
posix-spawn (~> 0.3.6)
yajl-ruby (~> 1.2.0)
rack (1.6.0)
rake (10.4.2)
rb-fsevent (0.9.4)
rb-inotify (0.9.5)
Expand All @@ -84,13 +91,24 @@ GEM
multi_json (~> 1.0)
simplecov-html (~> 0.8.0)
simplecov-html (0.8.0)
sprockets (2.12.3)
hike (~> 1.2)
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
sprockets-helpers (1.1.0)
sprockets (~> 2.0)
sprockets-sass (1.3.1)
sprockets (~> 2.0)
tilt (~> 1.1)
team_hub (0.0.2)
hash-joiner
jekyll
weekly_snippets
test_temp_file_helper (0.0.2)
rake (~> 10.0)
thor (0.19.1)
tilt (1.4.1)
timers (4.0.1)
hitimes
toml (0.1.2)
Expand All @@ -107,8 +125,9 @@ DEPENDENCIES
codeclimate-test-reporter
hash-joiner
jekyll
jekyll-assets
jekyll-sitemap
jekyll_pages_api!
jekyll_pages_api
minitest
rake
team_hub
Expand Down
116 changes: 116 additions & 0 deletions _assets/javascripts/search.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
//= require vendor/angular/angular
//= require vendor/angular-livesearch/liveSearch
//= require vendor/lunr.js/lunr

var ngHub = angular.module('hubSearch', ['LiveSearch']);

ngHub.factory('pagesPromise', function($http, $q) {
return $http.get(SITE_BASEURL + '/api/v1/pages.json').then(function(response) {
return response.data.entries;
});
});

ngHub.factory('pagesByUrl', function(pagesPromise) {
var result = {};

// populate asynchronously
pagesPromise.then(function(docs) {
angular.forEach(docs, function(doc) {
result[doc.url] = doc;
});
});

return result;
});

ngHub.factory('pageIndex', function(pagesPromise) {
var index = lunr(function() {
this.ref('url');

this.field('title', {boost: 10});
this.field('url', {boost: 5});
this.field('body');
});

// populate asynchronously
pagesPromise.then(function(docs) {
angular.forEach(docs, function(page) {
index.add(page);
});
});

return index;
});

ngHub.factory('pagesSearch', function(pagesByUrl, pageIndex) {
return function(term) {
var results = pageIndex.search(term);
angular.forEach(results, function(result) {
var page = pagesByUrl[result.ref];
result.page = page;
// make top-level attribute available for LiveSearch
result.displayTitle = page.title || page.url;
});
return results;
};
});

// based on https://github.com/angular/angular.js/blob/54ddca537/docs/app/src/search.js#L198-L206
ngHub.factory('searchUi', function($document) {
var isForwardSlash = function(keyCode) {
return keyCode === 191;
};

var isInput = function(el) {
var tagName = el.tagName.toLowerCase();
return tagName === 'input';
};

var giveSearchFocus = function() {
var input = angular.element('#search1')[0];
input.focus();
};

var onKeyDown = function(event) {
if (isForwardSlash(event.keyCode) && !isInput(document.activeElement)) {
event.stopPropagation();
event.preventDefault();
giveSearchFocus();
}
};

return {
enableGlobalShortcut: function() {
angular.element($document[0].body).on('keydown', onKeyDown);
},

getSelectedResult: function() {
// TODO find a less hacky way to retrieve this
var selectionScope = angular.element('.searchresultspopup').scope();
var resultIndex = selectionScope.selectedIndex;
return selectionScope.results[resultIndex];
}
};
});

ngHub.controller('SearchController', function($scope, $q, searchUi, pagesSearch) {
searchUi.enableGlobalShortcut();

var isEnter = function(keyCode) {
return keyCode === 13;
}

$scope.searchKeyDown = function($event) {
if (isEnter($event.keyCode)) {
var result = searchUi.getSelectedResult();
window.location = result.page.url;
}
};

$scope.searchCallback = function(params) {
var defer = $q.defer();
var results = pagesSearch(params.query);
defer.resolve(results);
return defer.promise;
};
});
2 changes: 2 additions & 0 deletions _config_public.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ generated_page_title_format: '%s — 18F Public Hub'
public: true
destination: _site_public/hub
baseurl: /hub
assets:
baseurl: /hub/assets
4 changes: 4 additions & 0 deletions _includes/head.html
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@
================================================== -->
<script src="{{ site.baseurl }}/assets/js/jquery-2.1.1.min.js"></script>
<script src="{{ site.baseurl }}/assets/js/responsiveslides.min.js"></script>
<script>
SITE_BASEURL = '{{site.baseurl}}';
</script>
{% javascript search %}

<!-- IE
================================================== -->
Expand Down
27 changes: 21 additions & 6 deletions _layouts/bare.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,27 @@

<section class="container bare">

<div class="bare-content" role="main" itemscope itemprop="mainContentOfPage">

{{ content }}

{% include edit_link.html %}

<div ng-app="hubSearch" ng-controller="SearchController" class="bare-content" role="main" itemscope itemprop="mainContentOfPage">
{% raw %}
<div>
<live-search id="search1" type="text"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of an id here concerns me. Why is there a "1"? What if another search for has to be included on the page? Could this be made modular instead?

live-search-callback="searchCallback"
live-search-item-template="<a href='{{result.page.url}}'>{{result.page.title || result.page.url}}</a>"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That a tag could probably use a title tag for 508 compliance.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What should be in there? Seems like it's not necessary since the text is displayed:

http://stackoverflow.com/questions/5997371/is-the-title-attribute-for-links-required-for-508-compliance

/cc @nickbristow

live-search-select="displayTitle"
live-search-max-result-size="20"
ng-model="searchText"
ng-keydown="searchKeyDown($event)"
placeholder="Search – click or press '/'"
></live-search>
</div>
<div ng-hide="searchText">
{% endraw %}
{{ content }}

{% include edit_link.html %}
{% raw %}
</div>
{% endraw %}
</div>

</section>
Expand Down
4 changes: 4 additions & 0 deletions assets/_sass/_hub.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// hub.18F.gsa.gov CUSTOM SASS
//********************************************************

@import "_search";

// Site-wide media queries
//********************************************************
.news {
Expand Down Expand Up @@ -207,6 +209,8 @@ ul li {
//********************************************************

.bare-content {
padding-top: 2em;

h1 {
margin-top: 0.5em;
margin-bottom: 0.5em;
Expand Down
36 changes: 36 additions & 0 deletions assets/_sass/_search.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// https://github.com/mauriciogentile/angular-livesearch/blob/1f4e357ab3b50701eeedcfb45c12cd901d612087/example/styles.css#L31-L65
ul.searchresultspopup {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need the ul here? Why is .searchresultspopup not specific enough?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, I copied-and-pasted this file from the URL above – didn't really spend any time cleaning it up. Worth a pass to delete anything we don't need, I gueeeeesssss 😑

border: #a4bed4 1px solid;
margin-top: 0px;
padding: 0px;
z-index: 99999!important;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its pretty dangerous to start using z-indexes without organizing them. you could end up having 9999999 next time. I suggest making sass variables for z-indexes.

position: fixed;
background-color: white;
/*max-height:200px;*/
border-collapse: separate;
overflow-y: hidden;

li {
cursor: pointer;
padding-left: 1px;
text-align: left;
list-style: none;
line-height: 20px;
list-style-image: none;
list-style-position: outside;
list-style-type: none;
}

li.selected,
li:hover {
background-color: #ededed;
}

b {
color: blue;
}

strong {
color: green;
}
}
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"requirejs": "~2.1.15"
},
"install": {
"path": "assets/js/vendor",
"path": "_assets/javascripts/vendor",
"sources": {
"angular-livesearch": "bower_components/angular-livesearch/liveSearch.js",
"requirejs": "bower_components/requirejs/require.js"
Expand Down