-
Notifications
You must be signed in to change notification settings - Fork 33
add client-side search #80
Changes from all commits
63e9e58
dc6fb06
4ced1cc
c77de82
833eae5
5e53b0f
0faf218
688bb41
a3fca59
ca160f5
2ff2495
a0b2aef
38e1c0c
ca72e5c
449ba9e
1e7d11e
8c3ad82
a0b396f
56796d4
b0d1ec5
24caedf
6c3db2d
a4b9493
d1d1142
c62da21
a2508a5
d7c8e9f
2af3979
3a7421d
fc37050
deb6027
6daf8f4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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; | ||
}; | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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" | ||
live-search-callback="searchCallback" | ||
live-search-item-template="<a href='{{result.page.url}}'>{{result.page.title || result.page.url}}</a>" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That a tag could probably use a title tag for 508 compliance. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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: /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> | ||
|
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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
} | ||
} |
There was a problem hiding this comment.
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?