Focus input text field on Esc

Focus the first visible input text field when you press Esc key, or restore the previously focused element on second press

  1. // ==UserScript==
  2. // @name Focus input text field on Esc
  3. // @description Focus the first visible input text field when you press Esc key, or restore the previously focused element on second press
  4. // @version 1.0.11
  5. // @include *
  6. // @author wOxxOm
  7. // @namespace wOxxOm.scripts
  8. // @license MIT License
  9. // @run-at document-start
  10. // @grant none
  11. // ==/UserScript==
  12.  
  13. var TEXT_FIELD = ' search text number url textarea ';
  14. var previousElement;
  15. var scrollPos;
  16. var first;
  17.  
  18. window.addEventListener('keydown', function (e) {
  19. if (e.defaultPrevented || e.which !== 27 || e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) {
  20. return;
  21. }
  22. if (window !== top) {
  23. rememberFocus();
  24. window.addEventListener('message', maybeRestoreFocus);
  25. top.postMessage(GM_info.script.name, '*');
  26. e.preventDefault();
  27. e.stopPropagation();
  28. return;
  29. }
  30. run();
  31. }, true);
  32.  
  33. if (window === top) {
  34. window.addEventListener('message', function (e) {
  35. if (e.data === GM_info.script.name) {
  36. run({relayedFromFrame: true});
  37. }
  38. });
  39. }
  40.  
  41. function run(params) {
  42. // find text inputs inside visible DOM containers
  43. var inputs = [];
  44. populateInputs(inputs);
  45. for (var i = 0, input, il = inputs.length; i < il && (input = inputs[i]); i++) {
  46. var priority = TEXT_FIELD.indexOf(' ' + input.type + ' ');
  47. if (priority < 0) continue;
  48. var n = input, style;
  49. while (n && n.style && (style = getComputedStyle(n)) && style.display !== 'none' && style.visibility !== 'hidden') {
  50. n = n.parentNode;
  51. }
  52. // visible if reached DOM root
  53. if (n && n.style) continue;
  54. // set the first OR if it's empty, try to select an identically named input field with some text (happens on some sites)
  55. if (!first || (
  56. input.value &&
  57. input.name === first.name && (
  58. !input.form && !first.form ||
  59. input.form && first.form && input.form.action === first.form.action
  60. )
  61. )) {
  62. first = input;
  63. if (first.value) break;
  64. }
  65. }
  66.  
  67. if (!first) return;
  68.  
  69. var invoke = params && params.relayedFromFrame ? passthru : onkeyup;
  70.  
  71. if (first !== getActiveElement()) {
  72. rememberFocus();
  73. invoke(setFocus);
  74. } else if (previousElement) {
  75. invoke(restoreFocus);
  76. if (previousElement && previousElement.localName === 'iframe') {
  77. previousElement.contentWindow.postMessage(GM_info.script.name, '*');
  78. }
  79. }
  80. }
  81.  
  82. function populateInputs(inputs, root) {
  83. var walker = document.createTreeWalker(root || document, NodeFilter.SHOW_ELEMENT);
  84. var el;
  85. while ((el = walker.nextNode())) {
  86. if (el.shadowRoot)
  87. populateInputs(inputs, el.shadowRoot);
  88. if (/^(input|textarea)$/.test(el.localName))
  89. inputs.push(el);
  90. }
  91. }
  92.  
  93. function getActiveElement() {
  94. var el = document.activeElement;
  95. while (el) {
  96. if (!el.shadowRoot)
  97. return el;
  98. el = el.shadowRoot.activeElement;
  99. }
  100. }
  101.  
  102. function rememberFocus() {
  103. previousElement = document.activeElement;
  104. scrollPos = [scrollX, scrollY];
  105. }
  106.  
  107. function setFocus() {
  108. first.focus();
  109. }
  110.  
  111. function restoreFocus() {
  112. // in case document.body (page "background") was previously selected
  113. document.activeElement.blur();
  114. previousElement.focus();
  115. scrollTo(scrollPos[0], scrollPos[1]);
  116. }
  117.  
  118. function maybeRestoreFocus(e) {
  119. if (e.data === GM_info.script.name) {
  120. restoreFocus();
  121. }
  122. }
  123.  
  124. // focusing should be done at key-up to prevent the Esc-keydown being also chain-handled by the just focused element
  125. function onkeyup(cb) {
  126. window.addEventListener('keyup', function keyup(e) {
  127. if (e.which !== 27) return;
  128. window.removeEventListener('keyup', keyup);
  129. if (e.defaultPrevented) return;
  130. cb(e);
  131. });
  132. }
  133.  
  134. function passthru(fn) {
  135. return fn.apply(this, arguments);
  136. }

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址