focus.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.backLastFocusNode = backLastFocusNode;
  7. exports.clearLastFocusNode = clearLastFocusNode;
  8. exports.getFocusNodeList = getFocusNodeList;
  9. exports.limitTabRange = limitTabRange;
  10. exports.saveLastFocusNode = saveLastFocusNode;
  11. var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
  12. var _isVisible = _interopRequireDefault(require("./isVisible"));
  13. function focusable(node) {
  14. var includePositive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
  15. if ((0, _isVisible.default)(node)) {
  16. var nodeName = node.nodeName.toLowerCase();
  17. var isFocusableElement =
  18. // Focusable element
  19. ['input', 'select', 'textarea', 'button'].includes(nodeName) ||
  20. // Editable element
  21. node.isContentEditable ||
  22. // Anchor with href element
  23. nodeName === 'a' && !!node.getAttribute('href');
  24. // Get tabIndex
  25. var tabIndexAttr = node.getAttribute('tabindex');
  26. var tabIndexNum = Number(tabIndexAttr);
  27. // Parse as number if validate
  28. var tabIndex = null;
  29. if (tabIndexAttr && !Number.isNaN(tabIndexNum)) {
  30. tabIndex = tabIndexNum;
  31. } else if (isFocusableElement && tabIndex === null) {
  32. tabIndex = 0;
  33. }
  34. // Block focusable if disabled
  35. if (isFocusableElement && node.disabled) {
  36. tabIndex = null;
  37. }
  38. return tabIndex !== null && (tabIndex >= 0 || includePositive && tabIndex < 0);
  39. }
  40. return false;
  41. }
  42. function getFocusNodeList(node) {
  43. var includePositive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
  44. var res = (0, _toConsumableArray2.default)(node.querySelectorAll('*')).filter(function (child) {
  45. return focusable(child, includePositive);
  46. });
  47. if (focusable(node, includePositive)) {
  48. res.unshift(node);
  49. }
  50. return res;
  51. }
  52. var lastFocusElement = null;
  53. /** @deprecated Do not use since this may failed when used in async */
  54. function saveLastFocusNode() {
  55. lastFocusElement = document.activeElement;
  56. }
  57. /** @deprecated Do not use since this may failed when used in async */
  58. function clearLastFocusNode() {
  59. lastFocusElement = null;
  60. }
  61. /** @deprecated Do not use since this may failed when used in async */
  62. function backLastFocusNode() {
  63. if (lastFocusElement) {
  64. try {
  65. // 元素可能已经被移动了
  66. lastFocusElement.focus();
  67. /* eslint-disable no-empty */
  68. } catch (e) {
  69. // empty
  70. }
  71. /* eslint-enable no-empty */
  72. }
  73. }
  74. function limitTabRange(node, e) {
  75. if (e.keyCode === 9) {
  76. var tabNodeList = getFocusNodeList(node);
  77. var lastTabNode = tabNodeList[e.shiftKey ? 0 : tabNodeList.length - 1];
  78. var leavingTab = lastTabNode === document.activeElement || node === document.activeElement;
  79. if (leavingTab) {
  80. var target = tabNodeList[e.shiftKey ? tabNodeList.length - 1 : 0];
  81. target.focus();
  82. e.preventDefault();
  83. }
  84. }
  85. }