From 5d505eaa7e1d8a3f03077f6246175bfac3f928f4 Mon Sep 17 00:00:00 2001 From: Irina Ershova Date: Fri, 24 Jan 2020 14:46:52 +0200 Subject: [PATCH] feat(rating): add aria-label attribute (#5607) Add aria label attribute Add RatingConfig class Close #5579 Co-authored-by: Dmitriy Danilov --- .../+rating/demos/config/config.html | 4 + .../components/+rating/demos/config/config.ts | 17 ++ .../src/app/components/+rating/demos/index.ts | 4 +- .../components/+rating/rating-section.list.ts | 15 +- demo/src/ng-api-doc.ts | 165 +++++++++++------- src/common/public_api.ts | 6 +- src/index.ts | 6 +- src/rating/public_api.ts | 1 + src/rating/rating.component.html | 4 +- src/rating/rating.component.ts | 9 +- src/rating/rating.config.ts | 8 + src/rating/rating.module.ts | 4 +- src/spec/rating.component.spec.ts | 14 +- 13 files changed, 188 insertions(+), 69 deletions(-) create mode 100644 demo/src/app/components/+rating/demos/config/config.html create mode 100644 demo/src/app/components/+rating/demos/config/config.ts create mode 100644 src/rating/rating.config.ts diff --git a/demo/src/app/components/+rating/demos/config/config.html b/demo/src/app/components/+rating/demos/config/config.html new file mode 100644 index 0000000000..9ecdd87710 --- /dev/null +++ b/demo/src/app/components/+rating/demos/config/config.html @@ -0,0 +1,4 @@ + +
+
Rate: {{rate}} 
+
diff --git a/demo/src/app/components/+rating/demos/config/config.ts b/demo/src/app/components/+rating/demos/config/config.ts new file mode 100644 index 0000000000..b6d7fc754c --- /dev/null +++ b/demo/src/app/components/+rating/demos/config/config.ts @@ -0,0 +1,17 @@ +import { Component } from '@angular/core'; +import { RatingConfig } from 'ngx-bootstrap/rating'; + +// such override allows to keep some initial values +export function getRatingConfig(): RatingConfig { + return Object.assign(new RatingConfig(), { ariaLabel: 'My Rating' }); +} + +@Component({ + selector: 'demo-rating-config', + templateUrl: './config.html', + providers: [{ provide: RatingConfig, useFactory: getRatingConfig }] +}) +export class DemoRatingConfigComponent { + max = 10; + rate = 7; +} diff --git a/demo/src/app/components/+rating/demos/index.ts b/demo/src/app/components/+rating/demos/index.ts index 45dc258d43..ffea7559a0 100644 --- a/demo/src/app/components/+rating/demos/index.ts +++ b/demo/src/app/components/+rating/demos/index.ts @@ -2,10 +2,12 @@ import { DemoRatingBasicComponent } from './basic/basic'; import { DemoRatingCustomComponent } from './custom/custom'; import { DemoRatingDynamicComponent } from './dynamic/dynamic'; import { DemoRatingSelectOnEnterComponent } from './select-on-enter/select-on-enter'; +import { DemoRatingConfigComponent } from './config/config'; export const DEMO_COMPONENTS = [ DemoRatingBasicComponent, DemoRatingCustomComponent, DemoRatingDynamicComponent, - DemoRatingSelectOnEnterComponent + DemoRatingSelectOnEnterComponent, + DemoRatingConfigComponent ]; diff --git a/demo/src/app/components/+rating/rating-section.list.ts b/demo/src/app/components/+rating/rating-section.list.ts index eda9badb21..e545e4d496 100644 --- a/demo/src/app/components/+rating/rating-section.list.ts +++ b/demo/src/app/components/+rating/rating-section.list.ts @@ -2,13 +2,14 @@ import { DemoRatingBasicComponent } from './demos/basic/basic'; import { DemoRatingCustomComponent } from './demos/custom/custom'; import { DemoRatingDynamicComponent } from './demos/dynamic/dynamic'; import { DemoRatingSelectOnEnterComponent } from './demos/select-on-enter/select-on-enter'; +import { DemoRatingConfigComponent } from './demos/config/config'; import { ContentSection } from '../../docs/models/content-section.model'; import { DemoTopSectionComponent } from '../../docs/demo-section-components/demo-top-section/index'; import { ExamplesComponent } from '../../docs/demo-section-components/demo-examples-section/index'; import { ApiSectionsComponent } from '../../docs/demo-section-components/demo-api-section/index'; -import { NgApiDocComponent } from '../../docs/api-docs'; +import { NgApiDocComponent, NgApiDocConfigComponent } from '../../docs/api-docs'; export const demoComponentContent: ContentSection[] = [ { @@ -53,6 +54,13 @@ export const demoComponentContent: ContentSection[] = [ component: require('!!raw-loader!./demos/select-on-enter/select-on-enter'), html: require('!!raw-loader!./demos/select-on-enter/select-on-enter.html'), outlet: DemoRatingSelectOnEnterComponent + }, + { + title: 'Configuring defaults', + anchor: 'demo-rating-config', + component: require('!!raw-loader!./demos/config/config'), + html: require('!!raw-loader!./demos/config/config.html'), + outlet: DemoRatingConfigComponent } ] }, @@ -65,6 +73,11 @@ export const demoComponentContent: ContentSection[] = [ title: 'RatingComponent', anchor: 'rating-component', outlet: NgApiDocComponent + }, + { + title: 'RatingConfig', + anchor: 'rating-config', + outlet: NgApiDocConfigComponent } ] } diff --git a/demo/src/ng-api-doc.ts b/demo/src/ng-api-doc.ts index 79934a5d4d..aced44d9ee 100644 --- a/demo/src/ng-api-doc.ts +++ b/demo/src/ng-api-doc.ts @@ -1025,11 +1025,6 @@ export const ngdoc: any = { "type": "BsDatepickerViewMode", "description": "

Default mode for all date pickers

\n" }, - { - "name": "showPreviousMonth", - "type": "boolean", - "description": "

Shows previous and current month, instead of current and next (daterangepicker only

\n" - }, { "name": "rangeInputFormat", "defaultValue": "L", @@ -1044,13 +1039,24 @@ export const ngdoc: any = { { "name": "selectWeek", "type": "boolean", - "description": "

Makes dates from other months active

\n" + "description": "

Allows select first date of the week by click on week number

\n" + }, + { + "name": "showPreviousMonth", + "type": "boolean", + "description": "

Shows previous and current month, instead of current and next (dateRangePicker only)

\n" }, { "name": "showWeekNumbers", "defaultValue": "true", "type": "boolean", "description": "

Allows to hide week numbers in datepicker

\n" + }, + { + "name": "useUtc", + "defaultValue": "false", + "type": "boolean", + "description": "

sets use UTC date time format

\n" } ] }, @@ -1262,14 +1268,7 @@ export const ngdoc: any = { "className": "BsDaterangepickerConfig", "description": "", "methods": [], - "properties": [ - { - "name": "isAnimated", - "defaultValue": "false", - "type": "boolean", - "description": "

turn on/off animation

\n" - } - ] + "properties": [] }, "BsLocaleService": { "fileName": "src/datepicker/bs-locale.service.ts", @@ -2093,6 +2092,12 @@ export const ngdoc: any = { "defaultValue": "false", "type": "boolean", "description": "

default dropdown auto closing behavior

\n" + }, + { + "name": "isAnimated", + "defaultValue": "false", + "type": "boolean", + "description": "

turn on/off animation

\n" } ] }, @@ -2123,6 +2128,11 @@ export const ngdoc: any = { "type": "boolean", "description": "

This attribute indicates that the dropdown shouldn't close on inside click when autoClose is set to true

\n" }, + { + "name": "isAnimated", + "type": "boolean", + "description": "

Indicates that dropdown will be animated

\n" + }, { "name": "isDisabled", "type": "boolean", @@ -2169,6 +2179,11 @@ export const ngdoc: any = { "type": "boolean", "description": "

This attribute indicates that the dropdown shouldn't close on inside click when autoClose is set to true

\n" }, + { + "name": "isAnimated", + "type": "boolean", + "description": "

Indicates that dropdown will be animated

\n" + }, { "name": "isDisabled", "type": "boolean", @@ -2268,7 +2283,7 @@ export const ngdoc: any = { }, { "name": "checkScrollbar", - "description": "

AFTER PR MERGE MODAL.COMPONENT WILL BE USING THIS CODE\nScroll bar tricks

\n", + "description": "

Checks if the body is overflowing and sets scrollbar width

\n", "args": [], "returnType": "void" } @@ -2696,6 +2711,12 @@ export const ngdoc: any = { "type": "string", "description": "

A selector specifying the element the popover should be appended to.

\n" }, + { + "name": "delay", + "defaultValue": "0", + "type": "number", + "description": "

delay before showing the tooltip

\n" + }, { "name": "placement", "defaultValue": "top", @@ -2707,12 +2728,6 @@ export const ngdoc: any = { "defaultValue": "click", "type": "string", "description": "

Specifies events that should trigger. Supports a space separated list of\nevent names.

\n" - }, - { - "name": "delay", - "defaultValue": "0", - "type": "number", - "description": "

delay before showing the popover

\n" } ] }, @@ -2741,7 +2756,7 @@ export const ngdoc: any = { { "name": "delay", "type": "number", - "description": "

Delay before showing the popover

\n" + "description": "

Delay before showing the tooltip

\n" }, { "name": "isOpen", @@ -2927,7 +2942,7 @@ export const ngdoc: any = { }, { "name": "type", - "type": "string", + "type": "ProgressbarType", "description": "

provide one of the four supported contextual classes: success, info, warning, danger

\n" }, { @@ -3012,9 +3027,29 @@ export const ngdoc: any = { "description": "

fired when icon selected, $event:number equals to previous rating value

\n" } ], - "properties": [], + "properties": [ + { + "name": "ariaLabel", + "type": "string", + "description": "

aria label for rating

\n" + } + ], "methods": [] }, + "RatingConfig": { + "fileName": "src/rating/rating.config.ts", + "className": "RatingConfig", + "description": "

Default values provider for rating

\n", + "methods": [], + "properties": [ + { + "name": "ariaLabel", + "defaultValue": "rating", + "type": "string", + "description": "

aria label for rating

\n" + } + ] + }, "DraggableItemService": { "fileName": "src/sortable/draggable-item.service.ts", "className": "DraggableItemService", @@ -3211,7 +3246,13 @@ export const ngdoc: any = { } ], "outputs": [], - "properties": [], + "properties": [ + { + "name": "ariaLabel", + "type": "string", + "description": "

aria label for tab list

\n" + } + ], "methods": [] }, "TabsetConfig": { @@ -3220,6 +3261,12 @@ export const ngdoc: any = { "description": "", "methods": [], "properties": [ + { + "name": "ariaLabel", + "defaultValue": "Tabs", + "type": "string", + "description": "

aria label for tab list

\n" + }, { "name": "type", "defaultValue": "tabs", @@ -3265,6 +3312,11 @@ export const ngdoc: any = { "type": "boolean", "description": "

if true hours and minutes fields will be disabled

\n" }, + { + "name": "hoursPlaceholder", + "type": "string", + "description": "

placeholder for hours field in timepicker

\n" + }, { "name": "hourStep", "type": "number", @@ -3285,6 +3337,11 @@ export const ngdoc: any = { "type": "Date", "description": "

minimum time user can select

\n" }, + { + "name": "minutesPlaceholder", + "type": "string", + "description": "

placeholder for minutes field in timepicker

\n" + }, { "name": "minuteStep", "type": "number", @@ -3300,6 +3357,11 @@ export const ngdoc: any = { "type": "boolean", "description": "

if true hours and minutes fields will be readonly

\n" }, + { + "name": "secondsPlaceholder", + "type": "string", + "description": "

placeholder for seconds field in timepicker

\n" + }, { "name": "secondsStep", "type": "number", @@ -3324,21 +3386,6 @@ export const ngdoc: any = { "name": "showSpinners", "type": "boolean", "description": "

if true spinner arrows above and below the inputs will be shown

\n" - }, - { - "name": "hoursPlaceholder", - "type": "string", - "description": "

placeholder for hours field

\n" - }, - { - "name": "minutesPlacesholder", - "type": "string", - "description": "

placeholder for minutes field

\n" - }, - { - "name": "secondsPlaceholder", - "type": "string", - "description": "

placeholder for seconds field

\n" } ], "outputs": [ @@ -3368,6 +3415,12 @@ export const ngdoc: any = { "type": "boolean", "description": "

if true hours and minutes fields will be disabled

\n" }, + { + "name": "hoursPlaceholder", + "defaultValue": "HH", + "type": "string", + "description": "

placeholder for hours field in timepicker

\n" + }, { "name": "hourStep", "defaultValue": "1", @@ -3389,6 +3442,12 @@ export const ngdoc: any = { "type": "Date", "description": "

minimum time user can select

\n" }, + { + "name": "minutesPlaceholder", + "defaultValue": "MM", + "type": "string", + "description": "

placeholder for minutes field in timepicker

\n" + }, { "name": "minuteStep", "defaultValue": "5", @@ -3407,6 +3466,12 @@ export const ngdoc: any = { "type": "boolean", "description": "

if true hours and minutes fields will be readonly

\n" }, + { + "name": "secondsPlaceholder", + "defaultValue": "SS", + "type": "string", + "description": "

placeholder for seconds field in timepicker

\n" + }, { "name": "secondsStep", "defaultValue": "10", @@ -3436,24 +3501,6 @@ export const ngdoc: any = { "defaultValue": "true", "type": "boolean", "description": "

if true spinner arrows above and below the inputs will be shown

\n" - }, - { - "name": "hoursPlaceholder", - "defaultValue": "HH", - "type": "string", - "description": "

placeholder for hours field

\n" - }, - { - "name": "minutesPlacesholder", - "defaultValue": "MM", - "type": "string", - "description": "

placeholder for minutes field

\n" - }, - { - "name": "secondsPlaceholder", - "defaultValue": "SS", - "type": "string", - "description": "

placeholder for seconds field

\n" } ] }, @@ -3778,7 +3825,7 @@ export const ngdoc: any = { { "name": "typeaheadAsync", "type": "boolean", - "description": "

should be used only in case of typeahead attribute is array.\nIf true - loading of options will be async, otherwise - sync.\ntrue make sense if options array is large.

\n" + "description": "

should be used only in case of typeahead attribute is Observable of array.\nIf true - loading of options will be async, otherwise - sync.\ntrue make sense if options array is large.

\n" }, { "name": "typeaheadGroupField", diff --git a/src/common/public_api.ts b/src/common/public_api.ts index f3dc2614ee..e35d33efa5 100644 --- a/src/common/public_api.ts +++ b/src/common/public_api.ts @@ -104,7 +104,11 @@ export { ProgressbarModule } from 'ngx-bootstrap/progressbar'; -export { RatingComponent, RatingModule } from 'ngx-bootstrap/rating'; +export { + RatingComponent, + RatingModule, + RatingConfig +} from 'ngx-bootstrap/rating'; export { DraggableItem, diff --git a/src/index.ts b/src/index.ts index fe8c968cc4..0fdfafff10 100644 --- a/src/index.ts +++ b/src/index.ts @@ -100,7 +100,11 @@ export { ProgressbarModule } from './progressbar/index'; -export { RatingComponent, RatingModule } from './rating/index'; +export { + RatingComponent, + RatingModule, + RatingConfig +} from './rating/index'; export { DraggableItem, diff --git a/src/rating/public_api.ts b/src/rating/public_api.ts index 0df9080d2e..9eeff904a7 100644 --- a/src/rating/public_api.ts +++ b/src/rating/public_api.ts @@ -1,2 +1,3 @@ +export { RatingConfig } from './rating.config'; export { RatingComponent } from './rating.component'; export { RatingModule } from './rating.module'; diff --git a/src/rating/rating.component.html b/src/rating/rating.component.html index 86b9554d94..c0d7dff94c 100644 --- a/src/rating/rating.component.html +++ b/src/rating/rating.component.html @@ -1,5 +1,7 @@ {{ index < value ? '★' : '☆' }} diff --git a/src/rating/rating.component.ts b/src/rating/rating.component.ts index 7cc84be0bb..1075e6419c 100644 --- a/src/rating/rating.component.ts +++ b/src/rating/rating.component.ts @@ -9,6 +9,7 @@ import { } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { AccessorContent, RatingResults } from './models'; +import { RatingConfig } from './rating.config'; export const RATING_CONTROL_VALUE_ACCESSOR: AccessorContent = { provide: NG_VALUE_ACCESSOR, @@ -42,12 +43,16 @@ export class RatingComponent implements ControlValueAccessor, OnInit { onChange: any = Function.prototype; // tslint:disable-next-line:no-any onTouched: any = Function.prototype; - + /** aria label for rating */ + ariaLabel: string; range: RatingResults[]; value: number; protected preValue: number; - constructor(private changeDetection: ChangeDetectorRef) {} + constructor(private changeDetection: ChangeDetectorRef, + config: RatingConfig) { + Object.assign(this, config); + } @HostListener('keydown', ['$event']) onKeydown(event: KeyboardEvent): void { diff --git a/src/rating/rating.config.ts b/src/rating/rating.config.ts new file mode 100644 index 0000000000..062c4b97f4 --- /dev/null +++ b/src/rating/rating.config.ts @@ -0,0 +1,8 @@ +import { Injectable } from '@angular/core'; + +/** Default values provider for rating */ +@Injectable() +export class RatingConfig { + /** aria label for rating */ + ariaLabel = 'rating'; +} diff --git a/src/rating/rating.module.ts b/src/rating/rating.module.ts index c85f3f8160..37e5fd9a90 100644 --- a/src/rating/rating.module.ts +++ b/src/rating/rating.module.ts @@ -1,6 +1,8 @@ import { CommonModule } from '@angular/common'; import { NgModule, ModuleWithProviders } from '@angular/core'; + import { RatingComponent } from './rating.component'; +import { RatingConfig } from './rating.config'; @NgModule({ imports: [CommonModule], @@ -11,7 +13,7 @@ export class RatingModule { static forRoot(): ModuleWithProviders { return { ngModule: RatingModule, - providers: [] + providers: [RatingConfig] }; } } diff --git a/src/spec/rating.component.spec.ts b/src/spec/rating.component.spec.ts index 079f2435c3..70e5237306 100644 --- a/src/spec/rating.component.spec.ts +++ b/src/spec/rating.component.spec.ts @@ -2,7 +2,7 @@ import { Component } from '@angular/core'; import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { FormsModule } from '@angular/forms'; -import { RatingComponent, RatingModule } from '../rating'; +import { RatingComponent, RatingConfig, RatingModule } from '../rating'; @Component({ selector: 'rating-test', @@ -13,6 +13,10 @@ class TestRatingComponent { rate = 0; isReadonly = false; titles: string[] = ['one', 'two', 'three', 'four', 'five']; + + constructor(config: RatingConfig) { + Object.assign(this, config); + } } describe('Component: Rating. Init:', () => { @@ -24,7 +28,8 @@ describe('Component: Rating. Init:', () => { beforeEach(() => { TestBed.configureTestingModule({ - declarations: [RatingComponent] + declarations: [RatingComponent], + providers: [RatingConfig] }); fixture = TestBed.createComponent(RatingComponent); context = fixture.debugElement.componentInstance; @@ -46,6 +51,11 @@ describe('Component: Rating. Init:', () => { expect(icons[0].classList).not.toContain('active'); expect(icons[4].classList).not.toContain('active'); expect(icons[4].getAttribute('title')).toEqual('5'); + + const container = element.querySelector('[role="slider"]'); + const ariaAttribute = container.getAttribute('aria-label'); + + expect(ariaAttribute).toEqual('rating'); }); it('checking of working with changed values', () => {