| var aria = aria || {}; | 
|   | 
| aria.Utils = aria.Utils || {}; | 
|   | 
| /** | 
|  * @desc Set focus on descendant nodes until the first focusable element is | 
|  *       found. | 
|  * @param element | 
|  *          DOM node for which to find the first focusable descendant. | 
|  * @returns | 
|  *  true if a focusable element is found and focus is set. | 
|  */ | 
| aria.Utils.focusFirstDescendant = function(element) { | 
|   for (var i = 0; i < element.childNodes.length; i++) { | 
|     var child = element.childNodes[i]; | 
|     if (aria.Utils.attemptFocus(child) || aria.Utils.focusFirstDescendant(child)) { | 
|       return true; | 
|     } | 
|   } | 
|   return false; | 
| }; | 
|   | 
| /** | 
|  * @desc Find the last descendant node that is focusable. | 
|  * @param element | 
|  *          DOM node for which to find the last focusable descendant. | 
|  * @returns | 
|  *  true if a focusable element is found and focus is set. | 
|  */ | 
|   | 
| aria.Utils.focusLastDescendant = function(element) { | 
|   for (var i = element.childNodes.length - 1; i >= 0; i--) { | 
|     var child = element.childNodes[i]; | 
|     if (aria.Utils.attemptFocus(child) || aria.Utils.focusLastDescendant(child)) { | 
|       return true; | 
|     } | 
|   } | 
|   return false; | 
| }; | 
|   | 
| /** | 
|  * @desc Set Attempt to set focus on the current node. | 
|  * @param element | 
|  *          The node to attempt to focus on. | 
|  * @returns | 
|  *  true if element is focused. | 
|  */ | 
| aria.Utils.attemptFocus = function(element) { | 
|   if (!aria.Utils.isFocusable(element)) { | 
|     return false; | 
|   } | 
|   aria.Utils.IgnoreUtilFocusChanges = true; | 
|   try { | 
|     element.focus(); | 
|   } catch (e) { | 
|   } | 
|   aria.Utils.IgnoreUtilFocusChanges = false; | 
|   return (document.activeElement === element); | 
| }; | 
|   | 
| aria.Utils.isFocusable = function(element) { | 
|   if (element.tabIndex > 0 || (element.tabIndex === 0 && element.getAttribute('tabIndex') !== null)) { | 
|     return true; | 
|   } | 
|   | 
|   if (element.disabled) { | 
|     return false; | 
|   } | 
|   | 
|   switch (element.nodeName) { | 
|     case 'A': | 
|       return !!element.href && element.rel !== 'ignore'; | 
|     case 'INPUT': | 
|       return element.type !== 'hidden' && element.type !== 'file'; | 
|     case 'BUTTON': | 
|     case 'SELECT': | 
|     case 'TEXTAREA': | 
|       return true; | 
|     default: | 
|       return false; | 
|   } | 
| }; | 
|   | 
| /** | 
|  * 触发一个事件 | 
|  * mouseenter, mouseleave, mouseover, keyup, change, click 等 | 
|  * @param  {Element} elm | 
|  * @param  {String} name | 
|  * @param  {*} opts | 
|  */ | 
| aria.Utils.triggerEvent = function(elm, name, ...opts) { | 
|   let eventName; | 
|   | 
|   if (/^mouse|click/.test(name)) { | 
|     eventName = 'MouseEvents'; | 
|   } else if (/^key/.test(name)) { | 
|     eventName = 'KeyboardEvent'; | 
|   } else { | 
|     eventName = 'HTMLEvents'; | 
|   } | 
|   const evt = document.createEvent(eventName); | 
|   | 
|   evt.initEvent(name, ...opts); | 
|   elm.dispatchEvent | 
|     ? elm.dispatchEvent(evt) | 
|     : elm.fireEvent('on' + name, evt); | 
|   | 
|   return elm; | 
| }; | 
|   | 
| aria.Utils.keys = { | 
|   tab: 9, | 
|   enter: 13, | 
|   space: 32, | 
|   left: 37, | 
|   up: 38, | 
|   right: 39, | 
|   down: 40, | 
|   esc: 27 | 
| }; | 
|   | 
| export default aria.Utils; |