From dfc81c3dab06dd45ad2fb9a27b29d127ada7272d Mon Sep 17 00:00:00 2001 From: Ward Bell Date: Sat, 15 Apr 2017 00:04:34 -0700 Subject: [PATCH] feat(aio): sort search results by area/title MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Display area names in all caps Exclude results with no title because they don’t show & can’t be clicked. Should find these and give their docs a title. --- .../search-results.component.spec.ts | 43 ++++++++++++++++--- .../search-results.component.ts | 13 +++++- aio/src/styles/1-layouts/_search-results.scss | 3 +- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/aio/src/app/search/search-results/search-results.component.spec.ts b/aio/src/app/search/search-results/search-results.component.spec.ts index 14b37e9d36..d6beda7214 100644 --- a/aio/src/app/search/search-results/search-results.component.spec.ts +++ b/aio/src/app/search/search-results/search-results.component.spec.ts @@ -42,30 +42,63 @@ describe('SearchResultsComponent', () => { searchResults.next({ query: '', results: results}); expect(currentAreas).toEqual([ + { name: 'api', pages: [ + { path: 'api/c', title: 'API C', type: 'class', keywords: '', titleWords: '' } + ] }, { name: 'guide', pages: [ { path: 'guide/a', title: 'Guide A', type: 'content', keywords: '', titleWords: '' }, { path: 'guide/b', title: 'Guide B', type: 'content', keywords: '', titleWords: '' }, { path: 'guide/b/c', title: 'Guide B - C', type: 'content', keywords: '', titleWords: '' } - ] }, - { name: 'api', pages: [ - { path: 'api/c', title: 'API C', type: 'class', keywords: '', titleWords: '' } ] } ]); }); - it('should put search results with no containing folder into the default area (Other)', () => { + it('should sort by title within sorted area', () => { + const results = [ + {path: 'guide/b', title: 'Guide B', type: 'content', keywords: '', titleWords: '' }, + {path: 'guide/a', title: 'Guide A', type: 'content', keywords: '', titleWords: '' }, + {path: 'api/d', title: 'API D', type: 'class', keywords: '', titleWords: '' }, + {path: 'guide/a/c', title: 'Guide A - C', type: 'content', keywords: '', titleWords: '' }, + {path: 'api/c', title: 'API C', type: 'class', keywords: '', titleWords: '' }, + ]; + + searchResults.next({ query: '', results: results }); + + expect(currentAreas).toEqual([ + { name: 'api', pages: [ + {path: 'api/c', title: 'API C', type: 'class', keywords: '', titleWords: '' }, + {path: 'api/d', title: 'API D', type: 'class', keywords: '', titleWords: '' }, + ] }, + { name: 'guide', pages: [ + {path: 'guide/a', title: 'Guide A', type: 'content', keywords: '', titleWords: '' }, + {path: 'guide/a/c', title: 'Guide A - C', type: 'content', keywords: '', titleWords: '' }, + {path: 'guide/b', title: 'Guide B', type: 'content', keywords: '', titleWords: '' }, + ] } + ]); + }); + + it('should put search results with no containing folder into the default area (other)', () => { const results = [ {path: 'news', title: 'News', type: 'marketing', keywords: '', titleWords: '' } ]; searchResults.next({ query: '', results: results }); expect(currentAreas).toEqual([ - { name: 'Other', pages: [ + { name: 'other', pages: [ { path: 'news', title: 'News', type: 'marketing', keywords: '', titleWords: '' } ] } ]); }); + it('should omit search results with no title', () => { + const results = [ + {path: 'news', title: undefined, type: 'marketing', keywords: '', titleWords: '' } + ]; + + searchResults.next({ query: '', results: results }); + expect(currentAreas).toEqual([]); + }); + it('should emit an "resultSelected" event when a search result anchor is clicked', () => { let selectedResult: SearchResult; component.resultSelected.subscribe((result: SearchResult) => selectedResult = result); diff --git a/aio/src/app/search/search-results/search-results.component.ts b/aio/src/app/search/search-results/search-results.component.ts index 8f2a189bcd..93a64751d3 100644 --- a/aio/src/app/search/search-results/search-results.component.ts +++ b/aio/src/app/search/search-results/search-results.component.ts @@ -18,7 +18,7 @@ export interface SearchArea { }) export class SearchResultsComponent implements OnInit { - readonly defaultArea = 'Other'; + readonly defaultArea = 'other'; showResults = false; @@ -57,11 +57,16 @@ export class SearchResultsComponent implements OnInit { this.showResults = true; 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); }); - return Object.keys(searchAreaMap).map(name => ({ name, pages: searchAreaMap[name] })); + const keys = Object.keys(searchAreaMap).sort((l, r) => l > r ? 1 : -1); + return keys.map(name => ({ + name, + pages: searchAreaMap[name].sort(compareResults) + })); } // Split the search result path and use the top level folder, if there is one, as the area name. @@ -70,3 +75,7 @@ export class SearchResultsComponent implements OnInit { return rest && areaName; } } + +function compareResults(l: {title: string}, r: {title: string}) { + return l.title.toUpperCase() > r.title.toUpperCase() ? 1 : -1; +} diff --git a/aio/src/styles/1-layouts/_search-results.scss b/aio/src/styles/1-layouts/_search-results.scss index 9f6b39e794..38a0f509d0 100644 --- a/aio/src/styles/1-layouts/_search-results.scss +++ b/aio/src/styles/1-layouts/_search-results.scss @@ -37,6 +37,7 @@ aio-search-results { h2 { font-size: 16px; margin: 10px 0px 5px; + text-transform: uppercase; } a { font-size: 14px; @@ -56,4 +57,4 @@ aio-search-results { width: 100%; display: block; } -} \ No newline at end of file +}