Greasy Fork is available in English.

LeetCode Assistant

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

2021-09-11 يوللانغان نەشرى. ئەڭ يېڭى نەشرىنى كۆرۈش.

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