Skip to content

Commit fe7ce4b

Browse files
authored
Merge branch 'master' into tabs-template
2 parents db46d84 + f2cae6e commit fe7ce4b

File tree

90 files changed

+1339
-320
lines changed

Some content is hidden

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

90 files changed

+1339
-320
lines changed

CODING_STANDARDS.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ use `//` style comments for everything else (explanations, background info, etc.
4343

4444
In SCSS code, always use `//` style comments.
4545

46+
In HTML code, use `<!-- ... -->` comments, which will be stripped when packaging a build.
47+
4648
#### Prefer more focused, granular components vs. complex, configurable components.
4749

4850
For example, rather than doing this:
@@ -198,6 +200,13 @@ Boolean properties and return values should use "Whether..." as opposed to "True
198200
disabled: boolean = false;
199201
```
200202

203+
#### Try-Catch
204+
205+
Avoid `try-catch` blocks, instead preferring to prevent an error from being thrown in the first
206+
place. When impossible to avoid, the `try-catch` block must include a comment that explains the
207+
specific error being caught and why it cannot be prevented.
208+
209+
201210
#### Naming
202211

203212
##### General
@@ -221,7 +230,8 @@ Avoid suffixing a class with "Service", as it communicates nothing about what th
221230
think of the class name as a person's job title.
222231

223232
Classes that correspond to a directive with an `md-` prefix should also be prefixed with `Md`.
224-
CDK classes should not have a prefix.
233+
CDK classes should only have a `Cdk` prefix when the class is a directive with a `cdk` selector
234+
prefix.
225235

226236
##### Methods
227237
The name of a method should capture the action that is performed *by* that method rather than
@@ -242,7 +252,8 @@ activateRipple() {
242252
#### Inheritance
243253

244254
Avoid using inheritance to apply reusable behaviors to multiple components. This limits how many
245-
behaviors can be composed.
255+
behaviors can be composed. Instead, [TypeScript mixins][ts-mixins] can be used to compose multiple
256+
common behaviors into a single component.
246257

247258
### Angular
248259

@@ -346,3 +357,5 @@ When it is not super obvious, include a brief description of what a class repres
346357
// Portion of the floating panel that sits, invisibly, on top of the input.
347358
.mat-datepicker-input-mask { }
348359
```
360+
361+
[ts-mixins]: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-mix-in-classes

e2e/components/stepper-e2e.spec.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import {
2+
browser, by, element, ElementFinder, ExpectedConditions
3+
} from 'protractor';
4+
import {expectFocusOn, expectToExist} from '../util/asserts';
5+
import {pressKeys} from '../util/actions';
6+
import {Key} from 'selenium-webdriver';
7+
import {screenshot} from '../screenshot';
8+
9+
describe('stepper', () => {
10+
beforeEach(() => browser.get('/stepper'));
11+
12+
it('should render a stepper', () => {
13+
expectToExist('md-horizontal-stepper');
14+
screenshot('md-horizontal-stepper');
15+
});
16+
17+
describe('basic behavior', () => {
18+
it('should change steps correctly when stepper button is clicked', async () => {
19+
const previousButton = element.all(by.buttonText('Back'));
20+
const nextButton = element.all(by.buttonText('Next'));
21+
22+
expect(element(by.css('md-step-header[aria-selected="true"]')).getText())
23+
.toBe('1\nFill out your name');
24+
25+
screenshot('start');
26+
nextButton.get(0).click();
27+
28+
expect(element(by.css('md-step-header[aria-selected="true"]')).getText())
29+
.toBe('2\nFill out your address');
30+
31+
await browser.wait(ExpectedConditions.not(
32+
ExpectedConditions.presenceOf(element(by.css('div.mat-ripple-element')))));
33+
screenshot('click next');
34+
35+
previousButton.get(0).click();
36+
37+
expect(element(by.css('md-step-header[aria-selected="true"]')).getText())
38+
.toBe('1\nFill out your name');
39+
40+
await browser.wait(ExpectedConditions.not(
41+
ExpectedConditions.presenceOf(element(by.css('div.mat-ripple-element')))));
42+
screenshot('click back');
43+
});
44+
45+
it('should change focus with keyboard interaction', () => {
46+
let stepHeaders = element.all(by.css('md-step-header'));
47+
stepHeaders.get(0).click();
48+
49+
expectFocusOn(stepHeaders.get(0));
50+
51+
pressKeys(Key.RIGHT);
52+
expectFocusOn(stepHeaders.get(1));
53+
54+
pressKeys(Key.RIGHT);
55+
expectFocusOn(stepHeaders.get(2));
56+
57+
pressKeys(Key.RIGHT);
58+
expectFocusOn(stepHeaders.get(0));
59+
60+
pressKeys(Key.LEFT);
61+
expectFocusOn(stepHeaders.get(2));
62+
63+
pressKeys(Key.SPACE, Key.ENTER);
64+
expectFocusOn(stepHeaders.get(2));
65+
});
66+
});
67+
68+
describe('linear stepper', () => {
69+
let linearButton: ElementFinder;
70+
71+
beforeEach(() => {
72+
linearButton = element(by.id('toggle-linear'));
73+
linearButton.click();
74+
});
75+
76+
it('should not move to next step when stepper button is clicked', () => {
77+
let nextButton = element.all(by.buttonText('Next'));
78+
nextButton.get(0).click();
79+
80+
expect(element(by.css('md-step-header[aria-selected="true"]')).getText())
81+
.toBe('1\nFill out your name');
82+
});
83+
});
84+
});

src/cdk/a11y/focus-key-manager.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
### FocusKeyManager
2+
`ListKeyManager` manages the focus of an item based on keyboard interaction.

src/cdk/bidi/bidi.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,25 @@ text direction (RTL or LTR);
66
#### Example
77
```ts
88
@Component({ ... })
9-
export class MyWidget {
9+
export class MyWidget implements OnDestroy {
10+
11+
/** Whether the widget is in RTL mode or not. */
1012
private isRtl: boolean;
1113

14+
/** Subscription to the Directionality change EventEmitter. */
15+
private _dirChangeSubscription = Subscription.EMPTY;
16+
1217
constructor(dir: Directionality) {
1318
this.isRtl = dir.value === 'rtl';
1419

15-
dir.change.subscribe(() => {
20+
_dirChangeSubscription = dir.change.subscribe(() => {
1621
this.flipDirection();
1722
});
1823
}
24+
25+
ngOnDestroy() {
26+
this._dirChangeSubscription.unsubscribe();
27+
}
1928
}
2029
```
2130

src/cdk/coercion/coercion.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
### Coercion
2+
3+
Utility functions for coercing `@Input`s into specific types.

src/cdk/collections/collections.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
### Collections
2+
3+
A set of utilities for managing collections.

src/cdk/keycodes/keycodes.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
### KeyCodes
2+
3+
Commonly used keycode constants.
4+
5+
#### Example
6+
```ts
7+
import {Directive} from '@angular/core';
8+
import {UP_ARROW, DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW} from '@angular/cdk/keycodes';
9+
10+
@Directive({
11+
selector: '[count-arrows]'
12+
host: {
13+
(keypress): 'handleKeyPress($event)'
14+
}
15+
})
16+
export class ArrowCounterDirective {
17+
arrowPressCount = 0;
18+
19+
handleKeyPress(event: KeyboardEvent) {
20+
if ([UP_ARROW, DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW].includes(event.keyCode)) {
21+
this.arrowPresscount++;
22+
}
23+
}
24+
}
25+
```
26+

src/cdk/observers/observers.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
### Observers
2+
3+
A directive for observing when the content of the host element changes. An event is emitted when a
4+
mutation to the content is observed.
5+
6+
#### Example
7+
8+
```html
9+
<div class="projected-content-wrapper" (cdkObserveContent)="projectContentChanged()">
10+
<ng-content></ng-content>
11+
</div>
12+
```

src/cdk/overlay/overlay.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
### Overlay
2+
3+
A service used to manage overlays.

src/cdk/platform/platform.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
### Platform
2+
3+
A service for determing the current platform.

src/cdk/rxjs/rxjs.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
### RxJS Usage
2+
When dealing with RxJS operators it is important to be aware that using the "patch" imports will
3+
pollute the global Observable object (e.g. `import "rxjs/add/operator/map"`). When creating a
4+
component library, it is highly recommended to import the operator functions directly (e.g.
5+
`import "rxjs/operator/map"`):
6+
7+
```ts
8+
// NO
9+
import 'rxjs/add/operator/map';
10+
someObservable.map(...).subscribe(...);
11+
12+
// YES
13+
import {map} from 'rxjs/operator/map';
14+
map.call(someObservable, ...).subscribe(...);
15+
```
16+
17+
#### RxChain
18+
Because this approach can be inflexible when dealing with long chains of operators. You should use
19+
the `RxChain` class to help with it:
20+
21+
```ts
22+
// Before
23+
someObservable.filter(...).map(...).do(...);
24+
25+
// After
26+
RxChain.from(someObservable).call(filter, ...).call(map, ...).subscribe(...);
27+
```

src/cdk/scrolling/scrolling.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
### Scrolling
2+
3+
Some things to help with scrollling.

src/cdk/scrolling/viewport.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
### Viewport
2+
3+
A utility for getting the bounds of the browser viewport.

src/cdk/stepper/stepper.ts

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import {LEFT_ARROW, RIGHT_ARROW, ENTER, SPACE} from '@angular/cdk/keycodes';
3030
import {CdkStepLabel} from './step-label';
3131
import {coerceBooleanProperty} from '@angular/cdk/coercion';
3232
import {AbstractControl} from '@angular/forms';
33-
import {Directionality} from '@angular/cdk/bidi';
33+
import {Direction, Directionality} from '@angular/cdk/bidi';
3434

3535
/** Used to generate unique ID for each stepper component. */
3636
let nextId = 0;
@@ -151,8 +151,7 @@ export class CdkStepper {
151151
@Input()
152152
get selected() { return this._steps[this.selectedIndex]; }
153153
set selected(step: CdkStep) {
154-
let index = this._steps.toArray().indexOf(step);
155-
this.selectedIndex = index;
154+
this.selectedIndex = this._steps.toArray().indexOf(step);
156155
}
157156

158157
/** Event emitted when the selected step has changed. */
@@ -192,12 +191,11 @@ export class CdkStepper {
192191
_getAnimationDirection(index: number): StepContentPositionState {
193192
const position = index - this._selectedIndex;
194193
if (position < 0) {
195-
return 'previous';
194+
return this._layoutDirection() === 'rtl' ? 'next' : 'previous';
196195
} else if (position > 0) {
197-
return 'next';
198-
} else {
199-
return 'current';
196+
return this._layoutDirection() === 'rtl' ? 'previous' : 'next';
200197
}
198+
return 'current';
201199
}
202200

203201
/** Returns the type of icon to be displayed. */
@@ -224,17 +222,17 @@ export class CdkStepper {
224222
_onKeydown(event: KeyboardEvent) {
225223
switch (event.keyCode) {
226224
case RIGHT_ARROW:
227-
if (this._dir && this._dir.value === 'rtl') {
228-
this._focusStep((this._focusIndex + this._steps.length - 1) % this._steps.length);
225+
if (this._layoutDirection() === 'rtl') {
226+
this._focusPreviousStep();
229227
} else {
230-
this._focusStep((this._focusIndex + 1) % this._steps.length);
228+
this._focusNextStep();
231229
}
232230
break;
233231
case LEFT_ARROW:
234-
if (this._dir && this._dir.value === 'rtl') {
235-
this._focusStep((this._focusIndex + 1) % this._steps.length);
232+
if (this._layoutDirection() === 'rtl') {
233+
this._focusNextStep();
236234
} else {
237-
this._focusStep((this._focusIndex + this._steps.length - 1) % this._steps.length);
235+
this._focusPreviousStep();
238236
}
239237
break;
240238
case SPACE:
@@ -248,17 +246,28 @@ export class CdkStepper {
248246
event.preventDefault();
249247
}
250248

249+
private _focusNextStep() {
250+
this._focusStep((this._focusIndex + 1) % this._steps.length);
251+
}
252+
253+
private _focusPreviousStep() {
254+
this._focusStep((this._focusIndex + this._steps.length - 1) % this._steps.length);
255+
}
256+
251257
private _focusStep(index: number) {
252258
this._focusIndex = index;
253259
this._stepHeader.toArray()[this._focusIndex].nativeElement.focus();
254260
}
255261

256262
private _anyControlsInvalid(index: number): boolean {
257-
const stepsArray = this._steps.toArray();
258-
stepsArray[this._selectedIndex].interacted = true;
259-
if (this._linear) {
260-
return stepsArray.slice(0, index).some(step => step.stepControl.invalid);
263+
this._steps.toArray()[this._selectedIndex].interacted = true;
264+
if (this._linear && index >= 0) {
265+
return this._steps.toArray().slice(0, index).some(step => step.stepControl.invalid);
261266
}
262267
return false;
263268
}
269+
270+
private _layoutDirection(): Direction {
271+
return this._dir && this._dir.value === 'rtl' ? 'rtl' : 'ltr';
272+
}
264273
}

src/cdk/table/row.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ export class CdkCellOutlet {
141141

142142
/** Header template container that contains the cell outlet. Adds the right class and role. */
143143
@Component({
144+
moduleId: module.id,
144145
selector: 'cdk-header-row',
145146
template: CDK_ROW_TEMPLATE,
146147
host: {
@@ -154,6 +155,7 @@ export class CdkHeaderRow { }
154155

155156
/** Data row template container that contains the cell outlet. Adds the right class and role. */
156157
@Component({
158+
moduleId: module.id,
157159
selector: 'cdk-row',
158160
template: CDK_ROW_TEMPLATE,
159161
host: {

src/cdk/table/table.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ export const CDK_TABLE_TEMPLATE = `
6969
* a header row and data rows. Updates the rows when new data is provided by the data source.
7070
*/
7171
@Component({
72+
moduleId: module.id,
7273
selector: 'cdk-table',
7374
template: CDK_TABLE_TEMPLATE,
7475
host: {

src/cdk/table/tsconfig-build.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
{
22
"extends": "../tsconfig-build",
33
"files": [
4-
"public_api.ts"
4+
"public_api.ts",
5+
"../typings.d.ts"
56
],
67
"angularCompilerOptions": {
78
"annotateForClosureCompiler": true,

0 commit comments

Comments
 (0)