66 * found in the LICENSE file at https://angular.io/license
77 */
88
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 ' ;
1111import { addAriaReferencedId , getAriaReferenceIds , removeAriaReferencedId } from './aria-reference' ;
1212
1313/**
@@ -45,151 +45,158 @@ let messagesContainer: HTMLElement | null = null;
4545 */
4646@Injectable ( )
4747export class AriaDescriber {
48- constructor ( private _platform : Platform ) { }
48+ private _document : Document ;
49+
50+ constructor ( @Inject ( DOCUMENT ) _document : any ) {
51+ this . _document = _document ;
52+ }
4953
5054 /**
5155 * Adds to the host element an aria-describedby reference to a hidden element that contains
5256 * the message. If the same message has already been registered, then it will reuse the created
5357 * message element.
5458 */
5559 describe ( hostElement : Element , message : string ) {
56- if ( ! this . _platform . isBrowser || ! message . trim ( ) ) { return ; }
60+ if ( ! message . trim ( ) ) {
61+ return ;
62+ }
5763
5864 if ( ! messageRegistry . has ( message ) ) {
59- createMessageElement ( message ) ;
65+ this . _createMessageElement ( message ) ;
6066 }
6167
62- if ( ! isElementDescribedByMessage ( hostElement , message ) ) {
63- addMessageReference ( hostElement , message ) ;
68+ if ( ! this . _isElementDescribedByMessage ( hostElement , message ) ) {
69+ this . _addMessageReference ( hostElement , message ) ;
6470 }
6571 }
6672
6773 /** Removes the host element's aria-describedby reference to the message element. */
6874 removeDescription ( hostElement : Element , message : string ) {
69- if ( ! this . _platform . isBrowser || ! message . trim ( ) ) {
75+ if ( ! message . trim ( ) ) {
7076 return ;
7177 }
7278
73- if ( isElementDescribedByMessage ( hostElement , message ) ) {
74- removeMessageReference ( hostElement , message ) ;
79+ if ( this . _isElementDescribedByMessage ( hostElement , message ) ) {
80+ this . _removeMessageReference ( hostElement , message ) ;
7581 }
7682
7783 const registeredMessage = messageRegistry . get ( message ) ;
7884 if ( registeredMessage && registeredMessage . referenceCount === 0 ) {
79- deleteMessageElement ( message ) ;
85+ this . _deleteMessageElement ( message ) ;
8086 }
8187
8288 if ( messagesContainer && messagesContainer . childNodes . length === 0 ) {
83- deleteMessagesContainer ( ) ;
89+ this . _deleteMessagesContainer ( ) ;
8490 }
8591 }
8692
8793 /** Unregisters all created message elements and removes the message container. */
8894 ngOnDestroy ( ) {
89- if ( ! this . _platform . isBrowser ) { return ; }
95+ const describedElements =
96+ this . _document . querySelectorAll ( `[${ CDK_DESCRIBEDBY_HOST_ATTRIBUTE } ]` ) ;
9097
91- const describedElements = document . querySelectorAll ( `[${ CDK_DESCRIBEDBY_HOST_ATTRIBUTE } ]` ) ;
9298 for ( let i = 0 ; i < describedElements . length ; i ++ ) {
93- removeCdkDescribedByReferenceIds ( describedElements [ i ] ) ;
99+ this . _removeCdkDescribedByReferenceIds ( describedElements [ i ] ) ;
94100 describedElements [ i ] . removeAttribute ( CDK_DESCRIBEDBY_HOST_ATTRIBUTE ) ;
95101 }
96102
97103 if ( messagesContainer ) {
98- deleteMessagesContainer ( ) ;
104+ this . _deleteMessagesContainer ( ) ;
99105 }
100106
101107 messageRegistry . clear ( ) ;
102108 }
103- }
104109
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 ) ! ) ;
113118
114- if ( ! messagesContainer ) { createMessagesContainer ( ) ; }
115- messagesContainer ! . appendChild ( messageElement ) ;
119+ if ( ! messagesContainer ) { this . _createMessagesContainer ( ) ; }
120+ messagesContainer ! . appendChild ( messageElement ) ;
116121
117- messageRegistry . set ( message , { messageElement, referenceCount : 0 } ) ;
118- }
122+ messageRegistry . set ( message , { messageElement, referenceCount : 0 } ) ;
123+ }
119124
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 ) ;
126133 }
127- messageRegistry . delete ( message ) ;
128- }
129134
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' ) ;
133138
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+ }
139144
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+ }
145150
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+ }
153158
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 ) ! ;
160165
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 , '' ) ;
164170
165- registeredMessage . referenceCount ++ ;
166- }
171+ registeredMessage . referenceCount ++ ;
172+ }
167173
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 -- ;
175181
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 ;
179191
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+ }
185194
186- return ! ! messageId && referenceIds . indexOf ( messageId ) != - 1 ;
187195}
188196
189197/** @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 ) ;
193200}
194201
195202/** @docs -private */
@@ -198,7 +205,7 @@ export const ARIA_DESCRIBER_PROVIDER = {
198205 provide : AriaDescriber ,
199206 deps : [
200207 [ new Optional ( ) , new SkipSelf ( ) , AriaDescriber ] ,
201- Platform
208+ DOCUMENT as InjectionToken < any >
202209 ] ,
203210 useFactory : ARIA_DESCRIBER_PROVIDER_FACTORY
204211} ;
0 commit comments