From f90258162a1bf29be5a3dbcf62611afef3bc437f Mon Sep 17 00:00:00 2001 From: Ward Bell Date: Tue, 18 Apr 2017 12:13:13 -0700 Subject: [PATCH] fix(aio): handle clicks deep within anchor tags --- aio/src/app/app.component.spec.ts | 28 +++++++++++++++++++++++++--- aio/src/app/app.component.ts | 12 +++++++----- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/aio/src/app/app.component.spec.ts b/aio/src/app/app.component.spec.ts index ff16d977bf..ebeaba3273 100644 --- a/aio/src/app/app.component.spec.ts +++ b/aio/src/app/app.component.spec.ts @@ -308,13 +308,35 @@ describe('AppComponent', () => { describe('click intercepting', () => { it('should intercept clicks on anchors and call `location.handleAnchorClick()`', inject([LocationService], (location: LocationService) => { - const anchorElement: HTMLAnchorElement = document.createElement('a'); - anchorElement.href = 'some/local/url'; - fixture.nativeElement.append(anchorElement); + + const el = fixture.nativeElement as Element; + el.innerHTML = 'click me'; + const anchorElement = el.getElementsByTagName('a')[0]; anchorElement.click(); expect(location.handleAnchorClick).toHaveBeenCalledWith(anchorElement, 0, false, false); })); + it('should intercept clicks on elements deep within an anchor tag', + inject([LocationService], (location: LocationService) => { + + const el = fixture.nativeElement as Element; + el.innerHTML = '
'; + const imageElement = el.getElementsByTagName('img')[0]; + const anchorElement = el.getElementsByTagName('a')[0]; + imageElement.click(); + expect(location.handleAnchorClick).toHaveBeenCalledWith(anchorElement, 0, false, false); + })); + + it('should ignore clicks on elements without an anchor ancestor', + inject([LocationService], (location: LocationService) => { + + const el = fixture.nativeElement as Element; + el.innerHTML = '

'; + const imageElement = el.getElementsByTagName('img')[0]; + imageElement.click(); + expect(location.handleAnchorClick).not.toHaveBeenCalled(); + })); + it('should intercept clicks not on the search elements and hide the search results', () => { const searchResults: SearchResultsComponent = fixture.debugElement.query(By.directive(SearchResultsComponent)).componentInstance; spyOn(searchResults, 'hideResults'); diff --git a/aio/src/app/app.component.ts b/aio/src/app/app.component.ts index ad4ece0801..88db3bf41c 100644 --- a/aio/src/app/app.component.ts +++ b/aio/src/app/app.component.ts @@ -133,14 +133,16 @@ export class AppComponent implements OnInit { if (eventTarget.tagName === 'FOOTER' && metaKey && altKey) { this.dtOn = !this.dtOn; + return false; } - // Deal with anchor clicks - if (eventTarget instanceof HTMLImageElement) { - eventTarget = eventTarget.parentElement; // assume image wrapped in Anchor + // Deal with anchor clicks; climb DOM tree until anchor found (or null) + let target = eventTarget; + while (target && !(target instanceof HTMLAnchorElement)) { + target = target.parentElement; } - if (eventTarget instanceof HTMLAnchorElement) { - return this.locationService.handleAnchorClick(eventTarget, button, ctrlKey, metaKey); + if (target) { + return this.locationService.handleAnchorClick(target as HTMLAnchorElement, button, ctrlKey, metaKey); } return true; }