Skip to content

Commit

Permalink
Merge branch 'master' into autocomplete-demos
Browse files Browse the repository at this point in the history
  • Loading branch information
amcdnl authored Jul 9, 2017
2 parents 26bedeb + 077ebf6 commit e72ab91
Show file tree
Hide file tree
Showing 129 changed files with 2,071 additions and 924 deletions.
18 changes: 9 additions & 9 deletions src/cdk/a11y/live-announcer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ describe('LiveAnnouncer', () => {
})));

afterEach(() => {
// In our tests we always remove the current live element, because otherwise we would have
// multiple live elements due multiple service instantiations.
announcer._removeLiveElement();
// In our tests we always remove the current live element, in
// order to avoid having multiple announcer elements in the DOM.
announcer.ngOnDestroy();
});

it('should correctly update the announce text', fakeAsync(() => {
Expand Down Expand Up @@ -58,13 +58,14 @@ describe('LiveAnnouncer', () => {
expect(ariaLiveElement.getAttribute('aria-live')).toBe('polite');
}));

it('should remove the aria-live element from the DOM', fakeAsync(() => {
it('should remove the aria-live element from the DOM on destroy', fakeAsync(() => {
announcer.announce('Hey Google');

// This flushes our 100ms timeout for the screenreaders.
tick(100);

announcer._removeLiveElement();
// Call the lifecycle hook manually since Angular won't do it in tests.
announcer.ngOnDestroy();

expect(document.body.querySelector('[aria-live]'))
.toBeFalsy('Expected that the aria-live element was remove from the DOM.');
Expand All @@ -85,10 +86,9 @@ describe('LiveAnnouncer', () => {
});

beforeEach(inject([LiveAnnouncer], (la: LiveAnnouncer) => {
announcer = la;
ariaLiveElement = getLiveElement();
}));

announcer = la;
ariaLiveElement = getLiveElement();
}));

it('should allow to use a custom live element', fakeAsync(() => {
announcer.announce('Custom Element');
Expand Down
7 changes: 3 additions & 4 deletions src/cdk/a11y/live-announcer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
Optional,
Inject,
SkipSelf,
OnDestroy,
} from '@angular/core';
import {Platform} from '../platform/platform';

Expand All @@ -22,8 +23,7 @@ export const LIVE_ANNOUNCER_ELEMENT_TOKEN = new InjectionToken<HTMLElement>('liv
export type AriaLivePoliteness = 'off' | 'polite' | 'assertive';

@Injectable()
export class LiveAnnouncer {

export class LiveAnnouncer implements OnDestroy {
private _liveElement: Element;

constructor(
Expand Down Expand Up @@ -57,8 +57,7 @@ export class LiveAnnouncer {
setTimeout(() => this._liveElement.textContent = message, 100);
}

/** Removes the aria-live element from the DOM. */
_removeLiveElement() {
ngOnDestroy() {
if (this._liveElement && this._liveElement.parentNode) {
this._liveElement.parentNode.removeChild(this._liveElement);
}
Expand Down
36 changes: 32 additions & 4 deletions src/demo-app/datepicker/datepicker-demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,26 @@ <h2>Options</h2>
<md-checkbox [(ngModel)]="touch">Use touch UI</md-checkbox>
<md-checkbox [(ngModel)]="filterOdd">Filter odd months and dates</md-checkbox>
<md-checkbox [(ngModel)]="yearView">Start in year view</md-checkbox>
<md-checkbox [(ngModel)]="datepickerDisabled">Disable datepicker</md-checkbox>
</p>
<p>
<md-input-container>
<input mdInput [mdDatepicker]="minDatePicker" [(ngModel)]="minDate" placeholder="Min date">
<button mdSuffix [mdDatepickerToggle]="minDatePicker"></button>
</md-input-container>
<md-datepicker #minDatePicker [touchUi]="touch"></md-datepicker>
<md-datepicker #minDatePicker [touchUi]="touch" [disabled]="datepickerDisabled"></md-datepicker>
<md-input-container>
<input mdInput [mdDatepicker]="maxDatePicker" [(ngModel)]="maxDate" placeholder="Max date">
<button mdSuffix [mdDatepickerToggle]="maxDatePicker"></button>
</md-input-container>
<md-datepicker #maxDatePicker [touchUi]="touch"></md-datepicker>
<md-datepicker #maxDatePicker [touchUi]="touch" [disabled]="datepickerDisabled"></md-datepicker>
</p>
<p>
<md-input-container>
<input mdInput [mdDatepicker]="startAtPicker" [(ngModel)]="startAt" placeholder="Start at date">
<button mdSuffix [mdDatepickerToggle]="startAtPicker"></button>
</md-input-container>
<md-datepicker #startAtPicker [touchUi]="touch"></md-datepicker>
<md-datepicker #startAtPicker [touchUi]="touch" [disabled]="datepickerDisabled"></md-datepicker>
</p>

<h2>Result</h2>
Expand All @@ -44,12 +45,14 @@ <h2>Result</h2>
<md-datepicker
#resultPicker
[touchUi]="touch"
[disabled]="datepickerDisabled"
[startAt]="startAt"
[startView]="yearView ? 'year' : 'month'">
</md-datepicker>
</p>
<p>
<input [mdDatepicker]="resultPicker2"
<input #resultPickerModel2
[mdDatepicker]="resultPicker2"
[(ngModel)]="date"
[min]="minDate"
[max]="maxDate"
Expand All @@ -59,7 +62,32 @@ <h2>Result</h2>
<md-datepicker
#resultPicker2
[touchUi]="touch"
[disabled]="datepickerDisabled"
[startAt]="startAt"
[startView]="yearView ? 'year' : 'month'">
</md-datepicker>
</p>

<h2>Input disabled datepicker</h2>
<p>
<button [mdDatepickerToggle]="datePicker1"></button>
<md-input-container>
<input mdInput [mdDatepicker]="datePicker1" [(ngModel)]="date" [min]="minDate" [max]="maxDate"
[mdDatepickerFilter]="filterOdd ? dateFilter : null" [disabled]="true"
placeholder="Input disabled">
</md-input-container>
<md-datepicker #datePicker1 [touchUi]="touch" [startAt]="startAt"
[startView]="yearView ? 'year' : 'month'"></md-datepicker>
</p>

<h2>Input disabled, datepicker popup enabled</h2>
<p>
<button [mdDatepickerToggle]="datePicker2"></button>
<md-input-container>
<input mdInput disabled [mdDatepicker]="datePicker2" [(ngModel)]="date" [min]="minDate" [max]="maxDate"
[mdDatepickerFilter]="filterOdd ? dateFilter : null"
placeholder="Input disabled, datepicker enabled">
</md-input-container>
<md-datepicker #datePicker2 [touchUi]="touch" [disabled]="false" [startAt]="startAt"
[startView]="yearView ? 'year' : 'month'"></md-datepicker>
</p>
2 changes: 2 additions & 0 deletions src/demo-app/datepicker/datepicker-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export class DatepickerDemo {
touch: boolean;
filterOdd: boolean;
yearView: boolean;
inputDisabled: boolean;
datepickerDisabled: boolean;
minDate: Date;
maxDate: Date;
startAt: Date;
Expand Down
6 changes: 3 additions & 3 deletions src/demo-app/progress-spinner/progress-spinner-demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ <h1>Determinate</h1>
<p>Value: {{progressValue}}</p>
<button md-raised-button (click)="step(10)">Increase</button>
<button md-raised-button (click)="step(-10)">Decrease</button>
<md-checkbox [(ngModel)]="modeToggle">Is determinate</md-checkbox>
<md-checkbox [(ngModel)]="isDeterminate">Is determinate</md-checkbox>
</div>

<div class="demo-progress-spinner">
<md-progress-spinner [mode]="modeToggle ? 'indeterminate' : 'determinate'"
<md-progress-spinner [mode]="isDeterminate ? 'determinate' : 'indeterminate'"
[value]="progressValue" color="primary" [strokeWidth]="1"></md-progress-spinner>
<md-progress-spinner [mode]="modeToggle ? 'indeterminate' : 'determinate'"
<md-progress-spinner [mode]="isDeterminate ? 'determinate' : 'indeterminate'"
[value]="progressValue" color="accent"></md-progress-spinner>
</div>

Expand Down
6 changes: 3 additions & 3 deletions src/demo-app/progress-spinner/progress-spinner-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import {Component} from '@angular/core';
styleUrls: ['progress-spinner-demo.css'],
})
export class ProgressSpinnerDemo {
progressValue: number = 60;
color: string = 'primary';
modeToggle: boolean = false;
progressValue = 60;
color = 'primary';
isDeterminate = true;

step(val: number) {
this.progressValue = Math.max(0, Math.min(100, val + this.progressValue));
Expand Down
4 changes: 4 additions & 0 deletions src/lib/autocomplete/autocomplete-trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {

/** Closes the autocomplete suggestion panel. */
closePanel(): void {
if (!this.panelOpen) {
return;
}

if (this._overlayRef && this._overlayRef.hasAttached()) {
this._overlayRef.detach();
this._closingActionsSubscription.unsubscribe();
Expand Down
46 changes: 31 additions & 15 deletions src/lib/autocomplete/autocomplete.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,17 +221,31 @@ describe('MdAutocomplete', () => {
});
}));

it('should close the panel programmatically', () => {
it('should close the panel programmatically', async(() => {
fixture.componentInstance.trigger.openPanel();
fixture.detectChanges();

fixture.componentInstance.trigger.closePanel();
fixture.whenStable().then(() => {
fixture.componentInstance.trigger.closePanel();
fixture.detectChanges();

fixture.whenStable().then(() => {
expect(fixture.componentInstance.trigger.panelOpen)
.toBe(false, `Expected closing programmatically to set the panel state to closed.`);
expect(overlayContainerElement.textContent)
.toEqual('', `Expected closing programmatically to close the panel.`);
});
});
}));

it('should not throw when attempting to close the panel of a destroyed autocomplete', () => {
const trigger = fixture.componentInstance.trigger;

trigger.openPanel();
fixture.detectChanges();
fixture.destroy();

expect(fixture.componentInstance.trigger.panelOpen)
.toBe(false, `Expected closing programmatically to set the panel state to closed.`);
expect(overlayContainerElement.textContent)
.toEqual('', `Expected closing programmatically to close the panel.`);
expect(() => trigger.closePanel()).not.toThrow();
});

it('should hide the panel when the options list is empty', async(() => {
Expand Down Expand Up @@ -763,17 +777,19 @@ describe('MdAutocomplete', () => {
.toEqual(32, `Expected panel to reveal the sixth option.`);
}));

it('should scroll to active options on UP arrow', fakeAsync(() => {
tick();
const scrollContainer =
document.querySelector('.cdk-overlay-pane .mat-autocomplete-panel')!;
it('should scroll to active options on UP arrow', async(() => {
fixture.whenStable().then(() => {
const scrollContainer =
document.querySelector('.cdk-overlay-pane .mat-autocomplete-panel')!;

fixture.componentInstance.trigger._handleKeydown(UP_ARROW_EVENT);
tick();
fixture.detectChanges();
fixture.componentInstance.trigger._handleKeydown(UP_ARROW_EVENT);
fixture.detectChanges();

// Expect option bottom minus the panel height (528 - 256 = 272)
expect(scrollContainer.scrollTop).toEqual(272, `Expected panel to reveal last option.`);
fixture.whenStable().then(() => {
// Expect option bottom minus the panel height (528 - 256 = 272)
expect(scrollContainer.scrollTop).toEqual(272, `Expected panel to reveal last option.`);
});
});
}));

it('should not scroll to active options that are fully in the panel', fakeAsync(() => {
Expand Down
2 changes: 2 additions & 0 deletions src/lib/autocomplete/autocomplete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
ViewChild,
ViewEncapsulation,
ChangeDetectorRef,
ChangeDetectionStrategy,
} from '@angular/core';
import {MdOption} from '../core';
import {ActiveDescendantKeyManager} from '../core/a11y/activedescendant-key-manager';
Expand All @@ -35,6 +36,7 @@ export type AutocompletePositionY = 'above' | 'below';
templateUrl: 'autocomplete.html',
styleUrls: ['autocomplete.css'],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
exportAs: 'mdAutocomplete',
host: {
'class': 'mat-autocomplete'
Expand Down
Loading

0 comments on commit e72ab91

Please sign in to comment.