diff --git a/aio/src/app/app.component.html b/aio/src/app/app.component.html index 6ecd5b23eb..92fe8e1db0 100644 --- a/aio/src/app/app.component.html +++ b/aio/src/app/app.component.html @@ -1,7 +1,7 @@ - + @@ -13,7 +13,7 @@
- +
diff --git a/aio/src/app/app.component.spec.ts b/aio/src/app/app.component.spec.ts index a668074a44..f8c9312d54 100644 --- a/aio/src/app/app.component.spec.ts +++ b/aio/src/app/app.component.spec.ts @@ -1,9 +1,12 @@ import { async, inject, ComponentFixture, TestBed } from '@angular/core/testing'; import { APP_BASE_HREF } from '@angular/common'; +import { By } from '@angular/platform-browser'; import { AppComponent } from './app.component'; import { AppModule } from './app.module'; import { GaService } from 'app/shared/ga.service'; import { SearchService } from 'app/search/search.service'; +import { SearchResultsComponent } from 'app/search/search-results/search-results.component'; +import { SearchBoxComponent } from 'app/search/search-box/search-box.component'; import { MockSearchService } from 'testing/search.service'; import { LocationService } from 'app/shared/location.service'; import { MockLocationService } from 'testing/location.service'; @@ -84,6 +87,27 @@ describe('AppComponent', () => { anchorElement.click(); expect(location.handleAnchorClick).toHaveBeenCalledWith(anchorElement, 0, false, false); })); + + it('should intercept clicks not on the search elements and hide the search results', () => { + const searchResults: SearchResultsComponent = fixture.debugElement.query(By.directive(SearchResultsComponent)).componentInstance; + const docViewer = fixture.debugElement.query(By.css('aio-doc-viewer')); + spyOn(searchResults, 'hideResults'); + docViewer.nativeElement.click(); + expect(searchResults.hideResults).toHaveBeenCalled(); + }); + + it('should not intercept clicks on any of the search elements', () => { + const searchResults = fixture.debugElement.query(By.directive(SearchResultsComponent)); + const searchResultsComponent: SearchResultsComponent = searchResults.componentInstance; + const searchBox = fixture.debugElement.query(By.directive(SearchBoxComponent)); + spyOn(searchResultsComponent, 'hideResults'); + + searchResults.nativeElement.click(); + expect(searchResultsComponent.hideResults).not.toHaveBeenCalled(); + + searchBox.nativeElement.click(); + expect(searchResultsComponent.hideResults).not.toHaveBeenCalled(); + }); }); }); diff --git a/aio/src/app/app.component.ts b/aio/src/app/app.component.ts index 874fdf24d6..4f131a3f8d 100644 --- a/aio/src/app/app.component.ts +++ b/aio/src/app/app.component.ts @@ -1,4 +1,4 @@ -import { Component, HostListener, ViewChild, OnInit } from '@angular/core'; +import { Component, ElementRef, HostListener, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core'; import { Observable } from 'rxjs/Observable'; import { GaService } from 'app/shared/ga.service'; @@ -6,6 +6,7 @@ import { LocationService } from 'app/shared/location.service'; import { DocumentService, DocumentContents } from 'app/documents/document.service'; import { NavigationService, NavigationViews, NavigationNode } from 'app/navigation/navigation.service'; import { SearchService } from 'app/search/search.service'; +import { SearchResultsComponent } from 'app/search/search-results/search-results.component'; @Component({ selector: 'aio-shell', @@ -23,13 +24,18 @@ export class AppComponent implements OnInit { navigationViews: Observable; selectedNodes: Observable; - constructor( - documentService: DocumentService, - gaService: GaService, - private locationService: LocationService, - navigationService: NavigationService, - private searchService: SearchService) { + @ViewChildren('searchBox, searchResults', { read: ElementRef }) + searchElements: QueryList; + @ViewChild(SearchResultsComponent) + searchResults: SearchResultsComponent; + + constructor( + documentService: DocumentService, + gaService: GaService, + private locationService: LocationService, + navigationService: NavigationService, + private searchService: SearchService) { this.currentDocument = documentService.currentDocument; locationService.currentUrl.subscribe(url => gaService.locationChanged(url)); this.navigationViews = navigationService.navigationViews; @@ -50,6 +56,16 @@ export class AppComponent implements OnInit { @HostListener('click', ['$event.target', '$event.button', '$event.ctrlKey', '$event.metaKey']) onClick(eventTarget: HTMLElement, button: number, ctrlKey: boolean, metaKey: boolean): boolean { + + // Hide the search results if we clicked outside both the search box and the search results + if (this.searchResults) { + const hits = this.searchElements.filter(element => element.nativeElement.contains(eventTarget)); + if (hits.length === 0) { + this.searchResults.hideResults(); + } + } + + // Deal with anchor clicks if (eventTarget instanceof HTMLAnchorElement) { return this.locationService.handleAnchorClick(eventTarget, button, ctrlKey, metaKey); }