- // ==UserScript==
- // @name vjudge++
- // @namespace vjudge-plus-v2
- // @version 1.8.4b12.6
- // @description 为vJudge设置背景,并汉化部分界面
- // @author axototl (original by Suntra)
- // @match https://vjudge.net/*
- // @noframes
- // @icon https://vjudge.net/favicon.ico
- // @license AGPLv3 or later
- // @grant GM_addStyle
- // @grant GM_registerMenuCommand
- // @grant GM_getValue
- // @grant GM_setValue
- // @grant GM_info
- // @run-at document-end
- // ==/UserScript==
-
- 'use strict';
-
- // license text: https://www.gnu.org/licenses/agpl-3.0.txt
- (() => {
- // 在基于 Blink 浏览器上检测是否为正常返回
- if (GM_info.platform.browserName == "chrome" && performance.getEntries()[0].responseStatus != 200) return;
-
- let config = {};
-
- function dbgopt(...txt) {
- if (config.debug) console.debug(txt.join(' '));
- }
-
-
- function reloader() {
- alert("设置成功,刷新生效");
- if (!navigator.onLine) {
- alert("离线状态,无法重加载。\n修改无法即刻生效");
- return;
- }
- location.reload();
- }
-
-
- // 初始化Getter / Setter
- (() => {
- const def_props = {
- experimental: false,
- debug: true,
- ads: true,
- enable_style: true,
- back: "https://cdn.luogu.com.cn/images/bg/fe/Day_And_Night_1.jpg",
- col: "#fff",
- collink: "#ff4c8c"
- }
-
- function getVal(key) {
- let gg = GM_getValue(key);
- if ('' === gg || undefined === gg) {
- let def = def_props[key];
- GM_setValue(key, def);
- gg = def;
- }
- return gg;
- }
- for (let prop in def_props) {
- Object.defineProperty(config, prop, {
- get: () => getVal(prop),
- set: val => GM_setValue(prop, val)
- });
- }
- })();
-
-
- // 获取环境配置(不得异步处理) -Begin-
- (() => {
- function reg_command(name, prompts, need_reload = true) {
- let flag = true;
- GM_registerMenuCommand(prompts[config[name] | 0], () => {
- if (flag) {
- config[name] = !config[name];
- flag = false;
- }
- if (need_reload) reloader();
- })
- }
- // 设置实验性功能
- reg_command("experimental", ["× 点击启用实验性功能(界面汉化等)", "✔ 点击关闭实验性功能"]);
- // 设置debug
- reg_command("debug", ["已禁用 debug 输出", "已启用debug输出"], false);
- reg_command("ads", ["× 屏蔽广告(点击启用)", "✔ 屏蔽广告(点击禁用)"]);
- reg_command("enable_style", ["✖ 点击开启美化功能", '✔ 点击关闭美化功能']);
- // 禁用美化功能
- if (!config.enable_style) return;
- // 设置背景
- GM_registerMenuCommand("设置背景URL", () => {
- let tmp = window.prompt("请输入背景URL", config.back);
- if (null === tmp) {
- alert("未更改背景图片URL");
- return;
- }
- config.back = tmp;
- GM_setValue("background", config.back);
- reloader();
- });
-
- // 设置文字颜色
- const tester = /^#([0-9a-f]{3,6})$/i;
-
- function getColor(t) {
- let tmp;
- do {
- tmp = window.prompt("请输入颜色的Hexcode\n(比如#b93e3e)\n建议选择背景主色调的反差色", t);
- } while (null !== tmp && !tester.test(tmp) && '' !== tmp);
- if (null === tmp) tmp = t;
- return tmp;
- }
- GM_registerMenuCommand("设置文字颜色", () => {
- config.col = getColor(config.col);
- reloader();
- });
- GM_registerMenuCommand("设置链接背景颜色", () => {
- config.collink = getColor(config.collink);
- reloader();
- });
- })();
- // 获取环境配置 -End-
-
- // 界面美化程序 -Begin-
- (async () => {
- if (!config.enable_style) return;
- document.body.innerHTML = "<div style='height: 60px'></div>" + document.body.innerHTML; // 防止顶栏和页面内容重叠
- // User defined style
- GM_addStyle("body {background: url(" + config.back + ") no-repeat center top fixed;background-size: 100% 100%;-moz-background-size: 100% 100%;color: " + config.col + ";}" +
- "a:focus, a:hover, .active {&:not(.nav-link){color: " + config.collink + " !important;text-decoration: underline;}}");
- // Global Style
- GM_addStyle(
- ".navbar {border-radius:0rem;background-color: rgba(0,0,0,65%) !important;position: fixed;top: 0;left: 0;z-index: 1000;width: 100%;}" +
- "scrollbar-width: none" +
- ".modal-content {background-color: rgba(255,255,255,90%);}" +
- ".form-control {background-color: rgba(255,255,255,50%);}" +
- ".tab-content {background-color: rgba(255,255,255,50%);border: 2px solid #eceeef;border-radius: 0.25rem;padding: 20px;}" +
- "table {background-color: rgba(255,255,255,70%);border-radius: 0.25rem;color: #000;}"
- );
- GM_addStyle(".card-block, .card, .list-group-item, .btn-secondary, .page-link, .page-item.disabled .page-link, .dropdown-menu {background-color: rgba(255,255,255,0%) !important;}");
- document.querySelector("body > div.body-footer").innerHTML += '<p style="color: #3fb98b">Theme powered by vjudge++ (original <a href="https://greasyfork.org/scripts/448801">vjudge+</a>)</p>';
- })();
- // 界面美化程序 -End-
-
- (async () => {
- if (!config.ads) return;
- let arr = document.querySelectorAll(".social, #prob-ads, #img-support");
- for (let x of arr) x.remove();
- })(); // 广告移除
-
- // 界面汉化程序 -Begin-
- (async () => {
- if (!config.experimental) return;
- console.warn("未来版本将分离JSON文件,请注意");
- const basicTranslateTable = {
- "#nav-problem > a": "问题列表",
- "#nav-status > a": "提交记录",
- "#nav-contest > a": "比赛",
- "#nav-workbook > a": "题单",
- "#nav-user > a": "用户",
- "#nav-group > a": "小组",
- "#nav-comment > a": "留言板",
- ".login": "登录",
- ".register": "注册",
- ".logout": "登出",
- ".user-dropdown > a:nth-child(1)": "个人主页",
- ".update-profile": "更新个人信息",
- ".message": "消息"
- };
-
- const basicDynTransTable = {
- ".previous > a": "上一页",
- ".next > a": "下一页",
- "#filter": "应用过滤器", // 无法工作
- "#reset": "重置过滤器", // 无法工作
- };
- const loginBoxTranslate = {
- "#loginModalLabel": "登录",
- "#btn-forget-password": "忘记密码",
- "#btn-login": "登录",
- ".btn[data-dismiss]": "取消"
- };
-
- const registerBoxTrans = {
- "#registerModalLabel": "注册",
- "[for=register-username]": "用户名\n(必填)",
- "[for=register-password]": "密码\n(必填)",
- "[for=register-repeat-password]": "重复密码\n(必填)",
- "[for=register-nickname]": "昵称\n(可修改)",
- "[for=register-school]": "学校",
- "[for=register-email]": "邮箱\n(必填)",
- "[for=register-introduction]": "自我介绍",
- "[for=register-captcha]": "验证码\n(必填)",
- "#btn-register": "注册",
- ".btn[data-dismiss]": "取消"
- };
-
- const updateProfileTrans = {
- "#updateModalLabel": "更新个人信息",
- "[for=update-username]": "用户名",
- "[for=update-orig-password]": "原密码(必填)",
- "[for=update-password]": "新密码\n(可选)",
- "[for=update-repeat-password]": "重复新密码",
- "[for=update-nickname]": "昵称",
- "[for=update-school]": "学校",
- "[for=update-captcha]": "验证码",
- "[for=update-email]": "邮箱",
- "[for=update-introduction]": "个人简介",
- "#btn-update-profile": "更新",
- ".btn[data-dismiss]": "取消"
- };
-
- function upd_trans(tr, flag = false) {
- for (let prop in tr) {
- let k = document.querySelector(prop);
- if (null != k)
- if (flag && k.childNodes.length >= 1) k.childNodes[0].data = tr[prop];
- else {
- k.innerText = tr[prop];
- }
- else dbgopt(prop, "is null");
- }
- }
-
- function dynamic_trans(table, triggerDOM = null) {
- let ev = "click";
- if (null == triggerDOM)
- ev = "load", triggerDOM = window;
- triggerDOM.addEventListener(ev, () => setTimeout(() => upd_trans(table), 200));
- }
-
- function reg_box_trans(triggerElem_selector, table) {
- let s = document.querySelector(triggerElem_selector);
- if (null != s) dynamic_trans(table, s);
- else dbgopt(triggerElem_selector, "is null");
- }
-
- (async () => {
- document.querySelector(".navbar-brand").childNodes[2].data = " 首页";
- upd_trans(basicTranslateTable);
- reg_box_trans(".login", loginBoxTranslate);
- reg_box_trans(".register", registerBoxTrans);
- reg_box_trans(".update-profile", updateProfileTrans);
- dynamic_trans(basicDynTransTable);
- })(); //基本汉化
-
- // 静态内容汉化
- /* -Begin- */
- const staticTransTable = {
- "/": [{
- "#index-intro > div > div > p": "Vritual Judge(以下简称vj)并不是一个真实的在线评测网站(以下简称OJ),\
- 而是整合了各大OJ平台的题目形成的虚拟OJ平台。你提交的所有代码都会被发回原平台进行评测。\n\
- vj可以让你轻松开展比赛,不再为测试数据发愁\n\n\
- 目前我们支持以下平台的题库:"
- }, 0],
- "/problem": [{
- "[data-category=all]": "全部问题",
- "[data-category=solved]": "已解决问题",
- '[data-category=favorites]': "收藏的问题",
- "[data-category=attempted]": "未通过/正在评测的问题"
- }, 1],
- "/status": [{
- "[data-owner=all]": "所有提交",
- "[data-owner=mine]": "我的提交",
- ".username": "用户名",
- ".oj": "测评平台",
- ".prob_num": "问题编号",
- ".status": "状态",
- ".runtime": "运行时长",
- ".memory": "运行内存",
- ".length": "代码长度",
- ".language": "语言",
- ".date": "提交时间"
- }, 1],
- };
- (async () => {
- for (const path in staticTransTable) {
- if (path == location.pathname) {
- const tr = staticTransTable[path]
- upd_trans(tr[0], tr[1]);
- break;
- }
- }
- })();
- /* -End- */
- })();
- // 界面汉化程序 -End-
- })();