LeetCode Assistant

【使用前先看介绍/有问题可反馈】力扣助手 (LeetCode Assistant):为力扣页面增加辅助功能。

As of 2021-09-10. See the latest version.

  1. // ==UserScript==
  2. // @name LeetCode Assistant
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.0.0
  5. // @description 【使用前先看介绍/有问题可反馈】力扣助手 (LeetCode Assistant):为力扣页面增加辅助功能。
  6. // @author cc
  7. // @require https://cdn.bootcss.com/jquery/3.4.1/jquery.js
  8. // @require https://greatest.deepsurf.us/scripts/422854-bubble-message.js
  9. // @include https://leetcode-cn.com/problems/*
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. const bm = new BubbleMessage();
  14. var executing = false;
  15.  
  16. function insertTextarea() {
  17. let textarea = document.createElement('textarea');
  18. textarea.setAttribute('id', 'leetcode-assistant-textarea');
  19. document.body.appendChild(textarea);
  20. }
  21.  
  22. function executeCopy(value) {
  23. let textarea = document.getElementById('leetcode-assistant-textarea');
  24. textarea.value = value;
  25. textarea.setAttribute('value', value);
  26. textarea.select();
  27. document.execCommand('copy');
  28. bm.message({
  29. type: 'success',
  30. message: '复制成功',
  31. duration: 1500,
  32. });
  33. }
  34.  
  35. function requestCode(qid) {
  36. let query = `
  37. query mySubmissionDetail($id: ID!) {
  38. submissionDetail(submissionId: $id) {
  39. id
  40. code
  41. runtime
  42. memory
  43. rawMemory
  44. statusDisplay
  45. timestamp
  46. lang
  47. passedTestCaseCnt
  48. totalTestCaseCnt
  49. sourceUrl
  50. question {
  51. titleSlug
  52. title
  53. translatedTitle
  54. questionId
  55. __typename
  56. }
  57. ... on GeneralSubmissionNode {
  58. outputDetail {
  59. codeOutput
  60. expectedOutput
  61. input
  62. compileError
  63. runtimeError
  64. lastTestcase
  65. __typename
  66. }
  67. __typename
  68. }
  69. submissionComment {
  70. comment
  71. flagType
  72. __typename
  73. }
  74. __typename
  75. }
  76. }`;
  77. $.ajax({
  78. url: 'https://leetcode-cn.com/graphql/',
  79. method: 'POST',
  80. contentType: 'application/json',
  81. data: JSON.stringify({
  82. operationName: 'mySubmissionDetail',
  83. query: query,
  84. variables: {
  85. id: qid
  86. },
  87. }),
  88. }).then(res => {
  89. executeCopy(res.data.submissionDetail.code);
  90. });
  91. }
  92.  
  93. function insertCopyFunction() {
  94. let tbody = document.querySelector('.ant-table-tbody');
  95. let trs = [...tbody.querySelectorAll('tr')];
  96. let processTr = (tr) => {
  97. let qid = tr.dataset.rowKey;
  98. let cell = tr.querySelector(':nth-child(4)');
  99. cell.title = '点击复制代码'
  100. cell.style = 'cursor: pointer; color: #007aff';
  101. cell.addEventListener('click', function() {
  102. requestCode(qid);
  103. });
  104. }
  105. trs.forEach(processTr);
  106. let observer = new MutationObserver(function(mutations) {
  107. console.log(mutations);
  108. mutations.forEach((mutation) => {
  109. if (mutation.type == 'childList' && mutation.addedNodes.length == 1) {
  110. let tr = mutation.addedNodes[0];
  111. if (tr.tagName == 'TR')
  112. processTr(tr);
  113. }
  114. });
  115. });
  116. observer.observe(tbody, { childList: true, subtree: true });
  117. executing = false;
  118. }
  119.  
  120. function listenHistoryState() {
  121. const _historyWrap = function(type) {
  122. const orig = history[type];
  123. const e = new Event(type);
  124. return function() {
  125. const rv = orig.apply(this, arguments);
  126. e.arguments = arguments;
  127. window.dispatchEvent(e);
  128. return rv;
  129. };
  130. };
  131. history.pushState = _historyWrap('pushState');
  132. window.addEventListener('pushState', () => {
  133. if (!executing) {
  134. executing = true;
  135. main();
  136. }
  137. });
  138. }
  139.  
  140. function main() {
  141. if (location.href.match(/\/submissions\/$/)) {
  142. (function r() {
  143. if (document.querySelector('.ant-table-thead')) {
  144. insertCopyFunction();
  145. } else {
  146. setTimeout(r, 500);
  147. }
  148. })();
  149. } else {
  150. executing = false;
  151. }
  152. }
  153.  
  154. window.addEventListener('load', () => {
  155. insertTextarea();
  156. listenHistoryState();
  157. main();
  158. });
  159. })();