6
6
* found in the LICENSE file at https://angular.io/license
7
7
*/
8
8
9
- import { Injectable , Optional , SkipSelf } from '@angular/core' ;
10
- import { Platform } from '@angular/cdk/platform ' ;
9
+ import { Injectable , Inject , InjectionToken , Optional , SkipSelf } from '@angular/core' ;
10
+ import { DOCUMENT } from '@angular/common ' ;
11
11
import { addAriaReferencedId , getAriaReferenceIds , removeAriaReferencedId } from './aria-reference' ;
12
12
13
13
/**
@@ -45,151 +45,158 @@ let messagesContainer: HTMLElement | null = null;
45
45
*/
46
46
@Injectable ( )
47
47
export class AriaDescriber {
48
- constructor ( private _platform : Platform ) { }
48
+ private _document : Document ;
49
+
50
+ constructor ( @Inject ( DOCUMENT ) _document : any ) {
51
+ this . _document = _document ;
52
+ }
49
53
50
54
/**
51
55
* Adds to the host element an aria-describedby reference to a hidden element that contains
52
56
* the message. If the same message has already been registered, then it will reuse the created
53
57
* message element.
54
58
*/
55
59
describe ( hostElement : Element , message : string ) {
56
- if ( ! this . _platform . isBrowser || ! message . trim ( ) ) { return ; }
60
+ if ( ! message . trim ( ) ) {
61
+ return ;
62
+ }
57
63
58
64
if ( ! messageRegistry . has ( message ) ) {
59
- createMessageElement ( message ) ;
65
+ this . _createMessageElement ( message ) ;
60
66
}
61
67
62
- if ( ! isElementDescribedByMessage ( hostElement , message ) ) {
63
- addMessageReference ( hostElement , message ) ;
68
+ if ( ! this . _isElementDescribedByMessage ( hostElement , message ) ) {
69
+ this . _addMessageReference ( hostElement , message ) ;
64
70
}
65
71
}
66
72
67
73
/** Removes the host element's aria-describedby reference to the message element. */
68
74
removeDescription ( hostElement : Element , message : string ) {
69
- if ( ! this . _platform . isBrowser || ! message . trim ( ) ) {
75
+ if ( ! message . trim ( ) ) {
70
76
return ;
71
77
}
72
78
73
- if ( isElementDescribedByMessage ( hostElement , message ) ) {
74
- removeMessageReference ( hostElement , message ) ;
79
+ if ( this . _isElementDescribedByMessage ( hostElement , message ) ) {
80
+ this . _removeMessageReference ( hostElement , message ) ;
75
81
}
76
82
77
83
const registeredMessage = messageRegistry . get ( message ) ;
78
84
if ( registeredMessage && registeredMessage . referenceCount === 0 ) {
79
- deleteMessageElement ( message ) ;
85
+ this . _deleteMessageElement ( message ) ;
80
86
}
81
87
82
88
if ( messagesContainer && messagesContainer . childNodes . length === 0 ) {
83
- deleteMessagesContainer ( ) ;
89
+ this . _deleteMessagesContainer ( ) ;
84
90
}
85
91
}
86
92
87
93
/** Unregisters all created message elements and removes the message container. */
88
94
ngOnDestroy ( ) {
89
- if ( ! this . _platform . isBrowser ) { return ; }
95
+ const describedElements =
96
+ this . _document . querySelectorAll ( `[${ CDK_DESCRIBEDBY_HOST_ATTRIBUTE } ]` ) ;
90
97
91
- const describedElements = document . querySelectorAll ( `[${ CDK_DESCRIBEDBY_HOST_ATTRIBUTE } ]` ) ;
92
98
for ( let i = 0 ; i < describedElements . length ; i ++ ) {
93
- removeCdkDescribedByReferenceIds ( describedElements [ i ] ) ;
99
+ this . _removeCdkDescribedByReferenceIds ( describedElements [ i ] ) ;
94
100
describedElements [ i ] . removeAttribute ( CDK_DESCRIBEDBY_HOST_ATTRIBUTE ) ;
95
101
}
96
102
97
103
if ( messagesContainer ) {
98
- deleteMessagesContainer ( ) ;
104
+ this . _deleteMessagesContainer ( ) ;
99
105
}
100
106
101
107
messageRegistry . clear ( ) ;
102
108
}
103
- }
104
109
105
- /**
106
- * Creates a new element in the visually hidden message container element with the message
107
- * as its content and adds it to the message registry.
108
- */
109
- function createMessageElement ( message : string ) {
110
- const messageElement = document . createElement ( 'div' ) ;
111
- messageElement . setAttribute ( 'id' , `${ CDK_DESCRIBEDBY_ID_PREFIX } -${ nextId ++ } ` ) ;
112
- messageElement . appendChild ( document . createTextNode ( message ) ! ) ;
110
+ /**
111
+ * Creates a new element in the visually hidden message container element with the message
112
+ * as its content and adds it to the message registry.
113
+ */
114
+ private _createMessageElement ( message : string ) {
115
+ const messageElement = this . _document . createElement ( 'div' ) ;
116
+ messageElement . setAttribute ( 'id' , `${ CDK_DESCRIBEDBY_ID_PREFIX } -${ nextId ++ } ` ) ;
117
+ messageElement . appendChild ( this . _document . createTextNode ( message ) ! ) ;
113
118
114
- if ( ! messagesContainer ) { createMessagesContainer ( ) ; }
115
- messagesContainer ! . appendChild ( messageElement ) ;
119
+ if ( ! messagesContainer ) { this . _createMessagesContainer ( ) ; }
120
+ messagesContainer ! . appendChild ( messageElement ) ;
116
121
117
- messageRegistry . set ( message , { messageElement, referenceCount : 0 } ) ;
118
- }
122
+ messageRegistry . set ( message , { messageElement, referenceCount : 0 } ) ;
123
+ }
119
124
120
- /** Deletes the message element from the global messages container. */
121
- function deleteMessageElement ( message : string ) {
122
- const registeredMessage = messageRegistry . get ( message ) ;
123
- const messageElement = registeredMessage && registeredMessage . messageElement ;
124
- if ( messagesContainer && messageElement ) {
125
- messagesContainer . removeChild ( messageElement ) ;
125
+ /** Deletes the message element from the global messages container. */
126
+ private _deleteMessageElement ( message : string ) {
127
+ const registeredMessage = messageRegistry . get ( message ) ;
128
+ const messageElement = registeredMessage && registeredMessage . messageElement ;
129
+ if ( messagesContainer && messageElement ) {
130
+ messagesContainer . removeChild ( messageElement ) ;
131
+ }
132
+ messageRegistry . delete ( message ) ;
126
133
}
127
- messageRegistry . delete ( message ) ;
128
- }
129
134
130
- /** Creates the global container for all aria-describedby messages. */
131
- function createMessagesContainer ( ) {
132
- messagesContainer = document . createElement ( 'div' ) ;
135
+ /** Creates the global container for all aria-describedby messages. */
136
+ private _createMessagesContainer ( ) {
137
+ messagesContainer = this . _document . createElement ( 'div' ) ;
133
138
134
- messagesContainer . setAttribute ( 'id' , MESSAGES_CONTAINER_ID ) ;
135
- messagesContainer . setAttribute ( 'aria-hidden' , 'true' ) ;
136
- messagesContainer . style . display = 'none' ;
137
- document . body . appendChild ( messagesContainer ) ;
138
- }
139
+ messagesContainer . setAttribute ( 'id' , MESSAGES_CONTAINER_ID ) ;
140
+ messagesContainer . setAttribute ( 'aria-hidden' , 'true' ) ;
141
+ messagesContainer . style . display = 'none' ;
142
+ this . _document . body . appendChild ( messagesContainer ) ;
143
+ }
139
144
140
- /** Deletes the global messages container. */
141
- function deleteMessagesContainer ( ) {
142
- document . body . removeChild ( messagesContainer ! ) ;
143
- messagesContainer = null ;
144
- }
145
+ /** Deletes the global messages container. */
146
+ private _deleteMessagesContainer ( ) {
147
+ this . _document . body . removeChild ( messagesContainer ! ) ;
148
+ messagesContainer = null ;
149
+ }
145
150
146
- /** Removes all cdk-describedby messages that are hosted through the element. */
147
- function removeCdkDescribedByReferenceIds ( element : Element ) {
148
- // Remove all aria-describedby reference IDs that are prefixed by CDK_DESCRIBEDBY_ID_PREFIX
149
- const originalReferenceIds = getAriaReferenceIds ( element , 'aria-describedby' )
150
- . filter ( id => id . indexOf ( CDK_DESCRIBEDBY_ID_PREFIX ) != 0 ) ;
151
- element . setAttribute ( 'aria-describedby' , originalReferenceIds . join ( ' ' ) ) ;
152
- }
151
+ /** Removes all cdk-describedby messages that are hosted through the element. */
152
+ private _removeCdkDescribedByReferenceIds ( element : Element ) {
153
+ // Remove all aria-describedby reference IDs that are prefixed by CDK_DESCRIBEDBY_ID_PREFIX
154
+ const originalReferenceIds = getAriaReferenceIds ( element , 'aria-describedby' )
155
+ . filter ( id => id . indexOf ( CDK_DESCRIBEDBY_ID_PREFIX ) != 0 ) ;
156
+ element . setAttribute ( 'aria-describedby' , originalReferenceIds . join ( ' ' ) ) ;
157
+ }
153
158
154
- /**
155
- * Adds a message reference to the element using aria-describedby and increments the registered
156
- * message's reference count.
157
- */
158
- function addMessageReference ( element : Element , message : string ) {
159
- const registeredMessage = messageRegistry . get ( message ) ! ;
159
+ /**
160
+ * Adds a message reference to the element using aria-describedby and increments the registered
161
+ * message's reference count.
162
+ */
163
+ private _addMessageReference ( element : Element , message : string ) {
164
+ const registeredMessage = messageRegistry . get ( message ) ! ;
160
165
161
- // Add the aria-describedby reference and set the describedby_host attribute to mark the element.
162
- addAriaReferencedId ( element , 'aria-describedby' , registeredMessage . messageElement . id ) ;
163
- element . setAttribute ( CDK_DESCRIBEDBY_HOST_ATTRIBUTE , '' ) ;
166
+ // Add the aria-describedby reference and set the
167
+ // describedby_host attribute to mark the element.
168
+ addAriaReferencedId ( element , 'aria-describedby' , registeredMessage . messageElement . id ) ;
169
+ element . setAttribute ( CDK_DESCRIBEDBY_HOST_ATTRIBUTE , '' ) ;
164
170
165
- registeredMessage . referenceCount ++ ;
166
- }
171
+ registeredMessage . referenceCount ++ ;
172
+ }
167
173
168
- /**
169
- * Removes a message reference from the element using aria-describedby and decrements the registered
170
- * message's reference count.
171
- */
172
- function removeMessageReference ( element : Element , message : string ) {
173
- const registeredMessage = messageRegistry . get ( message ) ! ;
174
- registeredMessage . referenceCount -- ;
174
+ /**
175
+ * Removes a message reference from the element using aria-describedby
176
+ * and decrements the registered message's reference count.
177
+ */
178
+ private _removeMessageReference ( element : Element , message : string ) {
179
+ const registeredMessage = messageRegistry . get ( message ) ! ;
180
+ registeredMessage . referenceCount -- ;
175
181
176
- removeAriaReferencedId ( element , 'aria-describedby' , registeredMessage . messageElement . id ) ;
177
- element . removeAttribute ( CDK_DESCRIBEDBY_HOST_ATTRIBUTE ) ;
178
- }
182
+ removeAriaReferencedId ( element , 'aria-describedby' , registeredMessage . messageElement . id ) ;
183
+ element . removeAttribute ( CDK_DESCRIBEDBY_HOST_ATTRIBUTE ) ;
184
+ }
185
+
186
+ /** Returns true if the element has been described by the provided message ID. */
187
+ private _isElementDescribedByMessage ( element : Element , message : string ) : boolean {
188
+ const referenceIds = getAriaReferenceIds ( element , 'aria-describedby' ) ;
189
+ const registeredMessage = messageRegistry . get ( message ) ;
190
+ const messageId = registeredMessage && registeredMessage . messageElement . id ;
179
191
180
- /** Returns true if the element has been described by the provided message ID. */
181
- function isElementDescribedByMessage ( element : Element , message : string ) : boolean {
182
- const referenceIds = getAriaReferenceIds ( element , 'aria-describedby' ) ;
183
- const registeredMessage = messageRegistry . get ( message ) ;
184
- const messageId = registeredMessage && registeredMessage . messageElement . id ;
192
+ return ! ! messageId && referenceIds . indexOf ( messageId ) != - 1 ;
193
+ }
185
194
186
- return ! ! messageId && referenceIds . indexOf ( messageId ) != - 1 ;
187
195
}
188
196
189
197
/** @docs -private */
190
- export function ARIA_DESCRIBER_PROVIDER_FACTORY (
191
- parentDispatcher : AriaDescriber , platform : Platform ) {
192
- return parentDispatcher || new AriaDescriber ( platform ) ;
198
+ export function ARIA_DESCRIBER_PROVIDER_FACTORY ( parentDispatcher : AriaDescriber , _document : any ) {
199
+ return parentDispatcher || new AriaDescriber ( _document ) ;
193
200
}
194
201
195
202
/** @docs -private */
@@ -198,7 +205,7 @@ export const ARIA_DESCRIBER_PROVIDER = {
198
205
provide : AriaDescriber ,
199
206
deps : [
200
207
[ new Optional ( ) , new SkipSelf ( ) , AriaDescriber ] ,
201
- Platform
208
+ DOCUMENT as InjectionToken < any >
202
209
] ,
203
210
useFactory : ARIA_DESCRIBER_PROVIDER_FACTORY
204
211
} ;
0 commit comments