angular/aio/src/app/shared/search-results/search-results.component.ts
Peter Bacon Darwin 88c46feb20 refactor(aio): move SearchResultsComponent into shared module (#19682)
This will allow it to be used by an embedded component.

PR Close #19682
2017-10-13 09:18:42 -07:00

78 lines
2.4 KiB
TypeScript

import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { SearchResult, SearchResults, SearchArea } from 'app/search/interfaces';
/**
* A component to display search results in groups
*/
@Component({
selector: 'aio-search-results',
templateUrl: './search-results.component.html',
})
export class SearchResultsComponent implements OnChanges {
/**
* The results to display
*/
@Input()
searchResults: SearchResults;
/**
* Emitted when the user selects a search result
*/
@Output()
resultSelected = new EventEmitter<SearchResult>();
readonly defaultArea = 'other';
notFoundMessage = 'Searching ...';
readonly topLevelFolders = ['guide', 'tutorial'];
searchAreas: SearchArea[] = [];
ngOnChanges(changes: SimpleChanges) {
this.searchAreas = this.processSearchResults(this.searchResults);
}
onResultSelected(page: SearchResult, event: MouseEvent) {
// Emit a `resultSelected` event if the result is to be displayed on this page.
if (event.button === 0 && !event.ctrlKey && !event.metaKey) {
this.resultSelected.emit(page);
}
}
// Map the search results into groups by area
private processSearchResults(search: SearchResults) {
if (!search) {
return [];
}
this.notFoundMessage = 'No results found.';
const searchAreaMap = {};
search.results.forEach(result => {
if (!result.title) { return; } // bad data; should fix
const areaName = this.computeAreaName(result) || this.defaultArea;
const area = searchAreaMap[areaName] = searchAreaMap[areaName] || [];
area.push(result);
});
const keys = Object.keys(searchAreaMap).sort((l, r) => l > r ? 1 : -1);
return keys.map(name => {
let pages: SearchResult[] = searchAreaMap[name];
// Extract the top 5 most relevant results as priorityPages
const priorityPages = pages.splice(0, 5);
pages = pages.sort(compareResults);
return { name, pages, priorityPages };
});
}
// Split the search result path and use the top level folder, if there is one, as the area name.
private computeAreaName(result: SearchResult) {
if (this.topLevelFolders.indexOf(result.path) !== -1) {
return result.path;
}
const [areaName, rest] = result.path.split('/', 2);
return rest && areaName;
}
}
function compareResults(l: SearchResult, r: SearchResult) {
return l.title.toUpperCase() > r.title.toUpperCase() ? 1 : -1;
}