Skip to content

Commit

Permalink
fix(timepicker): improve accessibility
Browse files Browse the repository at this point in the history
link label to input in timepicker demo
add text to button and aria-label to inputs in timepicker

Closes #1480
  • Loading branch information
troy authored and pkozlowski-opensource committed Apr 12, 2017
1 parent 4575573 commit b2942d3
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 8 deletions.
@@ -1,18 +1,18 @@
<ngb-timepicker [(ngModel)]="time" [seconds]="true"
<ngb-timepicker [(ngModel)]="time" [seconds]="true"
[hourStep]="hourStep" [minuteStep]="minuteStep" [secondStep]="secondStep"></ngb-timepicker>

<div class="row">
<div class="col-sm-3">
<label for="changeHourStep">Hour Step</label>
<input type="number" class="form-control form-control-sm" [(ngModel)]="hourStep" />
</div>
<input id="changeHourStep" type="number" class="form-control form-control-sm" [(ngModel)]="hourStep" />
</div>
<div class="col-sm-3">
<label for="changeMinuteStep">Minute Step</label>
<input type="number" class="form-control form-control-sm" [(ngModel)]="minuteStep" />
<input id="changeMinuteStep" type="number" class="form-control form-control-sm" [(ngModel)]="minuteStep" />
</div>
<div class="col-sm-3">
<label for="changeSecondStep">Second Step</label>
<input type="number" class="form-control form-control-sm" [(ngModel)]="secondStep" />
<input id="changeSecondStep" type="number" class="form-control form-control-sm" [(ngModel)]="secondStep" />
</div>
</div>
<hr>
Expand Down
48 changes: 48 additions & 0 deletions src/timepicker/timepicker.spec.ts
Expand Up @@ -952,6 +952,54 @@ describe('ngb-timepicker', () => {
});
});

describe('accessibility', () => {

it('should have text for screen readers on buttons', async(() => {
const html = `<ngb-timepicker [(ngModel)]="model" [seconds]="true"></ngb-timepicker>`;

const fixture = createTestComponent(html);
fixture.componentInstance.model = {hour: 10, minute: 30, second: 0};
fixture.detectChanges();
fixture.whenStable()
.then(() => {
fixture.detectChanges();
return fixture.whenStable();
})
.then(() => {
const buttons = getButtons(fixture.nativeElement);

expect((<HTMLButtonElement>buttons[0]).querySelector('.sr-only').textContent).toBe('Increment hours');
expect((<HTMLButtonElement>buttons[1]).querySelector('.sr-only').textContent).toBe('Increment minutes');
expect((<HTMLButtonElement>buttons[2]).querySelector('.sr-only').textContent).toBe('Increment seconds');
expect((<HTMLButtonElement>buttons[3]).querySelector('.sr-only').textContent).toBe('Decrement hours');
expect((<HTMLButtonElement>buttons[4]).querySelector('.sr-only').textContent).toBe('Decrement minutes');
expect((<HTMLButtonElement>buttons[5]).querySelector('.sr-only').textContent).toBe('Decrement seconds');
});
}));

it('should have aria-label for inputs', async(() => {
const html = `<ngb-timepicker [(ngModel)]="model" [seconds]="true"></ngb-timepicker>`;

const fixture = createTestComponent(html);
fixture.componentInstance.model = {hour: 10, minute: 30, second: 0};
fixture.detectChanges();
fixture.whenStable()
.then(() => {
fixture.detectChanges();
return fixture.whenStable();
})
.then(() => {
const inputs = getInputs(fixture.nativeElement);

expect(inputs[0].getAttribute('aria-label')).toBe('Hours');
expect(inputs[1].getAttribute('aria-label')).toBe('Minutes');
expect(inputs[2].getAttribute('aria-label')).toBe('Seconds');
});
}));
});



describe('Seconds handling', () => {
it('should propagate seconds to 0 in model if seconds not shown and no second in initial model', async(() => {
const html = `<ngb-timepicker [(ngModel)]="model" [seconds]="false"></ngb-timepicker>`;
Expand Down
12 changes: 9 additions & 3 deletions src/timepicker/timepicker.ts
Expand Up @@ -61,13 +61,15 @@ const NGB_TIMEPICKER_VALUE_ACCESSOR = {
<button type="button" class="btn-link" [ngClass]="setButtonSize()" (click)="changeHour(hourStep)"
[disabled]="disabled" [class.disabled]="disabled">
<span class="chevron"></span>
<span class="sr-only">Increment hours</span>
</button>
</td>
<td>&nbsp;</td>
<td class="text-center">
<button type="button" class="btn-link" [ngClass]="setButtonSize()" (click)="changeMinute(minuteStep)"
[disabled]="disabled" [class.disabled]="disabled">
<span class="chevron"></span>
<span class="sr-only">Increment minutes</span>
</button>
</td>
<template [ngIf]="seconds">
Expand All @@ -76,6 +78,7 @@ const NGB_TIMEPICKER_VALUE_ACCESSOR = {
<button type="button" class="btn-link" [ngClass]="setButtonSize()" (click)="changeSecond(secondStep)"
[disabled]="disabled" [class.disabled]="disabled">
<span class="chevron"></span>
<span class="sr-only">Increment seconds</span>
</button>
</td>
</template>
Expand All @@ -88,20 +91,20 @@ const NGB_TIMEPICKER_VALUE_ACCESSOR = {
<td>
<input type="text" class="form-control" [ngClass]="setFormControlSize()" maxlength="2" size="2" placeholder="HH"
[value]="formatHour(model?.hour)" (change)="updateHour($event.target.value)"
[readonly]="readonlyInputs" [disabled]="disabled">
[readonly]="readonlyInputs" [disabled]="disabled" aria-label="Hours">
</td>
<td>&nbsp;:&nbsp;</td>
<td>
<input type="text" class="form-control" [ngClass]="setFormControlSize()" maxlength="2" size="2" placeholder="MM"
[value]="formatMinSec(model?.minute)" (change)="updateMinute($event.target.value)"
[readonly]="readonlyInputs" [disabled]="disabled">
[readonly]="readonlyInputs" [disabled]="disabled" aria-label="Minutes">
</td>
<template [ngIf]="seconds">
<td>&nbsp;:&nbsp;</td>
<td>
<input type="text" class="form-control" [ngClass]="setFormControlSize()" maxlength="2" size="2" placeholder="SS"
[value]="formatMinSec(model?.second)" (change)="updateSecond($event.target.value)"
[readonly]="readonlyInputs" [disabled]="disabled">
[readonly]="readonlyInputs" [disabled]="disabled" aria-label="Seconds">
</td>
</template>
<template [ngIf]="meridian">
Expand All @@ -117,13 +120,15 @@ const NGB_TIMEPICKER_VALUE_ACCESSOR = {
<button type="button" class="btn-link" [ngClass]="setButtonSize()" (click)="changeHour(-hourStep)"
[disabled]="disabled" [class.disabled]="disabled">
<span class="chevron bottom"></span>
<span class="sr-only">Decrement hours</span>
</button>
</td>
<td>&nbsp;</td>
<td class="text-center">
<button type="button" class="btn-link" [ngClass]="setButtonSize()" (click)="changeMinute(-minuteStep)"
[disabled]="disabled" [class.disabled]="disabled">
<span class="chevron bottom"></span>
<span class="sr-only">Decrement minutes</span>
</button>
</td>
<template [ngIf]="seconds">
Expand All @@ -132,6 +137,7 @@ const NGB_TIMEPICKER_VALUE_ACCESSOR = {
<button type="button" class="btn-link" [ngClass]="setButtonSize()" (click)="changeSecond(-secondStep)"
[disabled]="disabled" [class.disabled]="disabled">
<span class="chevron bottom"></span>
<span class="sr-only">Decrement seconds</span>
</button>
</td>
</template>
Expand Down

0 comments on commit b2942d3

Please sign in to comment.