vjudge++

为vJudge设置背景,并汉化部分界面

当前为 2023-08-17 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name vjudge++
  3. // @namespace vjudge-plus-v2
  4. // @version 1.8.4b4
  5. // @description 为vJudge设置背景,并汉化部分界面
  6. // @author axototl (original by Suntra)
  7. // @match https://vjudge.net/*
  8. // @noframes
  9. // @icon https://vjudge.net/favicon.ico
  10. // @license AGPLv3 or later
  11. // @grant GM_addStyle
  12. // @grant GM_registerMenuCommand
  13. // @grant GM_getValue
  14. // @grant GM_setValue
  15. // @run-at document-end
  16. // ==/UserScript==
  17.  
  18. // license text: https://www.gnu.org/licenses/agpl-3.0.txt
  19.  
  20. let config = {experimental: false, debug: false};
  21.  
  22. function dbgopt(...txt) {
  23. if(config.debug) console.debug(txt);
  24. }
  25.  
  26. function getVal(key, def) {
  27. let gg = GM_getValue(key);
  28. if (gg === '' || gg === undefined) {
  29. GM_setValue(key, def);
  30. gg = def;
  31. }
  32. return gg;
  33. }
  34.  
  35. function reloader() {
  36. if (!navigator.onLine) {
  37. alert("离线状态,无法重加载。\n修改无法即刻生效");
  38. return;
  39. }
  40. alert("设置成功,刷新生效");
  41. location.reload();
  42. }
  43.  
  44. const loginBoxTranslate = {
  45. "#loginModalLabel": "登录(不可用)",
  46. "#btn-forget-password": "忘记密码",
  47. "#btn-login": "登录(不可用)"
  48. };
  49.  
  50. const registerBoxTrans = {
  51. "#registerModalLabel": "注册(不可用)",
  52. "[for=register-username]": "用户名\n(必填)",
  53. "[for=register-password]": "密码\n(必填)",
  54. "[for=register-repeat-password]": "重复密码\n(必填)",
  55. "[for=register-nickname]": "昵称\n(可修改)",
  56. "[for=register-school]": "学校",
  57. "[for=register-email]": "邮箱\n(必填)",
  58. "[for=register-introduction]": "自我介绍",
  59. "[for=register-captcha]": "验证码\n(必填)",
  60. "#btn-register": "注册(不可用)",
  61. };
  62.  
  63. const translateTable = {
  64. "#nav-problem > a": "问题列表",
  65. "#nav-status > a": "提交记录",
  66. "#nav-contest > a": "比赛",
  67. "#nav-workbook > a": "题单",
  68. "#nav-user > a": "用户",
  69. "#nav-group > a": "小组",
  70. "#nav-comment > a": "留言板",
  71. ".navbar-brand": "vJudge",
  72. ".login": "登录(不可用)",
  73. ".register": "注册(不可用)",
  74. ".logout": "登出",
  75. ".user-dropdown > a:nth-child(1)": "个人主页",
  76. ".update-profile": "更新个人信息",
  77. ".message": "消息"
  78. };
  79.  
  80. const updateProfileTrans = {
  81. "#updateModalLabel": "更新个人信息",
  82. "[for=update-username]": "用户名",
  83. "[for=update-orig-password]": "原密码(必填)",
  84. "[for=update-password]": "新密码\n(可选)",
  85. "[for=update-repeat-password]": "重复新密码",
  86. "[for=update-nickname]": "昵称",
  87. "[for=update-school]": "学校",
  88. "[for=update-captcha]": "验证码",
  89. "[for=update-email]": "邮箱",
  90. "[for=update-introduction]": "个人简介",
  91. "#btn-update-profile": "更新"
  92. }
  93.  
  94. function upd_trans(tr) {
  95. if (!config.experimental) return;
  96. for (let prop in tr) {
  97. let k = document.querySelector(prop);
  98. if(null != k) k.innerText = tr[prop];
  99. else dbgopt(prop, "is null");
  100. }
  101. }
  102.  
  103. const commonBoxTrans = {
  104. ".btn[data-dismiss]": "取消"
  105. }
  106.  
  107. function reg_box_trans(triggerElem_selector, table) {
  108. if (!config.experimental) return;
  109. let s = document.querySelector(triggerElem_selector);
  110. if (null != s) s.addEventListener("click", () => setTimeout(() => {upd_trans(table); upd_trans(commonBoxTrans);}, 100));
  111. else dbgopt(triggerElem_selector, "is null");
  112. }
  113.  
  114. (async () => {
  115. config.experimental = getVal("experimental", false);
  116. debug = getVal("debug", true);
  117. upd_trans(translateTable);
  118.  
  119. function reg_command(name, prompts, need_reload = true) {
  120. let flag = true;
  121. GM_registerMenuCommand(prompts[config[name] | 0], () => {
  122. if(flag) {
  123. config[name] = !config[name];
  124. GM_setValue(name, config[name]);
  125. flag = false;
  126. }
  127. if (need_reload) reloader();
  128. })
  129. }
  130. // 设置实验性功能
  131. reg_command("experimental", ["× 点击启用实验性功能(界面汉化等)", "✔ 点击关闭实验性功能"]);
  132. // 设置debug
  133. reg_command("debug", ["已禁用 debug 输出", "已启用debug输出"], false);
  134. // 在基于 Blink 浏览器上检测是否为正常返回
  135. if (navigator.userAgent.includes("Chrome") && performance.getEntries()[0].responseStatus != 200) return;
  136.  
  137. // 设置背景
  138. let back = getVal("background", "https://cdn.luogu.com.cn/images/bg/fe/Day_And_Night_1.jpg");
  139. GM_registerMenuCommand("设置背景URL", () => {
  140. back = window.prompt("请输入背景URL", back);
  141. GM_setValue("background", back);
  142. reloader();
  143. });
  144.  
  145. // 设置文字颜色
  146. let col = getVal("col", "#b93e3e");
  147. const tes = /^#([0-9a-f]{3,4}|[0-9a-f]{6})$/i;
  148. function getColor(t) {
  149. do {
  150. tmp = window.prompt("请输入颜色的Hexcode\n(比如#b93e3e)\n建议选择背景主色调的反差色", t);
  151. } while (!tes.test(t));
  152. return t;
  153. }
  154. GM_registerMenuCommand("设置文字颜色", () => {
  155. GM_setValue("col", getColor(col));
  156. reloader();
  157. });
  158. let collink = getVal("collink", "#ff4c8c");
  159. GM_registerMenuCommand("设置链接背景颜色", () => {
  160. GM_setValue("collink", getColor(collink));
  161. reloader();
  162. });
  163. document.body.innerHTML = "<div style='height: 60px'></div>" + document.body.innerHTML; // 防止顶栏和页面内容重叠
  164. // User defined style
  165. GM_addStyle("body {background: url("+back+") no-repeat center top fixed;background-size: 100% 100%;-moz-background-size: 100% 100%;color: "+col+";}"+
  166. "a:focus, a:hover {color: "+collink+";text-decoration: underline;}");
  167. // Global Style
  168. GM_addStyle(
  169. ".navbar {border-radius:0rem;background-color: rgba(0,0,0,65%) !important;position: fixed;top: 0;left: 0;z-index: 1000;width: 100%;}"+
  170. "scrollbar-width: none"+
  171. "#prob-ads {display: none;}"+ // 屏蔽广告
  172. "#img-support {display: none;}"+ // 屏蔽 sponsor 栏广告
  173. ".card-block, .card, .list-group-item, .btn-secondary, .page-link, .page-item.disabled .page-link, .dropdown-menu {background-color: rgba(255,255,255,65%)!important;}"+
  174. ".modal-content {background-color: rgba(255,255,255,90%);}"+
  175. ".form-control {background-color: rgba(255,255,255,50%);}"+
  176. ".tab-content {background-color: rgba(255,255,255,50%);border: 2px solid #eceeef;border-radius: 0.25rem;padding: 20px;}"+
  177. "table {background-color: rgba(255,255,255,70%);border-radius: 0.25rem;}"
  178. );
  179.  
  180. reg_box_trans(".login", loginBoxTranslate);
  181. reg_box_trans(".register", registerBoxTrans);
  182. reg_box_trans(".update-profile", updateProfileTrans);
  183. document.querySelector("body > div.body-footer").innerHTML += '<p style="color: #3fb98b">Theme powered by vjudge++ (original by <a href="https://gf.qytechs.cn/scripts/448801">vjudge+</a>)</p>';
  184. })();

QingJ © 2025

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