FEATURE: up/down arrow will highlight search result
Then you can use enter to visit result.
This commit is contained in:
parent
f9ff06b9d4
commit
304379d436
|
@ -20,13 +20,18 @@ class Highlighted extends RawHtml {
|
|||
function createSearchResult({ type, linkField, builder }) {
|
||||
return createWidget(`search-result-${type}`, {
|
||||
html(attrs) {
|
||||
return attrs.results.map(r => {
|
||||
|
||||
let i=-1;
|
||||
|
||||
return attrs.results.map(r => {
|
||||
i+=1;
|
||||
let searchResultId;
|
||||
if (type === "topic") {
|
||||
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),
|
||||
contents: () => builder.call(this, r, attrs.term),
|
||||
className: 'search-link',
|
||||
|
@ -126,7 +131,8 @@ createWidget('search-menu-results', {
|
|||
searchContextEnabled: attrs.searchContextEnabled,
|
||||
searchLogId: attrs.results.grouped_search_result.search_log_id,
|
||||
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)
|
||||
];
|
||||
|
|
|
@ -9,7 +9,8 @@ const searchData = {
|
|||
noResults: false,
|
||||
term: undefined,
|
||||
typeFilter: null,
|
||||
invalidTerm: false
|
||||
invalidTerm: false,
|
||||
selected: null
|
||||
};
|
||||
|
||||
// Helps with debouncing and cancelling promises
|
||||
|
@ -132,7 +133,8 @@ export default createWidget('search-menu', {
|
|||
noResults: searchData.noResults,
|
||||
results: searchData.results,
|
||||
invalidTerm: searchData.invalidTerm,
|
||||
searchContextEnabled: searchData.contextEnabled
|
||||
searchContextEnabled: searchData.contextEnabled,
|
||||
selected: searchData.selected
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -169,6 +171,81 @@ export default createWidget('search-menu', {
|
|||
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() {
|
||||
searchData.noResults = false;
|
||||
this.searchService().set('highlightTerm', searchData.term);
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
}
|
||||
|
||||
.menu-panel {
|
||||
border: 1px solid $primary-low;
|
||||
border: 1px solid $primary-low;
|
||||
box-shadow: 0 2px 2px rgba(0,0,0, .25);
|
||||
background-color: $secondary;
|
||||
z-index: 1100;
|
||||
|
@ -148,6 +148,13 @@
|
|||
padding: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
li.selected {
|
||||
background-color: $highlight-medium;
|
||||
}
|
||||
li:focus {
|
||||
outline: none;
|
||||
}
|
||||
.filter {
|
||||
padding: 0;
|
||||
&:hover {background: transparent;}
|
||||
|
|
Loading…
Reference in New Issue