Skip to content

Commit db27a85

Browse files
committed
feat(viewport-ruler): add common window resize handler
Moves the `FocusOriginMonitor` into `@angular/cdk/a11y`, renames it to `FocusMonitor`, deprecates the `StyleModule` and updates all the references. BREAKING CHANGE: `FocusOriginMonitor` has been renamed to `FocusMonitor`.
1 parent 881630f commit db27a85

9 files changed

+45
-99
lines changed

src/cdk/scrolling/scroll-dispatcher.spec.ts

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ describe('Scroll Dispatcher', () => {
7272

7373
scroll.scrolled(0, () => {});
7474
dispatchFakeEvent(document, 'scroll');
75+
dispatchFakeEvent(window, 'resize');
7576

7677
expect(spy).not.toHaveBeenCalled();
7778
subscription.unsubscribe();

src/cdk/scrolling/scroll-dispatcher.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {Platform} from '@angular/cdk/platform';
1111
import {Subject} from 'rxjs/Subject';
1212
import {Subscription} from 'rxjs/Subscription';
1313
import {fromEvent} from 'rxjs/observable/fromEvent';
14+
import {merge} from 'rxjs/observable/merge';
1415
import {auditTime} from 'rxjs/operator/auditTime';
1516
import {Scrollable} from './scrollable';
1617

@@ -86,7 +87,10 @@ export class ScrollDispatcher {
8687

8788
if (!this._globalSubscription) {
8889
this._globalSubscription = this._ngZone.runOutsideAngular(() => {
89-
return fromEvent(window.document, 'scroll').subscribe(() => this._notify());
90+
return merge(
91+
fromEvent(window.document, 'scroll'),
92+
fromEvent(window, 'resize')
93+
).subscribe(() => this._notify());
9094
});
9195
}
9296

src/cdk/scrolling/viewport-ruler.spec.ts

+1-39
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import {TestBed, inject, fakeAsync, tick} from '@angular/core/testing';
1+
import {TestBed, inject} from '@angular/core/testing';
22
import {ScrollDispatchModule} from './public_api';
33
import {ViewportRuler, VIEWPORT_RULER_PROVIDER} from './viewport-ruler';
4-
import {dispatchFakeEvent} from '@angular/cdk/testing';
54

65

76
// For all tests, we assume the browser window is 1024x786 (outerWidth x outerHeight).
@@ -33,10 +32,6 @@ describe('ViewportRuler', () => {
3332
scrollTo(0, 0);
3433
}));
3534

36-
afterEach(() => {
37-
ruler.ngOnDestroy();
38-
});
39-
4035
it('should get the viewport bounds when the page is not scrolled', () => {
4136
let bounds = ruler.getViewportRect();
4237
expect(bounds.top).toBe(0);
@@ -106,37 +101,4 @@ describe('ViewportRuler', () => {
106101

107102
document.body.removeChild(veryLargeElement);
108103
});
109-
110-
describe('changed event', () => {
111-
it('should dispatch an event when the window is resized', () => {
112-
const spy = jasmine.createSpy('viewport changed spy');
113-
const subscription = ruler.change(0).subscribe(spy);
114-
115-
dispatchFakeEvent(window, 'resize');
116-
expect(spy).toHaveBeenCalled();
117-
subscription.unsubscribe();
118-
});
119-
120-
it('should dispatch an event when the orientation is changed', () => {
121-
const spy = jasmine.createSpy('viewport changed spy');
122-
const subscription = ruler.change(0).subscribe(spy);
123-
124-
dispatchFakeEvent(window, 'orientationchange');
125-
expect(spy).toHaveBeenCalled();
126-
subscription.unsubscribe();
127-
});
128-
129-
it('should be able to throttle the callback', fakeAsync(() => {
130-
const spy = jasmine.createSpy('viewport changed spy');
131-
const subscription = ruler.change(1337).subscribe(spy);
132-
133-
dispatchFakeEvent(window, 'resize');
134-
expect(spy).not.toHaveBeenCalled();
135-
136-
tick(1337);
137-
138-
expect(spy).toHaveBeenCalledTimes(1);
139-
subscription.unsubscribe();
140-
}));
141-
});
142104
});

src/cdk/scrolling/viewport-ruler.ts

+9-43
Original file line numberDiff line numberDiff line change
@@ -6,49 +6,23 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {Injectable, Optional, SkipSelf, NgZone, OnDestroy} from '@angular/core';
10-
import {Platform} from '@angular/cdk/platform';
9+
import {Injectable, Optional, SkipSelf} from '@angular/core';
1110
import {ScrollDispatcher} from './scroll-dispatcher';
12-
import {Observable} from 'rxjs/Observable';
13-
import {fromEvent} from 'rxjs/observable/fromEvent';
14-
import {merge} from 'rxjs/observable/merge';
15-
import {auditTime} from 'rxjs/operator/auditTime';
16-
import {Subscription} from 'rxjs/Subscription';
17-
import {of as observableOf} from 'rxjs/observable/of';
1811

19-
/** Time in ms to throttle the resize events by default. */
20-
export const DEFAULT_RESIZE_TIME = 20;
2112

2213
/**
2314
* Simple utility for getting the bounds of the browser viewport.
2415
* @docs-private
2516
*/
2617
@Injectable()
27-
export class ViewportRuler implements OnDestroy {
18+
export class ViewportRuler {
2819

2920
/** Cached document client rectangle. */
3021
private _documentRect?: ClientRect;
3122

32-
/** Stream of viewport change events. */
33-
private _change: Observable<Event>;
34-
35-
/** Subscriptions to streams that invalidate the cached viewport dimensions. */
36-
private _invalidateCacheSubscriptions: Subscription[];
37-
38-
constructor(platform: Platform, ngZone: NgZone, scrollDispatcher: ScrollDispatcher) {
39-
this._change = platform.isBrowser ? ngZone.runOutsideAngular(() => {
40-
return merge<Event>(fromEvent(window, 'resize'), fromEvent(window, 'orientationchange'));
41-
}) : observableOf();
42-
23+
constructor(scrollDispatcher: ScrollDispatcher) {
4324
// Subscribe to scroll and resize events and update the document rectangle on changes.
44-
this._invalidateCacheSubscriptions = [
45-
scrollDispatcher.scrolled(0, () => this._cacheViewportGeometry()),
46-
this.change().subscribe(() => this._cacheViewportGeometry())
47-
];
48-
}
49-
50-
ngOnDestroy() {
51-
this._invalidateCacheSubscriptions.forEach(subscription => subscription.unsubscribe());
25+
scrollDispatcher.scrolled(0, () => this._cacheViewportGeometry());
5226
}
5327

5428
/** Gets a ClientRect for the viewport's bounds. */
@@ -82,6 +56,7 @@ export class ViewportRuler implements OnDestroy {
8256
};
8357
}
8458

59+
8560
/**
8661
* Gets the (top, left) scroll position of the viewport.
8762
* @param documentRect
@@ -100,40 +75,31 @@ export class ViewportRuler implements OnDestroy {
10075
// `document.documentElement` works consistently, where the `top` and `left` values will
10176
// equal negative the scroll position.
10277
const top = -documentRect!.top || document.body.scrollTop || window.scrollY ||
103-
document.documentElement.scrollTop || 0;
78+
document.documentElement.scrollTop || 0;
10479

10580
const left = -documentRect!.left || document.body.scrollLeft || window.scrollX ||
10681
document.documentElement.scrollLeft || 0;
10782

10883
return {top, left};
10984
}
11085

111-
/**
112-
* Returns a stream that emits whenever the size of the viewport changes.
113-
* @param throttle Time in milliseconds to throttle the stream.
114-
*/
115-
change(throttleTime: number = DEFAULT_RESIZE_TIME): Observable<string> {
116-
return throttleTime > 0 ? auditTime.call(this._change, throttleTime) : this._change;
117-
}
118-
11986
/** Caches the latest client rectangle of the document element. */
12087
_cacheViewportGeometry() {
12188
this._documentRect = document.documentElement.getBoundingClientRect();
12289
}
90+
12391
}
12492

12593
/** @docs-private */
12694
export function VIEWPORT_RULER_PROVIDER_FACTORY(parentRuler: ViewportRuler,
127-
platform: Platform,
128-
ngZone: NgZone,
12995
scrollDispatcher: ScrollDispatcher) {
130-
return parentRuler || new ViewportRuler(platform, ngZone, scrollDispatcher);
96+
return parentRuler || new ViewportRuler(scrollDispatcher);
13197
}
13298

13399
/** @docs-private */
134100
export const VIEWPORT_RULER_PROVIDER = {
135101
// If there is already a ViewportRuler available, use that. Otherwise, provide a new one.
136102
provide: ViewportRuler,
137-
deps: [[new Optional(), new SkipSelf(), ViewportRuler], Platform, NgZone, ScrollDispatcher],
103+
deps: [[new Optional(), new SkipSelf(), ViewportRuler], ScrollDispatcher],
138104
useFactory: VIEWPORT_RULER_PROVIDER_FACTORY
139105
};

src/lib/tabs/tab-group.spec.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import {async, ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/t
22
import {Component, QueryList, ViewChild, ViewChildren} from '@angular/core';
33
import {BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations';
44
import {By} from '@angular/platform-browser';
5-
import {dispatchFakeEvent} from '@angular/cdk/testing';
5+
import {ViewportRuler} from '@angular/cdk/scrolling';
6+
import {dispatchFakeEvent, FakeViewportRuler} from '@angular/cdk/testing';
67
import {Observable} from 'rxjs/Observable';
78
import {MdTab, MdTabGroup, MdTabHeaderPosition, MdTabsModule} from './index';
89

@@ -18,6 +19,9 @@ describe('MdTabGroup', () => {
1819
AsyncTabsTestApp,
1920
DisabledTabsTestApp,
2021
TabGroupWithSimpleApi,
22+
],
23+
providers: [
24+
{provide: ViewportRuler, useClass: FakeViewportRuler},
2125
]
2226
});
2327

src/lib/tabs/tab-header.spec.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ import {CommonModule} from '@angular/common';
66
import {By} from '@angular/platform-browser';
77
import {ENTER, LEFT_ARROW, RIGHT_ARROW, SPACE} from '@angular/cdk/keycodes';
88
import {PortalModule} from '@angular/cdk/portal';
9+
import {ViewportRuler} from '@angular/cdk/scrolling';
910
import {Direction, Directionality} from '@angular/cdk/bidi';
10-
import {dispatchFakeEvent, dispatchKeyboardEvent} from '@angular/cdk/testing';
11+
import {dispatchFakeEvent, dispatchKeyboardEvent, FakeViewportRuler} from '@angular/cdk/testing';
1112
import {MdTabHeader} from './tab-header';
1213
import {MdRippleModule} from '../core/ripple/index';
1314
import {MdInkBar} from './ink-bar';
@@ -34,6 +35,7 @@ describe('MdTabHeader', () => {
3435
],
3536
providers: [
3637
{provide: Directionality, useFactory: () => ({value: dir, change: change.asObservable()})},
38+
{provide: ViewportRuler, useClass: FakeViewportRuler},
3739
]
3840
});
3941

src/lib/tabs/tab-header.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,14 @@ import {
2626
} from '@angular/core';
2727
import {Directionality, Direction} from '@angular/cdk/bidi';
2828
import {RIGHT_ARROW, LEFT_ARROW, ENTER, SPACE} from '@angular/cdk/keycodes';
29-
import {startWith} from '@angular/cdk/rxjs';
29+
import {auditTime, startWith} from '@angular/cdk/rxjs';
3030
import {Subscription} from 'rxjs/Subscription';
3131
import {of as observableOf} from 'rxjs/observable/of';
3232
import {merge} from 'rxjs/observable/merge';
33+
import {fromEvent} from 'rxjs/observable/fromEvent';
3334
import {MdTabLabelWrapper} from './tab-label-wrapper';
3435
import {MdInkBar} from './ink-bar';
3536
import {CanDisableRipple, mixinDisableRipple} from '../core/common-behaviors/disable-ripple';
36-
import {ViewportRuler} from '@angular/cdk/scrolling';
3737

3838
/**
3939
* The directions that scrolling can go in when the header's tabs exceed the header width. 'After'
@@ -132,7 +132,6 @@ export class MdTabHeader extends _MdTabHeaderMixinBase
132132
constructor(private _elementRef: ElementRef,
133133
private _renderer: Renderer2,
134134
private _changeDetectorRef: ChangeDetectorRef,
135-
private _viewportRuler: ViewportRuler,
136135
@Optional() private _dir: Directionality) {
137136
super();
138137
}
@@ -185,7 +184,9 @@ export class MdTabHeader extends _MdTabHeaderMixinBase
185184
*/
186185
ngAfterContentInit() {
187186
const dirChange = this._dir ? this._dir.change : observableOf(null);
188-
const resize = this._viewportRuler.change(150);
187+
const resize = typeof window !== 'undefined' ?
188+
auditTime.call(fromEvent(window, 'resize'), 150) :
189+
observableOf(null);
189190

190191
this._realignInkBar = startWith.call(merge(dirChange, resize), null).subscribe(() => {
191192
this._updatePagination();

src/lib/tabs/tab-nav-bar/tab-nav-bar.spec.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import {async, ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing';
22
import {Component, ViewChild} from '@angular/core';
33
import {By} from '@angular/platform-browser';
4-
import {dispatchFakeEvent, dispatchMouseEvent} from '@angular/cdk/testing';
4+
import {ViewportRuler} from '@angular/cdk/scrolling';
5+
import {dispatchFakeEvent, dispatchMouseEvent, FakeViewportRuler} from '@angular/cdk/testing';
56
import {Direction, Directionality} from '@angular/cdk/bidi';
67
import {Subject} from 'rxjs/Subject';
78
import {MdTabNav, MdTabsModule, MdTabLink} from '../index';
@@ -22,7 +23,8 @@ describe('MdTabNavBar', () => {
2223
{provide: Directionality, useFactory: () => ({
2324
value: dir,
2425
change: dirChange.asObservable()
25-
})}
26+
})},
27+
{provide: ViewportRuler, useClass: FakeViewportRuler},
2628
]
2729
});
2830

@@ -171,7 +173,7 @@ describe('MdTabNavBar', () => {
171173
spyOn(inkBar, 'alignToElement');
172174

173175
dispatchFakeEvent(window, 'resize');
174-
tick(150);
176+
tick(10);
175177
fixture.detectChanges();
176178

177179
expect(inkBar.alignToElement).toHaveBeenCalled();

src/lib/tabs/tab-nav-bar/tab-nav-bar.ts

+11-7
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,11 @@ import {
2828
import {ViewportRuler} from '@angular/cdk/scrolling';
2929
import {Directionality} from '@angular/cdk/bidi';
3030
import {Platform} from '@angular/cdk/platform';
31-
import {takeUntil} from '@angular/cdk/rxjs';
31+
import {auditTime, takeUntil} from '@angular/cdk/rxjs';
3232
import {Subject} from 'rxjs/Subject';
3333
import {of as observableOf} from 'rxjs/observable/of';
3434
import {merge} from 'rxjs/observable/merge';
35+
import {fromEvent} from 'rxjs/observable/fromEvent';
3536
import {CanDisableRipple, mixinDisableRipple} from '../../core/common-behaviors/disable-ripple';
3637
import {coerceBooleanProperty} from '@angular/cdk/coercion';
3738
import {CanDisable, mixinDisabled} from '../../core/common-behaviors/disabled';
@@ -104,8 +105,7 @@ export class MdTabNav extends _MdTabNavMixinBase implements AfterContentInit, Ca
104105
elementRef: ElementRef,
105106
@Optional() private _dir: Directionality,
106107
private _ngZone: NgZone,
107-
private _changeDetectorRef: ChangeDetectorRef,
108-
private _viewportRuler: ViewportRuler) {
108+
private _changeDetectorRef: ChangeDetectorRef) {
109109
super(renderer, elementRef);
110110
}
111111

@@ -121,10 +121,14 @@ export class MdTabNav extends _MdTabNavMixinBase implements AfterContentInit, Ca
121121

122122
ngAfterContentInit(): void {
123123
this._ngZone.runOutsideAngular(() => {
124-
const dirChange = this._dir ? this._dir.change : observableOf(null);
125-
126-
return takeUntil.call(merge(dirChange, this._viewportRuler.change(10)), this._onDestroy)
127-
.subscribe(() => this._alignInkBar());
124+
let dirChange = this._dir ? this._dir.change : observableOf(null);
125+
let resize = typeof window !== 'undefined' ?
126+
auditTime.call(fromEvent(window, 'resize'), 10) :
127+
observableOf(null);
128+
129+
return takeUntil.call(merge(dirChange, resize), this._onDestroy).subscribe(() => {
130+
this._alignInkBar();
131+
});
128132
});
129133

130134
this._setLinkDisableRipple();

0 commit comments

Comments
 (0)