code-plus

解放鼠标,学码快人一步! 代码随想录网站辅助工具, 支持快速跳转到指定语言类型, 跳转到leetcode对应题目, 首次打开跳转到上次位置,切换前后文章

当前为 2023-09-19 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name code-plus
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.2
  5. // @description 解放鼠标,学码快人一步! 代码随想录网站辅助工具, 支持快速跳转到指定语言类型, 跳转到leetcode对应题目, 首次打开跳转到上次位置,切换前后文章
  6. // @author righthan
  7. // @license MIT
  8. // @match https://*.programmercarl.com/*
  9. // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
  10. // @grant none
  11. // ==/UserScript==
  12.  
  13. (function () {
  14. 'use strict';
  15.  
  16. let lastKeyPressTime = 0; // 用于存储上一次按键的时间戳
  17.  
  18. let page = document.querySelector('.page')
  19. let sider = document.querySelector('.page-sidebar')
  20. let siderLinks = document.querySelector('.sidebar-links')
  21. let isDoubleKeyG = false; // 标识是否是第一次按G键
  22.  
  23.  
  24. // 跳转到上次浏览的网页
  25. let historyPath = getCookie('history')
  26. if (historyPath && encodeURI(historyPath) !== location.href) {
  27. toPath(historyPath)
  28. } else {
  29. setCookie('history', location.href)
  30. }
  31.  
  32. // 给导航容器列表添加监听器,检测网址变化
  33. siderLinks.addEventListener('click', (e) => { setCookie('history', e.target.href) })
  34.  
  35. // 如果cookie中没有语言, 则需要设置
  36. let lang = getCookie('lang')
  37. if (!lang) {
  38. setCodeLanguage();
  39. }
  40.  
  41. document.addEventListener("keyup", function (event) {
  42. // 检测是否快速连按了g开头的组合键
  43. const key = event.key
  44. if (key === 'g') {
  45. let currentTime = new Date().getTime(); // 更新第一次按g键的时间戳
  46. if (currentTime - lastKeyPressTime < 300) {
  47. isDoubleKeyG = true
  48. } else {
  49. isDoubleKeyG = false
  50. }
  51. lastKeyPressTime = currentTime
  52. }
  53.  
  54. let currentTime = new Date().getTime(); // 获取当前时间戳
  55. let time = currentTime - lastKeyPressTime
  56. if (time < 400) { // 如果两次按键的时间间隔小于400毫秒,认为是快速连按
  57. switch (key) {
  58. case 'g':
  59. lang = getCookie('lang')
  60. if (isDoubleKeyG && lang) {
  61. toCode(lang)
  62. isDoubleKeyG = false
  63. } else if (isDoubleKeyG && !lang) {
  64. setCodeLanguage()
  65. }
  66. break
  67. case 'k':
  68. // 跳转到上一篇文章
  69. changeArticle(0)
  70. break
  71. case 'j':
  72. // 跳转到下一篇文章
  73. changeArticle(1)
  74. break
  75. case 'l':
  76. toLeetCode()
  77. break
  78. case 'c':
  79. setCodeLanguage()
  80. break
  81. case 'h':
  82. alert(`
  83. code-plus是一款网页操作快捷辅助工具
  84. 按键及功能如下:
  85. gg: 跳转到指定语言代码
  86. gj: 跳转到下一篇
  87. gk: 跳转到上一篇
  88. gl: 跳转到leetcode页面
  89. gc: 设置代码语言(保存在网站的cookie中)
  90. gh: 显示本帮助页面
  91. 其他功能: 打开网页时恢复上次的进度
  92. `)
  93. break
  94. }
  95. }
  96. });
  97. // 跳转到指定语言的算法代码
  98. function toCode(langType) {
  99. // 获取对要滚动到的元素的引用
  100. let targetElement = page.querySelector('#' + langType);
  101. if (targetElement) { // 确保找到了元素
  102. // 使用scrollIntoView()方法将元素滚动到可见区域
  103. targetElement.scrollIntoView({
  104. behavior: "smooth", // 可选:使滚动平滑进行
  105. block: "start", // 可选:滚动到元素的顶部
  106. });
  107. } else {
  108. alert((langType !== 'c-2' ? langType : 'c#') + '语言的代码在此页面中不存在')
  109. }
  110. }
  111. // 文章跳转 flag:1表示下跳转到下一篇文章, 0表示上一篇文章
  112. function changeArticle(flag) {
  113. let optionButton = sider.querySelectorAll('div[title]')
  114. let path = optionButton[flag].childNodes[0].href
  115. toPath(decodeURI(path))
  116. }
  117.  
  118. // 跳转到leetcode刷题网站
  119. function toLeetCode() {
  120. let link = page.querySelector('a[href*="leetcode"] ')
  121. if (link && link.href.includes('leetcode')) {
  122. link.click()
  123. } else {
  124. alert("当前页面可能没有LeetCode题目")
  125. }
  126. }
  127. // 设置代码语言
  128. function setCodeLanguage() {
  129. const supportLang = ['java', 'python', 'go', 'rust', 'javascript', 'typescript', 'swift', 'ruby', 'c', 'php', 'kotlin', 'scala', 'c#']
  130. let userInput = window.prompt("可能支持的语言:\n(一些语言代码不是每题都有, c++代码在靠前的位置, 不需要配置)\n" + supportLang.join('/') + "\n请输入需要快速跳转到的目标语言")
  131.  
  132. if (userInput !== null) {
  133. if (supportLang.includes(userInput)) {
  134. // c#的id为c-2
  135. if (userInput === 'c#') { userInput = 'c-2' }
  136. setCookie('lang', userInput)
  137. } else {
  138. alert(userInput + "的语言类型似乎没有对应的代码, 请检查拼写, 并重新输入")
  139. }
  140. }
  141. }
  142. // 跳转对对应路径的页面
  143. function toPath(path) {
  144. setCookie('history', path)
  145. const paths = path.split('/')
  146. // 获取 .html之前的路径名
  147. const subPath = paths[paths.length - 1].split('.html')[0]
  148. clickAndScrollNavLink(subPath)
  149. }
  150. // 点击对应链接, 并且滚动侧边导航
  151. function clickAndScrollNavLink(path) {
  152. let targetElement = siderLinks.querySelector(`a[href*="${path}"]`)
  153. if (targetElement) { // 确保找到了元素
  154. targetElement.click()
  155. // 使用scrollIntoView() // 方法将元素滚动到可见区域
  156. targetElement.scrollIntoView({
  157. block: "start", // 可选:滚动到元素的顶部
  158. });
  159. document.querySelector('.sidebar').scrollBy({ top: -300 })
  160. }
  161. }
  162. // 解析特定的cookie值
  163. function getCookie(cookieName) {
  164. const allCookies = document.cookie;
  165. let name = cookieName + "=";
  166. let decodedCookie = decodeURIComponent(allCookies);
  167. let cookieArray = decodedCookie.split(';');
  168. for (let i = 0; i < cookieArray.length; i++) {
  169. let cookie = cookieArray[i];
  170. while (cookie.charAt(0) === ' ') {
  171. cookie = cookie.substring(1);
  172. }
  173. if (cookie.indexOf(name) === 0) {
  174. return cookie.substring(name.length, cookie.length);
  175. }
  176. }
  177. return "";
  178. }
  179. function setCookie(key, val) {
  180. document.cookie = `${key}=${val}; expires=Fri, 31 Dec 9999 23:59:59 GMT`
  181. }
  182. })();

QingJ © 2025

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