cdk-a11y.umd.js 119 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158
  1. /**
  2. * @license
  3. * Copyright Google LLC All Rights Reserved.
  4. *
  5. * Use of this source code is governed by an MIT-style license that can be
  6. * found in the LICENSE file at https://angular.io/license
  7. */
  8. (function (global, factory) {
  9. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/common'), require('@angular/core'), require('rxjs'), require('@angular/cdk/keycodes'), require('rxjs/operators'), require('@angular/cdk/platform'), require('@angular/cdk/coercion'), require('@angular/cdk/observers')) :
  10. typeof define === 'function' && define.amd ? define('@angular/cdk/a11y', ['exports', '@angular/common', '@angular/core', 'rxjs', '@angular/cdk/keycodes', 'rxjs/operators', '@angular/cdk/platform', '@angular/cdk/coercion', '@angular/cdk/observers'], factory) :
  11. (factory((global.ng = global.ng || {}, global.ng.cdk = global.ng.cdk || {}, global.ng.cdk.a11y = {}),global.ng.common,global.ng.core,global.rxjs,global.ng.cdk.keycodes,global.rxjs.operators,global.ng.cdk.platform,global.ng.cdk.coercion,global.ng.cdk.observers));
  12. }(this, (function (exports,common,core,rxjs,keycodes,operators,platform,coercion,observers) { 'use strict';
  13. /*! *****************************************************************************
  14. Copyright (c) Microsoft Corporation. All rights reserved.
  15. Licensed under the Apache License, Version 2.0 (the "License"); you may not use
  16. this file except in compliance with the License. You may obtain a copy of the
  17. License at http://www.apache.org/licenses/LICENSE-2.0
  18. THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  19. KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
  20. WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
  21. MERCHANTABLITY OR NON-INFRINGEMENT.
  22. See the Apache Version 2.0 License for specific language governing permissions
  23. and limitations under the License.
  24. ***************************************************************************** */
  25. /* global Reflect, Promise */
  26. var extendStatics = function(d, b) {
  27. extendStatics = Object.setPrototypeOf ||
  28. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  29. function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  30. return extendStatics(d, b);
  31. };
  32. function __extends(d, b) {
  33. extendStatics(d, b);
  34. function __() { this.constructor = d; }
  35. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  36. }
  37. /**
  38. * @fileoverview added by tsickle
  39. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  40. */
  41. /**
  42. * IDs are deliminated by an empty space, as per the spec.
  43. * @type {?}
  44. */
  45. var ID_DELIMINATOR = ' ';
  46. /**
  47. * Adds the given ID to the specified ARIA attribute on an element.
  48. * Used for attributes such as aria-labelledby, aria-owns, etc.
  49. * @param {?} el
  50. * @param {?} attr
  51. * @param {?} id
  52. * @return {?}
  53. */
  54. function addAriaReferencedId(el, attr, id) {
  55. /** @type {?} */
  56. var ids = getAriaReferenceIds(el, attr);
  57. if (ids.some((/**
  58. * @param {?} existingId
  59. * @return {?}
  60. */
  61. function (existingId) { return existingId.trim() == id.trim(); }))) {
  62. return;
  63. }
  64. ids.push(id.trim());
  65. el.setAttribute(attr, ids.join(ID_DELIMINATOR));
  66. }
  67. /**
  68. * Removes the given ID from the specified ARIA attribute on an element.
  69. * Used for attributes such as aria-labelledby, aria-owns, etc.
  70. * @param {?} el
  71. * @param {?} attr
  72. * @param {?} id
  73. * @return {?}
  74. */
  75. function removeAriaReferencedId(el, attr, id) {
  76. /** @type {?} */
  77. var ids = getAriaReferenceIds(el, attr);
  78. /** @type {?} */
  79. var filteredIds = ids.filter((/**
  80. * @param {?} val
  81. * @return {?}
  82. */
  83. function (val) { return val != id.trim(); }));
  84. if (filteredIds.length) {
  85. el.setAttribute(attr, filteredIds.join(ID_DELIMINATOR));
  86. }
  87. else {
  88. el.removeAttribute(attr);
  89. }
  90. }
  91. /**
  92. * Gets the list of IDs referenced by the given ARIA attribute on an element.
  93. * Used for attributes such as aria-labelledby, aria-owns, etc.
  94. * @param {?} el
  95. * @param {?} attr
  96. * @return {?}
  97. */
  98. function getAriaReferenceIds(el, attr) {
  99. // Get string array of all individual ids (whitespace deliminated) in the attribute value
  100. return (el.getAttribute(attr) || '').match(/\S+/g) || [];
  101. }
  102. /**
  103. * @fileoverview added by tsickle
  104. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  105. */
  106. /**
  107. * ID used for the body container where all messages are appended.
  108. * @type {?}
  109. */
  110. var MESSAGES_CONTAINER_ID = 'cdk-describedby-message-container';
  111. /**
  112. * ID prefix used for each created message element.
  113. * @type {?}
  114. */
  115. var CDK_DESCRIBEDBY_ID_PREFIX = 'cdk-describedby-message';
  116. /**
  117. * Attribute given to each host element that is described by a message element.
  118. * @type {?}
  119. */
  120. var CDK_DESCRIBEDBY_HOST_ATTRIBUTE = 'cdk-describedby-host';
  121. /**
  122. * Global incremental identifier for each registered message element.
  123. * @type {?}
  124. */
  125. var nextId = 0;
  126. /**
  127. * Global map of all registered message elements that have been placed into the document.
  128. * @type {?}
  129. */
  130. var messageRegistry = new Map();
  131. /**
  132. * Container for all registered messages.
  133. * @type {?}
  134. */
  135. var messagesContainer = null;
  136. /**
  137. * Utility that creates visually hidden elements with a message content. Useful for elements that
  138. * want to use aria-describedby to further describe themselves without adding additional visual
  139. * content.
  140. */
  141. var AriaDescriber = /** @class */ (function () {
  142. function AriaDescriber(_document) {
  143. this._document = _document;
  144. }
  145. /**
  146. * Adds to the host element an aria-describedby reference to a hidden element that contains
  147. * the message. If the same message has already been registered, then it will reuse the created
  148. * message element.
  149. */
  150. /**
  151. * Adds to the host element an aria-describedby reference to a hidden element that contains
  152. * the message. If the same message has already been registered, then it will reuse the created
  153. * message element.
  154. * @param {?} hostElement
  155. * @param {?} message
  156. * @return {?}
  157. */
  158. AriaDescriber.prototype.describe = /**
  159. * Adds to the host element an aria-describedby reference to a hidden element that contains
  160. * the message. If the same message has already been registered, then it will reuse the created
  161. * message element.
  162. * @param {?} hostElement
  163. * @param {?} message
  164. * @return {?}
  165. */
  166. function (hostElement, message) {
  167. if (!this._canBeDescribed(hostElement, message)) {
  168. return;
  169. }
  170. if (typeof message !== 'string') {
  171. // We need to ensure that the element has an ID.
  172. this._setMessageId(message);
  173. messageRegistry.set(message, { messageElement: message, referenceCount: 0 });
  174. }
  175. else if (!messageRegistry.has(message)) {
  176. this._createMessageElement(message);
  177. }
  178. if (!this._isElementDescribedByMessage(hostElement, message)) {
  179. this._addMessageReference(hostElement, message);
  180. }
  181. };
  182. /** Removes the host element's aria-describedby reference to the message element. */
  183. /**
  184. * Removes the host element's aria-describedby reference to the message element.
  185. * @param {?} hostElement
  186. * @param {?} message
  187. * @return {?}
  188. */
  189. AriaDescriber.prototype.removeDescription = /**
  190. * Removes the host element's aria-describedby reference to the message element.
  191. * @param {?} hostElement
  192. * @param {?} message
  193. * @return {?}
  194. */
  195. function (hostElement, message) {
  196. if (!this._isElementNode(hostElement)) {
  197. return;
  198. }
  199. if (this._isElementDescribedByMessage(hostElement, message)) {
  200. this._removeMessageReference(hostElement, message);
  201. }
  202. // If the message is a string, it means that it's one that we created for the
  203. // consumer so we can remove it safely, otherwise we should leave it in place.
  204. if (typeof message === 'string') {
  205. /** @type {?} */
  206. var registeredMessage = messageRegistry.get(message);
  207. if (registeredMessage && registeredMessage.referenceCount === 0) {
  208. this._deleteMessageElement(message);
  209. }
  210. }
  211. if (messagesContainer && messagesContainer.childNodes.length === 0) {
  212. this._deleteMessagesContainer();
  213. }
  214. };
  215. /** Unregisters all created message elements and removes the message container. */
  216. /**
  217. * Unregisters all created message elements and removes the message container.
  218. * @return {?}
  219. */
  220. AriaDescriber.prototype.ngOnDestroy = /**
  221. * Unregisters all created message elements and removes the message container.
  222. * @return {?}
  223. */
  224. function () {
  225. /** @type {?} */
  226. var describedElements = this._document.querySelectorAll("[" + CDK_DESCRIBEDBY_HOST_ATTRIBUTE + "]");
  227. for (var i = 0; i < describedElements.length; i++) {
  228. this._removeCdkDescribedByReferenceIds(describedElements[i]);
  229. describedElements[i].removeAttribute(CDK_DESCRIBEDBY_HOST_ATTRIBUTE);
  230. }
  231. if (messagesContainer) {
  232. this._deleteMessagesContainer();
  233. }
  234. messageRegistry.clear();
  235. };
  236. /**
  237. * Creates a new element in the visually hidden message container element with the message
  238. * as its content and adds it to the message registry.
  239. */
  240. /**
  241. * Creates a new element in the visually hidden message container element with the message
  242. * as its content and adds it to the message registry.
  243. * @private
  244. * @param {?} message
  245. * @return {?}
  246. */
  247. AriaDescriber.prototype._createMessageElement = /**
  248. * Creates a new element in the visually hidden message container element with the message
  249. * as its content and adds it to the message registry.
  250. * @private
  251. * @param {?} message
  252. * @return {?}
  253. */
  254. function (message) {
  255. /** @type {?} */
  256. var messageElement = this._document.createElement('div');
  257. this._setMessageId(messageElement);
  258. messageElement.textContent = message;
  259. this._createMessagesContainer();
  260. (/** @type {?} */ (messagesContainer)).appendChild(messageElement);
  261. messageRegistry.set(message, { messageElement: messageElement, referenceCount: 0 });
  262. };
  263. /** Assigns a unique ID to an element, if it doesn't have one already. */
  264. /**
  265. * Assigns a unique ID to an element, if it doesn't have one already.
  266. * @private
  267. * @param {?} element
  268. * @return {?}
  269. */
  270. AriaDescriber.prototype._setMessageId = /**
  271. * Assigns a unique ID to an element, if it doesn't have one already.
  272. * @private
  273. * @param {?} element
  274. * @return {?}
  275. */
  276. function (element) {
  277. if (!element.id) {
  278. element.id = CDK_DESCRIBEDBY_ID_PREFIX + "-" + nextId++;
  279. }
  280. };
  281. /** Deletes the message element from the global messages container. */
  282. /**
  283. * Deletes the message element from the global messages container.
  284. * @private
  285. * @param {?} message
  286. * @return {?}
  287. */
  288. AriaDescriber.prototype._deleteMessageElement = /**
  289. * Deletes the message element from the global messages container.
  290. * @private
  291. * @param {?} message
  292. * @return {?}
  293. */
  294. function (message) {
  295. /** @type {?} */
  296. var registeredMessage = messageRegistry.get(message);
  297. /** @type {?} */
  298. var messageElement = registeredMessage && registeredMessage.messageElement;
  299. if (messagesContainer && messageElement) {
  300. messagesContainer.removeChild(messageElement);
  301. }
  302. messageRegistry.delete(message);
  303. };
  304. /** Creates the global container for all aria-describedby messages. */
  305. /**
  306. * Creates the global container for all aria-describedby messages.
  307. * @private
  308. * @return {?}
  309. */
  310. AriaDescriber.prototype._createMessagesContainer = /**
  311. * Creates the global container for all aria-describedby messages.
  312. * @private
  313. * @return {?}
  314. */
  315. function () {
  316. if (!messagesContainer) {
  317. /** @type {?} */
  318. var preExistingContainer = this._document.getElementById(MESSAGES_CONTAINER_ID);
  319. // When going from the server to the client, we may end up in a situation where there's
  320. // already a container on the page, but we don't have a reference to it. Clear the
  321. // old container so we don't get duplicates. Doing this, instead of emptying the previous
  322. // container, should be slightly faster.
  323. if (preExistingContainer) {
  324. (/** @type {?} */ (preExistingContainer.parentNode)).removeChild(preExistingContainer);
  325. }
  326. messagesContainer = this._document.createElement('div');
  327. messagesContainer.id = MESSAGES_CONTAINER_ID;
  328. messagesContainer.setAttribute('aria-hidden', 'true');
  329. messagesContainer.style.display = 'none';
  330. this._document.body.appendChild(messagesContainer);
  331. }
  332. };
  333. /** Deletes the global messages container. */
  334. /**
  335. * Deletes the global messages container.
  336. * @private
  337. * @return {?}
  338. */
  339. AriaDescriber.prototype._deleteMessagesContainer = /**
  340. * Deletes the global messages container.
  341. * @private
  342. * @return {?}
  343. */
  344. function () {
  345. if (messagesContainer && messagesContainer.parentNode) {
  346. messagesContainer.parentNode.removeChild(messagesContainer);
  347. messagesContainer = null;
  348. }
  349. };
  350. /** Removes all cdk-describedby messages that are hosted through the element. */
  351. /**
  352. * Removes all cdk-describedby messages that are hosted through the element.
  353. * @private
  354. * @param {?} element
  355. * @return {?}
  356. */
  357. AriaDescriber.prototype._removeCdkDescribedByReferenceIds = /**
  358. * Removes all cdk-describedby messages that are hosted through the element.
  359. * @private
  360. * @param {?} element
  361. * @return {?}
  362. */
  363. function (element) {
  364. // Remove all aria-describedby reference IDs that are prefixed by CDK_DESCRIBEDBY_ID_PREFIX
  365. /** @type {?} */
  366. var originalReferenceIds = getAriaReferenceIds(element, 'aria-describedby')
  367. .filter((/**
  368. * @param {?} id
  369. * @return {?}
  370. */
  371. function (id) { return id.indexOf(CDK_DESCRIBEDBY_ID_PREFIX) != 0; }));
  372. element.setAttribute('aria-describedby', originalReferenceIds.join(' '));
  373. };
  374. /**
  375. * Adds a message reference to the element using aria-describedby and increments the registered
  376. * message's reference count.
  377. */
  378. /**
  379. * Adds a message reference to the element using aria-describedby and increments the registered
  380. * message's reference count.
  381. * @private
  382. * @param {?} element
  383. * @param {?} message
  384. * @return {?}
  385. */
  386. AriaDescriber.prototype._addMessageReference = /**
  387. * Adds a message reference to the element using aria-describedby and increments the registered
  388. * message's reference count.
  389. * @private
  390. * @param {?} element
  391. * @param {?} message
  392. * @return {?}
  393. */
  394. function (element, message) {
  395. /** @type {?} */
  396. var registeredMessage = (/** @type {?} */ (messageRegistry.get(message)));
  397. // Add the aria-describedby reference and set the
  398. // describedby_host attribute to mark the element.
  399. addAriaReferencedId(element, 'aria-describedby', registeredMessage.messageElement.id);
  400. element.setAttribute(CDK_DESCRIBEDBY_HOST_ATTRIBUTE, '');
  401. registeredMessage.referenceCount++;
  402. };
  403. /**
  404. * Removes a message reference from the element using aria-describedby
  405. * and decrements the registered message's reference count.
  406. */
  407. /**
  408. * Removes a message reference from the element using aria-describedby
  409. * and decrements the registered message's reference count.
  410. * @private
  411. * @param {?} element
  412. * @param {?} message
  413. * @return {?}
  414. */
  415. AriaDescriber.prototype._removeMessageReference = /**
  416. * Removes a message reference from the element using aria-describedby
  417. * and decrements the registered message's reference count.
  418. * @private
  419. * @param {?} element
  420. * @param {?} message
  421. * @return {?}
  422. */
  423. function (element, message) {
  424. /** @type {?} */
  425. var registeredMessage = (/** @type {?} */ (messageRegistry.get(message)));
  426. registeredMessage.referenceCount--;
  427. removeAriaReferencedId(element, 'aria-describedby', registeredMessage.messageElement.id);
  428. element.removeAttribute(CDK_DESCRIBEDBY_HOST_ATTRIBUTE);
  429. };
  430. /** Returns true if the element has been described by the provided message ID. */
  431. /**
  432. * Returns true if the element has been described by the provided message ID.
  433. * @private
  434. * @param {?} element
  435. * @param {?} message
  436. * @return {?}
  437. */
  438. AriaDescriber.prototype._isElementDescribedByMessage = /**
  439. * Returns true if the element has been described by the provided message ID.
  440. * @private
  441. * @param {?} element
  442. * @param {?} message
  443. * @return {?}
  444. */
  445. function (element, message) {
  446. /** @type {?} */
  447. var referenceIds = getAriaReferenceIds(element, 'aria-describedby');
  448. /** @type {?} */
  449. var registeredMessage = messageRegistry.get(message);
  450. /** @type {?} */
  451. var messageId = registeredMessage && registeredMessage.messageElement.id;
  452. return !!messageId && referenceIds.indexOf(messageId) != -1;
  453. };
  454. /** Determines whether a message can be described on a particular element. */
  455. /**
  456. * Determines whether a message can be described on a particular element.
  457. * @private
  458. * @param {?} element
  459. * @param {?} message
  460. * @return {?}
  461. */
  462. AriaDescriber.prototype._canBeDescribed = /**
  463. * Determines whether a message can be described on a particular element.
  464. * @private
  465. * @param {?} element
  466. * @param {?} message
  467. * @return {?}
  468. */
  469. function (element, message) {
  470. if (!this._isElementNode(element)) {
  471. return false;
  472. }
  473. if (message && typeof message === 'object') {
  474. // We'd have to make some assumptions about the description element's text, if the consumer
  475. // passed in an element. Assume that if an element is passed in, the consumer has verified
  476. // that it can be used as a description.
  477. return true;
  478. }
  479. /** @type {?} */
  480. var trimmedMessage = message == null ? '' : ("" + message).trim();
  481. /** @type {?} */
  482. var ariaLabel = element.getAttribute('aria-label');
  483. // We shouldn't set descriptions if they're exactly the same as the `aria-label` of the
  484. // element, because screen readers will end up reading out the same text twice in a row.
  485. return trimmedMessage ? (!ariaLabel || ariaLabel.trim() !== trimmedMessage) : false;
  486. };
  487. /** Checks whether a node is an Element node. */
  488. /**
  489. * Checks whether a node is an Element node.
  490. * @private
  491. * @param {?} element
  492. * @return {?}
  493. */
  494. AriaDescriber.prototype._isElementNode = /**
  495. * Checks whether a node is an Element node.
  496. * @private
  497. * @param {?} element
  498. * @return {?}
  499. */
  500. function (element) {
  501. return element.nodeType === this._document.ELEMENT_NODE;
  502. };
  503. AriaDescriber.decorators = [
  504. { type: core.Injectable, args: [{ providedIn: 'root' },] },
  505. ];
  506. /** @nocollapse */
  507. AriaDescriber.ctorParameters = function () { return [
  508. { type: undefined, decorators: [{ type: core.Inject, args: [common.DOCUMENT,] }] }
  509. ]; };
  510. /** @nocollapse */ AriaDescriber.ngInjectableDef = core.ɵɵdefineInjectable({ factory: function AriaDescriber_Factory() { return new AriaDescriber(core.ɵɵinject(common.DOCUMENT)); }, token: AriaDescriber, providedIn: "root" });
  511. return AriaDescriber;
  512. }());
  513. /**
  514. * \@docs-private \@deprecated \@breaking-change 8.0.0
  515. * @param {?} parentDispatcher
  516. * @param {?} _document
  517. * @return {?}
  518. */
  519. function ARIA_DESCRIBER_PROVIDER_FACTORY(parentDispatcher, _document) {
  520. return parentDispatcher || new AriaDescriber(_document);
  521. }
  522. /**
  523. * \@docs-private \@deprecated \@breaking-change 8.0.0
  524. * @type {?}
  525. */
  526. var ARIA_DESCRIBER_PROVIDER = {
  527. // If there is already an AriaDescriber available, use that. Otherwise, provide a new one.
  528. provide: AriaDescriber,
  529. deps: [
  530. [new core.Optional(), new core.SkipSelf(), AriaDescriber],
  531. (/** @type {?} */ (common.DOCUMENT))
  532. ],
  533. useFactory: ARIA_DESCRIBER_PROVIDER_FACTORY
  534. };
  535. /**
  536. * @fileoverview added by tsickle
  537. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  538. */
  539. /**
  540. * This class manages keyboard events for selectable lists. If you pass it a query list
  541. * of items, it will set the active item correctly when arrow events occur.
  542. * @template T
  543. */
  544. var /**
  545. * This class manages keyboard events for selectable lists. If you pass it a query list
  546. * of items, it will set the active item correctly when arrow events occur.
  547. * @template T
  548. */
  549. ListKeyManager = /** @class */ (function () {
  550. function ListKeyManager(_items) {
  551. var _this = this;
  552. this._items = _items;
  553. this._activeItemIndex = -1;
  554. this._activeItem = null;
  555. this._wrap = false;
  556. this._letterKeyStream = new rxjs.Subject();
  557. this._typeaheadSubscription = rxjs.Subscription.EMPTY;
  558. this._vertical = true;
  559. this._allowedModifierKeys = [];
  560. /**
  561. * Predicate function that can be used to check whether an item should be skipped
  562. * by the key manager. By default, disabled items are skipped.
  563. */
  564. this._skipPredicateFn = (/**
  565. * @param {?} item
  566. * @return {?}
  567. */
  568. function (item) { return item.disabled; });
  569. // Buffer for the letters that the user has pressed when the typeahead option is turned on.
  570. this._pressedLetters = [];
  571. /**
  572. * Stream that emits any time the TAB key is pressed, so components can react
  573. * when focus is shifted off of the list.
  574. */
  575. this.tabOut = new rxjs.Subject();
  576. /**
  577. * Stream that emits whenever the active item of the list manager changes.
  578. */
  579. this.change = new rxjs.Subject();
  580. // We allow for the items to be an array because, in some cases, the consumer may
  581. // not have access to a QueryList of the items they want to manage (e.g. when the
  582. // items aren't being collected via `ViewChildren` or `ContentChildren`).
  583. if (_items instanceof core.QueryList) {
  584. _items.changes.subscribe((/**
  585. * @param {?} newItems
  586. * @return {?}
  587. */
  588. function (newItems) {
  589. if (_this._activeItem) {
  590. /** @type {?} */
  591. var itemArray = newItems.toArray();
  592. /** @type {?} */
  593. var newIndex = itemArray.indexOf(_this._activeItem);
  594. if (newIndex > -1 && newIndex !== _this._activeItemIndex) {
  595. _this._activeItemIndex = newIndex;
  596. }
  597. }
  598. }));
  599. }
  600. }
  601. /**
  602. * Sets the predicate function that determines which items should be skipped by the
  603. * list key manager.
  604. * @param predicate Function that determines whether the given item should be skipped.
  605. */
  606. /**
  607. * Sets the predicate function that determines which items should be skipped by the
  608. * list key manager.
  609. * @template THIS
  610. * @this {THIS}
  611. * @param {?} predicate Function that determines whether the given item should be skipped.
  612. * @return {THIS}
  613. */
  614. ListKeyManager.prototype.skipPredicate = /**
  615. * Sets the predicate function that determines which items should be skipped by the
  616. * list key manager.
  617. * @template THIS
  618. * @this {THIS}
  619. * @param {?} predicate Function that determines whether the given item should be skipped.
  620. * @return {THIS}
  621. */
  622. function (predicate) {
  623. (/** @type {?} */ (this))._skipPredicateFn = predicate;
  624. return (/** @type {?} */ (this));
  625. };
  626. /**
  627. * Configures wrapping mode, which determines whether the active item will wrap to
  628. * the other end of list when there are no more items in the given direction.
  629. * @param shouldWrap Whether the list should wrap when reaching the end.
  630. */
  631. /**
  632. * Configures wrapping mode, which determines whether the active item will wrap to
  633. * the other end of list when there are no more items in the given direction.
  634. * @template THIS
  635. * @this {THIS}
  636. * @param {?=} shouldWrap Whether the list should wrap when reaching the end.
  637. * @return {THIS}
  638. */
  639. ListKeyManager.prototype.withWrap = /**
  640. * Configures wrapping mode, which determines whether the active item will wrap to
  641. * the other end of list when there are no more items in the given direction.
  642. * @template THIS
  643. * @this {THIS}
  644. * @param {?=} shouldWrap Whether the list should wrap when reaching the end.
  645. * @return {THIS}
  646. */
  647. function (shouldWrap) {
  648. if (shouldWrap === void 0) { shouldWrap = true; }
  649. (/** @type {?} */ (this))._wrap = shouldWrap;
  650. return (/** @type {?} */ (this));
  651. };
  652. /**
  653. * Configures whether the key manager should be able to move the selection vertically.
  654. * @param enabled Whether vertical selection should be enabled.
  655. */
  656. /**
  657. * Configures whether the key manager should be able to move the selection vertically.
  658. * @template THIS
  659. * @this {THIS}
  660. * @param {?=} enabled Whether vertical selection should be enabled.
  661. * @return {THIS}
  662. */
  663. ListKeyManager.prototype.withVerticalOrientation = /**
  664. * Configures whether the key manager should be able to move the selection vertically.
  665. * @template THIS
  666. * @this {THIS}
  667. * @param {?=} enabled Whether vertical selection should be enabled.
  668. * @return {THIS}
  669. */
  670. function (enabled) {
  671. if (enabled === void 0) { enabled = true; }
  672. (/** @type {?} */ (this))._vertical = enabled;
  673. return (/** @type {?} */ (this));
  674. };
  675. /**
  676. * Configures the key manager to move the selection horizontally.
  677. * Passing in `null` will disable horizontal movement.
  678. * @param direction Direction in which the selection can be moved.
  679. */
  680. /**
  681. * Configures the key manager to move the selection horizontally.
  682. * Passing in `null` will disable horizontal movement.
  683. * @template THIS
  684. * @this {THIS}
  685. * @param {?} direction Direction in which the selection can be moved.
  686. * @return {THIS}
  687. */
  688. ListKeyManager.prototype.withHorizontalOrientation = /**
  689. * Configures the key manager to move the selection horizontally.
  690. * Passing in `null` will disable horizontal movement.
  691. * @template THIS
  692. * @this {THIS}
  693. * @param {?} direction Direction in which the selection can be moved.
  694. * @return {THIS}
  695. */
  696. function (direction) {
  697. (/** @type {?} */ (this))._horizontal = direction;
  698. return (/** @type {?} */ (this));
  699. };
  700. /**
  701. * Modifier keys which are allowed to be held down and whose default actions will be prevented
  702. * as the user is pressing the arrow keys. Defaults to not allowing any modifier keys.
  703. */
  704. /**
  705. * Modifier keys which are allowed to be held down and whose default actions will be prevented
  706. * as the user is pressing the arrow keys. Defaults to not allowing any modifier keys.
  707. * @template THIS
  708. * @this {THIS}
  709. * @param {?} keys
  710. * @return {THIS}
  711. */
  712. ListKeyManager.prototype.withAllowedModifierKeys = /**
  713. * Modifier keys which are allowed to be held down and whose default actions will be prevented
  714. * as the user is pressing the arrow keys. Defaults to not allowing any modifier keys.
  715. * @template THIS
  716. * @this {THIS}
  717. * @param {?} keys
  718. * @return {THIS}
  719. */
  720. function (keys) {
  721. (/** @type {?} */ (this))._allowedModifierKeys = keys;
  722. return (/** @type {?} */ (this));
  723. };
  724. /**
  725. * Turns on typeahead mode which allows users to set the active item by typing.
  726. * @param debounceInterval Time to wait after the last keystroke before setting the active item.
  727. */
  728. /**
  729. * Turns on typeahead mode which allows users to set the active item by typing.
  730. * @template THIS
  731. * @this {THIS}
  732. * @param {?=} debounceInterval Time to wait after the last keystroke before setting the active item.
  733. * @return {THIS}
  734. */
  735. ListKeyManager.prototype.withTypeAhead = /**
  736. * Turns on typeahead mode which allows users to set the active item by typing.
  737. * @template THIS
  738. * @this {THIS}
  739. * @param {?=} debounceInterval Time to wait after the last keystroke before setting the active item.
  740. * @return {THIS}
  741. */
  742. function (debounceInterval) {
  743. var _this = this;
  744. if (debounceInterval === void 0) { debounceInterval = 200; }
  745. if ((/** @type {?} */ (this))._items.length && (/** @type {?} */ (this))._items.some((/**
  746. * @param {?} item
  747. * @return {?}
  748. */
  749. function (item) { return typeof item.getLabel !== 'function'; }))) {
  750. throw Error('ListKeyManager items in typeahead mode must implement the `getLabel` method.');
  751. }
  752. (/** @type {?} */ (this))._typeaheadSubscription.unsubscribe();
  753. // Debounce the presses of non-navigational keys, collect the ones that correspond to letters
  754. // and convert those letters back into a string. Afterwards find the first item that starts
  755. // with that string and select it.
  756. (/** @type {?} */ (this))._typeaheadSubscription = (/** @type {?} */ (this))._letterKeyStream.pipe(operators.tap((/**
  757. * @param {?} keyCode
  758. * @return {?}
  759. */
  760. function (keyCode) { return (/** @type {?} */ (_this))._pressedLetters.push(keyCode); })), operators.debounceTime(debounceInterval), operators.filter((/**
  761. * @return {?}
  762. */
  763. function () { return (/** @type {?} */ (_this))._pressedLetters.length > 0; })), operators.map((/**
  764. * @return {?}
  765. */
  766. function () { return (/** @type {?} */ (_this))._pressedLetters.join(''); }))).subscribe((/**
  767. * @param {?} inputString
  768. * @return {?}
  769. */
  770. function (inputString) {
  771. /** @type {?} */
  772. var items = (/** @type {?} */ (_this))._getItemsArray();
  773. // Start at 1 because we want to start searching at the item immediately
  774. // following the current active item.
  775. for (var i = 1; i < items.length + 1; i++) {
  776. /** @type {?} */
  777. var index = ((/** @type {?} */ (_this))._activeItemIndex + i) % items.length;
  778. /** @type {?} */
  779. var item = items[index];
  780. if (!(/** @type {?} */ (_this))._skipPredicateFn(item) &&
  781. (/** @type {?} */ (item.getLabel))().toUpperCase().trim().indexOf(inputString) === 0) {
  782. (/** @type {?} */ (_this)).setActiveItem(index);
  783. break;
  784. }
  785. }
  786. (/** @type {?} */ (_this))._pressedLetters = [];
  787. }));
  788. return (/** @type {?} */ (this));
  789. };
  790. /**
  791. * @param {?} item
  792. * @return {?}
  793. */
  794. ListKeyManager.prototype.setActiveItem = /**
  795. * @param {?} item
  796. * @return {?}
  797. */
  798. function (item) {
  799. /** @type {?} */
  800. var previousIndex = this._activeItemIndex;
  801. this.updateActiveItem(item);
  802. if (this._activeItemIndex !== previousIndex) {
  803. this.change.next(this._activeItemIndex);
  804. }
  805. };
  806. /**
  807. * Sets the active item depending on the key event passed in.
  808. * @param event Keyboard event to be used for determining which element should be active.
  809. */
  810. /**
  811. * Sets the active item depending on the key event passed in.
  812. * @param {?} event Keyboard event to be used for determining which element should be active.
  813. * @return {?}
  814. */
  815. ListKeyManager.prototype.onKeydown = /**
  816. * Sets the active item depending on the key event passed in.
  817. * @param {?} event Keyboard event to be used for determining which element should be active.
  818. * @return {?}
  819. */
  820. function (event) {
  821. var _this = this;
  822. /** @type {?} */
  823. var keyCode = event.keyCode;
  824. /** @type {?} */
  825. var modifiers = ['altKey', 'ctrlKey', 'metaKey', 'shiftKey'];
  826. /** @type {?} */
  827. var isModifierAllowed = modifiers.every((/**
  828. * @param {?} modifier
  829. * @return {?}
  830. */
  831. function (modifier) {
  832. return !event[modifier] || _this._allowedModifierKeys.indexOf(modifier) > -1;
  833. }));
  834. switch (keyCode) {
  835. case keycodes.TAB:
  836. this.tabOut.next();
  837. return;
  838. case keycodes.DOWN_ARROW:
  839. if (this._vertical && isModifierAllowed) {
  840. this.setNextItemActive();
  841. break;
  842. }
  843. else {
  844. return;
  845. }
  846. case keycodes.UP_ARROW:
  847. if (this._vertical && isModifierAllowed) {
  848. this.setPreviousItemActive();
  849. break;
  850. }
  851. else {
  852. return;
  853. }
  854. case keycodes.RIGHT_ARROW:
  855. if (this._horizontal && isModifierAllowed) {
  856. this._horizontal === 'rtl' ? this.setPreviousItemActive() : this.setNextItemActive();
  857. break;
  858. }
  859. else {
  860. return;
  861. }
  862. case keycodes.LEFT_ARROW:
  863. if (this._horizontal && isModifierAllowed) {
  864. this._horizontal === 'rtl' ? this.setNextItemActive() : this.setPreviousItemActive();
  865. break;
  866. }
  867. else {
  868. return;
  869. }
  870. default:
  871. if (isModifierAllowed || keycodes.hasModifierKey(event, 'shiftKey')) {
  872. // Attempt to use the `event.key` which also maps it to the user's keyboard language,
  873. // otherwise fall back to resolving alphanumeric characters via the keyCode.
  874. if (event.key && event.key.length === 1) {
  875. this._letterKeyStream.next(event.key.toLocaleUpperCase());
  876. }
  877. else if ((keyCode >= keycodes.A && keyCode <= keycodes.Z) || (keyCode >= keycodes.ZERO && keyCode <= keycodes.NINE)) {
  878. this._letterKeyStream.next(String.fromCharCode(keyCode));
  879. }
  880. }
  881. // Note that we return here, in order to avoid preventing
  882. // the default action of non-navigational keys.
  883. return;
  884. }
  885. this._pressedLetters = [];
  886. event.preventDefault();
  887. };
  888. Object.defineProperty(ListKeyManager.prototype, "activeItemIndex", {
  889. /** Index of the currently active item. */
  890. get: /**
  891. * Index of the currently active item.
  892. * @return {?}
  893. */
  894. function () {
  895. return this._activeItemIndex;
  896. },
  897. enumerable: true,
  898. configurable: true
  899. });
  900. Object.defineProperty(ListKeyManager.prototype, "activeItem", {
  901. /** The active item. */
  902. get: /**
  903. * The active item.
  904. * @return {?}
  905. */
  906. function () {
  907. return this._activeItem;
  908. },
  909. enumerable: true,
  910. configurable: true
  911. });
  912. /** Sets the active item to the first enabled item in the list. */
  913. /**
  914. * Sets the active item to the first enabled item in the list.
  915. * @return {?}
  916. */
  917. ListKeyManager.prototype.setFirstItemActive = /**
  918. * Sets the active item to the first enabled item in the list.
  919. * @return {?}
  920. */
  921. function () {
  922. this._setActiveItemByIndex(0, 1);
  923. };
  924. /** Sets the active item to the last enabled item in the list. */
  925. /**
  926. * Sets the active item to the last enabled item in the list.
  927. * @return {?}
  928. */
  929. ListKeyManager.prototype.setLastItemActive = /**
  930. * Sets the active item to the last enabled item in the list.
  931. * @return {?}
  932. */
  933. function () {
  934. this._setActiveItemByIndex(this._items.length - 1, -1);
  935. };
  936. /** Sets the active item to the next enabled item in the list. */
  937. /**
  938. * Sets the active item to the next enabled item in the list.
  939. * @return {?}
  940. */
  941. ListKeyManager.prototype.setNextItemActive = /**
  942. * Sets the active item to the next enabled item in the list.
  943. * @return {?}
  944. */
  945. function () {
  946. this._activeItemIndex < 0 ? this.setFirstItemActive() : this._setActiveItemByDelta(1);
  947. };
  948. /** Sets the active item to a previous enabled item in the list. */
  949. /**
  950. * Sets the active item to a previous enabled item in the list.
  951. * @return {?}
  952. */
  953. ListKeyManager.prototype.setPreviousItemActive = /**
  954. * Sets the active item to a previous enabled item in the list.
  955. * @return {?}
  956. */
  957. function () {
  958. this._activeItemIndex < 0 && this._wrap ? this.setLastItemActive()
  959. : this._setActiveItemByDelta(-1);
  960. };
  961. /**
  962. * @param {?} item
  963. * @return {?}
  964. */
  965. ListKeyManager.prototype.updateActiveItem = /**
  966. * @param {?} item
  967. * @return {?}
  968. */
  969. function (item) {
  970. /** @type {?} */
  971. var itemArray = this._getItemsArray();
  972. /** @type {?} */
  973. var index = typeof item === 'number' ? item : itemArray.indexOf(item);
  974. /** @type {?} */
  975. var activeItem = itemArray[index];
  976. // Explicitly check for `null` and `undefined` because other falsy values are valid.
  977. this._activeItem = activeItem == null ? null : activeItem;
  978. this._activeItemIndex = index;
  979. };
  980. /**
  981. * Allows setting of the activeItemIndex without any other effects.
  982. * @param index The new activeItemIndex.
  983. * @deprecated Use `updateActiveItem` instead.
  984. * @breaking-change 8.0.0
  985. */
  986. /**
  987. * Allows setting of the activeItemIndex without any other effects.
  988. * @deprecated Use `updateActiveItem` instead.
  989. * \@breaking-change 8.0.0
  990. * @param {?} index The new activeItemIndex.
  991. * @return {?}
  992. */
  993. ListKeyManager.prototype.updateActiveItemIndex = /**
  994. * Allows setting of the activeItemIndex without any other effects.
  995. * @deprecated Use `updateActiveItem` instead.
  996. * \@breaking-change 8.0.0
  997. * @param {?} index The new activeItemIndex.
  998. * @return {?}
  999. */
  1000. function (index) {
  1001. this.updateActiveItem(index);
  1002. };
  1003. /**
  1004. * This method sets the active item, given a list of items and the delta between the
  1005. * currently active item and the new active item. It will calculate differently
  1006. * depending on whether wrap mode is turned on.
  1007. */
  1008. /**
  1009. * This method sets the active item, given a list of items and the delta between the
  1010. * currently active item and the new active item. It will calculate differently
  1011. * depending on whether wrap mode is turned on.
  1012. * @private
  1013. * @param {?} delta
  1014. * @return {?}
  1015. */
  1016. ListKeyManager.prototype._setActiveItemByDelta = /**
  1017. * This method sets the active item, given a list of items and the delta between the
  1018. * currently active item and the new active item. It will calculate differently
  1019. * depending on whether wrap mode is turned on.
  1020. * @private
  1021. * @param {?} delta
  1022. * @return {?}
  1023. */
  1024. function (delta) {
  1025. this._wrap ? this._setActiveInWrapMode(delta) : this._setActiveInDefaultMode(delta);
  1026. };
  1027. /**
  1028. * Sets the active item properly given "wrap" mode. In other words, it will continue to move
  1029. * down the list until it finds an item that is not disabled, and it will wrap if it
  1030. * encounters either end of the list.
  1031. */
  1032. /**
  1033. * Sets the active item properly given "wrap" mode. In other words, it will continue to move
  1034. * down the list until it finds an item that is not disabled, and it will wrap if it
  1035. * encounters either end of the list.
  1036. * @private
  1037. * @param {?} delta
  1038. * @return {?}
  1039. */
  1040. ListKeyManager.prototype._setActiveInWrapMode = /**
  1041. * Sets the active item properly given "wrap" mode. In other words, it will continue to move
  1042. * down the list until it finds an item that is not disabled, and it will wrap if it
  1043. * encounters either end of the list.
  1044. * @private
  1045. * @param {?} delta
  1046. * @return {?}
  1047. */
  1048. function (delta) {
  1049. /** @type {?} */
  1050. var items = this._getItemsArray();
  1051. for (var i = 1; i <= items.length; i++) {
  1052. /** @type {?} */
  1053. var index = (this._activeItemIndex + (delta * i) + items.length) % items.length;
  1054. /** @type {?} */
  1055. var item = items[index];
  1056. if (!this._skipPredicateFn(item)) {
  1057. this.setActiveItem(index);
  1058. return;
  1059. }
  1060. }
  1061. };
  1062. /**
  1063. * Sets the active item properly given the default mode. In other words, it will
  1064. * continue to move down the list until it finds an item that is not disabled. If
  1065. * it encounters either end of the list, it will stop and not wrap.
  1066. */
  1067. /**
  1068. * Sets the active item properly given the default mode. In other words, it will
  1069. * continue to move down the list until it finds an item that is not disabled. If
  1070. * it encounters either end of the list, it will stop and not wrap.
  1071. * @private
  1072. * @param {?} delta
  1073. * @return {?}
  1074. */
  1075. ListKeyManager.prototype._setActiveInDefaultMode = /**
  1076. * Sets the active item properly given the default mode. In other words, it will
  1077. * continue to move down the list until it finds an item that is not disabled. If
  1078. * it encounters either end of the list, it will stop and not wrap.
  1079. * @private
  1080. * @param {?} delta
  1081. * @return {?}
  1082. */
  1083. function (delta) {
  1084. this._setActiveItemByIndex(this._activeItemIndex + delta, delta);
  1085. };
  1086. /**
  1087. * Sets the active item to the first enabled item starting at the index specified. If the
  1088. * item is disabled, it will move in the fallbackDelta direction until it either
  1089. * finds an enabled item or encounters the end of the list.
  1090. */
  1091. /**
  1092. * Sets the active item to the first enabled item starting at the index specified. If the
  1093. * item is disabled, it will move in the fallbackDelta direction until it either
  1094. * finds an enabled item or encounters the end of the list.
  1095. * @private
  1096. * @param {?} index
  1097. * @param {?} fallbackDelta
  1098. * @return {?}
  1099. */
  1100. ListKeyManager.prototype._setActiveItemByIndex = /**
  1101. * Sets the active item to the first enabled item starting at the index specified. If the
  1102. * item is disabled, it will move in the fallbackDelta direction until it either
  1103. * finds an enabled item or encounters the end of the list.
  1104. * @private
  1105. * @param {?} index
  1106. * @param {?} fallbackDelta
  1107. * @return {?}
  1108. */
  1109. function (index, fallbackDelta) {
  1110. /** @type {?} */
  1111. var items = this._getItemsArray();
  1112. if (!items[index]) {
  1113. return;
  1114. }
  1115. while (this._skipPredicateFn(items[index])) {
  1116. index += fallbackDelta;
  1117. if (!items[index]) {
  1118. return;
  1119. }
  1120. }
  1121. this.setActiveItem(index);
  1122. };
  1123. /** Returns the items as an array. */
  1124. /**
  1125. * Returns the items as an array.
  1126. * @private
  1127. * @return {?}
  1128. */
  1129. ListKeyManager.prototype._getItemsArray = /**
  1130. * Returns the items as an array.
  1131. * @private
  1132. * @return {?}
  1133. */
  1134. function () {
  1135. return this._items instanceof core.QueryList ? this._items.toArray() : this._items;
  1136. };
  1137. return ListKeyManager;
  1138. }());
  1139. /**
  1140. * @fileoverview added by tsickle
  1141. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  1142. */
  1143. /**
  1144. * @template T
  1145. */
  1146. var /**
  1147. * @template T
  1148. */
  1149. ActiveDescendantKeyManager = /** @class */ (function (_super) {
  1150. __extends(ActiveDescendantKeyManager, _super);
  1151. function ActiveDescendantKeyManager() {
  1152. return _super !== null && _super.apply(this, arguments) || this;
  1153. }
  1154. /**
  1155. * @param {?} index
  1156. * @return {?}
  1157. */
  1158. ActiveDescendantKeyManager.prototype.setActiveItem = /**
  1159. * @param {?} index
  1160. * @return {?}
  1161. */
  1162. function (index) {
  1163. if (this.activeItem) {
  1164. this.activeItem.setInactiveStyles();
  1165. }
  1166. _super.prototype.setActiveItem.call(this, index);
  1167. if (this.activeItem) {
  1168. this.activeItem.setActiveStyles();
  1169. }
  1170. };
  1171. return ActiveDescendantKeyManager;
  1172. }(ListKeyManager));
  1173. /**
  1174. * @fileoverview added by tsickle
  1175. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  1176. */
  1177. /**
  1178. * @template T
  1179. */
  1180. var /**
  1181. * @template T
  1182. */
  1183. FocusKeyManager = /** @class */ (function (_super) {
  1184. __extends(FocusKeyManager, _super);
  1185. function FocusKeyManager() {
  1186. var _this = _super !== null && _super.apply(this, arguments) || this;
  1187. _this._origin = 'program';
  1188. return _this;
  1189. }
  1190. /**
  1191. * Sets the focus origin that will be passed in to the items for any subsequent `focus` calls.
  1192. * @param origin Focus origin to be used when focusing items.
  1193. */
  1194. /**
  1195. * Sets the focus origin that will be passed in to the items for any subsequent `focus` calls.
  1196. * @template THIS
  1197. * @this {THIS}
  1198. * @param {?} origin Focus origin to be used when focusing items.
  1199. * @return {THIS}
  1200. */
  1201. FocusKeyManager.prototype.setFocusOrigin = /**
  1202. * Sets the focus origin that will be passed in to the items for any subsequent `focus` calls.
  1203. * @template THIS
  1204. * @this {THIS}
  1205. * @param {?} origin Focus origin to be used when focusing items.
  1206. * @return {THIS}
  1207. */
  1208. function (origin) {
  1209. (/** @type {?} */ (this))._origin = origin;
  1210. return (/** @type {?} */ (this));
  1211. };
  1212. /**
  1213. * @param {?} item
  1214. * @return {?}
  1215. */
  1216. FocusKeyManager.prototype.setActiveItem = /**
  1217. * @param {?} item
  1218. * @return {?}
  1219. */
  1220. function (item) {
  1221. _super.prototype.setActiveItem.call(this, item);
  1222. if (this.activeItem) {
  1223. this.activeItem.focus(this._origin);
  1224. }
  1225. };
  1226. return FocusKeyManager;
  1227. }(ListKeyManager));
  1228. /**
  1229. * @fileoverview added by tsickle
  1230. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  1231. */
  1232. // The InteractivityChecker leans heavily on the ally.js accessibility utilities.
  1233. // Methods like `isTabbable` are only covering specific edge-cases for the browsers which are
  1234. // supported.
  1235. /**
  1236. * Utility for checking the interactivity of an element, such as whether is is focusable or
  1237. * tabbable.
  1238. */
  1239. var InteractivityChecker = /** @class */ (function () {
  1240. function InteractivityChecker(_platform) {
  1241. this._platform = _platform;
  1242. }
  1243. /**
  1244. * Gets whether an element is disabled.
  1245. *
  1246. * @param element Element to be checked.
  1247. * @returns Whether the element is disabled.
  1248. */
  1249. /**
  1250. * Gets whether an element is disabled.
  1251. *
  1252. * @param {?} element Element to be checked.
  1253. * @return {?} Whether the element is disabled.
  1254. */
  1255. InteractivityChecker.prototype.isDisabled = /**
  1256. * Gets whether an element is disabled.
  1257. *
  1258. * @param {?} element Element to be checked.
  1259. * @return {?} Whether the element is disabled.
  1260. */
  1261. function (element) {
  1262. // This does not capture some cases, such as a non-form control with a disabled attribute or
  1263. // a form control inside of a disabled form, but should capture the most common cases.
  1264. return element.hasAttribute('disabled');
  1265. };
  1266. /**
  1267. * Gets whether an element is visible for the purposes of interactivity.
  1268. *
  1269. * This will capture states like `display: none` and `visibility: hidden`, but not things like
  1270. * being clipped by an `overflow: hidden` parent or being outside the viewport.
  1271. *
  1272. * @returns Whether the element is visible.
  1273. */
  1274. /**
  1275. * Gets whether an element is visible for the purposes of interactivity.
  1276. *
  1277. * This will capture states like `display: none` and `visibility: hidden`, but not things like
  1278. * being clipped by an `overflow: hidden` parent or being outside the viewport.
  1279. *
  1280. * @param {?} element
  1281. * @return {?} Whether the element is visible.
  1282. */
  1283. InteractivityChecker.prototype.isVisible = /**
  1284. * Gets whether an element is visible for the purposes of interactivity.
  1285. *
  1286. * This will capture states like `display: none` and `visibility: hidden`, but not things like
  1287. * being clipped by an `overflow: hidden` parent or being outside the viewport.
  1288. *
  1289. * @param {?} element
  1290. * @return {?} Whether the element is visible.
  1291. */
  1292. function (element) {
  1293. return hasGeometry(element) && getComputedStyle(element).visibility === 'visible';
  1294. };
  1295. /**
  1296. * Gets whether an element can be reached via Tab key.
  1297. * Assumes that the element has already been checked with isFocusable.
  1298. *
  1299. * @param element Element to be checked.
  1300. * @returns Whether the element is tabbable.
  1301. */
  1302. /**
  1303. * Gets whether an element can be reached via Tab key.
  1304. * Assumes that the element has already been checked with isFocusable.
  1305. *
  1306. * @param {?} element Element to be checked.
  1307. * @return {?} Whether the element is tabbable.
  1308. */
  1309. InteractivityChecker.prototype.isTabbable = /**
  1310. * Gets whether an element can be reached via Tab key.
  1311. * Assumes that the element has already been checked with isFocusable.
  1312. *
  1313. * @param {?} element Element to be checked.
  1314. * @return {?} Whether the element is tabbable.
  1315. */
  1316. function (element) {
  1317. // Nothing is tabbable on the server 😎
  1318. if (!this._platform.isBrowser) {
  1319. return false;
  1320. }
  1321. /** @type {?} */
  1322. var frameElement = getFrameElement(getWindow(element));
  1323. if (frameElement) {
  1324. /** @type {?} */
  1325. var frameType = frameElement && frameElement.nodeName.toLowerCase();
  1326. // Frame elements inherit their tabindex onto all child elements.
  1327. if (getTabIndexValue(frameElement) === -1) {
  1328. return false;
  1329. }
  1330. // Webkit and Blink consider anything inside of an <object> element as non-tabbable.
  1331. if ((this._platform.BLINK || this._platform.WEBKIT) && frameType === 'object') {
  1332. return false;
  1333. }
  1334. // Webkit and Blink disable tabbing to an element inside of an invisible frame.
  1335. if ((this._platform.BLINK || this._platform.WEBKIT) && !this.isVisible(frameElement)) {
  1336. return false;
  1337. }
  1338. }
  1339. /** @type {?} */
  1340. var nodeName = element.nodeName.toLowerCase();
  1341. /** @type {?} */
  1342. var tabIndexValue = getTabIndexValue(element);
  1343. if (element.hasAttribute('contenteditable')) {
  1344. return tabIndexValue !== -1;
  1345. }
  1346. if (nodeName === 'iframe') {
  1347. // The frames may be tabbable depending on content, but it's not possibly to reliably
  1348. // investigate the content of the frames.
  1349. return false;
  1350. }
  1351. if (nodeName === 'audio') {
  1352. if (!element.hasAttribute('controls')) {
  1353. // By default an <audio> element without the controls enabled is not tabbable.
  1354. return false;
  1355. }
  1356. else if (this._platform.BLINK) {
  1357. // In Blink <audio controls> elements are always tabbable.
  1358. return true;
  1359. }
  1360. }
  1361. if (nodeName === 'video') {
  1362. if (!element.hasAttribute('controls') && this._platform.TRIDENT) {
  1363. // In Trident a <video> element without the controls enabled is not tabbable.
  1364. return false;
  1365. }
  1366. else if (this._platform.BLINK || this._platform.FIREFOX) {
  1367. // In Chrome and Firefox <video controls> elements are always tabbable.
  1368. return true;
  1369. }
  1370. }
  1371. if (nodeName === 'object' && (this._platform.BLINK || this._platform.WEBKIT)) {
  1372. // In all Blink and WebKit based browsers <object> elements are never tabbable.
  1373. return false;
  1374. }
  1375. // In iOS the browser only considers some specific elements as tabbable.
  1376. if (this._platform.WEBKIT && this._platform.IOS && !isPotentiallyTabbableIOS(element)) {
  1377. return false;
  1378. }
  1379. return element.tabIndex >= 0;
  1380. };
  1381. /**
  1382. * Gets whether an element can be focused by the user.
  1383. *
  1384. * @param element Element to be checked.
  1385. * @returns Whether the element is focusable.
  1386. */
  1387. /**
  1388. * Gets whether an element can be focused by the user.
  1389. *
  1390. * @param {?} element Element to be checked.
  1391. * @return {?} Whether the element is focusable.
  1392. */
  1393. InteractivityChecker.prototype.isFocusable = /**
  1394. * Gets whether an element can be focused by the user.
  1395. *
  1396. * @param {?} element Element to be checked.
  1397. * @return {?} Whether the element is focusable.
  1398. */
  1399. function (element) {
  1400. // Perform checks in order of left to most expensive.
  1401. // Again, naive approach that does not capture many edge cases and browser quirks.
  1402. return isPotentiallyFocusable(element) && !this.isDisabled(element) && this.isVisible(element);
  1403. };
  1404. InteractivityChecker.decorators = [
  1405. { type: core.Injectable, args: [{ providedIn: 'root' },] },
  1406. ];
  1407. /** @nocollapse */
  1408. InteractivityChecker.ctorParameters = function () { return [
  1409. { type: platform.Platform }
  1410. ]; };
  1411. /** @nocollapse */ InteractivityChecker.ngInjectableDef = core.ɵɵdefineInjectable({ factory: function InteractivityChecker_Factory() { return new InteractivityChecker(core.ɵɵinject(platform.Platform)); }, token: InteractivityChecker, providedIn: "root" });
  1412. return InteractivityChecker;
  1413. }());
  1414. /**
  1415. * Returns the frame element from a window object. Since browsers like MS Edge throw errors if
  1416. * the frameElement property is being accessed from a different host address, this property
  1417. * should be accessed carefully.
  1418. * @param {?} window
  1419. * @return {?}
  1420. */
  1421. function getFrameElement(window) {
  1422. try {
  1423. return (/** @type {?} */ (window.frameElement));
  1424. }
  1425. catch (_a) {
  1426. return null;
  1427. }
  1428. }
  1429. /**
  1430. * Checks whether the specified element has any geometry / rectangles.
  1431. * @param {?} element
  1432. * @return {?}
  1433. */
  1434. function hasGeometry(element) {
  1435. // Use logic from jQuery to check for an invisible element.
  1436. // See https://github.com/jquery/jquery/blob/master/src/css/hiddenVisibleSelectors.js#L12
  1437. return !!(element.offsetWidth || element.offsetHeight ||
  1438. (typeof element.getClientRects === 'function' && element.getClientRects().length));
  1439. }
  1440. /**
  1441. * Gets whether an element's
  1442. * @param {?} element
  1443. * @return {?}
  1444. */
  1445. function isNativeFormElement(element) {
  1446. /** @type {?} */
  1447. var nodeName = element.nodeName.toLowerCase();
  1448. return nodeName === 'input' ||
  1449. nodeName === 'select' ||
  1450. nodeName === 'button' ||
  1451. nodeName === 'textarea';
  1452. }
  1453. /**
  1454. * Gets whether an element is an `<input type="hidden">`.
  1455. * @param {?} element
  1456. * @return {?}
  1457. */
  1458. function isHiddenInput(element) {
  1459. return isInputElement(element) && element.type == 'hidden';
  1460. }
  1461. /**
  1462. * Gets whether an element is an anchor that has an href attribute.
  1463. * @param {?} element
  1464. * @return {?}
  1465. */
  1466. function isAnchorWithHref(element) {
  1467. return isAnchorElement(element) && element.hasAttribute('href');
  1468. }
  1469. /**
  1470. * Gets whether an element is an input element.
  1471. * @param {?} element
  1472. * @return {?}
  1473. */
  1474. function isInputElement(element) {
  1475. return element.nodeName.toLowerCase() == 'input';
  1476. }
  1477. /**
  1478. * Gets whether an element is an anchor element.
  1479. * @param {?} element
  1480. * @return {?}
  1481. */
  1482. function isAnchorElement(element) {
  1483. return element.nodeName.toLowerCase() == 'a';
  1484. }
  1485. /**
  1486. * Gets whether an element has a valid tabindex.
  1487. * @param {?} element
  1488. * @return {?}
  1489. */
  1490. function hasValidTabIndex(element) {
  1491. if (!element.hasAttribute('tabindex') || element.tabIndex === undefined) {
  1492. return false;
  1493. }
  1494. /** @type {?} */
  1495. var tabIndex = element.getAttribute('tabindex');
  1496. // IE11 parses tabindex="" as the value "-32768"
  1497. if (tabIndex == '-32768') {
  1498. return false;
  1499. }
  1500. return !!(tabIndex && !isNaN(parseInt(tabIndex, 10)));
  1501. }
  1502. /**
  1503. * Returns the parsed tabindex from the element attributes instead of returning the
  1504. * evaluated tabindex from the browsers defaults.
  1505. * @param {?} element
  1506. * @return {?}
  1507. */
  1508. function getTabIndexValue(element) {
  1509. if (!hasValidTabIndex(element)) {
  1510. return null;
  1511. }
  1512. // See browser issue in Gecko https://bugzilla.mozilla.org/show_bug.cgi?id=1128054
  1513. /** @type {?} */
  1514. var tabIndex = parseInt(element.getAttribute('tabindex') || '', 10);
  1515. return isNaN(tabIndex) ? -1 : tabIndex;
  1516. }
  1517. /**
  1518. * Checks whether the specified element is potentially tabbable on iOS
  1519. * @param {?} element
  1520. * @return {?}
  1521. */
  1522. function isPotentiallyTabbableIOS(element) {
  1523. /** @type {?} */
  1524. var nodeName = element.nodeName.toLowerCase();
  1525. /** @type {?} */
  1526. var inputType = nodeName === 'input' && ((/** @type {?} */ (element))).type;
  1527. return inputType === 'text'
  1528. || inputType === 'password'
  1529. || nodeName === 'select'
  1530. || nodeName === 'textarea';
  1531. }
  1532. /**
  1533. * Gets whether an element is potentially focusable without taking current visible/disabled state
  1534. * into account.
  1535. * @param {?} element
  1536. * @return {?}
  1537. */
  1538. function isPotentiallyFocusable(element) {
  1539. // Inputs are potentially focusable *unless* they're type="hidden".
  1540. if (isHiddenInput(element)) {
  1541. return false;
  1542. }
  1543. return isNativeFormElement(element) ||
  1544. isAnchorWithHref(element) ||
  1545. element.hasAttribute('contenteditable') ||
  1546. hasValidTabIndex(element);
  1547. }
  1548. /**
  1549. * Gets the parent window of a DOM node with regards of being inside of an iframe.
  1550. * @param {?} node
  1551. * @return {?}
  1552. */
  1553. function getWindow(node) {
  1554. // ownerDocument is null if `node` itself *is* a document.
  1555. return node.ownerDocument && node.ownerDocument.defaultView || window;
  1556. }
  1557. /**
  1558. * @fileoverview added by tsickle
  1559. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  1560. */
  1561. /**
  1562. * Class that allows for trapping focus within a DOM element.
  1563. *
  1564. * This class currently uses a relatively simple approach to focus trapping.
  1565. * It assumes that the tab order is the same as DOM order, which is not necessarily true.
  1566. * Things like `tabIndex > 0`, flex `order`, and shadow roots can cause to two to misalign.
  1567. */
  1568. var /**
  1569. * Class that allows for trapping focus within a DOM element.
  1570. *
  1571. * This class currently uses a relatively simple approach to focus trapping.
  1572. * It assumes that the tab order is the same as DOM order, which is not necessarily true.
  1573. * Things like `tabIndex > 0`, flex `order`, and shadow roots can cause to two to misalign.
  1574. */
  1575. FocusTrap = /** @class */ (function () {
  1576. function FocusTrap(_element, _checker, _ngZone, _document, deferAnchors) {
  1577. var _this = this;
  1578. if (deferAnchors === void 0) { deferAnchors = false; }
  1579. this._element = _element;
  1580. this._checker = _checker;
  1581. this._ngZone = _ngZone;
  1582. this._document = _document;
  1583. this._hasAttached = false;
  1584. // Event listeners for the anchors. Need to be regular functions so that we can unbind them later.
  1585. this.startAnchorListener = (/**
  1586. * @return {?}
  1587. */
  1588. function () { return _this.focusLastTabbableElement(); });
  1589. this.endAnchorListener = (/**
  1590. * @return {?}
  1591. */
  1592. function () { return _this.focusFirstTabbableElement(); });
  1593. this._enabled = true;
  1594. if (!deferAnchors) {
  1595. this.attachAnchors();
  1596. }
  1597. }
  1598. Object.defineProperty(FocusTrap.prototype, "enabled", {
  1599. /** Whether the focus trap is active. */
  1600. get: /**
  1601. * Whether the focus trap is active.
  1602. * @return {?}
  1603. */
  1604. function () { return this._enabled; },
  1605. set: /**
  1606. * @param {?} value
  1607. * @return {?}
  1608. */
  1609. function (value) {
  1610. this._enabled = value;
  1611. if (this._startAnchor && this._endAnchor) {
  1612. this._toggleAnchorTabIndex(value, this._startAnchor);
  1613. this._toggleAnchorTabIndex(value, this._endAnchor);
  1614. }
  1615. },
  1616. enumerable: true,
  1617. configurable: true
  1618. });
  1619. /** Destroys the focus trap by cleaning up the anchors. */
  1620. /**
  1621. * Destroys the focus trap by cleaning up the anchors.
  1622. * @return {?}
  1623. */
  1624. FocusTrap.prototype.destroy = /**
  1625. * Destroys the focus trap by cleaning up the anchors.
  1626. * @return {?}
  1627. */
  1628. function () {
  1629. /** @type {?} */
  1630. var startAnchor = this._startAnchor;
  1631. /** @type {?} */
  1632. var endAnchor = this._endAnchor;
  1633. if (startAnchor) {
  1634. startAnchor.removeEventListener('focus', this.startAnchorListener);
  1635. if (startAnchor.parentNode) {
  1636. startAnchor.parentNode.removeChild(startAnchor);
  1637. }
  1638. }
  1639. if (endAnchor) {
  1640. endAnchor.removeEventListener('focus', this.endAnchorListener);
  1641. if (endAnchor.parentNode) {
  1642. endAnchor.parentNode.removeChild(endAnchor);
  1643. }
  1644. }
  1645. this._startAnchor = this._endAnchor = null;
  1646. };
  1647. /**
  1648. * Inserts the anchors into the DOM. This is usually done automatically
  1649. * in the constructor, but can be deferred for cases like directives with `*ngIf`.
  1650. * @returns Whether the focus trap managed to attach successfuly. This may not be the case
  1651. * if the target element isn't currently in the DOM.
  1652. */
  1653. /**
  1654. * Inserts the anchors into the DOM. This is usually done automatically
  1655. * in the constructor, but can be deferred for cases like directives with `*ngIf`.
  1656. * @return {?} Whether the focus trap managed to attach successfuly. This may not be the case
  1657. * if the target element isn't currently in the DOM.
  1658. */
  1659. FocusTrap.prototype.attachAnchors = /**
  1660. * Inserts the anchors into the DOM. This is usually done automatically
  1661. * in the constructor, but can be deferred for cases like directives with `*ngIf`.
  1662. * @return {?} Whether the focus trap managed to attach successfuly. This may not be the case
  1663. * if the target element isn't currently in the DOM.
  1664. */
  1665. function () {
  1666. var _this = this;
  1667. // If we're not on the browser, there can be no focus to trap.
  1668. if (this._hasAttached) {
  1669. return true;
  1670. }
  1671. this._ngZone.runOutsideAngular((/**
  1672. * @return {?}
  1673. */
  1674. function () {
  1675. if (!_this._startAnchor) {
  1676. _this._startAnchor = _this._createAnchor();
  1677. (/** @type {?} */ (_this._startAnchor)).addEventListener('focus', _this.startAnchorListener);
  1678. }
  1679. if (!_this._endAnchor) {
  1680. _this._endAnchor = _this._createAnchor();
  1681. (/** @type {?} */ (_this._endAnchor)).addEventListener('focus', _this.endAnchorListener);
  1682. }
  1683. }));
  1684. if (this._element.parentNode) {
  1685. this._element.parentNode.insertBefore((/** @type {?} */ (this._startAnchor)), this._element);
  1686. this._element.parentNode.insertBefore((/** @type {?} */ (this._endAnchor)), this._element.nextSibling);
  1687. this._hasAttached = true;
  1688. }
  1689. return this._hasAttached;
  1690. };
  1691. /**
  1692. * Waits for the zone to stabilize, then either focuses the first element that the
  1693. * user specified, or the first tabbable element.
  1694. * @returns Returns a promise that resolves with a boolean, depending
  1695. * on whether focus was moved successfuly.
  1696. */
  1697. /**
  1698. * Waits for the zone to stabilize, then either focuses the first element that the
  1699. * user specified, or the first tabbable element.
  1700. * @return {?} Returns a promise that resolves with a boolean, depending
  1701. * on whether focus was moved successfuly.
  1702. */
  1703. FocusTrap.prototype.focusInitialElementWhenReady = /**
  1704. * Waits for the zone to stabilize, then either focuses the first element that the
  1705. * user specified, or the first tabbable element.
  1706. * @return {?} Returns a promise that resolves with a boolean, depending
  1707. * on whether focus was moved successfuly.
  1708. */
  1709. function () {
  1710. var _this = this;
  1711. return new Promise((/**
  1712. * @param {?} resolve
  1713. * @return {?}
  1714. */
  1715. function (resolve) {
  1716. _this._executeOnStable((/**
  1717. * @return {?}
  1718. */
  1719. function () { return resolve(_this.focusInitialElement()); }));
  1720. }));
  1721. };
  1722. /**
  1723. * Waits for the zone to stabilize, then focuses
  1724. * the first tabbable element within the focus trap region.
  1725. * @returns Returns a promise that resolves with a boolean, depending
  1726. * on whether focus was moved successfuly.
  1727. */
  1728. /**
  1729. * Waits for the zone to stabilize, then focuses
  1730. * the first tabbable element within the focus trap region.
  1731. * @return {?} Returns a promise that resolves with a boolean, depending
  1732. * on whether focus was moved successfuly.
  1733. */
  1734. FocusTrap.prototype.focusFirstTabbableElementWhenReady = /**
  1735. * Waits for the zone to stabilize, then focuses
  1736. * the first tabbable element within the focus trap region.
  1737. * @return {?} Returns a promise that resolves with a boolean, depending
  1738. * on whether focus was moved successfuly.
  1739. */
  1740. function () {
  1741. var _this = this;
  1742. return new Promise((/**
  1743. * @param {?} resolve
  1744. * @return {?}
  1745. */
  1746. function (resolve) {
  1747. _this._executeOnStable((/**
  1748. * @return {?}
  1749. */
  1750. function () { return resolve(_this.focusFirstTabbableElement()); }));
  1751. }));
  1752. };
  1753. /**
  1754. * Waits for the zone to stabilize, then focuses
  1755. * the last tabbable element within the focus trap region.
  1756. * @returns Returns a promise that resolves with a boolean, depending
  1757. * on whether focus was moved successfuly.
  1758. */
  1759. /**
  1760. * Waits for the zone to stabilize, then focuses
  1761. * the last tabbable element within the focus trap region.
  1762. * @return {?} Returns a promise that resolves with a boolean, depending
  1763. * on whether focus was moved successfuly.
  1764. */
  1765. FocusTrap.prototype.focusLastTabbableElementWhenReady = /**
  1766. * Waits for the zone to stabilize, then focuses
  1767. * the last tabbable element within the focus trap region.
  1768. * @return {?} Returns a promise that resolves with a boolean, depending
  1769. * on whether focus was moved successfuly.
  1770. */
  1771. function () {
  1772. var _this = this;
  1773. return new Promise((/**
  1774. * @param {?} resolve
  1775. * @return {?}
  1776. */
  1777. function (resolve) {
  1778. _this._executeOnStable((/**
  1779. * @return {?}
  1780. */
  1781. function () { return resolve(_this.focusLastTabbableElement()); }));
  1782. }));
  1783. };
  1784. /**
  1785. * Get the specified boundary element of the trapped region.
  1786. * @param bound The boundary to get (start or end of trapped region).
  1787. * @returns The boundary element.
  1788. */
  1789. /**
  1790. * Get the specified boundary element of the trapped region.
  1791. * @private
  1792. * @param {?} bound The boundary to get (start or end of trapped region).
  1793. * @return {?} The boundary element.
  1794. */
  1795. FocusTrap.prototype._getRegionBoundary = /**
  1796. * Get the specified boundary element of the trapped region.
  1797. * @private
  1798. * @param {?} bound The boundary to get (start or end of trapped region).
  1799. * @return {?} The boundary element.
  1800. */
  1801. function (bound) {
  1802. // Contains the deprecated version of selector, for temporary backwards comparability.
  1803. /** @type {?} */
  1804. var markers = (/** @type {?} */ (this._element.querySelectorAll("[cdk-focus-region-" + bound + "], " +
  1805. ("[cdkFocusRegion" + bound + "], ") +
  1806. ("[cdk-focus-" + bound + "]"))));
  1807. for (var i = 0; i < markers.length; i++) {
  1808. // @breaking-change 8.0.0
  1809. if (markers[i].hasAttribute("cdk-focus-" + bound)) {
  1810. console.warn("Found use of deprecated attribute 'cdk-focus-" + bound + "', " +
  1811. ("use 'cdkFocusRegion" + bound + "' instead. The deprecated ") +
  1812. "attribute will be removed in 8.0.0.", markers[i]);
  1813. }
  1814. else if (markers[i].hasAttribute("cdk-focus-region-" + bound)) {
  1815. console.warn("Found use of deprecated attribute 'cdk-focus-region-" + bound + "', " +
  1816. ("use 'cdkFocusRegion" + bound + "' instead. The deprecated attribute ") +
  1817. "will be removed in 8.0.0.", markers[i]);
  1818. }
  1819. }
  1820. if (bound == 'start') {
  1821. return markers.length ? markers[0] : this._getFirstTabbableElement(this._element);
  1822. }
  1823. return markers.length ?
  1824. markers[markers.length - 1] : this._getLastTabbableElement(this._element);
  1825. };
  1826. /**
  1827. * Focuses the element that should be focused when the focus trap is initialized.
  1828. * @returns Whether focus was moved successfuly.
  1829. */
  1830. /**
  1831. * Focuses the element that should be focused when the focus trap is initialized.
  1832. * @return {?} Whether focus was moved successfuly.
  1833. */
  1834. FocusTrap.prototype.focusInitialElement = /**
  1835. * Focuses the element that should be focused when the focus trap is initialized.
  1836. * @return {?} Whether focus was moved successfuly.
  1837. */
  1838. function () {
  1839. // Contains the deprecated version of selector, for temporary backwards comparability.
  1840. /** @type {?} */
  1841. var redirectToElement = (/** @type {?} */ (this._element.querySelector("[cdk-focus-initial], " +
  1842. "[cdkFocusInitial]")));
  1843. if (redirectToElement) {
  1844. // @breaking-change 8.0.0
  1845. if (redirectToElement.hasAttribute("cdk-focus-initial")) {
  1846. console.warn("Found use of deprecated attribute 'cdk-focus-initial', " +
  1847. "use 'cdkFocusInitial' instead. The deprecated attribute " +
  1848. "will be removed in 8.0.0", redirectToElement);
  1849. }
  1850. // Warn the consumer if the element they've pointed to
  1851. // isn't focusable, when not in production mode.
  1852. if (core.isDevMode() && !this._checker.isFocusable(redirectToElement)) {
  1853. console.warn("Element matching '[cdkFocusInitial]' is not focusable.", redirectToElement);
  1854. }
  1855. redirectToElement.focus();
  1856. return true;
  1857. }
  1858. return this.focusFirstTabbableElement();
  1859. };
  1860. /**
  1861. * Focuses the first tabbable element within the focus trap region.
  1862. * @returns Whether focus was moved successfuly.
  1863. */
  1864. /**
  1865. * Focuses the first tabbable element within the focus trap region.
  1866. * @return {?} Whether focus was moved successfuly.
  1867. */
  1868. FocusTrap.prototype.focusFirstTabbableElement = /**
  1869. * Focuses the first tabbable element within the focus trap region.
  1870. * @return {?} Whether focus was moved successfuly.
  1871. */
  1872. function () {
  1873. /** @type {?} */
  1874. var redirectToElement = this._getRegionBoundary('start');
  1875. if (redirectToElement) {
  1876. redirectToElement.focus();
  1877. }
  1878. return !!redirectToElement;
  1879. };
  1880. /**
  1881. * Focuses the last tabbable element within the focus trap region.
  1882. * @returns Whether focus was moved successfuly.
  1883. */
  1884. /**
  1885. * Focuses the last tabbable element within the focus trap region.
  1886. * @return {?} Whether focus was moved successfuly.
  1887. */
  1888. FocusTrap.prototype.focusLastTabbableElement = /**
  1889. * Focuses the last tabbable element within the focus trap region.
  1890. * @return {?} Whether focus was moved successfuly.
  1891. */
  1892. function () {
  1893. /** @type {?} */
  1894. var redirectToElement = this._getRegionBoundary('end');
  1895. if (redirectToElement) {
  1896. redirectToElement.focus();
  1897. }
  1898. return !!redirectToElement;
  1899. };
  1900. /**
  1901. * Checks whether the focus trap has successfuly been attached.
  1902. */
  1903. /**
  1904. * Checks whether the focus trap has successfuly been attached.
  1905. * @return {?}
  1906. */
  1907. FocusTrap.prototype.hasAttached = /**
  1908. * Checks whether the focus trap has successfuly been attached.
  1909. * @return {?}
  1910. */
  1911. function () {
  1912. return this._hasAttached;
  1913. };
  1914. /** Get the first tabbable element from a DOM subtree (inclusive). */
  1915. /**
  1916. * Get the first tabbable element from a DOM subtree (inclusive).
  1917. * @private
  1918. * @param {?} root
  1919. * @return {?}
  1920. */
  1921. FocusTrap.prototype._getFirstTabbableElement = /**
  1922. * Get the first tabbable element from a DOM subtree (inclusive).
  1923. * @private
  1924. * @param {?} root
  1925. * @return {?}
  1926. */
  1927. function (root) {
  1928. if (this._checker.isFocusable(root) && this._checker.isTabbable(root)) {
  1929. return root;
  1930. }
  1931. // Iterate in DOM order. Note that IE doesn't have `children` for SVG so we fall
  1932. // back to `childNodes` which includes text nodes, comments etc.
  1933. /** @type {?} */
  1934. var children = root.children || root.childNodes;
  1935. for (var i = 0; i < children.length; i++) {
  1936. /** @type {?} */
  1937. var tabbableChild = children[i].nodeType === this._document.ELEMENT_NODE ?
  1938. this._getFirstTabbableElement((/** @type {?} */ (children[i]))) :
  1939. null;
  1940. if (tabbableChild) {
  1941. return tabbableChild;
  1942. }
  1943. }
  1944. return null;
  1945. };
  1946. /** Get the last tabbable element from a DOM subtree (inclusive). */
  1947. /**
  1948. * Get the last tabbable element from a DOM subtree (inclusive).
  1949. * @private
  1950. * @param {?} root
  1951. * @return {?}
  1952. */
  1953. FocusTrap.prototype._getLastTabbableElement = /**
  1954. * Get the last tabbable element from a DOM subtree (inclusive).
  1955. * @private
  1956. * @param {?} root
  1957. * @return {?}
  1958. */
  1959. function (root) {
  1960. if (this._checker.isFocusable(root) && this._checker.isTabbable(root)) {
  1961. return root;
  1962. }
  1963. // Iterate in reverse DOM order.
  1964. /** @type {?} */
  1965. var children = root.children || root.childNodes;
  1966. for (var i = children.length - 1; i >= 0; i--) {
  1967. /** @type {?} */
  1968. var tabbableChild = children[i].nodeType === this._document.ELEMENT_NODE ?
  1969. this._getLastTabbableElement((/** @type {?} */ (children[i]))) :
  1970. null;
  1971. if (tabbableChild) {
  1972. return tabbableChild;
  1973. }
  1974. }
  1975. return null;
  1976. };
  1977. /** Creates an anchor element. */
  1978. /**
  1979. * Creates an anchor element.
  1980. * @private
  1981. * @return {?}
  1982. */
  1983. FocusTrap.prototype._createAnchor = /**
  1984. * Creates an anchor element.
  1985. * @private
  1986. * @return {?}
  1987. */
  1988. function () {
  1989. /** @type {?} */
  1990. var anchor = this._document.createElement('div');
  1991. this._toggleAnchorTabIndex(this._enabled, anchor);
  1992. anchor.classList.add('cdk-visually-hidden');
  1993. anchor.classList.add('cdk-focus-trap-anchor');
  1994. anchor.setAttribute('aria-hidden', 'true');
  1995. return anchor;
  1996. };
  1997. /**
  1998. * Toggles the `tabindex` of an anchor, based on the enabled state of the focus trap.
  1999. * @param isEnabled Whether the focus trap is enabled.
  2000. * @param anchor Anchor on which to toggle the tabindex.
  2001. */
  2002. /**
  2003. * Toggles the `tabindex` of an anchor, based on the enabled state of the focus trap.
  2004. * @private
  2005. * @param {?} isEnabled Whether the focus trap is enabled.
  2006. * @param {?} anchor Anchor on which to toggle the tabindex.
  2007. * @return {?}
  2008. */
  2009. FocusTrap.prototype._toggleAnchorTabIndex = /**
  2010. * Toggles the `tabindex` of an anchor, based on the enabled state of the focus trap.
  2011. * @private
  2012. * @param {?} isEnabled Whether the focus trap is enabled.
  2013. * @param {?} anchor Anchor on which to toggle the tabindex.
  2014. * @return {?}
  2015. */
  2016. function (isEnabled, anchor) {
  2017. // Remove the tabindex completely, rather than setting it to -1, because if the
  2018. // element has a tabindex, the user might still hit it when navigating with the arrow keys.
  2019. isEnabled ? anchor.setAttribute('tabindex', '0') : anchor.removeAttribute('tabindex');
  2020. };
  2021. /** Executes a function when the zone is stable. */
  2022. /**
  2023. * Executes a function when the zone is stable.
  2024. * @private
  2025. * @param {?} fn
  2026. * @return {?}
  2027. */
  2028. FocusTrap.prototype._executeOnStable = /**
  2029. * Executes a function when the zone is stable.
  2030. * @private
  2031. * @param {?} fn
  2032. * @return {?}
  2033. */
  2034. function (fn) {
  2035. if (this._ngZone.isStable) {
  2036. fn();
  2037. }
  2038. else {
  2039. this._ngZone.onStable.asObservable().pipe(operators.take(1)).subscribe(fn);
  2040. }
  2041. };
  2042. return FocusTrap;
  2043. }());
  2044. /**
  2045. * Factory that allows easy instantiation of focus traps.
  2046. */
  2047. var FocusTrapFactory = /** @class */ (function () {
  2048. function FocusTrapFactory(_checker, _ngZone, _document) {
  2049. this._checker = _checker;
  2050. this._ngZone = _ngZone;
  2051. this._document = _document;
  2052. }
  2053. /**
  2054. * Creates a focus-trapped region around the given element.
  2055. * @param element The element around which focus will be trapped.
  2056. * @param deferCaptureElements Defers the creation of focus-capturing elements to be done
  2057. * manually by the user.
  2058. * @returns The created focus trap instance.
  2059. */
  2060. /**
  2061. * Creates a focus-trapped region around the given element.
  2062. * @param {?} element The element around which focus will be trapped.
  2063. * @param {?=} deferCaptureElements Defers the creation of focus-capturing elements to be done
  2064. * manually by the user.
  2065. * @return {?} The created focus trap instance.
  2066. */
  2067. FocusTrapFactory.prototype.create = /**
  2068. * Creates a focus-trapped region around the given element.
  2069. * @param {?} element The element around which focus will be trapped.
  2070. * @param {?=} deferCaptureElements Defers the creation of focus-capturing elements to be done
  2071. * manually by the user.
  2072. * @return {?} The created focus trap instance.
  2073. */
  2074. function (element, deferCaptureElements) {
  2075. if (deferCaptureElements === void 0) { deferCaptureElements = false; }
  2076. return new FocusTrap(element, this._checker, this._ngZone, this._document, deferCaptureElements);
  2077. };
  2078. FocusTrapFactory.decorators = [
  2079. { type: core.Injectable, args: [{ providedIn: 'root' },] },
  2080. ];
  2081. /** @nocollapse */
  2082. FocusTrapFactory.ctorParameters = function () { return [
  2083. { type: InteractivityChecker },
  2084. { type: core.NgZone },
  2085. { type: undefined, decorators: [{ type: core.Inject, args: [common.DOCUMENT,] }] }
  2086. ]; };
  2087. /** @nocollapse */ FocusTrapFactory.ngInjectableDef = core.ɵɵdefineInjectable({ factory: function FocusTrapFactory_Factory() { return new FocusTrapFactory(core.ɵɵinject(InteractivityChecker), core.ɵɵinject(core.NgZone), core.ɵɵinject(common.DOCUMENT)); }, token: FocusTrapFactory, providedIn: "root" });
  2088. return FocusTrapFactory;
  2089. }());
  2090. /**
  2091. * Directive for trapping focus within a region.
  2092. */
  2093. var CdkTrapFocus = /** @class */ (function () {
  2094. function CdkTrapFocus(_elementRef, _focusTrapFactory, _document) {
  2095. this._elementRef = _elementRef;
  2096. this._focusTrapFactory = _focusTrapFactory;
  2097. /**
  2098. * Previously focused element to restore focus to upon destroy when using autoCapture.
  2099. */
  2100. this._previouslyFocusedElement = null;
  2101. this._document = _document;
  2102. this.focusTrap = this._focusTrapFactory.create(this._elementRef.nativeElement, true);
  2103. }
  2104. Object.defineProperty(CdkTrapFocus.prototype, "enabled", {
  2105. /** Whether the focus trap is active. */
  2106. get: /**
  2107. * Whether the focus trap is active.
  2108. * @return {?}
  2109. */
  2110. function () { return this.focusTrap.enabled; },
  2111. set: /**
  2112. * @param {?} value
  2113. * @return {?}
  2114. */
  2115. function (value) { this.focusTrap.enabled = coercion.coerceBooleanProperty(value); },
  2116. enumerable: true,
  2117. configurable: true
  2118. });
  2119. Object.defineProperty(CdkTrapFocus.prototype, "autoCapture", {
  2120. /**
  2121. * Whether the directive should automatially move focus into the trapped region upon
  2122. * initialization and return focus to the previous activeElement upon destruction.
  2123. */
  2124. get: /**
  2125. * Whether the directive should automatially move focus into the trapped region upon
  2126. * initialization and return focus to the previous activeElement upon destruction.
  2127. * @return {?}
  2128. */
  2129. function () { return this._autoCapture; },
  2130. set: /**
  2131. * @param {?} value
  2132. * @return {?}
  2133. */
  2134. function (value) { this._autoCapture = coercion.coerceBooleanProperty(value); },
  2135. enumerable: true,
  2136. configurable: true
  2137. });
  2138. /**
  2139. * @return {?}
  2140. */
  2141. CdkTrapFocus.prototype.ngOnDestroy = /**
  2142. * @return {?}
  2143. */
  2144. function () {
  2145. this.focusTrap.destroy();
  2146. // If we stored a previously focused element when using autoCapture, return focus to that
  2147. // element now that the trapped region is being destroyed.
  2148. if (this._previouslyFocusedElement) {
  2149. this._previouslyFocusedElement.focus();
  2150. this._previouslyFocusedElement = null;
  2151. }
  2152. };
  2153. /**
  2154. * @return {?}
  2155. */
  2156. CdkTrapFocus.prototype.ngAfterContentInit = /**
  2157. * @return {?}
  2158. */
  2159. function () {
  2160. this.focusTrap.attachAnchors();
  2161. if (this.autoCapture) {
  2162. this._previouslyFocusedElement = (/** @type {?} */ (this._document.activeElement));
  2163. this.focusTrap.focusInitialElementWhenReady();
  2164. }
  2165. };
  2166. /**
  2167. * @return {?}
  2168. */
  2169. CdkTrapFocus.prototype.ngDoCheck = /**
  2170. * @return {?}
  2171. */
  2172. function () {
  2173. if (!this.focusTrap.hasAttached()) {
  2174. this.focusTrap.attachAnchors();
  2175. }
  2176. };
  2177. CdkTrapFocus.decorators = [
  2178. { type: core.Directive, args: [{
  2179. selector: '[cdkTrapFocus]',
  2180. exportAs: 'cdkTrapFocus',
  2181. },] },
  2182. ];
  2183. /** @nocollapse */
  2184. CdkTrapFocus.ctorParameters = function () { return [
  2185. { type: core.ElementRef },
  2186. { type: FocusTrapFactory },
  2187. { type: undefined, decorators: [{ type: core.Inject, args: [common.DOCUMENT,] }] }
  2188. ]; };
  2189. CdkTrapFocus.propDecorators = {
  2190. enabled: [{ type: core.Input, args: ['cdkTrapFocus',] }],
  2191. autoCapture: [{ type: core.Input, args: ['cdkTrapFocusAutoCapture',] }]
  2192. };
  2193. return CdkTrapFocus;
  2194. }());
  2195. /**
  2196. * @fileoverview added by tsickle
  2197. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  2198. */
  2199. /** @type {?} */
  2200. var LIVE_ANNOUNCER_ELEMENT_TOKEN = new core.InjectionToken('liveAnnouncerElement', {
  2201. providedIn: 'root',
  2202. factory: LIVE_ANNOUNCER_ELEMENT_TOKEN_FACTORY,
  2203. });
  2204. /**
  2205. * \@docs-private
  2206. * @return {?}
  2207. */
  2208. function LIVE_ANNOUNCER_ELEMENT_TOKEN_FACTORY() {
  2209. return null;
  2210. }
  2211. /**
  2212. * Injection token that can be used to configure the default options for the LiveAnnouncer.
  2213. * @type {?}
  2214. */
  2215. var LIVE_ANNOUNCER_DEFAULT_OPTIONS = new core.InjectionToken('LIVE_ANNOUNCER_DEFAULT_OPTIONS');
  2216. /**
  2217. * @fileoverview added by tsickle
  2218. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  2219. */
  2220. var LiveAnnouncer = /** @class */ (function () {
  2221. function LiveAnnouncer(elementToken, _ngZone, _document, _defaultOptions) {
  2222. this._ngZone = _ngZone;
  2223. this._defaultOptions = _defaultOptions;
  2224. // We inject the live element and document as `any` because the constructor signature cannot
  2225. // reference browser globals (HTMLElement, Document) on non-browser environments, since having
  2226. // a class decorator causes TypeScript to preserve the constructor signature types.
  2227. this._document = _document;
  2228. this._liveElement = elementToken || this._createLiveElement();
  2229. }
  2230. /**
  2231. * @param {?} message
  2232. * @param {...?} args
  2233. * @return {?}
  2234. */
  2235. LiveAnnouncer.prototype.announce = /**
  2236. * @param {?} message
  2237. * @param {...?} args
  2238. * @return {?}
  2239. */
  2240. function (message) {
  2241. var _this = this;
  2242. var args = [];
  2243. for (var _i = 1; _i < arguments.length; _i++) {
  2244. args[_i - 1] = arguments[_i];
  2245. }
  2246. /** @type {?} */
  2247. var defaultOptions = this._defaultOptions;
  2248. /** @type {?} */
  2249. var politeness;
  2250. /** @type {?} */
  2251. var duration;
  2252. if (args.length === 1 && typeof args[0] === 'number') {
  2253. duration = args[0];
  2254. }
  2255. else {
  2256. politeness = args[0], duration = args[1];
  2257. }
  2258. this.clear();
  2259. clearTimeout(this._previousTimeout);
  2260. if (!politeness) {
  2261. politeness =
  2262. (defaultOptions && defaultOptions.politeness) ? defaultOptions.politeness : 'polite';
  2263. }
  2264. if (duration == null && defaultOptions) {
  2265. duration = defaultOptions.duration;
  2266. }
  2267. // TODO: ensure changing the politeness works on all environments we support.
  2268. this._liveElement.setAttribute('aria-live', politeness);
  2269. // This 100ms timeout is necessary for some browser + screen-reader combinations:
  2270. // - Both JAWS and NVDA over IE11 will not announce anything without a non-zero timeout.
  2271. // - With Chrome and IE11 with NVDA or JAWS, a repeated (identical) message won't be read a
  2272. // second time without clearing and then using a non-zero delay.
  2273. // (using JAWS 17 at time of this writing).
  2274. return this._ngZone.runOutsideAngular((/**
  2275. * @return {?}
  2276. */
  2277. function () {
  2278. return new Promise((/**
  2279. * @param {?} resolve
  2280. * @return {?}
  2281. */
  2282. function (resolve) {
  2283. clearTimeout(_this._previousTimeout);
  2284. _this._previousTimeout = setTimeout((/**
  2285. * @return {?}
  2286. */
  2287. function () {
  2288. _this._liveElement.textContent = message;
  2289. resolve();
  2290. if (typeof duration === 'number') {
  2291. _this._previousTimeout = setTimeout((/**
  2292. * @return {?}
  2293. */
  2294. function () { return _this.clear(); }), duration);
  2295. }
  2296. }), 100);
  2297. }));
  2298. }));
  2299. };
  2300. /**
  2301. * Clears the current text from the announcer element. Can be used to prevent
  2302. * screen readers from reading the text out again while the user is going
  2303. * through the page landmarks.
  2304. */
  2305. /**
  2306. * Clears the current text from the announcer element. Can be used to prevent
  2307. * screen readers from reading the text out again while the user is going
  2308. * through the page landmarks.
  2309. * @return {?}
  2310. */
  2311. LiveAnnouncer.prototype.clear = /**
  2312. * Clears the current text from the announcer element. Can be used to prevent
  2313. * screen readers from reading the text out again while the user is going
  2314. * through the page landmarks.
  2315. * @return {?}
  2316. */
  2317. function () {
  2318. if (this._liveElement) {
  2319. this._liveElement.textContent = '';
  2320. }
  2321. };
  2322. /**
  2323. * @return {?}
  2324. */
  2325. LiveAnnouncer.prototype.ngOnDestroy = /**
  2326. * @return {?}
  2327. */
  2328. function () {
  2329. clearTimeout(this._previousTimeout);
  2330. if (this._liveElement && this._liveElement.parentNode) {
  2331. this._liveElement.parentNode.removeChild(this._liveElement);
  2332. this._liveElement = (/** @type {?} */ (null));
  2333. }
  2334. };
  2335. /**
  2336. * @private
  2337. * @return {?}
  2338. */
  2339. LiveAnnouncer.prototype._createLiveElement = /**
  2340. * @private
  2341. * @return {?}
  2342. */
  2343. function () {
  2344. /** @type {?} */
  2345. var elementClass = 'cdk-live-announcer-element';
  2346. /** @type {?} */
  2347. var previousElements = this._document.getElementsByClassName(elementClass);
  2348. /** @type {?} */
  2349. var liveEl = this._document.createElement('div');
  2350. // Remove any old containers. This can happen when coming in from a server-side-rendered page.
  2351. for (var i = 0; i < previousElements.length; i++) {
  2352. (/** @type {?} */ (previousElements[i].parentNode)).removeChild(previousElements[i]);
  2353. }
  2354. liveEl.classList.add(elementClass);
  2355. liveEl.classList.add('cdk-visually-hidden');
  2356. liveEl.setAttribute('aria-atomic', 'true');
  2357. liveEl.setAttribute('aria-live', 'polite');
  2358. this._document.body.appendChild(liveEl);
  2359. return liveEl;
  2360. };
  2361. LiveAnnouncer.decorators = [
  2362. { type: core.Injectable, args: [{ providedIn: 'root' },] },
  2363. ];
  2364. /** @nocollapse */
  2365. LiveAnnouncer.ctorParameters = function () { return [
  2366. { type: undefined, decorators: [{ type: core.Optional }, { type: core.Inject, args: [LIVE_ANNOUNCER_ELEMENT_TOKEN,] }] },
  2367. { type: core.NgZone },
  2368. { type: undefined, decorators: [{ type: core.Inject, args: [common.DOCUMENT,] }] },
  2369. { type: undefined, decorators: [{ type: core.Optional }, { type: core.Inject, args: [LIVE_ANNOUNCER_DEFAULT_OPTIONS,] }] }
  2370. ]; };
  2371. /** @nocollapse */ LiveAnnouncer.ngInjectableDef = core.ɵɵdefineInjectable({ factory: function LiveAnnouncer_Factory() { return new LiveAnnouncer(core.ɵɵinject(LIVE_ANNOUNCER_ELEMENT_TOKEN, 8), core.ɵɵinject(core.NgZone), core.ɵɵinject(common.DOCUMENT), core.ɵɵinject(LIVE_ANNOUNCER_DEFAULT_OPTIONS, 8)); }, token: LiveAnnouncer, providedIn: "root" });
  2372. return LiveAnnouncer;
  2373. }());
  2374. /**
  2375. * A directive that works similarly to aria-live, but uses the LiveAnnouncer to ensure compatibility
  2376. * with a wider range of browsers and screen readers.
  2377. */
  2378. var CdkAriaLive = /** @class */ (function () {
  2379. function CdkAriaLive(_elementRef, _liveAnnouncer, _contentObserver, _ngZone) {
  2380. this._elementRef = _elementRef;
  2381. this._liveAnnouncer = _liveAnnouncer;
  2382. this._contentObserver = _contentObserver;
  2383. this._ngZone = _ngZone;
  2384. this._politeness = 'off';
  2385. }
  2386. Object.defineProperty(CdkAriaLive.prototype, "politeness", {
  2387. /** The aria-live politeness level to use when announcing messages. */
  2388. get: /**
  2389. * The aria-live politeness level to use when announcing messages.
  2390. * @return {?}
  2391. */
  2392. function () { return this._politeness; },
  2393. set: /**
  2394. * @param {?} value
  2395. * @return {?}
  2396. */
  2397. function (value) {
  2398. var _this = this;
  2399. this._politeness = value === 'polite' || value === 'assertive' ? value : 'off';
  2400. if (this._politeness === 'off') {
  2401. if (this._subscription) {
  2402. this._subscription.unsubscribe();
  2403. this._subscription = null;
  2404. }
  2405. }
  2406. else if (!this._subscription) {
  2407. this._subscription = this._ngZone.runOutsideAngular((/**
  2408. * @return {?}
  2409. */
  2410. function () {
  2411. return _this._contentObserver
  2412. .observe(_this._elementRef)
  2413. .subscribe((/**
  2414. * @return {?}
  2415. */
  2416. function () {
  2417. // Note that we use textContent here, rather than innerText, in order to avoid a reflow.
  2418. /** @type {?} */
  2419. var elementText = _this._elementRef.nativeElement.textContent;
  2420. // The `MutationObserver` fires also for attribute
  2421. // changes which we don't want to announce.
  2422. if (elementText !== _this._previousAnnouncedText) {
  2423. _this._liveAnnouncer.announce(elementText, _this._politeness);
  2424. _this._previousAnnouncedText = elementText;
  2425. }
  2426. }));
  2427. }));
  2428. }
  2429. },
  2430. enumerable: true,
  2431. configurable: true
  2432. });
  2433. /**
  2434. * @return {?}
  2435. */
  2436. CdkAriaLive.prototype.ngOnDestroy = /**
  2437. * @return {?}
  2438. */
  2439. function () {
  2440. if (this._subscription) {
  2441. this._subscription.unsubscribe();
  2442. }
  2443. };
  2444. CdkAriaLive.decorators = [
  2445. { type: core.Directive, args: [{
  2446. selector: '[cdkAriaLive]',
  2447. exportAs: 'cdkAriaLive',
  2448. },] },
  2449. ];
  2450. /** @nocollapse */
  2451. CdkAriaLive.ctorParameters = function () { return [
  2452. { type: core.ElementRef },
  2453. { type: LiveAnnouncer },
  2454. { type: observers.ContentObserver },
  2455. { type: core.NgZone }
  2456. ]; };
  2457. CdkAriaLive.propDecorators = {
  2458. politeness: [{ type: core.Input, args: ['cdkAriaLive',] }]
  2459. };
  2460. return CdkAriaLive;
  2461. }());
  2462. /**
  2463. * \@docs-private \@deprecated \@breaking-change 8.0.0
  2464. * @param {?} parentAnnouncer
  2465. * @param {?} liveElement
  2466. * @param {?} _document
  2467. * @param {?} ngZone
  2468. * @return {?}
  2469. */
  2470. function LIVE_ANNOUNCER_PROVIDER_FACTORY(parentAnnouncer, liveElement, _document, ngZone) {
  2471. return parentAnnouncer || new LiveAnnouncer(liveElement, ngZone, _document);
  2472. }
  2473. /**
  2474. * \@docs-private \@deprecated \@breaking-change 8.0.0
  2475. * @type {?}
  2476. */
  2477. var LIVE_ANNOUNCER_PROVIDER = {
  2478. // If there is already a LiveAnnouncer available, use that. Otherwise, provide a new one.
  2479. provide: LiveAnnouncer,
  2480. deps: [
  2481. [new core.Optional(), new core.SkipSelf(), LiveAnnouncer],
  2482. [new core.Optional(), new core.Inject(LIVE_ANNOUNCER_ELEMENT_TOKEN)],
  2483. common.DOCUMENT,
  2484. core.NgZone,
  2485. ],
  2486. useFactory: LIVE_ANNOUNCER_PROVIDER_FACTORY
  2487. };
  2488. /**
  2489. * @fileoverview added by tsickle
  2490. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  2491. */
  2492. // This is the value used by AngularJS Material. Through trial and error (on iPhone 6S) they found
  2493. // that a value of around 650ms seems appropriate.
  2494. /** @type {?} */
  2495. var TOUCH_BUFFER_MS = 650;
  2496. /**
  2497. * Event listener options that enable capturing and also
  2498. * mark the listener as passive if the browser supports it.
  2499. * @type {?}
  2500. */
  2501. var captureEventListenerOptions = platform.normalizePassiveListenerOptions({
  2502. passive: true,
  2503. capture: true
  2504. });
  2505. /**
  2506. * Monitors mouse and keyboard events to determine the cause of focus events.
  2507. */
  2508. var FocusMonitor = /** @class */ (function () {
  2509. function FocusMonitor(_ngZone, _platform) {
  2510. var _this = this;
  2511. this._ngZone = _ngZone;
  2512. this._platform = _platform;
  2513. /**
  2514. * The focus origin that the next focus event is a result of.
  2515. */
  2516. this._origin = null;
  2517. /**
  2518. * Whether the window has just been focused.
  2519. */
  2520. this._windowFocused = false;
  2521. /**
  2522. * Map of elements being monitored to their info.
  2523. */
  2524. this._elementInfo = new Map();
  2525. /**
  2526. * The number of elements currently being monitored.
  2527. */
  2528. this._monitoredElementCount = 0;
  2529. /**
  2530. * Event listener for `keydown` events on the document.
  2531. * Needs to be an arrow function in order to preserve the context when it gets bound.
  2532. */
  2533. this._documentKeydownListener = (/**
  2534. * @return {?}
  2535. */
  2536. function () {
  2537. // On keydown record the origin and clear any touch event that may be in progress.
  2538. _this._lastTouchTarget = null;
  2539. _this._setOriginForCurrentEventQueue('keyboard');
  2540. });
  2541. /**
  2542. * Event listener for `mousedown` events on the document.
  2543. * Needs to be an arrow function in order to preserve the context when it gets bound.
  2544. */
  2545. this._documentMousedownListener = (/**
  2546. * @return {?}
  2547. */
  2548. function () {
  2549. // On mousedown record the origin only if there is not touch
  2550. // target, since a mousedown can happen as a result of a touch event.
  2551. if (!_this._lastTouchTarget) {
  2552. _this._setOriginForCurrentEventQueue('mouse');
  2553. }
  2554. });
  2555. /**
  2556. * Event listener for `touchstart` events on the document.
  2557. * Needs to be an arrow function in order to preserve the context when it gets bound.
  2558. */
  2559. this._documentTouchstartListener = (/**
  2560. * @param {?} event
  2561. * @return {?}
  2562. */
  2563. function (event) {
  2564. // When the touchstart event fires the focus event is not yet in the event queue. This means
  2565. // we can't rely on the trick used above (setting timeout of 1ms). Instead we wait 650ms to
  2566. // see if a focus happens.
  2567. if (_this._touchTimeoutId != null) {
  2568. clearTimeout(_this._touchTimeoutId);
  2569. }
  2570. // Since this listener is bound on the `document` level, any events coming from the shadow DOM
  2571. // will have their `target` set to the shadow root. If available, use `composedPath` to
  2572. // figure out the event target.
  2573. _this._lastTouchTarget = event.composedPath ? event.composedPath()[0] : event.target;
  2574. _this._touchTimeoutId = setTimeout((/**
  2575. * @return {?}
  2576. */
  2577. function () { return _this._lastTouchTarget = null; }), TOUCH_BUFFER_MS);
  2578. });
  2579. /**
  2580. * Event listener for `focus` events on the window.
  2581. * Needs to be an arrow function in order to preserve the context when it gets bound.
  2582. */
  2583. this._windowFocusListener = (/**
  2584. * @return {?}
  2585. */
  2586. function () {
  2587. // Make a note of when the window regains focus, so we can
  2588. // restore the origin info for the focused element.
  2589. _this._windowFocused = true;
  2590. _this._windowFocusTimeoutId = setTimeout((/**
  2591. * @return {?}
  2592. */
  2593. function () { return _this._windowFocused = false; }));
  2594. });
  2595. }
  2596. /**
  2597. * @param {?} element
  2598. * @param {?=} checkChildren
  2599. * @return {?}
  2600. */
  2601. FocusMonitor.prototype.monitor = /**
  2602. * @param {?} element
  2603. * @param {?=} checkChildren
  2604. * @return {?}
  2605. */
  2606. function (element, checkChildren) {
  2607. var _this = this;
  2608. if (checkChildren === void 0) { checkChildren = false; }
  2609. // Do nothing if we're not on the browser platform.
  2610. if (!this._platform.isBrowser) {
  2611. return rxjs.of(null);
  2612. }
  2613. /** @type {?} */
  2614. var nativeElement = coercion.coerceElement(element);
  2615. // Check if we're already monitoring this element.
  2616. if (this._elementInfo.has(nativeElement)) {
  2617. /** @type {?} */
  2618. var cachedInfo = this._elementInfo.get(nativeElement);
  2619. (/** @type {?} */ (cachedInfo)).checkChildren = checkChildren;
  2620. return (/** @type {?} */ (cachedInfo)).subject.asObservable();
  2621. }
  2622. // Create monitored element info.
  2623. /** @type {?} */
  2624. var info = {
  2625. unlisten: (/**
  2626. * @return {?}
  2627. */
  2628. function () { }),
  2629. checkChildren: checkChildren,
  2630. subject: new rxjs.Subject()
  2631. };
  2632. this._elementInfo.set(nativeElement, info);
  2633. this._incrementMonitoredElementCount();
  2634. // Start listening. We need to listen in capture phase since focus events don't bubble.
  2635. /** @type {?} */
  2636. var focusListener = (/**
  2637. * @param {?} event
  2638. * @return {?}
  2639. */
  2640. function (event) { return _this._onFocus(event, nativeElement); });
  2641. /** @type {?} */
  2642. var blurListener = (/**
  2643. * @param {?} event
  2644. * @return {?}
  2645. */
  2646. function (event) { return _this._onBlur(event, nativeElement); });
  2647. this._ngZone.runOutsideAngular((/**
  2648. * @return {?}
  2649. */
  2650. function () {
  2651. nativeElement.addEventListener('focus', focusListener, true);
  2652. nativeElement.addEventListener('blur', blurListener, true);
  2653. }));
  2654. // Create an unlisten function for later.
  2655. info.unlisten = (/**
  2656. * @return {?}
  2657. */
  2658. function () {
  2659. nativeElement.removeEventListener('focus', focusListener, true);
  2660. nativeElement.removeEventListener('blur', blurListener, true);
  2661. });
  2662. return info.subject.asObservable();
  2663. };
  2664. /**
  2665. * @param {?} element
  2666. * @return {?}
  2667. */
  2668. FocusMonitor.prototype.stopMonitoring = /**
  2669. * @param {?} element
  2670. * @return {?}
  2671. */
  2672. function (element) {
  2673. /** @type {?} */
  2674. var nativeElement = coercion.coerceElement(element);
  2675. /** @type {?} */
  2676. var elementInfo = this._elementInfo.get(nativeElement);
  2677. if (elementInfo) {
  2678. elementInfo.unlisten();
  2679. elementInfo.subject.complete();
  2680. this._setClasses(nativeElement);
  2681. this._elementInfo.delete(nativeElement);
  2682. this._decrementMonitoredElementCount();
  2683. }
  2684. };
  2685. /**
  2686. * @param {?} element
  2687. * @param {?} origin
  2688. * @param {?=} options
  2689. * @return {?}
  2690. */
  2691. FocusMonitor.prototype.focusVia = /**
  2692. * @param {?} element
  2693. * @param {?} origin
  2694. * @param {?=} options
  2695. * @return {?}
  2696. */
  2697. function (element, origin, options) {
  2698. /** @type {?} */
  2699. var nativeElement = coercion.coerceElement(element);
  2700. this._setOriginForCurrentEventQueue(origin);
  2701. // `focus` isn't available on the server
  2702. if (typeof nativeElement.focus === 'function') {
  2703. // Cast the element to `any`, because the TS typings don't have the `options` parameter yet.
  2704. ((/** @type {?} */ (nativeElement))).focus(options);
  2705. }
  2706. };
  2707. /**
  2708. * @return {?}
  2709. */
  2710. FocusMonitor.prototype.ngOnDestroy = /**
  2711. * @return {?}
  2712. */
  2713. function () {
  2714. var _this = this;
  2715. this._elementInfo.forEach((/**
  2716. * @param {?} _info
  2717. * @param {?} element
  2718. * @return {?}
  2719. */
  2720. function (_info, element) { return _this.stopMonitoring(element); }));
  2721. };
  2722. /**
  2723. * @private
  2724. * @param {?} element
  2725. * @param {?} className
  2726. * @param {?} shouldSet
  2727. * @return {?}
  2728. */
  2729. FocusMonitor.prototype._toggleClass = /**
  2730. * @private
  2731. * @param {?} element
  2732. * @param {?} className
  2733. * @param {?} shouldSet
  2734. * @return {?}
  2735. */
  2736. function (element, className, shouldSet) {
  2737. if (shouldSet) {
  2738. element.classList.add(className);
  2739. }
  2740. else {
  2741. element.classList.remove(className);
  2742. }
  2743. };
  2744. /**
  2745. * Sets the focus classes on the element based on the given focus origin.
  2746. * @param element The element to update the classes on.
  2747. * @param origin The focus origin.
  2748. */
  2749. /**
  2750. * Sets the focus classes on the element based on the given focus origin.
  2751. * @private
  2752. * @param {?} element The element to update the classes on.
  2753. * @param {?=} origin The focus origin.
  2754. * @return {?}
  2755. */
  2756. FocusMonitor.prototype._setClasses = /**
  2757. * Sets the focus classes on the element based on the given focus origin.
  2758. * @private
  2759. * @param {?} element The element to update the classes on.
  2760. * @param {?=} origin The focus origin.
  2761. * @return {?}
  2762. */
  2763. function (element, origin) {
  2764. /** @type {?} */
  2765. var elementInfo = this._elementInfo.get(element);
  2766. if (elementInfo) {
  2767. this._toggleClass(element, 'cdk-focused', !!origin);
  2768. this._toggleClass(element, 'cdk-touch-focused', origin === 'touch');
  2769. this._toggleClass(element, 'cdk-keyboard-focused', origin === 'keyboard');
  2770. this._toggleClass(element, 'cdk-mouse-focused', origin === 'mouse');
  2771. this._toggleClass(element, 'cdk-program-focused', origin === 'program');
  2772. }
  2773. };
  2774. /**
  2775. * Sets the origin and schedules an async function to clear it at the end of the event queue.
  2776. * @param origin The origin to set.
  2777. */
  2778. /**
  2779. * Sets the origin and schedules an async function to clear it at the end of the event queue.
  2780. * @private
  2781. * @param {?} origin The origin to set.
  2782. * @return {?}
  2783. */
  2784. FocusMonitor.prototype._setOriginForCurrentEventQueue = /**
  2785. * Sets the origin and schedules an async function to clear it at the end of the event queue.
  2786. * @private
  2787. * @param {?} origin The origin to set.
  2788. * @return {?}
  2789. */
  2790. function (origin) {
  2791. var _this = this;
  2792. this._ngZone.runOutsideAngular((/**
  2793. * @return {?}
  2794. */
  2795. function () {
  2796. _this._origin = origin;
  2797. // Sometimes the focus origin won't be valid in Firefox because Firefox seems to focus *one*
  2798. // tick after the interaction event fired. To ensure the focus origin is always correct,
  2799. // the focus origin will be determined at the beginning of the next tick.
  2800. _this._originTimeoutId = setTimeout((/**
  2801. * @return {?}
  2802. */
  2803. function () { return _this._origin = null; }), 1);
  2804. }));
  2805. };
  2806. /**
  2807. * Checks whether the given focus event was caused by a touchstart event.
  2808. * @param event The focus event to check.
  2809. * @returns Whether the event was caused by a touch.
  2810. */
  2811. /**
  2812. * Checks whether the given focus event was caused by a touchstart event.
  2813. * @private
  2814. * @param {?} event The focus event to check.
  2815. * @return {?} Whether the event was caused by a touch.
  2816. */
  2817. FocusMonitor.prototype._wasCausedByTouch = /**
  2818. * Checks whether the given focus event was caused by a touchstart event.
  2819. * @private
  2820. * @param {?} event The focus event to check.
  2821. * @return {?} Whether the event was caused by a touch.
  2822. */
  2823. function (event) {
  2824. // Note(mmalerba): This implementation is not quite perfect, there is a small edge case.
  2825. // Consider the following dom structure:
  2826. //
  2827. // <div #parent tabindex="0" cdkFocusClasses>
  2828. // <div #child (click)="#parent.focus()"></div>
  2829. // </div>
  2830. //
  2831. // If the user touches the #child element and the #parent is programmatically focused as a
  2832. // result, this code will still consider it to have been caused by the touch event and will
  2833. // apply the cdk-touch-focused class rather than the cdk-program-focused class. This is a
  2834. // relatively small edge-case that can be worked around by using
  2835. // focusVia(parentEl, 'program') to focus the parent element.
  2836. //
  2837. // If we decide that we absolutely must handle this case correctly, we can do so by listening
  2838. // for the first focus event after the touchstart, and then the first blur event after that
  2839. // focus event. When that blur event fires we know that whatever follows is not a result of the
  2840. // touchstart.
  2841. /** @type {?} */
  2842. var focusTarget = event.target;
  2843. return this._lastTouchTarget instanceof Node && focusTarget instanceof Node &&
  2844. (focusTarget === this._lastTouchTarget || focusTarget.contains(this._lastTouchTarget));
  2845. };
  2846. /**
  2847. * Handles focus events on a registered element.
  2848. * @param event The focus event.
  2849. * @param element The monitored element.
  2850. */
  2851. /**
  2852. * Handles focus events on a registered element.
  2853. * @private
  2854. * @param {?} event The focus event.
  2855. * @param {?} element The monitored element.
  2856. * @return {?}
  2857. */
  2858. FocusMonitor.prototype._onFocus = /**
  2859. * Handles focus events on a registered element.
  2860. * @private
  2861. * @param {?} event The focus event.
  2862. * @param {?} element The monitored element.
  2863. * @return {?}
  2864. */
  2865. function (event, element) {
  2866. // NOTE(mmalerba): We currently set the classes based on the focus origin of the most recent
  2867. // focus event affecting the monitored element. If we want to use the origin of the first event
  2868. // instead we should check for the cdk-focused class here and return if the element already has
  2869. // it. (This only matters for elements that have includesChildren = true).
  2870. // NOTE(mmalerba): We currently set the classes based on the focus origin of the most recent
  2871. // focus event affecting the monitored element. If we want to use the origin of the first event
  2872. // instead we should check for the cdk-focused class here and return if the element already has
  2873. // it. (This only matters for elements that have includesChildren = true).
  2874. // If we are not counting child-element-focus as focused, make sure that the event target is the
  2875. // monitored element itself.
  2876. /** @type {?} */
  2877. var elementInfo = this._elementInfo.get(element);
  2878. if (!elementInfo || (!elementInfo.checkChildren && element !== event.target)) {
  2879. return;
  2880. }
  2881. // If we couldn't detect a cause for the focus event, it's due to one of three reasons:
  2882. // 1) The window has just regained focus, in which case we want to restore the focused state of
  2883. // the element from before the window blurred.
  2884. // 2) It was caused by a touch event, in which case we mark the origin as 'touch'.
  2885. // 3) The element was programmatically focused, in which case we should mark the origin as
  2886. // 'program'.
  2887. /** @type {?} */
  2888. var origin = this._origin;
  2889. if (!origin) {
  2890. if (this._windowFocused && this._lastFocusOrigin) {
  2891. origin = this._lastFocusOrigin;
  2892. }
  2893. else if (this._wasCausedByTouch(event)) {
  2894. origin = 'touch';
  2895. }
  2896. else {
  2897. origin = 'program';
  2898. }
  2899. }
  2900. this._setClasses(element, origin);
  2901. this._emitOrigin(elementInfo.subject, origin);
  2902. this._lastFocusOrigin = origin;
  2903. };
  2904. /**
  2905. * Handles blur events on a registered element.
  2906. * @param event The blur event.
  2907. * @param element The monitored element.
  2908. */
  2909. /**
  2910. * Handles blur events on a registered element.
  2911. * @param {?} event The blur event.
  2912. * @param {?} element The monitored element.
  2913. * @return {?}
  2914. */
  2915. FocusMonitor.prototype._onBlur = /**
  2916. * Handles blur events on a registered element.
  2917. * @param {?} event The blur event.
  2918. * @param {?} element The monitored element.
  2919. * @return {?}
  2920. */
  2921. function (event, element) {
  2922. // If we are counting child-element-focus as focused, make sure that we aren't just blurring in
  2923. // order to focus another child of the monitored element.
  2924. /** @type {?} */
  2925. var elementInfo = this._elementInfo.get(element);
  2926. if (!elementInfo || (elementInfo.checkChildren && event.relatedTarget instanceof Node &&
  2927. element.contains(event.relatedTarget))) {
  2928. return;
  2929. }
  2930. this._setClasses(element);
  2931. this._emitOrigin(elementInfo.subject, null);
  2932. };
  2933. /**
  2934. * @private
  2935. * @param {?} subject
  2936. * @param {?} origin
  2937. * @return {?}
  2938. */
  2939. FocusMonitor.prototype._emitOrigin = /**
  2940. * @private
  2941. * @param {?} subject
  2942. * @param {?} origin
  2943. * @return {?}
  2944. */
  2945. function (subject, origin) {
  2946. this._ngZone.run((/**
  2947. * @return {?}
  2948. */
  2949. function () { return subject.next(origin); }));
  2950. };
  2951. /**
  2952. * @private
  2953. * @return {?}
  2954. */
  2955. FocusMonitor.prototype._incrementMonitoredElementCount = /**
  2956. * @private
  2957. * @return {?}
  2958. */
  2959. function () {
  2960. var _this = this;
  2961. // Register global listeners when first element is monitored.
  2962. if (++this._monitoredElementCount == 1 && this._platform.isBrowser) {
  2963. // Note: we listen to events in the capture phase so we
  2964. // can detect them even if the user stops propagation.
  2965. this._ngZone.runOutsideAngular((/**
  2966. * @return {?}
  2967. */
  2968. function () {
  2969. document.addEventListener('keydown', _this._documentKeydownListener, captureEventListenerOptions);
  2970. document.addEventListener('mousedown', _this._documentMousedownListener, captureEventListenerOptions);
  2971. document.addEventListener('touchstart', _this._documentTouchstartListener, captureEventListenerOptions);
  2972. window.addEventListener('focus', _this._windowFocusListener);
  2973. }));
  2974. }
  2975. };
  2976. /**
  2977. * @private
  2978. * @return {?}
  2979. */
  2980. FocusMonitor.prototype._decrementMonitoredElementCount = /**
  2981. * @private
  2982. * @return {?}
  2983. */
  2984. function () {
  2985. // Unregister global listeners when last element is unmonitored.
  2986. if (!--this._monitoredElementCount) {
  2987. document.removeEventListener('keydown', this._documentKeydownListener, captureEventListenerOptions);
  2988. document.removeEventListener('mousedown', this._documentMousedownListener, captureEventListenerOptions);
  2989. document.removeEventListener('touchstart', this._documentTouchstartListener, captureEventListenerOptions);
  2990. window.removeEventListener('focus', this._windowFocusListener);
  2991. // Clear timeouts for all potentially pending timeouts to prevent the leaks.
  2992. clearTimeout(this._windowFocusTimeoutId);
  2993. clearTimeout(this._touchTimeoutId);
  2994. clearTimeout(this._originTimeoutId);
  2995. }
  2996. };
  2997. FocusMonitor.decorators = [
  2998. { type: core.Injectable, args: [{ providedIn: 'root' },] },
  2999. ];
  3000. /** @nocollapse */
  3001. FocusMonitor.ctorParameters = function () { return [
  3002. { type: core.NgZone },
  3003. { type: platform.Platform }
  3004. ]; };
  3005. /** @nocollapse */ FocusMonitor.ngInjectableDef = core.ɵɵdefineInjectable({ factory: function FocusMonitor_Factory() { return new FocusMonitor(core.ɵɵinject(core.NgZone), core.ɵɵinject(platform.Platform)); }, token: FocusMonitor, providedIn: "root" });
  3006. return FocusMonitor;
  3007. }());
  3008. /**
  3009. * Directive that determines how a particular element was focused (via keyboard, mouse, touch, or
  3010. * programmatically) and adds corresponding classes to the element.
  3011. *
  3012. * There are two variants of this directive:
  3013. * 1) cdkMonitorElementFocus: does not consider an element to be focused if one of its children is
  3014. * focused.
  3015. * 2) cdkMonitorSubtreeFocus: considers an element focused if it or any of its children are focused.
  3016. */
  3017. var CdkMonitorFocus = /** @class */ (function () {
  3018. function CdkMonitorFocus(_elementRef, _focusMonitor) {
  3019. var _this = this;
  3020. this._elementRef = _elementRef;
  3021. this._focusMonitor = _focusMonitor;
  3022. this.cdkFocusChange = new core.EventEmitter();
  3023. this._monitorSubscription = this._focusMonitor.monitor(this._elementRef, this._elementRef.nativeElement.hasAttribute('cdkMonitorSubtreeFocus'))
  3024. .subscribe((/**
  3025. * @param {?} origin
  3026. * @return {?}
  3027. */
  3028. function (origin) { return _this.cdkFocusChange.emit(origin); }));
  3029. }
  3030. /**
  3031. * @return {?}
  3032. */
  3033. CdkMonitorFocus.prototype.ngOnDestroy = /**
  3034. * @return {?}
  3035. */
  3036. function () {
  3037. this._focusMonitor.stopMonitoring(this._elementRef);
  3038. this._monitorSubscription.unsubscribe();
  3039. };
  3040. CdkMonitorFocus.decorators = [
  3041. { type: core.Directive, args: [{
  3042. selector: '[cdkMonitorElementFocus], [cdkMonitorSubtreeFocus]',
  3043. },] },
  3044. ];
  3045. /** @nocollapse */
  3046. CdkMonitorFocus.ctorParameters = function () { return [
  3047. { type: core.ElementRef },
  3048. { type: FocusMonitor }
  3049. ]; };
  3050. CdkMonitorFocus.propDecorators = {
  3051. cdkFocusChange: [{ type: core.Output }]
  3052. };
  3053. return CdkMonitorFocus;
  3054. }());
  3055. /**
  3056. * \@docs-private \@deprecated \@breaking-change 8.0.0
  3057. * @param {?} parentDispatcher
  3058. * @param {?} ngZone
  3059. * @param {?} platform
  3060. * @return {?}
  3061. */
  3062. function FOCUS_MONITOR_PROVIDER_FACTORY(parentDispatcher, ngZone, platform$$1) {
  3063. return parentDispatcher || new FocusMonitor(ngZone, platform$$1);
  3064. }
  3065. /**
  3066. * \@docs-private \@deprecated \@breaking-change 8.0.0
  3067. * @type {?}
  3068. */
  3069. var FOCUS_MONITOR_PROVIDER = {
  3070. // If there is already a FocusMonitor available, use that. Otherwise, provide a new one.
  3071. provide: FocusMonitor,
  3072. deps: [[new core.Optional(), new core.SkipSelf(), FocusMonitor], core.NgZone, platform.Platform],
  3073. useFactory: FOCUS_MONITOR_PROVIDER_FACTORY
  3074. };
  3075. /**
  3076. * @fileoverview added by tsickle
  3077. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  3078. */
  3079. /**
  3080. * Screenreaders will often fire fake mousedown events when a focusable element
  3081. * is activated using the keyboard. We can typically distinguish between these faked
  3082. * mousedown events and real mousedown events using the "buttons" property. While
  3083. * real mousedowns will indicate the mouse button that was pressed (e.g. "1" for
  3084. * the left mouse button), faked mousedowns will usually set the property value to 0.
  3085. * @param {?} event
  3086. * @return {?}
  3087. */
  3088. function isFakeMousedownFromScreenReader(event) {
  3089. return event.buttons === 0;
  3090. }
  3091. /**
  3092. * @fileoverview added by tsickle
  3093. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  3094. */
  3095. var A11yModule = /** @class */ (function () {
  3096. function A11yModule() {
  3097. }
  3098. A11yModule.decorators = [
  3099. { type: core.NgModule, args: [{
  3100. imports: [common.CommonModule, platform.PlatformModule, observers.ObserversModule],
  3101. declarations: [CdkAriaLive, CdkTrapFocus, CdkMonitorFocus],
  3102. exports: [CdkAriaLive, CdkTrapFocus, CdkMonitorFocus],
  3103. },] },
  3104. ];
  3105. return A11yModule;
  3106. }());
  3107. exports.ARIA_DESCRIBER_PROVIDER_FACTORY = ARIA_DESCRIBER_PROVIDER_FACTORY;
  3108. exports.MESSAGES_CONTAINER_ID = MESSAGES_CONTAINER_ID;
  3109. exports.CDK_DESCRIBEDBY_ID_PREFIX = CDK_DESCRIBEDBY_ID_PREFIX;
  3110. exports.CDK_DESCRIBEDBY_HOST_ATTRIBUTE = CDK_DESCRIBEDBY_HOST_ATTRIBUTE;
  3111. exports.AriaDescriber = AriaDescriber;
  3112. exports.ARIA_DESCRIBER_PROVIDER = ARIA_DESCRIBER_PROVIDER;
  3113. exports.ActiveDescendantKeyManager = ActiveDescendantKeyManager;
  3114. exports.FocusKeyManager = FocusKeyManager;
  3115. exports.ListKeyManager = ListKeyManager;
  3116. exports.FocusTrap = FocusTrap;
  3117. exports.FocusTrapFactory = FocusTrapFactory;
  3118. exports.CdkTrapFocus = CdkTrapFocus;
  3119. exports.InteractivityChecker = InteractivityChecker;
  3120. exports.LIVE_ANNOUNCER_PROVIDER_FACTORY = LIVE_ANNOUNCER_PROVIDER_FACTORY;
  3121. exports.LiveAnnouncer = LiveAnnouncer;
  3122. exports.CdkAriaLive = CdkAriaLive;
  3123. exports.LIVE_ANNOUNCER_PROVIDER = LIVE_ANNOUNCER_PROVIDER;
  3124. exports.LIVE_ANNOUNCER_ELEMENT_TOKEN_FACTORY = LIVE_ANNOUNCER_ELEMENT_TOKEN_FACTORY;
  3125. exports.LIVE_ANNOUNCER_ELEMENT_TOKEN = LIVE_ANNOUNCER_ELEMENT_TOKEN;
  3126. exports.LIVE_ANNOUNCER_DEFAULT_OPTIONS = LIVE_ANNOUNCER_DEFAULT_OPTIONS;
  3127. exports.FOCUS_MONITOR_PROVIDER_FACTORY = FOCUS_MONITOR_PROVIDER_FACTORY;
  3128. exports.TOUCH_BUFFER_MS = TOUCH_BUFFER_MS;
  3129. exports.FocusMonitor = FocusMonitor;
  3130. exports.CdkMonitorFocus = CdkMonitorFocus;
  3131. exports.FOCUS_MONITOR_PROVIDER = FOCUS_MONITOR_PROVIDER;
  3132. exports.isFakeMousedownFromScreenReader = isFakeMousedownFromScreenReader;
  3133. exports.A11yModule = A11yModule;
  3134. Object.defineProperty(exports, '__esModule', { value: true });
  3135. })));
  3136. //# sourceMappingURL=cdk-a11y.umd.js.map