Greasy Fork is available in English.

LeetCode Assistant

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

Από την 11/09/2021. Δείτε την τελευταία έκδοση.

  1. // ==UserScript==
  2. // @name LeetCode Assistant
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.0.1
  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. // @match https://leetcode-cn.com/problems/*
  10. // @match https://leetcode-cn.com/problemset/all/
  11. // @grant GM_setValue
  12. // @grant GM_getValue
  13. // ==/UserScript==
  14.  
  15. (function() {
  16. var executing = false;
  17. const bm = new BubbleMessage();
  18. const config = {
  19. recommendVisible: false,
  20. };
  21.  
  22. // 通用
  23. function updateData(obj) {
  24. var data = GM_getValue('data');
  25. if (!obj) {
  26. // 初始化调用
  27. if (!data) {
  28. // 未初始化
  29. data = {};
  30. Object.assign(data, config);
  31. GM_setValue('data', data);
  32. } else {
  33. // 已初始化
  34. Object.assign(config, data);
  35. }
  36. } else {
  37. // 更新调用
  38. Object.assign(config, obj);
  39. Object.assign(data, config);
  40. GM_setValue('data', data);
  41. }
  42. }
  43.  
  44. function insertTextarea() {
  45. let textarea = document.createElement('textarea');
  46. textarea.setAttribute('id', 'leetcode-assistant-textarea');
  47. document.body.appendChild(textarea);
  48. }
  49.  
  50. function executeCopy(value) {
  51. let textarea = document.getElementById('leetcode-assistant-textarea');
  52. textarea.value = value;
  53. textarea.setAttribute('value', value);
  54. textarea.select();
  55. document.execCommand('copy');
  56. bm.message({
  57. type: 'success',
  58. message: '复制成功',
  59. duration: 1500,
  60. });
  61. }
  62.  
  63. function switchVisible(nodes, visible) {
  64. if (visible) {
  65. nodes.forEach(node => node.style.display = '');
  66. } else {
  67. nodes.forEach(node => node.style.display = 'none');
  68. }
  69. }
  70.  
  71. function observeChildList(node, callback) {
  72. let observer = new MutationObserver(function(mutations) {
  73. mutations.forEach((mutation) => {
  74. if (mutation.type == 'childList' && mutation.addedNodes.length > 0) {
  75. callback([...mutation.addedNodes]);
  76. }
  77. });
  78. });
  79. observer.observe(node, { childList: true });
  80. }
  81.  
  82. function listenHistoryState() {
  83. const _historyWrap = function(type) {
  84. const orig = history[type];
  85. const e = new Event(type);
  86. return function() {
  87. const rv = orig.apply(this, arguments);
  88. e.arguments = arguments;
  89. window.dispatchEvent(e);
  90. return rv;
  91. };
  92. };
  93. history.pushState = _historyWrap('pushState');
  94. window.addEventListener('pushState', () => {
  95. if (!executing) {
  96. executing = true;
  97. main();
  98. }
  99. });
  100. }
  101.  
  102. // 提交记录页
  103. function requestCode(qid) {
  104. let query = `
  105. query mySubmissionDetail($id: ID!) {
  106. submissionDetail(submissionId: $id) {
  107. id
  108. code
  109. runtime
  110. memory
  111. rawMemory
  112. statusDisplay
  113. timestamp
  114. lang
  115. passedTestCaseCnt
  116. totalTestCaseCnt
  117. sourceUrl
  118. question {
  119. titleSlug
  120. title
  121. translatedTitle
  122. questionId
  123. __typename
  124. }
  125. ... on GeneralSubmissionNode {
  126. outputDetail {
  127. codeOutput
  128. expectedOutput
  129. input
  130. compileError
  131. runtimeError
  132. lastTestcase
  133. __typename
  134. }
  135. __typename
  136. }
  137. submissionComment {
  138. comment
  139. flagType
  140. __typename
  141. }
  142. __typename
  143. }
  144. }`;
  145. $.ajax({
  146. url: 'https://leetcode-cn.com/graphql/',
  147. method: 'POST',
  148. contentType: 'application/json',
  149. data: JSON.stringify({
  150. operationName: 'mySubmissionDetail',
  151. query: query,
  152. variables: {
  153. id: qid
  154. },
  155. }),
  156. }).then(res => {
  157. executeCopy(res.data.submissionDetail.code);
  158. });
  159. }
  160.  
  161. function insertCopyFunction() {
  162. let tbody = document.querySelector('.ant-table-tbody');
  163. let trs = [...tbody.querySelectorAll('tr')];
  164. let processTr = (tr) => {
  165. let qid = tr.dataset.rowKey;
  166. let cell = tr.querySelector(':nth-child(4)');
  167. cell.title = '点击复制代码'
  168. cell.style = 'cursor: pointer; color: #007aff';
  169. cell.addEventListener('click', function() {
  170. requestCode(qid);
  171. });
  172. }
  173. trs.forEach(processTr);
  174. observeChildList(tbody, (nodes) => {
  175. let node = nodes[0];
  176. if (node.tagName == 'TR')
  177. processTr(node);
  178. });
  179. executing = false;
  180. }
  181.  
  182. // 首页
  183. function switchRecommendVisible() {
  184. var nodes = [];
  185. var target = document.querySelector('.border-divider-border-2');
  186. while (target) {
  187. nodes.push(target);
  188. target = target.previousElementSibling;
  189. }
  190. var sidebar = document.querySelector('.col-span-4:nth-child(2)');
  191. target = sidebar.querySelector('.space-y-4:nth-child(2)');
  192. while (target) {
  193. nodes.push(target);
  194. target = target.nextElementSibling;
  195. }
  196. switchVisible(nodes, config.recommendVisible);
  197. observeChildList(sidebar, (nodes) => {
  198. switchVisible(nodes, config.recommendVisible);
  199. });
  200. }
  201. function insertVisibleSwitch() {
  202. var insertDiv = document.querySelector('.relative.space-x-5').nextElementSibling;
  203. insertDiv.style = 'display: inline-flex; align-items: center;';
  204. var switchCheckbox = document.createElement('input');
  205. switchCheckbox.type = 'checkbox';
  206. switchCheckbox.checked = true;
  207. switchCheckbox.setAttribute('id', 'leetcode-assistant-recommend-switch');
  208. switchCheckbox.addEventListener('change', function() {
  209. updateData({ recommendVisible: !this.checked });
  210. switchRecommendVisible();
  211. });
  212. var switchLabel = document.createElement('label');
  213. switchLabel.setAttribute('for', 'leetcode-assistant-recommend-switch');
  214. switchLabel.innerText = '简洁模式';
  215. switchLabel.style.marginLeft = '5px';
  216. insertDiv.appendChild(switchCheckbox);
  217. insertDiv.appendChild(switchLabel);
  218. }
  219.  
  220. // 主函数
  221. function main() {
  222. if (location.href.match(/\/submissions\/$/)) {
  223. (function r() {
  224. if (document.querySelector('.ant-table-thead')) {
  225. insertCopyFunction();
  226. } else {
  227. setTimeout(r, 500);
  228. }
  229. })();
  230. } else if (location.href == 'https://leetcode-cn.com/problemset/all/') {
  231. insertVisibleSwitch();
  232. switchRecommendVisible();
  233. } else {
  234. executing = false;
  235. }
  236. }
  237.  
  238. window.addEventListener('load', () => {
  239. updateData();
  240. insertTextarea();
  241. listenHistoryState();
  242. main();
  243. });
  244. })();