882d9cfad36dfd111e609524fb925e5b9fae40c2ee4cc2c7bcc735cc42276473dde7664ba173d70f4b2f4528f095a14445ee6578d9d2e67a97ab1ba237708c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. var aria = aria || {};
  2. aria.Utils = aria.Utils || {};
  3. /**
  4. * @desc Set focus on descendant nodes until the first focusable element is
  5. * found.
  6. * @param element
  7. * DOM node for which to find the first focusable descendant.
  8. * @returns
  9. * true if a focusable element is found and focus is set.
  10. */
  11. aria.Utils.focusFirstDescendant = function(element) {
  12. for (var i = 0; i < element.childNodes.length; i++) {
  13. var child = element.childNodes[i];
  14. if (aria.Utils.attemptFocus(child) || aria.Utils.focusFirstDescendant(child)) {
  15. return true;
  16. }
  17. }
  18. return false;
  19. };
  20. /**
  21. * @desc Find the last descendant node that is focusable.
  22. * @param element
  23. * DOM node for which to find the last focusable descendant.
  24. * @returns
  25. * true if a focusable element is found and focus is set.
  26. */
  27. aria.Utils.focusLastDescendant = function(element) {
  28. for (var i = element.childNodes.length - 1; i >= 0; i--) {
  29. var child = element.childNodes[i];
  30. if (aria.Utils.attemptFocus(child) || aria.Utils.focusLastDescendant(child)) {
  31. return true;
  32. }
  33. }
  34. return false;
  35. };
  36. /**
  37. * @desc Set Attempt to set focus on the current node.
  38. * @param element
  39. * The node to attempt to focus on.
  40. * @returns
  41. * true if element is focused.
  42. */
  43. aria.Utils.attemptFocus = function(element) {
  44. if (!aria.Utils.isFocusable(element)) {
  45. return false;
  46. }
  47. aria.Utils.IgnoreUtilFocusChanges = true;
  48. try {
  49. element.focus();
  50. } catch (e) {
  51. }
  52. aria.Utils.IgnoreUtilFocusChanges = false;
  53. return (document.activeElement === element);
  54. };
  55. aria.Utils.isFocusable = function(element) {
  56. if (element.tabIndex > 0 || (element.tabIndex === 0 && element.getAttribute('tabIndex') !== null)) {
  57. return true;
  58. }
  59. if (element.disabled) {
  60. return false;
  61. }
  62. switch (element.nodeName) {
  63. case 'A':
  64. return !!element.href && element.rel !== 'ignore';
  65. case 'INPUT':
  66. return element.type !== 'hidden' && element.type !== 'file';
  67. case 'BUTTON':
  68. case 'SELECT':
  69. case 'TEXTAREA':
  70. return true;
  71. default:
  72. return false;
  73. }
  74. };
  75. /**
  76. * 触发一个事件
  77. * mouseenter, mouseleave, mouseover, keyup, change, click 等
  78. * @param {Element} elm
  79. * @param {String} name
  80. * @param {*} opts
  81. */
  82. aria.Utils.triggerEvent = function(elm, name, ...opts) {
  83. let eventName;
  84. if (/^mouse|click/.test(name)) {
  85. eventName = 'MouseEvents';
  86. } else if (/^key/.test(name)) {
  87. eventName = 'KeyboardEvent';
  88. } else {
  89. eventName = 'HTMLEvents';
  90. }
  91. const evt = document.createEvent(eventName);
  92. evt.initEvent(name, ...opts);
  93. elm.dispatchEvent
  94. ? elm.dispatchEvent(evt)
  95. : elm.fireEvent('on' + name, evt);
  96. return elm;
  97. };
  98. aria.Utils.keys = {
  99. tab: 9,
  100. enter: 13,
  101. space: 32,
  102. left: 37,
  103. up: 38,
  104. right: 39,
  105. down: 40,
  106. esc: 27
  107. };
  108. export default aria.Utils;