您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
优化您在 bb.ustc.edu.cn 的评分体验(主要为了助教开发)
当前为
// ==UserScript== // @name Fuck bb // @namespace http://tampermonkey.net/ // @version 0.3 // @description Optimizes your grading experience using bb.ustc.edu.cn, mainly for TAs. // @description:zh-CN 优化您在 bb.ustc.edu.cn 的评分体验(主要为了助教开发) // @author PRO // @match https://www.bb.ustc.edu.cn/webapps/assignment/* // @icon http://ustc.edu.cn/favicon.ico // @run-at document-start // @license gpl-3.0 // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @grant unsafeWindow // @require https://update.greasyfork.org/scripts/470224/1288180/Tampermonkey%20Config.js // ==/UserScript== (function () { 'use strict'; function _boolDesc(name, title = undefined, default_value = true) { return { name: name, value: default_value, input: "current", processor: "not", formatter: "boolean", autoClose: false, title: title }; } const config_desc = { "alternate-count": _boolDesc("Alternate count", "Replace original count with a better one. Required for 'Group count' to work"), "group-cnt": { name: "Group count", value: 500, processor: "int_range-1-", autoClose: false, title: "Number of students in your group. Viewing grades of greater number of students will trigger an alert." }, "focus-grade": _boolDesc("Focus grade", "Automatically focuses on grade input"), "ignore-ungraded": _boolDesc("Ignore un-graded", "Skips un-graded attemps"), "submit-draft": _boolDesc("Submit draft", "Automatically submits drafts", false), "native-pdf": _boolDesc("*Native PDF", "View students' pdf files with browser's solution") }; const config = GM_config(config_desc); const window = unsafeWindow; if (config["native-pdf"]) { if (typeof window.gradeAssignment === "undefined") { Object.defineProperty(window, "gradeAssignment", { set: function (value) { console.log("[Fuck bb] Hooked gradeAssignment"); value._handleInlineViewResponse = value.handleInlineViewResponse; value.handleInlineViewResponse = function (responseJSON) { const PDF = responseJSON.downloadUrl; if (PDF.endsWith(".pdf")) { fetch(PDF).then(res => res.blob()).then(blob => { const url = URL.createObjectURL(blob); responseJSON.viewUrl = url; value._handleInlineViewResponse(responseJSON); }); } else { value._handleInlineViewResponse(responseJSON); } }; window._gradeAssignment = value; }, get: function () { return window._gradeAssignment; } }); } else { window.gradeAssignment._handleInlineViewResponse = window.gradeAssignment.handleInlineViewResponse; window.gradeAssignment.handleInlineViewResponse = function (responseJSON) { const PDF = responseJSON.downloadUrl; if (PDF.endsWith(".pdf")) { fetch(PDF).then(res => res.blob()).then(blob => { const url = URL.createObjectURL(blob); responseJSON.viewUrl = url; window.gradeAssignment._handleInlineViewResponse(responseJSON); }); } else { window.gradeAssignment._handleInlineViewResponse(responseJSON); } }; console.log("[Fuck bb] Unable to hook, fallback"); } } const timer = window.setInterval( () => { if (typeof theAttemptNavController !== "undefined") { window.clearInterval(timer); main(); } }, 500 ); // Alternate count function alternateCount() { const span = document.querySelector("span.count"); if (!span) return true; span.style.fontWeight = "bold"; span.style.color = "red"; const m = span.textContent.match(/正在查看 (\d+) 个可评分项目,共 (\d+) 个可评分项目/); if (!m) return true; const alternate = m[1] + " / " + m[2]; span.textContent = alternate; if (parseInt(m[2]) > config["group-cnt"]) { alert("Viewing all students!"); return false; } return true; } // Focus grade input function focusGrade() { const grade = document.querySelector("#currentAttempt_grade"); if (grade) grade.focus(); } // Ignore un-graded attempts function ignoreUngraded() { if (document.querySelector("#panelbutton2 div.students-pager img[alt='不计入用户的成绩']")) { console.log("Skip un-graded"); theAttemptNavController.viewNext(); } } // Auto submit drafts function submitDraft() { const grade = document.querySelector("#currentAttempt_grade"); const submit = document.querySelector("#currentAttempt_submitButton"); if (grade.value !== "" && submit) { submit.click(); } } // Main function main() { let isSelf = true; if (config["alternate-count"]) isSelf = alternateCount(); if (config["focus-grade"]) focusGrade(); if (!isSelf) return; if (config["ignore-ungraded"]) ignoreUngraded(); if (config["submit-draft"]) submitDraft(); } // Shortcuts document.addEventListener("keydown", e => { if (e.key === "Escape") document.activeElement.blur(); if (document.activeElement.nodeName != "INPUT") { switch (e.key) { case "ArrowLeft": theAttemptNavController.viewPrevious(); break; case "ArrowRight": theAttemptNavController.viewNext(); break; case "Enter": { const save = document.querySelector(e.ctrlKey ? "#currentAttempt_submitButton" : "#currentAttempt_saveButton"); if (save) save.click(); break; } default: break; } } }); // Listen to config changes const callbacks = { "alternate-count": alternateCount, "focus-grade": focusGrade, "ignore-ungraded": ignoreUngraded, "submit-draft": submitDraft, }; window.addEventListener(GM_config_event, e => { if (e.detail.type === "set" && e.detail.after) { const callback = callbacks[e.detail.prop]; if (callback) callback(); } }); })();