FEATURE: up/down arrow will highlight search result

Then you can use enter to visit result.
This commit is contained in:
Sam 2017-08-16 14:14:44 -04:00
parent f9ff06b9d4
commit 304379d436
3 changed files with 96 additions and 6 deletions

View File

@ -20,13 +20,18 @@ class Highlighted extends RawHtml {
function createSearchResult({ type, linkField, builder }) { function createSearchResult({ type, linkField, builder }) {
return createWidget(`search-result-${type}`, { return createWidget(`search-result-${type}`, {
html(attrs) { html(attrs) {
return attrs.results.map(r => {
let i=-1;
return attrs.results.map(r => {
i+=1;
let searchResultId; let searchResultId;
if (type === "topic") { if (type === "topic") {
searchResultId = r.get('topic_id'); searchResultId = r.get('topic_id');
} }
return h('li', this.attach('link', { let className = i === attrs.selected ? '.selected' : '';
return h('li' + className, { attributes: { tabindex: '-1' } }, this.attach('link', {
href: r.get(linkField), href: r.get(linkField),
contents: () => builder.call(this, r, attrs.term), contents: () => builder.call(this, r, attrs.term),
className: 'search-link', className: 'search-link',
@ -126,7 +131,8 @@ createWidget('search-menu-results', {
searchContextEnabled: attrs.searchContextEnabled, searchContextEnabled: attrs.searchContextEnabled,
searchLogId: attrs.results.grouped_search_result.search_log_id, searchLogId: attrs.results.grouped_search_result.search_log_id,
results: rt.results, results: rt.results,
term: attrs.term term: attrs.term,
selected: (attrs.selected && attrs.selected.type === rt.type) ? attrs.selected.index : -1
})), })),
h('div.no-results', more) h('div.no-results', more)
]; ];

View File

@ -9,7 +9,8 @@ const searchData = {
noResults: false, noResults: false,
term: undefined, term: undefined,
typeFilter: null, typeFilter: null,
invalidTerm: false invalidTerm: false,
selected: null
}; };
// Helps with debouncing and cancelling promises // Helps with debouncing and cancelling promises
@ -132,7 +133,8 @@ export default createWidget('search-menu', {
noResults: searchData.noResults, noResults: searchData.noResults,
results: searchData.results, results: searchData.results,
invalidTerm: searchData.invalidTerm, invalidTerm: searchData.invalidTerm,
searchContextEnabled: searchData.contextEnabled searchContextEnabled: searchData.contextEnabled,
selected: searchData.selected
})); }));
} }
} }
@ -169,6 +171,81 @@ export default createWidget('search-menu', {
this.sendWidgetAction('toggleSearchMenu'); this.sendWidgetAction('toggleSearchMenu');
}, },
keyDown(e) {
if (searchData.loading || searchData.noResults) {
return;
}
if (e.which === 13 /*enter*/ && searchData.selected) {
searchData.selected = null;
$('header .results li.selected a').click();
}
if (e.which === 38 /*arrow up*/ || e.which === 40 /*arrow down*/) {
this.moveSelected(e.which === 38 ? -1 : 1);
this.scheduleRerender();
Em.run.next(()=>{
if (searchData.selected) {
// so we do not clear selected
$('header .results li').off('blur');
let selected = $('header .results li.selected')
.focus()
.on('blur', ()=> {
searchData.selected = null;
this.scheduleRerender();
selected.off('blur');
});
} else {
$('#search-term').focus();
}
});
e.preventDefault();
return false;
}
},
moveSelected(offset) {
if (offset === 1 && !searchData.selected) {
searchData.selected = {type: searchData.results.resultTypes[0].type, index: 0};
return;
}
if (!searchData.selected) {
return;
}
let typeIndex = _.findIndex(searchData.results.resultTypes, item => item.type === searchData.selected.type);
if (typeIndex === 0 && searchData.selected.index === 0 && offset === -1) {
searchData.selected = null;
return;
}
let currentResults = searchData.results.resultTypes[typeIndex].results;
let newPosition = searchData.selected.index + offset;
if (newPosition < currentResults.length && newPosition >= 0) {
searchData.selected.index = newPosition;
} else {
// possibly move to next type
let newTypeIndex = typeIndex + offset;
if (newTypeIndex >= 0 && newTypeIndex < searchData.results.resultTypes.length) {
newPosition = 0;
if (offset === -1) {
newPosition = searchData.results.resultTypes[newTypeIndex].results.length - 1;
}
searchData.selected = {type: searchData.results.resultTypes[newTypeIndex].type, index: newPosition};
}
}
},
triggerSearch() { triggerSearch() {
searchData.noResults = false; searchData.noResults = false;
this.searchService().set('highlightTerm', searchData.term); this.searchService().set('highlightTerm', searchData.term);

View File

@ -148,6 +148,13 @@
padding: 5px; padding: 5px;
text-align: center; text-align: center;
} }
li.selected {
background-color: $highlight-medium;
}
li:focus {
outline: none;
}
.filter { .filter {
padding: 0; padding: 0;
&:hover {background: transparent;} &:hover {background: transparent;}