fix(aio): expand the main content width when there is no ToC
Previously, the main content would always leave a 18% margin on the right to be occupied by the ToC (even if there was no ToC). This commit lets the main content expand to the right to occupy all the available space when there is no ToC. Fixes #17205 Fixes #17270
This commit is contained in:
parent
8524187869
commit
e894f5c399
|
@ -15,7 +15,7 @@
|
||||||
</md-toolbar>
|
</md-toolbar>
|
||||||
<aio-search-results #searchResults *ngIf="showSearchResults" (resultSelected)="hideSearchResults()"></aio-search-results>
|
<aio-search-results #searchResults *ngIf="showSearchResults" (resultSelected)="hideSearchResults()"></aio-search-results>
|
||||||
|
|
||||||
<md-sidenav-container class="sidenav-container" [class.starting]="isStarting" role="main">
|
<md-sidenav-container class="sidenav-container" [class.starting]="isStarting" [class.has-floating-toc]="hasFloatingToc" role="main">
|
||||||
|
|
||||||
<md-sidenav [ngClass]="{'collapsed': !isSideBySide }" #sidenav class="sidenav" [opened]="isOpened" [mode]="mode" (open)="updateHostClasses()" (close)="updateHostClasses()">
|
<md-sidenav [ngClass]="{'collapsed': !isSideBySide }" #sidenav class="sidenav" [opened]="isOpened" [mode]="mode" (open)="updateHostClasses()" (close)="updateHostClasses()">
|
||||||
<aio-nav-menu *ngIf="!isSideBySide" [nodes]="topMenuNarrowNodes" [currentNode]="currentNodes?.TopBarNarrow"></aio-nav-menu>
|
<aio-nav-menu *ngIf="!isSideBySide" [nodes]="topMenuNarrowNodes" [currentNode]="currentNodes?.TopBarNarrow"></aio-nav-menu>
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
|
|
||||||
</md-sidenav-container>
|
</md-sidenav-container>
|
||||||
|
|
||||||
<div *ngIf="showFloatingToc" class="toc-container" [style.max-height.px]="tocMaxHeight" (mousewheel)="restrainScrolling($event)">
|
<div *ngIf="hasFloatingToc" class="toc-container" [style.max-height.px]="tocMaxHeight" (mousewheel)="restrainScrolling($event)">
|
||||||
<aio-toc></aio-toc>
|
<aio-toc></aio-toc>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { async, inject, ComponentFixture, TestBed, fakeAsync, tick } from '@angu
|
||||||
import { Title } from '@angular/platform-browser';
|
import { Title } from '@angular/platform-browser';
|
||||||
import { APP_BASE_HREF } from '@angular/common';
|
import { APP_BASE_HREF } from '@angular/common';
|
||||||
import { Http } from '@angular/http';
|
import { Http } from '@angular/http';
|
||||||
import { MdProgressBar } from '@angular/material';
|
import { MdProgressBar, MdSidenav } from '@angular/material';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
|
|
||||||
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
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 { SelectComponent, Option } from 'app/shared/select/select.component';
|
||||||
import { SwUpdateNotificationsService } from 'app/sw-updates/sw-update-notifications.service';
|
import { SwUpdateNotificationsService } from 'app/sw-updates/sw-update-notifications.service';
|
||||||
import { TocComponent } from 'app/embedded/toc/toc.component';
|
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 sideBySideBreakPoint = 992;
|
||||||
const hideToCBreakPoint = 800;
|
const hideToCBreakPoint = 800;
|
||||||
|
@ -40,6 +40,7 @@ describe('AppComponent', () => {
|
||||||
let hamburger: HTMLButtonElement;
|
let hamburger: HTMLButtonElement;
|
||||||
let locationService: MockLocationService;
|
let locationService: MockLocationService;
|
||||||
let sidenav: HTMLElement;
|
let sidenav: HTMLElement;
|
||||||
|
let tocService: TocService;
|
||||||
|
|
||||||
const initializeTest = () => {
|
const initializeTest = () => {
|
||||||
fixture = TestBed.createComponent(AppComponent);
|
fixture = TestBed.createComponent(AppComponent);
|
||||||
|
@ -48,10 +49,12 @@ describe('AppComponent', () => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
component.onResize(sideBySideBreakPoint + 1); // wide by default
|
component.onResize(sideBySideBreakPoint + 1); // wide by default
|
||||||
|
|
||||||
docViewer = fixture.debugElement.query(By.css('aio-doc-viewer')).nativeElement;
|
const de = fixture.debugElement;
|
||||||
hamburger = fixture.debugElement.query(By.css('.hamburger')).nativeElement;
|
docViewer = de.query(By.css('aio-doc-viewer')).nativeElement;
|
||||||
locationService = fixture.debugElement.injector.get(LocationService) as any;
|
hamburger = de.query(By.css('.hamburger')).nativeElement;
|
||||||
sidenav = fixture.debugElement.query(By.css('md-sidenav')).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', () => {
|
describe('with proper DocViewer', () => {
|
||||||
|
@ -72,19 +75,74 @@ describe('AppComponent', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('onResize', () => {
|
describe('hasFloatingToc', () => {
|
||||||
it('should update `isSideBySide` accordingly', () => {
|
it('should initially be true', () => {
|
||||||
component.onResize(sideBySideBreakPoint + 1);
|
const fixture2 = TestBed.createComponent(AppComponent);
|
||||||
expect(component.isSideBySide).toBe(true);
|
const component2 = fixture2.componentInstance;
|
||||||
component.onResize(sideBySideBreakPoint - 1);
|
|
||||||
expect(component.isSideBySide).toBe(false);
|
expect(component2.hasFloatingToc).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update `showFloatingToc` accordingly', () => {
|
it('should be false on narrow screens', () => {
|
||||||
component.onResize(hideToCBreakPoint + 1);
|
|
||||||
expect(component.showFloatingToc).toBe(true);
|
|
||||||
component.onResize(hideToCBreakPoint - 1);
|
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 tocDebugElement: DebugElement;
|
||||||
let tocContainer: DebugElement;
|
let tocContainer: DebugElement;
|
||||||
|
|
||||||
beforeEach(() => {
|
const setHasFloatingToc = hasFloatingToc => {
|
||||||
|
component.hasFloatingToc = hasFloatingToc;
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
tocDebugElement = fixture.debugElement.query(By.directive(TocComponent));
|
tocDebugElement = fixture.debugElement.query(By.directive(TocComponent));
|
||||||
tocContainer = tocDebugElement.parent;
|
tocContainer = tocDebugElement && tocDebugElement.parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => setHasFloatingToc(true));
|
||||||
|
|
||||||
|
|
||||||
|
it('should show/hide `<aio-toc>` 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 `<aio-toc>` element', () => {
|
it('should have a non-embedded `<aio-toc>` element', () => {
|
||||||
expect(tocDebugElement).toBeDefined();
|
|
||||||
expect(tocDebugElement.classes['embedded']).toBeFalsy();
|
expect(tocDebugElement.classes['embedded']).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,9 @@ import { SearchResultsComponent } from 'app/search/search-results/search-results
|
||||||
import { SearchBoxComponent } from 'app/search/search-box/search-box.component';
|
import { SearchBoxComponent } from 'app/search/search-box/search-box.component';
|
||||||
import { SearchService } from 'app/search/search.service';
|
import { SearchService } from 'app/search/search.service';
|
||||||
import { SwUpdateNotificationsService } from 'app/sw-updates/sw-update-notifications.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';
|
import { combineLatest } from 'rxjs/observable/combineLatest';
|
||||||
|
|
||||||
const sideNavView = 'SideNav';
|
const sideNavView = 'SideNav';
|
||||||
|
@ -65,8 +67,9 @@ export class AppComponent implements OnInit {
|
||||||
topMenuNodes: NavigationNode[];
|
topMenuNodes: NavigationNode[];
|
||||||
topMenuNarrowNodes: NavigationNode[];
|
topMenuNarrowNodes: NavigationNode[];
|
||||||
|
|
||||||
showFloatingToc = false;
|
hasFloatingToc = true;
|
||||||
showFloatingTocWidth = 800;
|
private showFloatingToc = new BehaviorSubject(false);
|
||||||
|
private showFloatingTocWidth = 800;
|
||||||
tocMaxHeight: string;
|
tocMaxHeight: string;
|
||||||
private tocMaxHeightOffset = 0;
|
private tocMaxHeightOffset = 0;
|
||||||
|
|
||||||
|
@ -103,8 +106,9 @@ export class AppComponent implements OnInit {
|
||||||
private navigationService: NavigationService,
|
private navigationService: NavigationService,
|
||||||
private scrollService: ScrollService,
|
private scrollService: ScrollService,
|
||||||
private searchService: SearchService,
|
private searchService: SearchService,
|
||||||
private swUpdateNotifications: SwUpdateNotificationsService
|
private swUpdateNotifications: SwUpdateNotificationsService,
|
||||||
) { }
|
private tocService: TocService
|
||||||
|
) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
// Do not initialize the search on browsers that lack web worker support
|
// 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.navigationService.versionInfo.subscribe( vi => this.versionInfo = vi );
|
||||||
|
|
||||||
this.swUpdateNotifications.enable();
|
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.
|
// 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'])
|
@HostListener('window:resize', ['$event.target.innerWidth'])
|
||||||
onResize(width) {
|
onResize(width) {
|
||||||
this.isSideBySide = width > this.sideBySideWidth;
|
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'])
|
@HostListener('click', ['$event.target', '$event.button', '$event.ctrlKey', '$event.metaKey', '$event.altKey'])
|
||||||
|
|
|
@ -42,12 +42,12 @@ md-sidenav.mat-sidenav.sidenav {
|
||||||
md-sidenav-container.sidenav-container {
|
md-sidenav-container.sidenav-container {
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
height: auto !important;
|
height: auto !important;
|
||||||
max-width: 82%;
|
max-width: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
transform: none;
|
transform: none;
|
||||||
|
|
||||||
@media (max-width: 800px) {
|
&.has-floating-toc {
|
||||||
max-width: 100%;
|
max-width: 82%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue