LeetCode - 加回提交代碼快捷鍵(Ctrl/Cmd + Enter)

參考:https://leetcode.com/discuss/general-discussion/136588/Is-there-any-keyboard-shortcut-to-run-code-and-submit-solution/346347

  1. // ==UserScript==
  2. // @name LeetCode - Bring back Submit Code shortcut (Ctrl/Cmd + Enter)
  3. // @name:zh-CN LeetCode - 加回提交代码快捷键(Ctrl/Cmd + Enter)
  4. // @name:zh-HK LeetCode - 加回提交代碼快捷鍵(Ctrl/Cmd + Enter)
  5. // @name:zh-TW LeetCode - 加回提交代碼快捷鍵(Ctrl/Cmd + Enter)
  6. // @description See: https://leetcode.com/discuss/general-discussion/136588/Is-there-any-keyboard-shortcut-to-run-code-and-submit-solution/346347
  7. // @description:zh-CN 参考:https://leetcode.com/discuss/general-discussion/136588/Is-there-any-keyboard-shortcut-to-run-code-and-submit-solution/346347
  8. // @description:zh-HK 參考:https://leetcode.com/discuss/general-discussion/136588/Is-there-any-keyboard-shortcut-to-run-code-and-submit-solution/346347
  9. // @description:zh-TW 參考:https://leetcode.com/discuss/general-discussion/136588/Is-there-any-keyboard-shortcut-to-run-code-and-submit-solution/346347
  10. // @namespace RainSlide
  11. // @author RainSlide
  12. // @icon https://assets.leetcode.com/static_assets/public/icons/favicon-192x192.png
  13. // @version 1.0
  14. // @match *://leetcode.com/problems/*
  15. // @grant none
  16. // ==/UserScript==
  17.  
  18. "use strict";
  19.  
  20. const debug = msg => console.debug("[LeetCode - Submit Code shortcut] ".conact(msg));
  21.  
  22. const addShortcut = () => {
  23.  
  24. const codeArea = document.querySelector('div[data-cy="code-area"]');
  25. if (codeArea !== null) {
  26.  
  27. // see: https://developer.mozilla.org/en-US/docs/Web/CSS/%3Ascope
  28. const selectInCodeArea = selector =>
  29. codeArea.querySelector(':scope '.concat(selector));
  30.  
  31. const submitButton = selectInCodeArea('button[data-cy="submit-code-btn"]');
  32. if (submitButton !== null) {
  33.  
  34. // see: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent
  35. document.addEventListener(
  36. "keydown", event => {
  37. if (
  38. event.key === "Enter" && (
  39. event.ctrlKey === true || event.metaKey === true
  40. )
  41. ) {
  42. event.preventDefault();
  43. submitButton.click();
  44. }
  45. }
  46. );
  47.  
  48. const shortcutsButton = selectInCodeArea('button[icon="information"]');
  49. if (shortcutsButton !== null) {
  50.  
  51. const addShortcutEntry = () => {
  52.  
  53. // select div[class^="shortcut__"] which is:
  54. // in a Ant modal titled with "Editor Shortcuts"
  55. /* has div[class^="shortcut-description__"] and
  56. div[class^="shortcut-keystrokes__"] as 1st & 2nd child */
  57.  
  58. // see: https://devhints.io/xpath
  59. const result = new XPathEvaluator().createExpression(
  60. `//div[@class="ant-modal-content"][
  61. ./div[@class="ant-modal-header"]
  62. //span[text()="Editor Shortcuts"]
  63. ]/div[@class="ant-modal-body"]
  64. //div[starts-with(@class,"shortcut__")][
  65. ./div[1][starts-with(@class,"shortcut-description__")] and
  66. ./div[2][starts-with(@class,"shortcut-keystrokes__")]
  67. ]` // .replace(/\n\s+/g, "")
  68. ).evaluate(
  69. document.body, XPathResult.FIRST_ORDERED_NODE_TYPE
  70. );
  71.  
  72. /* <div class="shortcut__1GGr">
  73. <div class="shortcut-description__23fr">Run code</div>
  74. <div class="shortcut-keystrokes__3HcT">CTRL + '</div>
  75. </div> */
  76.  
  77. const shortcut = result.singleNodeValue;
  78. if (shortcut !== null) {
  79. const submitShortcut = shortcut.cloneNode(true);
  80. submitShortcut.children[0].textContent = "Submit Code";
  81. submitShortcut.children[1].textContent = "Ctrl + Enter";
  82. shortcut.parentNode.insertBefore(submitShortcut, shortcut);
  83. } else debug("shortcut not found");
  84.  
  85. };
  86.  
  87. // use setTimeout(func, 0) to delay the exec of func
  88. // see:
  89. // https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals#settimeout
  90. // https://stackoverflow.com/questions/779379
  91. // https://stackoverflow.com/questions/33955650
  92. shortcutsButton.addEventListener(
  93. "click", () => setTimeout(addShortcutEntry, 0), { once: true }
  94. );
  95.  
  96. } else debug("shortcutsButton not found");
  97. } else debug("submitButton not found, won't add shortcut");
  98. } else debug("codeArea not found, won't add shortcut");
  99.  
  100. };
  101.  
  102. const loading = document.querySelector("body > #initial-loading");
  103. if (loading !== null) {
  104.  
  105. // run addShortcut() when #initial-loading is removed
  106. // see:
  107. // https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
  108. // https://developer.mozilla.org/en-US/docs/Web/API/MutationObserverInit
  109. new MutationObserver(
  110. (mutationList, observer) => mutationList.forEach(
  111. mutation => {
  112. if ( Array.from(mutation.removedNodes).includes(loading) ) {
  113. addShortcut();
  114. observer.disconnect();
  115. }
  116. /* const nodes = mutation.removedNodes;
  117. if (nodes instanceof NodeList && nodes.length > 0) {
  118. for (const node of nodes) {
  119. if (node.id === "initial-loading") {
  120. addShortcut();
  121. observer.disconnect();
  122. break;
  123. }
  124. }
  125. } */
  126. }
  127. )
  128. ).observe(
  129. document.body, { childList: true }
  130. );
  131.  
  132. } else {
  133. debug("loading not found");
  134. addShortcut();
  135. }