您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Codereview codeforces
当前为
// ==UserScript== // @name CFCodereviewer // @namespace http://tampermonkey.net/ // @version 2.1.2 // @description Codereview codeforces // @author kdzestelov // @license MIT // @match *://*codeforces.com/* // @grant GM_xmlhttpRequest // @updateUrl https://gist.githubusercontent.com/KhetagAb/000670a28c8a37b917ece858b142b747/raw/script.js // ==/UserScript== const SHEET_URL = 'https://script.google.com/macros/s/AKfycbxexwLQ_JV-zW5xFKNwlGUsT27uT4yXcE9NZ6pmLTmtPo59Tb1z1wbysmIze1Cu6skjAQ/exec'; const SUB_RJ_BUTTON_CLASS = "submission-rj-button"; const SUB_AC_BUTTON_CLASS = "submission-ac-button"; const SUB_RG_BUTTON_CLASS = "submission-rejudge-form"; const SUB_COMMENT_SEND_BUTTON_CLASS = "submission-comment-send-form"; function getLast(href) { return href.split("/").pop() } function getGroupUrl() { const url = window.location.href return url.substring(0, url.indexOf("contest")) } const getContestUrl = () => { const url = window.location.href return url.substring(0, url.indexOf("status")) } function getContestId() { const url = window.location.href return url.substr(url.indexOf("contest") + 8, 6); } function wrap(text) { return '[' + text + ']'; } function getSubRjButton(subId) { return $("[submissionid=" + subId + "] ." + SUB_RJ_BUTTON_CLASS); } function getSubAcButton(subId) { return $("[submissionid=" + subId + "] ." + SUB_AC_BUTTON_CLASS); } function getCommentSubAcButton(subId) { return $("." + SUB_COMMENT_SEND_BUTTON_CLASS) } function getProblemIndex(subId) { return getLast($("tr[data-submission-id=" + subId + "] .status-small a").attr('href')); } function getSubRow(subId) { return $('tr[data-submission-id="' + subId + '"]') } function getHandle(subId) { return $("tr[data-submission-id=" + subId + "] .status-party-cell").text().trim(); } function getAllSubmissionsRow() { return $(".status-frame-datatable tbody tr") } function getSubmissionRow(subId) { return $(".status-frame-datatable tbody tr[data-submission-id=" + subId + "]") } function getSubsId() { return $(".information-box-link") } function getCorrectSubs() { return $(".information-box-link .verdict-accepted").parent(); } function getSubButtons() { return $(".submission-action-form"); } function getSideBar() { return $("div[id=sidebar]") } function getFilterBox() { return $(".status-filter-box"); } const getSheetSubmissions = () => { const fullUrl = SHEET_URL + "?type=get" GM_xmlhttpRequest({ method: 'GET', url: fullUrl, onload: (response) => { if (response.status === 200) { localStorage.setItem("c_status", response.responseText); console.log("Submissions loaded from sheet: " + response.responseText); } else { console.error("Unable to load submissions from sheet: " + response.responseText); } }, onerror: (error) => { console.error(error); } }); } const acceptSheetSubmission = (subId, button, type) => { const full_url = SHEET_URL + "?type=" + type + "&value=" + subId; GM_xmlhttpRequest({ method: 'GET', url: full_url, timeout: 5000, onload: (response) => { if (response.status === 200) { const submissions = getSubmissions(); submissions.push(subId); localStorage.setItem("c_status", JSON.stringify(submissions)); button.style.backgroundColor = "#81D718"; button.style.borderColor = "#81D718"; if (showed_codes[subId] != null && showed_codes[subId].showed) { showed_codes[subId]["showButton"].click(); } button.innerText = (type === "star" ? "🔥 Восхвалено" : "Похвалить"); } else { button.innerText = "Ошибка!" console.error(response) } }, onerror: (error) => { console.error(error); } }); } const getSubmissions = () => { return JSON.parse(localStorage.getItem("c_status") ?? "[]"); }; const isSubAccepted = (subId) => { return getSubmissions().includes(subId) } const acceptSubmission = (subId, button) => { const type = isSubAccepted(subId) ? "star" : "accept"; acceptSheetSubmission(subId, button, type); } const showed_codes = {}; function createSubShowButton(subId) { const button = document.createElement("button"); button.className = "submission-show"; button.style.marginTop = "10px"; button.style.backgroundColor = "#176F95"; button.style.border = "1px solid #176F95"; button.style.borderRadius = "8px" button.style.boxShadow = "rgba(0, 0, 0, .1) 0 2px 4px 0" button.style.color = "#fff" button.style.cursor = "pointer" button.style.padding = "8px 0.5em" button.style.width = "100%"; button.innerText = "Показать код"; button.onclick = (_) => showButtonClick(subId, button); return button; } function patchCodeSection(subId) { const patchLine = (i, line) => { line.addEventListener('click', () => { const text = $("[data-submission-id=" + subId + "] textarea") text.val((text.val().length === 0 ? "" : text.val() + "\n") + "Строка " + i + ": ") text.focus(); }); return line; }; let pretty_code = $('[data-submission-id=' + subId + '] .program-source li'); const code_lines_count = pretty_code.length pretty_code.each((i, line) => patchLine(i, line)) pretty_code = pretty_code.parent().parent(); pretty_code.before((_) => { const lines = document.createElement("pre"); lines.style.width = '4%'; lines.style.padding = "0.5em"; lines.style.display = 'inline-block'; const lineNs = [...Array(code_lines_count).keys()].map((i) => { const line = document.createElement("span"); line.style.color = 'rgb(153, 153, 153)'; line.innerText = "[" + i + "]"; line.style.display = "block"; line.style.textAlign = "right"; line.style.userSelect = "none"; line.style.cursor = "pointer"; return patchLine(i, line); }) lines.append(...lineNs) return lines }) pretty_code.css({'display': 'inline-block', 'width': '90%'}) } function showButtonClick(subId, button) { if (showed_codes[subId] != null) { if (showed_codes[subId].showed == true) { $(showed_codes[subId]["commentSection"]).hide(); $(showed_codes[subId]["codeSection"]).hide(); button.innerText = "Показать код"; showed_codes[subId].showed = false; } else if (showed_codes[subId].showed == false) { $(showed_codes[subId]["commentSection"]).show(); $(showed_codes[subId]["codeSection"]).show(); button.innerText = "Скрыть код"; showed_codes[subId].showed = true; } } else { button.innerText = showed_codes[subId] = "Загружаю код..." const requestUrl = getContestUrl() + 'submission/' + subId; console.log(requestUrl); $.get(requestUrl, function (html) { const codeHtml = $(html).find(".SubmissionDetailsFrameRoundBox-" + subId).html() if (codeHtml == undefined) { button.innerText = "Ошибка!"; //location.reload(); return; } const commentSection = createCommentSection(subId) const subCodeSection = createSubCodeSection(subId, codeHtml); const subRow = getSubRow(subId); subRow.after(commentSection, subCodeSection) prettyPrint(subId); patchCodeSection(subId); showed_codes[subId] = { "showed": true, "showButton": button, "commentSection": commentSection, "codeSection": subCodeSection } button.innerText = "Скрыть код" }); } } function createSubCodeSection(subId, codeHtml) { const trSubCode = document.createElement("tr"); trSubCode.setAttribute('data-submission-id', subId); const tdSubCode = document.createElement("td"); tdSubCode.setAttribute('colspan', '8'); tdSubCode.innerHTML = codeHtml; tdSubCode.style.textAlign = "start" trSubCode.append(tdSubCode); return trSubCode; } const createCommentSection = (subId) => { const subAcButton = getSubAcButton(subId)[0]; const isAccepted = isSubAccepted(subId); const commentTextfield = createCommentTextfield() const commentAcButton = commentSendButtonTemplate(subId, (isAccepted ? "Похвалить" : "Принять") + " с комментарием", (isAccepted ? "#81D718" : "#13aa52"), (subId, button) => { const text = $(commentTextfield).val(); if (text.length === 0) { button.innerText = "Принимаю..."; acceptSubmission(subId, subAcButton); } else { button.innerText = "Отправляю..."; $.post(getGroupUrl() + 'data/newAnnouncement', { contestId: getContestId(), englishText: "", russianText: text, submittedProblemIndex: getProblemIndex(subId), targetUserHandle: getHandle(subId), announceInPairContest: true, }, () => { acceptSubmission(subId, subAcButton); }) } }) const commentRjButton = commentSendButtonTemplate(subId, "Отклонить с комментарием", "#EC431A", (subId, button) => { const text = $(commentTextfield).val(); if (text.length > 0) { button.innerText = "Отклоняю..."; $.post(getGroupUrl() + 'data/newAnnouncement', { contestId: getContestId(), englishText: "", russianText: text, submittedProblemIndex: getProblemIndex(subId), targetUserHandle: getHandle(subId), announceInPairContest: true, }, () => { rejectSub(subId); if (showed_codes[subId] != null) { showed_codes[subId]['codeSection'].hide() } button.innerText = "Отклонено"; }) } }); commentTextfield.addEventListener("keyup", (event) => { event.preventDefault(); if (event.keyCode === 13) { commentRjButton.click(); } }); const trSection = document.createElement("tr"); trSection.setAttribute('data-submission-id', subId); const tdSection = document.createElement("td"); tdSection.setAttribute('colspan', '8'); const tdSectionTitle = document.createElement("div"); tdSectionTitle.style.textAlign = "left"; tdSectionTitle.className = "caption titled" tdSectionTitle.innerText = "→ Комментарий" tdSection.append(tdSectionTitle, commentTextfield, commentAcButton, commentRjButton); trSection.append(tdSection) return trSection; } function createCommentTextfield() { const textField = document.createElement("textarea"); textField.name = "russianText" textField.className = "bottom-space-small monospaced" textField.style.width = "80rem"; textField.style.height = "5rem"; textField.style.margin = "4px"; return textField; } const commentSendButtonTemplate = (subId, text, color, action) => { const button = document.createElement("button"); button.className = SUB_COMMENT_SEND_BUTTON_CLASS; button.style.margin = "4px"; button.style.width = "40%"; button.style.backgroundColor = color; button.style.border = "1px solid " + color; button.style.borderRadius = "8px" button.style.boxShadow = "rgba(0, 0, 0, .1) 0 2px 4px 0" button.style.color = "#fff" button.style.cursor = "pointer" button.style.padding = "8px 0.5em" button.innerText = text; button.onclick = () => action(subId, button); return button } const acButtonTemplate = (subId, action, text) => { const acButton = document.createElement("button"); acButton.className = SUB_AC_BUTTON_CLASS; const color = (isSubAccepted(subId) ? "#81D718" : "#13aa52"); acButton.style.backgroundColor = color; acButton.style.border = "1px solid " + color; acButton.style.borderRadius = "8px" acButton.style.boxShadow = "rgba(0, 0, 0, .1) 0 2px 4px 0" acButton.style.color = "#fff" acButton.style.cursor = "pointer" acButton.style.padding = "8px 0.5em" acButton.style.margin = "5px 5px 0 0"; acButton.style.width = "59%"; acButton.innerText = text !== undefined ? text : (isSubAccepted(subId) ? "Похвалить" : "Принять"); acButton.onclick = (_) => action(subId, acButton); return acButton; } const createAcButton = (template, subId, ...args) => { return template(subId, (subId, button) => { button.innerText = "Подтверждаю..."; button.style.borderColor = "gray"; button.style.backgroundColor = "gray"; acceptSubmission(subId, button); }, ...args); } const createRjButton = (subId, text, action) => { const rjButton = document.createElement("button"); rjButton.className = SUB_RJ_BUTTON_CLASS; rjButton.style.width = "38%"; rjButton.style.backgroundColor = "#EC431A"; rjButton.style.border = "1px solid #EC431A" rjButton.style.borderRadius = "8px" rjButton.style.padding = "8px 0.5em" rjButton.style.boxShadow = "rgba(0, 0, 0, .1) 0 2px 4px 0" rjButton.style.color = "#fff" rjButton.style.cursor = "pointer" rjButton.innerText = text; rjButton.onclick = (_) => action(subId, rjButton); return rjButton } function createRgButtonFromTemplate(subId, text, action) { const button = document.createElement("button"); button.className = SUB_RG_BUTTON_CLASS; button.style.marginTop = "7px"; button.style.width = "200px"; button.innerText = text; button.onclick = (_) => action(subId, button); return button; } const createRgButton = (subId) => { return createRgButtonFromTemplate(subId, "Перетестировать", (subId, button) => { const requestUrl = getContestUrl() + 'submission/' + subId const data = {action: "rejudge", submissionId: subId} $.post(requestUrl, data, (_) => location.reload()); button.innerText = "Тестирую..."; }); } const rejectSub = (subId) => { const subRjButton = getSubRjButton(subId); subRjButton.innerText = "Отклоняю..."; const subAcButton = getSubAcButton(subId); const commentSubAcButton = getCommentSubAcButton(subId); const requestUrl = getContestUrl() + 'submission/' + subId const data = {action: "reject", submissionId: subId} $.post(requestUrl, data, function (_) { $("[submissionid=" + subId + "] .verdict-accepted").remove() subAcButton.remove() subRjButton.remove() commentSubAcButton.remove(); }) } const patchSubmissions = () => { const subsId = getSubsId(); subsId.after((i) => { const subId = Number($(subsId[i])[0].getAttribute('submissionid')) return createSubShowButton(subId); }) } const patchCorrectSubmissions = () => { const correctSubs = getCorrectSubs(); correctSubs.after((i) => { const subId = Number($(correctSubs[i]).attr('submissionid')) const acButton = createAcButton(acButtonTemplate, subId) const rgButton = createRgButton(subId); const rjButton = createRjButton(subId, "Отклонить", (subId, _) => { rejectSub(subId); }); return [acButton, rjButton, rgButton] }) } const patchContestSidebar = () => { const contestsSidebar = $(".GroupContestsSidebarFrame ul a") contestsSidebar.before((i) => { const contestHref = $(contestsSidebar[i]).attr('href'); return document.createTextNode(wrap(getLast(contestHref))); }); } const patchSubmission = () => { const buttons = getSubButtons() if (buttons.length > 0) { const subId = Number(getLast(location.pathname)); const acButton = createAcButton(acButtonTemplate, subId); buttons[0].before(acButton); } } const patchFilterBox = () => { const filterBox = getFilterBox(); const sidebar = getSideBar(); filterBox.detach().prependTo(sidebar); const filterBoxPart = filterBox.find(".status-filter-form-part")[0]; const correctSubsId = getCorrectSubs().map((i, e) => Number($(e).attr("submissionid"))).toArray(); const filter = (checkbox) => { localStorage.setItem("filterPendingSubs", checkbox.checked); const filtered = correctSubsId.filter(subId => { console.log(subId + " " + !isSubAccepted(subId)) return !isSubAccepted(subId) }); console.log(filtered) getAllSubmissionsRow().each((i, e) => { if (checkbox.checked) { if (!filtered.includes(Number($(e).attr('data-submission-id')))) { $(e).hide(); } } else { $(e).show() } }); }; const template = createFilterPendingCheckboxTemplate(filter); const label = template[0] const checkbox = template[1] checkbox.checked = ('true' === localStorage.getItem("filterPendingSubs") ?? false); filter(checkbox); filterBoxPart.before(label); } function createFilterPendingCheckboxTemplate(action) { const label = document.createElement("label"); const checkbox = document.createElement("input"); checkbox.type = "checkbox"; checkbox.onclick = (_) => action(checkbox); const title = document.createElement("span"); title.style.padding = "5px"; title.className = "smaller"; title.innerText = "Только непроверенные посылки"; label.append(checkbox, title); return [label, checkbox]; } (function () { getSheetSubmissions(); try { patchContestSidebar(); } catch (e) { console.error(e); } try { patchFilterBox(); } catch (e) { console.error(e); } try { patchCorrectSubmissions(); } catch (e) { console.error(e); } try { patchSubmissions(); } catch (e) { console.error(e); } try { patchSubmission(); } catch (e) { console.error(e); } })();