+
diff --git a/aio/src/app/app.component.spec.ts b/aio/src/app/app.component.spec.ts
index 6f9f995a75..531d9851a0 100644
--- a/aio/src/app/app.component.spec.ts
+++ b/aio/src/app/app.component.spec.ts
@@ -3,7 +3,7 @@ import { async, inject, ComponentFixture, TestBed, fakeAsync, tick } from '@angu
import { Title } from '@angular/platform-browser';
import { APP_BASE_HREF } from '@angular/common';
import { Http } from '@angular/http';
-import { MdProgressBar } from '@angular/material';
+import { MdProgressBar, MdSidenav } from '@angular/material';
import { By } from '@angular/platform-browser';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
@@ -27,7 +27,7 @@ import { SearchService } from 'app/search/search.service';
import { SelectComponent, Option } from 'app/shared/select/select.component';
import { SwUpdateNotificationsService } from 'app/sw-updates/sw-update-notifications.service';
import { TocComponent } from 'app/embedded/toc/toc.component';
-import { MdSidenav } from '@angular/material';
+import { TocItem, TocService } from 'app/shared/toc.service';
const sideBySideBreakPoint = 992;
const hideToCBreakPoint = 800;
@@ -40,6 +40,7 @@ describe('AppComponent', () => {
let hamburger: HTMLButtonElement;
let locationService: MockLocationService;
let sidenav: HTMLElement;
+ let tocService: TocService;
const initializeTest = () => {
fixture = TestBed.createComponent(AppComponent);
@@ -48,10 +49,12 @@ describe('AppComponent', () => {
fixture.detectChanges();
component.onResize(sideBySideBreakPoint + 1); // wide by default
- docViewer = fixture.debugElement.query(By.css('aio-doc-viewer')).nativeElement;
- hamburger = fixture.debugElement.query(By.css('.hamburger')).nativeElement;
- locationService = fixture.debugElement.injector.get(LocationService) as any;
- sidenav = fixture.debugElement.query(By.css('md-sidenav')).nativeElement;
+ const de = fixture.debugElement;
+ docViewer = de.query(By.css('aio-doc-viewer')).nativeElement;
+ hamburger = de.query(By.css('.hamburger')).nativeElement;
+ locationService = de.injector.get(LocationService) as any as MockLocationService;
+ sidenav = de.query(By.css('md-sidenav')).nativeElement;
+ tocService = de.injector.get(TocService);
};
describe('with proper DocViewer', () => {
@@ -72,19 +75,74 @@ describe('AppComponent', () => {
});
});
- describe('onResize', () => {
- it('should update `isSideBySide` accordingly', () => {
- component.onResize(sideBySideBreakPoint + 1);
- expect(component.isSideBySide).toBe(true);
- component.onResize(sideBySideBreakPoint - 1);
- expect(component.isSideBySide).toBe(false);
+ describe('hasFloatingToc', () => {
+ it('should initially be true', () => {
+ const fixture2 = TestBed.createComponent(AppComponent);
+ const component2 = fixture2.componentInstance;
+
+ expect(component2.hasFloatingToc).toBe(true);
});
- it('should update `showFloatingToc` accordingly', () => {
- component.onResize(hideToCBreakPoint + 1);
- expect(component.showFloatingToc).toBe(true);
+ it('should be false on narrow screens', () => {
component.onResize(hideToCBreakPoint - 1);
- expect(component.showFloatingToc).toBe(false);
+
+ tocService.tocList.next([{}, {}, {}] as TocItem[]);
+ expect(component.hasFloatingToc).toBe(false);
+
+ tocService.tocList.next([]);
+ expect(component.hasFloatingToc).toBe(false);
+
+ tocService.tocList.next([{}, {}, {}] as TocItem[]);
+ expect(component.hasFloatingToc).toBe(false);
+ });
+
+ it('should be true on wide screens unless the toc is empty', () => {
+ component.onResize(hideToCBreakPoint + 1);
+
+ tocService.tocList.next([{}, {}, {}] as TocItem[]);
+ expect(component.hasFloatingToc).toBe(true);
+
+ tocService.tocList.next([]);
+ expect(component.hasFloatingToc).toBe(false);
+
+ tocService.tocList.next([{}, {}, {}] as TocItem[]);
+ expect(component.hasFloatingToc).toBe(true);
+ });
+
+ it('should be false when toc is empty', () => {
+ tocService.tocList.next([]);
+
+ component.onResize(hideToCBreakPoint + 1);
+ expect(component.hasFloatingToc).toBe(false);
+
+ component.onResize(hideToCBreakPoint - 1);
+ expect(component.hasFloatingToc).toBe(false);
+
+ component.onResize(hideToCBreakPoint + 1);
+ expect(component.hasFloatingToc).toBe(false);
+ });
+
+ it('should be true when toc is not empty unless the screen is narrow', () => {
+ tocService.tocList.next([{}, {}, {}] as TocItem[]);
+
+ component.onResize(hideToCBreakPoint + 1);
+ expect(component.hasFloatingToc).toBe(true);
+
+ component.onResize(hideToCBreakPoint - 1);
+ expect(component.hasFloatingToc).toBe(false);
+
+ component.onResize(hideToCBreakPoint + 1);
+ expect(component.hasFloatingToc).toBe(true);
+ });
+ });
+
+ describe('isSideBySide', () => {
+ it('should be updated on resize', () => {
+ component.onResize(sideBySideBreakPoint - 1);
+ expect(component.isSideBySide).toBe(false);
+
+ component.onResize(sideBySideBreakPoint + 1);
+ expect(component.isSideBySide).toBe(true);
});
});
@@ -523,14 +581,31 @@ describe('AppComponent', () => {
let tocDebugElement: DebugElement;
let tocContainer: DebugElement;
- beforeEach(() => {
+ const setHasFloatingToc = hasFloatingToc => {
+ component.hasFloatingToc = hasFloatingToc;
+ fixture.detectChanges();
+
tocDebugElement = fixture.debugElement.query(By.directive(TocComponent));
- tocContainer = tocDebugElement.parent;
+ tocContainer = tocDebugElement && tocDebugElement.parent;
+ };
+
+ beforeEach(() => setHasFloatingToc(true));
+
+
+ it('should show/hide `
` based on `hasFloatingToc`', () => {
+ expect(tocDebugElement).toBeTruthy();
+ expect(tocContainer).toBeTruthy();
+
+ setHasFloatingToc(false);
+ expect(tocDebugElement).toBeFalsy();
+ expect(tocContainer).toBeFalsy();
+
+ setHasFloatingToc(true);
+ expect(tocDebugElement).toBeTruthy();
+ expect(tocContainer).toBeTruthy();
});
-
it('should have a non-embedded `` element', () => {
- expect(tocDebugElement).toBeDefined();
expect(tocDebugElement.classes['embedded']).toBeFalsy();
});
diff --git a/aio/src/app/app.component.ts b/aio/src/app/app.component.ts
index 7f20212c82..1f44e91a8a 100644
--- a/aio/src/app/app.component.ts
+++ b/aio/src/app/app.component.ts
@@ -12,7 +12,9 @@ import { SearchResultsComponent } from 'app/search/search-results/search-results
import { SearchBoxComponent } from 'app/search/search-box/search-box.component';
import { SearchService } from 'app/search/search.service';
import { SwUpdateNotificationsService } from 'app/sw-updates/sw-update-notifications.service';
+import { TocService } from 'app/shared/toc.service';
+import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { combineLatest } from 'rxjs/observable/combineLatest';
const sideNavView = 'SideNav';
@@ -65,8 +67,9 @@ export class AppComponent implements OnInit {
topMenuNodes: NavigationNode[];
topMenuNarrowNodes: NavigationNode[];
- showFloatingToc = false;
- showFloatingTocWidth = 800;
+ hasFloatingToc = true;
+ private showFloatingToc = new BehaviorSubject(false);
+ private showFloatingTocWidth = 800;
tocMaxHeight: string;
private tocMaxHeightOffset = 0;
@@ -103,8 +106,9 @@ export class AppComponent implements OnInit {
private navigationService: NavigationService,
private scrollService: ScrollService,
private searchService: SearchService,
- private swUpdateNotifications: SwUpdateNotificationsService
- ) { }
+ private swUpdateNotifications: SwUpdateNotificationsService,
+ private tocService: TocService
+ ) { }
ngOnInit() {
// Do not initialize the search on browsers that lack web worker support
@@ -174,6 +178,10 @@ export class AppComponent implements OnInit {
this.navigationService.versionInfo.subscribe( vi => this.versionInfo = vi );
this.swUpdateNotifications.enable();
+
+ const hasNonEmptyToc = this.tocService.tocList.map(tocList => tocList.length > 0);
+ combineLatest(hasNonEmptyToc, this.showFloatingToc)
+ .subscribe(([hasToc, showFloatingToc]) => this.hasFloatingToc = hasToc && showFloatingToc);
}
// Scroll to the anchor in the hash fragment or top of doc.
@@ -207,7 +215,7 @@ export class AppComponent implements OnInit {
@HostListener('window:resize', ['$event.target.innerWidth'])
onResize(width) {
this.isSideBySide = width > this.sideBySideWidth;
- this.showFloatingToc = width > this.showFloatingTocWidth;
+ this.showFloatingToc.next(width > this.showFloatingTocWidth);
}
@HostListener('click', ['$event.target', '$event.button', '$event.ctrlKey', '$event.metaKey', '$event.altKey'])
diff --git a/aio/src/styles/1-layouts/_sidenav.scss b/aio/src/styles/1-layouts/_sidenav.scss
index 2d97514fcb..fad21e9ac0 100644
--- a/aio/src/styles/1-layouts/_sidenav.scss
+++ b/aio/src/styles/1-layouts/_sidenav.scss
@@ -42,12 +42,12 @@ md-sidenav.mat-sidenav.sidenav {
md-sidenav-container.sidenav-container {
min-height: 100%;
height: auto !important;
- max-width: 82%;
+ max-width: 100%;
margin: 0;
transform: none;
- @media (max-width: 800px) {
- max-width: 100%;
+ &.has-floating-toc {
+ max-width: 82%;
}
}