This repository has been archived by the owner on Dec 8, 2017. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #80 from 18F/lunr-search
add client-side search
- Loading branch information
Showing
13 changed files
with
216 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
}; | ||
}); |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 { | ||
border: #a4bed4 1px solid; | ||
margin-top: 0px; | ||
padding: 0px; | ||
z-index: 99999!important; | ||
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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters