Skip to content

Commit aa8f837

Browse files
author
Tobias Schweizer
committed
Merge branch 'master' into tobiasschweizer/calendar-header-comp
# Conflicts: # src/lib/datepicker/datepicker-module.ts
2 parents 0faefc4 + 1417387 commit aa8f837

File tree

137 files changed

+2322
-1490
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

137 files changed

+2322
-1490
lines changed

.github/ISSUE_TEMPLATE.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@
88

99

1010
#### What are the steps to reproduce?
11-
Providing a StackBlitz/Plunker (or similar) is the *best* way to get the team to see your issue. <br/>
12-
Plunker starter (using on `@master`): https://goo.gl/uDmqyY<br/>
13-
StackBlitz starter (using latest `npm` release): https://goo.gl/wwnhMV<br/>
11+
Providing a StackBlitz reproduction is the *best* way to share your issue. <br/>
12+
StackBlitz starter: https://goo.gl/wwnhMV<br/>
1413

1514

1615
#### What is the use-case or motivation for changing an existing behavior?

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
/deploy
77
/screenshots
88

9+
# Example module file will be auto-generated.
10+
/src/material-examples/example-module.ts
11+
912
# dependencies
1013
node_modules
1114
/bower_components

CHANGELOG.md

Lines changed: 144 additions & 0 deletions
Large diffs are not rendered by default.

guides/theming-your-components.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,13 @@ You can use the `mat-color` function to extract a specific color from a palette.
6363
@import 'src/unicorn-app-theme.scss';
6464

6565
// Use mat-color to extract individual colors from a palette as necessary.
66+
// The hue can be one of the standard values (500, A400, etc.), one of the three preconfigured
67+
// hues (default, lighter, darker), or any of the aforementioned prefixed with "-contrast".
68+
// For example a hue of "darker-contrast" gives a light color to contrast with a "darker" hue
69+
// Available color palettes: https://www.google.com/design/spec/style/color.html
6670
.candy-carousel {
6771
background-color: mat-color($candy-app-primary);
6872
border-color: mat-color($candy-app-accent, A400);
73+
color: mat-color($candy-app-primary, darker);
6974
}
7075
```

guides/theming.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ A typical theme file will look something like this:
7575

7676
// Define the palettes for your theme using the Material Design palettes available in palette.scss
7777
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
78-
// hue.
78+
// hue. Available color palettes: https://www.google.com/design/spec/style/color.html
7979
$candy-app-primary: mat-palette($mat-indigo);
8080
$candy-app-accent: mat-palette($mat-pink, A200, A100, A400);
8181

package-lock.json

Lines changed: 4 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"docs": "gulp docs",
2121
"api": "gulp api-docs"
2222
},
23-
"version": "5.1.0",
23+
"version": "5.2.0-beta.0",
2424
"license": "MIT",
2525
"engines": {
2626
"node": ">= 5.4.1"
@@ -121,7 +121,7 @@
121121
"stylelint": "^8.4.0",
122122
"ts-node": "^3.0.4",
123123
"tsconfig-paths": "^2.3.0",
124-
"tslint": "^5.8.0",
124+
"tslint": "^5.9.1",
125125
"tsutils": "^2.6.0",
126126
"typescript": "~2.5.3",
127127
"uglify-js": "^2.8.14",

src/cdk/a11y/focus-monitor/focus-monitor.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
98
import {Platform, supportsPassiveEventListeners} from '@angular/cdk/platform';
109
import {
1110
Directive,
@@ -56,7 +55,13 @@ export class FocusMonitor implements OnDestroy {
5655
private _lastTouchTarget: EventTarget | null;
5756

5857
/** The timeout id of the touch timeout, used to cancel timeout later. */
59-
private _touchTimeout: number;
58+
private _touchTimeoutId: number;
59+
60+
/** The timeout id of the window focus timeout. */
61+
private _windowFocusTimeoutId: number;
62+
63+
/** The timeout id of the origin clearing timeout. */
64+
private _originTimeoutId: number;
6065

6166
/** Map of elements being monitored to their info. */
6267
private _elementInfo = new Map<HTMLElement, MonitoredElementInfo>();
@@ -187,18 +192,18 @@ export class FocusMonitor implements OnDestroy {
187192
// we can't rely on the trick used above (setting timeout of 0ms). Instead we wait 650ms to
188193
// see if a focus happens.
189194
let documentTouchstartListener = (event: TouchEvent) => {
190-
if (this._touchTimeout != null) {
191-
clearTimeout(this._touchTimeout);
195+
if (this._touchTimeoutId != null) {
196+
clearTimeout(this._touchTimeoutId);
192197
}
193198
this._lastTouchTarget = event.target;
194-
this._touchTimeout = setTimeout(() => this._lastTouchTarget = null, TOUCH_BUFFER_MS);
199+
this._touchTimeoutId = setTimeout(() => this._lastTouchTarget = null, TOUCH_BUFFER_MS);
195200
};
196201

197202
// Make a note of when the window regains focus, so we can restore the origin info for the
198203
// focused element.
199204
let windowFocusListener = () => {
200205
this._windowFocused = true;
201-
setTimeout(() => this._windowFocused = false, 0);
206+
this._windowFocusTimeoutId = setTimeout(() => this._windowFocused = false, 0);
202207
};
203208

204209
// Note: we listen to events in the capture phase so we can detect them even if the user stops
@@ -217,6 +222,11 @@ export class FocusMonitor implements OnDestroy {
217222
document.removeEventListener('touchstart', documentTouchstartListener,
218223
supportsPassiveEventListeners() ? ({passive: true, capture: true} as any) : true);
219224
window.removeEventListener('focus', windowFocusListener);
225+
226+
// Clear timeouts for all potentially pending timeouts to prevent the leaks.
227+
clearTimeout(this._windowFocusTimeoutId);
228+
clearTimeout(this._touchTimeoutId);
229+
clearTimeout(this._originTimeoutId);
220230
};
221231
}
222232

@@ -251,7 +261,7 @@ export class FocusMonitor implements OnDestroy {
251261
*/
252262
private _setOriginForCurrentEventQueue(origin: FocusOrigin): void {
253263
this._origin = origin;
254-
setTimeout(() => this._origin = null, 0);
264+
this._originTimeoutId = setTimeout(() => this._origin = null, 0);
255265
}
256266

257267
/**

src/cdk/a11y/focus-trap/focus-trap.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import {DOCUMENT} from '@angular/common';
2727
*
2828
* This class currently uses a relatively simple approach to focus trapping.
2929
* It assumes that the tab order is the same as DOM order, which is not necessarily true.
30-
* Things like tabIndex > 0, flex `order`, and shadow roots can cause to two to misalign.
30+
* Things like `tabIndex > 0`, flex `order`, and shadow roots can cause to two to misalign.
3131
*/
3232
export class FocusTrap {
3333
private _startAnchor: HTMLElement | null;

src/cdk/a11y/interactivity-checker/interactivity-checker.spec.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -346,9 +346,12 @@ describe('InteractivityChecker', () => {
346346
iframe.setAttribute('tabindex', '-1');
347347
iframe.contentDocument.body.appendChild(button);
348348

349-
Object.defineProperty(iframe.contentWindow, 'frameElement', {
350-
get: () => { throw 'Access Denied!'; }
351-
});
349+
// Some browsers explicitly prevent overwriting of properties on a `Window` object.
350+
if (!platform.SAFARI) {
351+
Object.defineProperty(iframe.contentWindow, 'frameElement', {
352+
get: () => { throw 'Access Denied!'; }
353+
});
354+
}
352355

353356
expect(() => checker.isTabbable(button)).not.toThrow();
354357
});

src/cdk/a11y/interactivity-checker/interactivity-checker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ function isNativeFormElement(element: Node) {
172172
nodeName === 'textarea';
173173
}
174174

175-
/** Gets whether an element is an <input type="hidden">. */
175+
/** Gets whether an element is an `<input type="hidden">`. */
176176
function isHiddenInput(element: HTMLElement): boolean {
177177
return isInputElement(element) && element.type == 'hidden';
178178
}

src/cdk/layout/breakpoints.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88
// PascalCase is being used as Breakpoints is used like an enum.
99
// tslint:disable-next-line:variable-name
1010
export const Breakpoints = {
11+
XSmall: '(max-width: 599px)',
12+
Small: '(min-width: 600px) and (max-width: 959px)',
13+
Medium: '(min-width: 960px) and (max-width: 1279px)',
14+
Large: '(min-width: 1280px) and (max-width: 1919px)',
15+
XLarge: '(min-width: 1920px)',
16+
1117
Handset: '(max-width: 599px) and (orientation: portrait), ' +
1218
'(max-width: 959px) and (orientation: landscape)',
1319
Tablet: '(min-width: 600px) and (max-width: 839px) and (orientation: portrait), ' +

src/cdk/platform/features.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export function supportsPassiveEventListeners(): boolean {
3030
/** Cached result Set of input types support by the current browser. */
3131
let supportedInputTypes: Set<string>;
3232

33-
/** Types of <input> that *might* be supported. */
33+
/** Types of `<input>` that *might* be supported. */
3434
const candidateInputTypes = [
3535
// `color` must come first. Chrome 56 shows a warning if we change the type to `color` after
3636
// first changing it to something else:

src/cdk/portal/portal-directives.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export type CdkPortalOutletAttachedRef = ComponentRef<any> | EmbeddedViewRef<any
4848
* directly attached to it, enabling declarative use.
4949
*
5050
* Usage:
51-
* <ng-template [cdkPortalOutlet]="greeting"></ng-template>
51+
* `<ng-template [cdkPortalOutlet]="greeting"></ng-template>`
5252
*/
5353
@Directive({
5454
selector: '[cdkPortalOutlet], [cdkPortalHost], [portalHost]',

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,22 @@ describe('Scroll Dispatcher', () => {
180180
.toBe(4, 'Expected scrollable count to stay the same');
181181
});
182182

183+
it('should remove the global subscription on destroy', () => {
184+
expect(scroll._globalSubscription).toBeNull('Expected no global listeners on init.');
185+
186+
const subscription = scroll.scrolled(0).subscribe(() => {});
187+
188+
expect(scroll._globalSubscription).toBeTruthy(
189+
'Expected global listeners after a subscription has been added.');
190+
191+
scroll.ngOnDestroy();
192+
193+
expect(scroll._globalSubscription).toBeNull(
194+
'Expected global listeners to have been removed after the subscription has stopped.');
195+
196+
subscription.unsubscribe();
197+
});
198+
183199
});
184200
});
185201

src/cdk/scrolling/scroll-dispatcher.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {ElementRef, Injectable, NgZone, Optional, SkipSelf} from '@angular/core';
9+
import {ElementRef, Injectable, NgZone, Optional, SkipSelf, OnDestroy} from '@angular/core';
1010
import {Platform} from '@angular/cdk/platform';
1111
import {Subject} from 'rxjs/Subject';
1212
import {Subscription} from 'rxjs/Subscription';
@@ -26,7 +26,7 @@ export const DEFAULT_SCROLL_TIME = 20;
2626
* Scrollable references emit a scrolled event.
2727
*/
2828
@Injectable()
29-
export class ScrollDispatcher {
29+
export class ScrollDispatcher implements OnDestroy {
3030
constructor(private _ngZone: NgZone, private _platform: Platform) { }
3131

3232
/** Subject for notifying that a registered scrollable reference element has been scrolled. */
@@ -97,14 +97,18 @@ export class ScrollDispatcher {
9797
subscription.unsubscribe();
9898
this._scrolledCount--;
9999

100-
if (this._globalSubscription && !this._scrolledCount) {
101-
this._globalSubscription.unsubscribe();
102-
this._globalSubscription = null;
100+
if (!this._scrolledCount) {
101+
this._removeGlobalListener();
103102
}
104103
};
105104
}) : observableOf<void>();
106105
}
107106

107+
ngOnDestroy() {
108+
this._removeGlobalListener();
109+
this.scrollContainers.forEach((_, container) => this.deregister(container));
110+
}
111+
108112
/**
109113
* Returns an observable that emits whenever any of the
110114
* scrollable ancestors of an element are scrolled.
@@ -146,12 +150,20 @@ export class ScrollDispatcher {
146150
return false;
147151
}
148152

149-
/** Sets up the global scroll and resize listeners. */
153+
/** Sets up the global scroll listeners. */
150154
private _addGlobalListener() {
151155
this._globalSubscription = this._ngZone.runOutsideAngular(() => {
152156
return fromEvent(window.document, 'scroll').subscribe(() => this._scrolled.next());
153157
});
154158
}
159+
160+
/** Cleans up the global scroll listener. */
161+
private _removeGlobalListener() {
162+
if (this._globalSubscription) {
163+
this._globalSubscription.unsubscribe();
164+
this._globalSubscription = null;
165+
}
166+
}
155167
}
156168

157169
/** @docs-private */

src/cdk/stepper/stepper.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,10 @@ export class CdkStep implements OnChanges {
126126
/** Resets the step to its initial state. Note that this includes resetting form data. */
127127
reset(): void {
128128
this.interacted = false;
129-
this.completed = false;
129+
130+
if (this._customCompleted != null) {
131+
this._customCompleted = false;
132+
}
130133

131134
if (this.stepControl) {
132135
this.stepControl.reset();
@@ -165,6 +168,11 @@ export class CdkStepper implements OnDestroy {
165168
get selectedIndex() { return this._selectedIndex; }
166169
set selectedIndex(index: number) {
167170
if (this._steps) {
171+
// Ensure that the index can't be out of bounds.
172+
if (index < 0 || index > this._steps.length - 1) {
173+
throw Error('cdkStepper: Cannot assign out-of-bounds value to `selectedIndex`.');
174+
}
175+
168176
if (this._anyControlsInvalidOrPending(index) || index < this._selectedIndex &&
169177
!this._steps.toArray()[index].editable) {
170178
// remove focus from clicked step header if the step is not able to be selected
@@ -177,7 +185,7 @@ export class CdkStepper implements OnDestroy {
177185
this._selectedIndex = this._focusIndex = index;
178186
}
179187
}
180-
private _selectedIndex: number = 0;
188+
private _selectedIndex = 0;
181189

182190
/** The step that is selected. */
183191
@Input()
File renamed without changes.

src/demo-app/list/list-demo.html

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ <h4 mat-line>{{message.from}}</h4>
3131
<span>{{message.subject}} -- </span>
3232
<span class="demo-secondary-text">{{message.message}}</span>
3333
</p>
34-
<mat-divider [inset]="true" *ngIf="!last"></mat-divider>
34+
<mat-divider inset *ngIf="!last"></mat-divider>
3535
</mat-list-item>
3636
<mat-divider></mat-divider>
3737
<mat-list-item *ngFor="let message of messages">
@@ -87,10 +87,11 @@ <h2>Nav lists</h2>
8787
</mat-list-item>
8888
</mat-nav-list>
8989
<mat-nav-list>
90-
<a mat-list-item *ngFor="let link of links" href="http://www.google.com">
90+
<a mat-list-item *ngFor="let link of links; last as last" href="http://www.google.com">
9191
<mat-icon mat-list-icon>folder</mat-icon>
9292
<span mat-line>{{ link.name }}</span>
9393
<span mat-line class="demo-secondary-text"> Description </span>
94+
<mat-divider inset *ngIf="!last"></mat-divider>
9495
</a>
9596
</mat-nav-list>
9697
<mat-nav-list dense>

src/demo-app/table/table-demo.html

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,24 @@ <h3>MatTable Example</h3>
172172
</mat-paginator>
173173
</div>
174174

175+
<h3>MatTable with First/Last Buttons Example</h3>
176+
177+
<div class="demo-table-container demo-mat-table-example mat-elevation-z4">
178+
179+
<table-header-demo>
180+
</table-header-demo>
181+
182+
<h4 class="paginator-output">{{paginatorOutput | json}}</h4>
183+
184+
<mat-paginator #paginator
185+
[length]="_peopleDatabase.data.length"
186+
[pageSize]="10"
187+
[pageSizeOptions]="[5, 10, 25, 100]"
188+
showFirstLastButtons
189+
(page)="handlePaginator($event)">
190+
</mat-paginator>
191+
</div>
192+
175193
<mat-card class="demo-table-card">
176194
<h3> MatTable Using 'When' Rows for Interactive Details</h3>
177195

@@ -235,7 +253,8 @@ <h3>MatTable With MatTableDataSource Example</h3>
235253
selected
236254
</div>
237255

238-
<mat-table [dataSource]="matTableDataSource" [trackBy]="userTrackBy" matSort
256+
<mat-table [dataSource]="matTableDataSource" [trackBy]="userTrackBy"
257+
matSort matSortActive="progress" matSortDirection="asc"
239258
#sortForDataSource="matSort">
240259

241260
<!-- Checkbox Column -->

src/demo-app/table/table-demo.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,7 @@
141141
background: #f5f5f5;
142142
}
143143
}
144+
145+
.paginator-output {
146+
margin-left: 20px;
147+
}

0 commit comments

Comments
 (0)