您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
For ICPC competitors practicing for the DOMjudge UI in codeforces.
当前为
// ==UserScript== // @name Domjudge-UI-for-Codeforces // @namespace http://tampermonkey.net/ // @version 0.1.0 // @license MIT // @description For ICPC competitors practicing for the DOMjudge UI in codeforces. // @author jakao // @match https://codeforces.com/gym/*/submit* // @match https://codeforces.com/contest/*/submit* // @icon https://i.imgur.com/RwGYTmF.png // @grant GM_addStyle // ==/UserScript== const css = ` .summary-table { text-align: center; } table { width: 100%; border-collapse: collapse; } .score-penalty-table { display: flex; align-items: center; } .score-penalty-table > div { flex: 1; padding: 5px; border-right: 1px solid #ccc; /* Optional border for visual separation */ } .score-penalty-table > div:first-child { border-right: 1px solid transparent; /* Transparent border between left and right */ } .badge { display: inline-block; padding: .25em .4em; font-size: 75%; font-weight: 700; line-height: 1; text-align: center; white-space: nowrap; vertical-align: baseline; border-radius: .25rem; transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out; } .problem-badge { font-size: 100%; } td.score_cell { min-width: 4.2em; padding: 2px 1px 2px 1px; border-right: none; } .summary-table td.score_cell { min-width: 4.2em; border-right: none; } thead { display: table-header-group; vertical-align: middle; unicode-bidi: isolate; border-color: inherit; } .sortorderswitch { border-top: 2px solid black; } .summary-table { margin-top: 2.5em; } .summary-table a { display: block; padding: 2px 1px 2px 1px; text-decoration: none; color: black; } .scorenc, .scorett, .scorepl { text-align: center; width: 2ex; } .scorenc { font-weight: bold; } .summary-table .scoreaf { white-space: nowrap; border: 0; text-align: center; } .summary-table tr { border-bottom: 1px solid black; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: black; height: 42px; } .summary-table .scoretn { padding: 0px 5px 0px; text-align: right; font-weight: bold; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .summary-table td, .summary-table th { border-right: 1px solid silver; padding: 0px; } .summary-table-header { font-variant: small-caps; border-bottom: 2px solid black; white-space: nowrap; } .summary-table-header th{ text-align: center; box-shadow: -1px 0px 0px 0px silver inset, 0px 2px 0px 0px black; border: none; background: var(--background-color); position: sticky; top: 0px; z-index: 1; } col { display: table-column; unicode-bidi: isolate; } colgroup { display: table-column-group; unicode-bidi: isolate; } .summary-table td { font-size: small; vertical-align: middle; text-align: center; } .summary-table td div { width: 4em; font-size: 120%; display: inline-block; } .summary-table td div span { font-weight: normal; font-size: 70%; display: block; } .summary-table th { text-align: center; box-shadow: -1px 0px 0px 0px silver inset, 0px 2px 0px 0px black; border: none; background: var(--background-color); position: sticky; top: 0px; z-index: 1; } td.scorenc { border-color: silver; border-right: 0; } *, ::after, ::before { box-sizing: border-box; } .row { display: -ms-flexbox; display: flex; -ms-flex-wrap: wrap; flex-wrap: wrap; margin-right: -15px; margin-left: -15px; } .col { -ms-flex-preferred-size: 0; flex-basis: 0; -ms-flex-positive: 1; flex-grow: 1; max-width: 100%; } .teamoverview { border-top: solid 1px darkgray; border-bottom: solid 1px darkgray; background-color: #c4d8ff; margin-top: 2ex; padding-left: 1ex; font-size: 1.17em; text-align: center; } .h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 { margin-bottom: .5rem; font-weight: 500 !important; line-height: 1.2; } h1 { display: block !important; font-size: 2em; margin-block-start: 0.67em !important; margin-block-end: 0.67em !important; margin-inline-start: 0px !important; margin-inline-end: 0px !important; font-weight: bold; unicode-bidi: isolate !important; } .data-table tr { border-bottom: 1px solid silver; } .table td, .table th { padding: .75rem; vertical-align: top; border-top: 1px solid #dee2e6; } .table-sm td, .table-sm th { padding: .3rem; } .table thead th { vertical-align: bottom; border-bottom: 2px solid #dee2e6; } .table .thead-light th { color: #495057; background-color: #e9ecef; border-color: #dee2e6; } table { border-collapse: collapse; } .table { width: 100%; margin-bottom: 1rem; color: #212529; } th { display: table-cell; vertical-align: inherit; font-weight: bold !important; text-align: -internal-center; unicode-bidi: isolate; } .sol { font-weight: bold; font-variant: small-caps; } .sol_queued { color: gray; } .sol_incorrect, .compile-unsuccessful { color: red; } .sol_correct, .compile-successful { color: green; } .probid, .langid { font-variant: small-caps; } .data-table td a, .data-table td a:hover { display: block; text-decoration: none; color: inherit; padding: 3px 5px; } .table-striped tbody tr:nth-of-type(odd) { background-color: rgba(0, 0, 0, .05); } body { color: var(--text-color); background-color: var(--background-color); font-family: Roboto, sans-serif !important; padding-bottom: 4em; padding-top: 4.5rem; } div { display: block; unicode-bidi: isolate; } .navbar-collapse { -ms-flex-preferred-size: 100%; flex-basis: 100%; -ms-flex-positive: 1; flex-grow: 1; -ms-flex-align: center; align-items: center; } ul { display: block; list-style-type: disc; margin-block-start: 1em; margin-block-end: 1em; margin-inline-start: 0px; margin-inline-end: 0px; padding-inline-start: 40px; unicode-bidi: isolate; } dl, ol, ul { margin-top: 0; margin-bottom: 1rem; } .mr-auto, .mx-auto { margin-right: auto !important; } .navbar-nav { display: -ms-flexbox; display: flex; -ms-flex-direction: column; flex-direction: row; padding-left: 0; margin-bottom: 0; list-style: none; } li { display: list-item; text-align: -webkit-match-parent; unicode-bidi: isolate; } #menuDefault ul li.nav-item { white-space: nowrap; white-space-collapse: collapse; text-wrap: nowrap; } #menuDefault { display: flex; } .nav-link { display: block; padding: .5rem 1rem; } .navbar-dark .navbar-nav .active>.nav-link, .navbar-dark .navbar-nav .nav-link.active, .navbar-dark .navbar-nav .nav-link.show, .navbar-dark .navbar-nav .show>.nav-link { color: #fff !important; } .navbar-dark .navbar-nav .nav-link { color: #FFFFFF80 !important; font-size: 16px; } .fa, .fa-brands, .fa-classic, .fa-regular, .fa-sharp, .fa-solid, .fab, .far, .fas { -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; display: var(--fa-display, inline-block); font-style: normal; font-variant: normal; line-height: 1; text-rendering: auto; } .fa-classic, .fa-regular, .fa-solid, .far, .fas { font-family: "Font Awesome 6 Free"; } .fa-solid, .fas { font-weight: 900; } a { color: #007bff; text-decoration: none; background-color: transparent; } .navbar-brand { display: inline-block; padding-top: .3125rem; padding-bottom: .3125rem; margin-right: 1rem; /* font-size: 1.25rem; */ font-size: 20px !important; line-height: inherit; white-space: nowrap; } .navbar-dark .navbar-brand { color: #fff; } .navbar-dark .navbar-text { color: rgba(255, 255, 255, .5); font-size: 16px; } .navbar-text { display: inline-block; padding-top: .5rem; padding-bottom: .5rem; } nav { display: block; unicode-bidi: isolate; } .navbar { position: relative; justify-content: space-between; -ms-flex-pack: justify; -ms-flex-wrap: wrap; -ms-flex-align: center; align-items: center; flex-direction: row; display: flex; display: -ms-flexbox; padding-top: 8px; padding-right: 16px; padding-bottom: 8px; padding-left: 16px; } .bg-dark { background-color: #343a40 !important; } .fixed-top { position: fixed; top: 0; right: 0; left: 0; z-index: 1030; } /* submit button */ .justify-content-center { -ms-flex-pack: center !important; justify-content: center !important; } .btn { display: inline-block; font-weight: 400; color: #212529; text-align: center; vertical-align: middle; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; background-color: transparent; border: 1px solid transparent; padding: 6px 12px; font-size: 16px; line-height: 1.5; border-radius: .25rem; transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out; } .btn:not(:disabled):not(.disabled) { cursor: pointer; } .btn-success { color: #fff !important; background: #0a8927 !important; } .btn-info { color: #fff !important; background-color: #17a2b8 !important; } .score_pending { background: #6666FF !important; } .btn-secondary { color: #fff; background-color: #6c757d; border-color: #6c757d; } .modal-footer>* { margin: .25rem; } .btn-group-sm>.btn, .btn-sm { padding: .25rem .5rem; font-size: 14px; line-height: 1.5; border-radius: .2rem; } .modal-header { display: -ms-flexbox; display: flex; -ms-flex-align: start; align-items: flex-start; -ms-flex-pack: justify; justify-content: space-between; padding: 1rem 1rem; border-bottom: 1px solid #dee2e6; border-top-left-radius: calc(.3rem - 1px); border-top-right-radius: calc(.3rem - 1px); } .modal-title { margin-bottom: 0; line-height: 1.5; } .modal-header .close { padding: 1rem 1rem; margin: -1rem -1rem -1rem auto; } button.close { padding: 0; background-color: transparent; border: 0; } .close { float: right; font-size: 1.5rem; font-weight: 700; line-height: 1; color: #000; text-shadow: 0 1px 0 #fff; opacity: .5; } [type=button], [type=reset], [type=submit], button { -webkit-appearance: button; } button, select { text-transform: none; } button, input { overflow: visible; } button, input, optgroup, select, textarea { margin: 0; font-family: inherit; font-size: inherit; line-height: inherit; } button { border-radius: 0; } .close { color: #aaa; float: right; font-size: 28px; font-weight: bold; } .close:hover, .close:focus { color: black; text-decoration: none; cursor: pointer; } .modal-open .modal { overflow-x: hidden; overflow-y: auto; } .modal { position: fixed; top: 0; left: 0; z-index: 1050; display: none; width: 100%; height: 100%; overflow: hidden; outline: 0; } .fade { transition: opacity .15s linear; } .modal-header { display: -ms-flexbox; display: flex; -ms-flex-align: start; align-items: flex-start; -ms-flex-pack: justify; justify-content: space-between; padding: 16px 16px; border-bottom: 1px solid #dee2e6; border-top-left-radius: calc(.3rem - 1px); border-top-right-radius: calc(.3rem - 1px); } .modal-body { position: relative; -ms-flex: 1 1 auto; flex: 1 1 auto; padding: 1rem; } form { display: block; margin-top: 0em; unicode-bidi: isolate; } .modal-content { position: relative; display: -ms-flexbox; display: flex; -ms-flex-direction: column; flex-direction: column; width: 100%; pointer-events: auto; background-color: #fff; background-clip: padding-box; border: 1px solid rgba(0, 0, 0, .2); border-radius: 4.8px; outline: 0; } .modal-footer { display: -ms-flexbox; display: flex; -ms-flex-wrap: wrap; flex-wrap: wrap; -ms-flex-align: center; align-items: center; -ms-flex-pack: end; justify-content: flex-end; padding: .75rem; border-top: 1px solid #dee2e6; border-bottom-right-radius: calc(.3rem - 1px); border-bottom-left-radius: calc(.3rem - 1px); } h5 { font-size: 20px !important; } .modal.fade .modal-dialog { transition: -webkit-transform .3s ease-out; transition: transform .3s ease-out; transition: transform .3s ease-out, -webkit-transform .3s ease-out; -webkit-transform: translate(0, -50px); transform: translate(0, -50px); } .modal.show .modal-dialog { -webkit-transform: none; transform: none; } .modal-dialog { position: relative; width: auto; margin: .5rem; pointer-events: none; } @media (min-width: 576px) { .modal-dialog { max-width: 500px; margin: 1.75rem auto; } } @media (min-width: 992px) { .modal-lg, .modal-xl { max-width: 800px; } } label { display: inline-block; margin-bottom: .5rem; } label { cursor: default; } .form-group { margin-bottom: 1rem; } .custom-file { position: relative; display: inline-block; width: 100%; height: calc(1.5em + .75rem + 2px); margin-bottom: 0; } input:not([type="image" i], [type="range" i], [type="checkbox" i], [type="radio" i]) { overflow-clip-margin: 0px !important; overflow: clip !important; } input[type="file" i] { appearance: none; background-color: initial; cursor: default; align-items: baseline; color: inherit; text-overflow: ellipsis; text-align: start !important; padding: initial; border: initial; white-space: pre; } input { font-style: ; font-variant-ligatures: ; font-variant-caps: ; font-variant-numeric: ; font-variant-east-asian: ; font-variant-alternates: ; font-variant-position: ; font-weight: ; font-stretch: ; font-size: ; font-family: ; font-optical-sizing: ; font-size-adjust: ; font-kerning: ; font-feature-settings: ; font-variation-settings: ; text-rendering: auto; color: fieldtext; letter-spacing: normal; word-spacing: normal; line-height: normal; text-transform: none; text-indent: 0px; text-shadow: none; display: inline-block; text-align: start; appearance: auto; -webkit-rtl-ordering: logical; cursor: text; background-color: field; margin: 0em; padding: 1px 0px; border-width: 2px; border-style: inset; border-color: light-dark(rgb(118, 118, 118), rgb(133, 133, 133)); border-image: initial; padding-block: 1px; padding-inline: 2px; } .text-muted { color: #6c757d !important; } .text-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } file-label, .custom-select { transition: background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out; } .custom-select { display: inline-block; width: 100%; height: calc(1.5em + .75rem + 2px); padding: .375rem 1.75rem .375rem .75rem; font-size: 14px; font-weight: 400; line-height: 1.5; color: #495057; vertical-align: middle; border: 1px solid #ced4da; border-radius: .25rem; -webkit-appearance: none; -moz-appearance: none; appearance: none; } .form-control { display: block; width: 100%; height: calc(1.5em + .75rem + 2px); padding: .375rem .75rem; font-size: 14px; font-family: Roboto, sans-serif; font-weight: 400; line-height: 1.5; color: #495057; background-color: #fff; background-clip: padding-box; border: 1px solid #ced4da; border-radius: .25rem; transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out; } select { word-wrap: normal; } .custom-file-label { position: absolute; top: 0; right: 0; left: 0; z-index: 1; height: calc(1.5em + .75rem + 2px); padding: .375rem .75rem; overflow: hidden; font-weight: 400; line-height: 1.5; color: #495057; background-color: #fff; border: 1px solid #ced4da; border-radius: .25rem; } .custom-file-label::after { position: absolute; top: 0; right: 0; bottom: 0; z-index: 3; display: block; height: calc(1.5em + .75rem); padding: .375rem .75rem; line-height: 1.5; color: #495057; content: "Browse"; background-color: #e9ecef; border-left: inherit; border-radius: 0 .25rem .25rem 0; } .alert-warning { color: #856404; background-color: #fff3cd; border-color: #ffeeba; } .alert { position: relative; padding: .75rem 1.25rem; margin-bottom: 1rem; border: 1px solid transparent; border-radius: .25rem; } option { font-weight: normal; display: block; padding-block-start: 0px; padding-block-end: 1px; min-block-size: 1.2em; padding-inline: 2px; white-space: nowrap; } .modal-backdrop.fade { opacity: 0; } .modal-backdrop.show { opacity: .5; } .modal-backdrop { position: fixed; top: 0; left: 0; z-index: 1040; width: 100vw; height: 100vh; background-color: #000; } `; GM_addStyle(css); let contestStartTime = -1; // let contestStartTime = 1726755078; let blueLine; let submissionResult; let contestProblems, contestProblemName, gymRound; let teamname, rank, penalty, score; let problemStatus = {}; let timerInterval; let submitForm; let contestLength = 18000; function getCurrentURL () { return window.location.href; } function parseLanguage(language){ if(language.startsWith('C++')){ return "CPP"; } if(language.startsWith('Py')){ return "PY3"; } return language; } function parseVerdict(verdict){ if(verdict == "OK") return "CORRECT"; if(verdict == "WRONG_ANSWER") return "WRONG-ANSWER"; if(verdict == "TIME_LIMIT_EXCEEDED") return "TIMELIMIT"; if(verdict == "RUNTIME_ERROR") return "RUN-ERROR"; if(verdict == "MEMORY_LIMIT_EXCEEDED") return "RUN-ERROR"; if(verdict == "COMPILATION_ERROR") return "COMPILER-ERROR"; if(verdict == "TESTING") return "PENDING"; return "PENDING"; } function parseSubmission(result){ submissionResult = []; for(let submission of result){ if(contestStartTime <= submission.creationTimeSeconds && submission.creationTimeSeconds - contestStartTime < contestLength){ const date = new Date(submission.creationTimeSeconds * 1000); submissionResult.push({ index: submission.problem.index, verdict: parseVerdict(submission.verdict), time: date.getHours().toString().padStart(2, '0')+":"+date.getMinutes().toString().padStart(2, '0'), submitMinute: Math.floor(submission.relativeTimeSeconds/60), language: parseLanguage(submission.programmingLanguage) }); } } const reversedSubmissionResult = submissionResult.slice().reverse(); for(let submission of reversedSubmissionResult){ if(submission.index in problemStatus){ if(submission.verdict == "CORRECT"){ if(problemStatus[submission.index].passtime == -1) problemStatus[submission.index].passtime = submission.submitMinute; } else if(submission.verdict == "PENDING"){ problemStatus[submission.index].pendingNumber = problemStatus[submission.index].pendingNumber+1; if(problemStatus[submission.index].pending == -1) problemStatus[submission.index].pending = submission.submitMinute; } else{ problemStatus[submission.index].rejected = problemStatus[submission.index].rejected + (submission.verdict == "COMPILER-ERROR" ? 0 : 1); } } else{ let newStatus; if(submission.verdict == "PENDING"){ newStatus = { rejected: 0, passtime: -1, pending: submission.submitMinute, pendingNumber: 1 } } else if(submission.verdict != "CORRECT"){ newStatus = { rejected: submission.verdict == "COMPILER-ERROR" ? 0 : 1, passtime: -1, pending: -1, pendingNumber: 0 } } else{ newStatus = { rejected: 0, passtime: submission.submitMinute, pending: -1, pendingNumber: 0 } } problemStatus[submission.index] = newStatus; } } } async function getApiData () { domjudgeView(); gymRound = getCurrentURL().split('/')[4]; // console.log(gymRound); let links = document.querySelectorAll('a'), username; // 取得 username for (let link of links) { if (link.href.includes('/profile/')) { username = link.href.split('/')[4]; break; } } const SubmissionApiURL = 'https://codeforces.com/api/contest.status?contestId=' + gymRound + '&handle=' + username; // console.log(SubmissionApiURL); await fetch(SubmissionApiURL) .then(response => response.json()) // 將回應轉為 JSON 格式 .then(data => { if (data.result && data.result.length > 0) { if("startTimeSeconds" in data.result[0].author) contestStartTime = data.result[0].author.startTimeSeconds; parseSubmission(data.result); // return data.result[0].creationTimeSeconds; } else { console.log("No result found in Submission API response"); } }) .then(() => drawHeader()) .catch(error => { console.error("Error fetching API:", error); }); const ContestApiURL = 'https://codeforces.com/api/contest.standings?contestId=' + gymRound + '&from=1&showUnofficial=true'; // console.log(ContestApiURL); await fetch(ContestApiURL) .then(response => response.json()) // 將回應轉為 JSON 格式 .then(data => { if (data.result) { contestLength = data.result.contest.durationSeconds; contestProblems = []; for(let problem of data.result.problems){ contestProblems.push(problem.index); } contestProblemName = []; for(let problem of data.result.problems){ contestProblemName.push(problem.index + " - " + problem.name); } for(let team of data.result.rows){ if(team.party.members.some(item => item.handle === username)){ penalty = team.penalty; rank = team.rank; score = team.points; if("teamName" in team.party) teamname = team.party.teamName; else teamname = username; break; } } } else { console.log("No result found in Contest API response"); } }) .then(() => drawTimeLine()) .then(() => updateTimeLine()) .then(() => drawTeamsSummary()) .then(() => drawSubmission()) .then(() => addSubmitPage()) .then(() => submitButtomJquery()); // .catch(error => { // console.error("Error fetching API:", error); // }); timerInterval = setInterval(updateTimer, 1000); } function updateTimeLine(){ if(contestStartTime == -1) return; // console.log((Date.now() / 1000 - contestStartTime), contestLength); let contestDuringPrecentage = (Date.now() / 1000 - contestStartTime) / contestLength; // contestDuringPrecentage = Math.random(); if(contestDuringPrecentage > 1) { return; } let pageWidth = window.innerWidth; let blueLineWidth = contestDuringPrecentage * pageWidth; blueLine.style.width = blueLineWidth + 'px'; // 設定寬度 } function addFontAwesome(){ // 獲取頁面中的 <header> 元素 let header = document.querySelector('head'); // 創建一個新的 <script> 元素 let scriptElement = document.createElement('script'); // 設置 <script> 標籤的屬性 scriptElement.src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js" scriptElement.type = "text/javascript"; let linkElement = document.createElement('link'); // 設置 <link> 標籤的屬性 linkElement.href = "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css"; linkElement.rel = "stylesheet"; linkElement.type = "text/css"; //linkElement.type = "text/javascript"; // 將 <link> 標籤添加到 <head> 中 // 將 <script> 元素添加到 <header> 中 if (header) { header.appendChild(scriptElement); header.appendChild(linkElement); } } function drawTimeLine(){ if(contestStartTime == -1) return; let contestDuringPrecentage = (Date.now() / 1000 - contestStartTime) / contestLength; // contestDuringPrecentage = 0.5; if(contestDuringPrecentage > 1) { return; } let pageWidth = window.innerWidth; let blueLineWidth = contestDuringPrecentage * pageWidth; blueLine = document.createElement('div'); blueLine.style.position = 'absolute'; blueLine.style.bottom = '0'; blueLine.style.left = '0'; blueLine.style.height = '5.5px'; // 可以調整高度 blueLine.style.backgroundColor = '#0079ff'; blueLine.style.zIndex = '9999'; // 保證藍線在最上層 blueLine.style.width = blueLineWidth + 'px'; // 設定寬度 document.querySelector('nav').appendChild(blueLine); } function drawHeader(){ document.getElementById('body').style.margin = "0"; // 選擇所有的 <a> 元素 let links = document.querySelectorAll('a'); let LogoutLink; // 遍歷每個 <a>,檢查其 innerHTML 是否包含 "Logout" links.forEach(link => { if (link.innerHTML.includes('Logout')) { // console.log(link); // 找到的 <a> 元素會被輸出到控制台 LogoutLink = link; } }); document.getElementById('header').remove(); document.querySelector('.menu-list-container').remove(); document.querySelector('.menu-box').remove(); document.querySelector('.alert-success').remove(); let baseUrl = getCurrentURL().split('/').slice(0, 5).join('/'); let navElement = document.createElement('nav'); navElement.classList.add('navbar','navbar-expand-md','navbar-dark','bg-dark','fixed-top'); let navHTML = ""; navHTML = `<a class="navbar-brand hidden-sm-down" href="${baseUrl}/submit">DOMjudge</a>`; navHTML += '<div class="collapse navbar-collapse" id="menuDefault">'; navHTML += '<ul class="navbar-nav mr-auto">'; navHTML += `<li class="nav-item active"><a class="nav-link" href="${baseUrl}/submit"><i class="fas fa-home"></i> Home </a></li>`; navHTML += `<li class="nav-item"><a class="nav-link" href="${baseUrl}"><i class="fas fa-book-open"></i> Problemset </a></li>`; navHTML += `<li class="nav-item"><a class="nav-link" href="${baseUrl}/standings"><i class="fas fa-list-ol"></i> Scoreboard </a></li>`; navHTML += '</ul>'; navHTML += '<div id="submitbut"><a id="submitLink" class="nav-link justify-content-center" data-ajax-modal="" data-ajax-modal-after="initSubmitModal" href="#"><span class="btn btn-success btn-sm"><i class="fas fa-cloud-upload-alt"></i> Submit</span></a></div>'; navHTML += `<a class="btn btn-info btn-sm justify-content-center" href="${LogoutLink}" onclick="return confirmLogout();"><i class="fas fa-sign-out-alt"></i> Logout</a>`; navHTML += `<div class="navbar-text" style="white-space:nowrap;"><span style="padding-left: 10px;"><i class="fas fa-clock loading-indicator"></i></span><span id="timeleft"> contest over</span></div>`; navHTML += '</div>'; navElement.innerHTML = navHTML; let bodyDiv = document.getElementById('body'); bodyDiv.insertBefore(navElement, bodyDiv.firstChild); } function updateTimer(){ if(Math.floor(Date.now()/1000) - contestStartTime > contestLength){ document.getElementById("timeleft").innerHTML = " contest over"; clearInterval(timerInterval); // 倒數結束時停止計時 } else{ let leftSecond = contestLength - (Math.floor(Date.now()/1000) - contestStartTime); let minutes = (Math.floor((leftSecond%3600)/60)); let seconds = leftSecond%60; let displayMinutes = minutes < 10 ? '0' + minutes : minutes; let displaySeconds = seconds < 10 ? '0' + seconds : seconds; if(leftSecond > 3600) document.getElementById("timeleft").innerHTML = " " + Math.floor(leftSecond/3600).toString() + ":" + displayMinutes + ":" + displaySeconds; else document.getElementById("timeleft").innerHTML = " " + displayMinutes + ":" + displaySeconds; } } function drawTeamsSummary(){ // console.log(contestProblems); let tableHTML = '<table class="summary-table center">'; // Table Header tableHTML += '<colgroup><col id="scorerank"><col id="scoreteamname"></colgroup>'; tableHTML += '<colgroup><col id="scoresolv"><col id="scoretotal"></colgroup>'; tableHTML += '<colgroup>'; for(let i = 0; i < contestProblems.length; i++){ tableHTML += '<col class="scoreprob"'; } tableHTML += '</colgroup>'; tableHTML += '<thead><tr class="summary-table-header">'; tableHTML += '<th title="rank" scope="col">rank</th>'; tableHTML += '<th title="team name" scope="col" colspan="3">team</th>'; tableHTML += '<th title="# solved / penalty time" colspan="2" scope="col">score</th>'; // tableHTML += '<th style="text-align: center;">score</th>'; contestProblems.forEach(problemIndex => { const linkURL = `https://codeforces.com/gym/${gymRound}/problem/${problemIndex.toString()}`; tableHTML += `<th title="" scope="col"><a href="${linkURL}" target="_blank"><span class="badge problem-badge" style="min-width: 28px; border: 1px solid"><span style="color: #000000;">${problemIndex}</span></span></a></th>`; }); tableHTML += '</tr></thead><tbody>'; tableHTML += '<tr class="sortorderswitch">'; tableHTML += `<td class="scorepl">${rank}</td>`; tableHTML += `<td class="scoreaf"> </td>`; tableHTML += `<td class="scoreaf"> </td>`; tableHTML += `<td class="scoretn">${teamname}</td>`; // tableHTML += `<td class="score-penalty-table"><div>${score}</div><div>${penalty}</div></td>`; tableHTML += `<td class="scorenc">${score}</td>`; tableHTML += `<td class="scorett">${penalty}</td>`; contestProblems.forEach(problemIndex => { if(!(problemIndex in problemStatus)) tableHTML += `<td class="score_cell"></td>`; else if(problemStatus[problemIndex].passtime != -1){ // console.log(problemIndex, problemStatus[problemIndex].passtime, problemStatus[problemIndex].pending, problemStatus[problemIndex].pendingNumber); if(problemStatus[problemIndex].passtime > problemStatus[problemIndex].pending && problemStatus[problemIndex].pendingNumber != 0){ const tryTime = problemStatus[problemIndex].rejected; const tryString = tryTime.toString() + " + " + (problemStatus[problemIndex].pendingNumber).toString() + " tries"; tableHTML += `<td class="score_cell"><a><div style="background:#6666FF"> <span>${tryString}</span></div></a></td>`; } else{ const tryTime = problemStatus[problemIndex].rejected+1; const tryString = tryTime.toString() + (tryTime > 1 ? " tries" : " try"); tableHTML += `<td class="score_cell"><a><div style="background:#60e760">${problemStatus[problemIndex].passtime}<span>${tryString}</span></div></a></td>`; } } else if(problemStatus[problemIndex].pendingNumber != 0){ const tryTime = problemStatus[problemIndex].rejected; const tryString = tryTime.toString() + " + " + (problemStatus[problemIndex].pendingNumber).toString() + " tries"; tableHTML += `<td class="score_cell"><a><div style="background:#6666FF"> <span>${tryString}</span></div></a></td>`; } else{ const tryTime = problemStatus[problemIndex].rejected; const tryString = tryTime.toString() + (tryTime > 1 ? " tries" : " try"); tableHTML += `<td class="score_cell"><a><div style="background:#e87272"> <span>${tryString}</span></div></a></td>`; } }); tableHTML += '</tr>'; tableHTML += '</tbody></table>'; submitForm = document.getElementById('pageContent').getElementsByTagName('form')[0]; document.getElementById('pageContent').innerHTML = tableHTML; } function drawSubmission(){ let tableHTML = '<div class="row><div class="col">'; tableHTML += '<h1 class="teamoverview">Submissions</h1>'; tableHTML += '<table class="data-table table table-hover table-striped table-sm submissions-table">' tableHTML += '<thead class="thead-light"><tr><th scope="col">time</th><th scope="col">problem</th><th scope="col">lang</th><th scope="col">result</th></tr></thead>'; tableHTML += '<tbody>'; submissionResult.forEach(Submission =>{ tableHTML += '<tr class>'; tableHTML += `<td>${Submission.time}</td>`; tableHTML += `<td class="probid"><a><span class="badge problem-badge" style="min-width: 28px;border: 1px solid #7293a8";><span>${Submission.index}</span></span><a></td>`; tableHTML += `<td class="langid"><a>${Submission.language}</a></td>`; if(Submission.verdict == "CORRECT") tableHTML += `<td class="sol sol_correct"><a>${Submission.verdict}</a></td>`; else if(Submission.verdict == "PENDING") tableHTML += `<td class="sol sol_queued"><a>${Submission.verdict}</a></td>`; else tableHTML += `<td class="sol sol_incorrect"><a>${Submission.verdict}</a></td>`; tableHTML += '</tr>'; }); tableHTML += '</tbody></table>'; tableHTML += '</div></div>'; document.getElementById('pageContent').innerHTML += tableHTML; document.getElementById('sidebar').innerHTML = ""; } addFontAwesome(); getApiData(); function domjudgeView() { // 遍歷所有的文本節點 let walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null, false); let node, nextNode; while (node = walker.nextNode()) { // 檢查節點是否包含 'on test' let textContent = node.nodeValue; let index = textContent.indexOf(' ON TEST'); if (index !== -1) { // 刪除 'on test' 及其後面的所有內容 node.nodeValue = textContent.substring(0, index); nextNode = walker.nextNode(); nextNode.nodeValue = ""; } else{ let pretestIndex = textContent.indexOf(' ON PRETEST'); if (pretestIndex !== -1) { // 刪除 'on pretest' 及其後面的所有內容 node.nodeValue = textContent.substring(0, pretestIndex); nextNode = walker.nextNode(); nextNode.nodeValue = ""; } } } } domjudgeView(); // 監聽 DOM 的變化以處理動態更新的內容 const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { // 針對新增的節點,重新執行移除操作 if (mutation.addedNodes.length) { // chrome.storage.sync.get(['featureEnabled'], function (result) { // if (result.featureEnabled) { // domjudgeView(); // updateTimeLine(); // } // }); domjudgeView(); updateTimeLine(); } }); }); // 配置監聽器參數 const observerConfig = { childList: true, // 監聽子節點變動 subtree: true, // 監聽整個子樹 characterData: true // 監聽文字內容變動 }; // 啟動監聽器 observer.observe(document.body, observerConfig); function humanReadableTimeDiff(seconds) { var intervals = [ ['years', 365 * 24 * 60 * 60], ['months', 30 * 24 * 60 * 60], ['days', 24 * 60 * 60], ['hours', 60 * 60], ['minutes', 60], ]; for (let [name, length] of intervals) { if (seconds / length >= 2) { return Math.floor(seconds/length) + ' ' + name; } } return Math.floor(seconds) + ' seconds'; } function humanReadableBytes(bytes) { var sizes = [ ['GB', 1024*1024*1024], ['MB', 1024*1024], ['KB', 1024], ]; for (let [name, length] of sizes) { if (bytes / length >= 2) { return Math.floor(bytes/length) + name; } } return Math.floor(bytes) + 'B'; } function addSubmitPage(){ // 創建模態框的 HTML let submitTable = submitForm.querySelector('tbody'); let rows = submitTable.querySelectorAll('tr'); submitTable.insertBefore(rows[4], rows[0]); submitTable.removeChild(rows[3]); submitForm.querySelector('.field-name').innerHTML = "Source files"; submitForm.querySelector('.programTypeNotice').remove(); submitForm.querySelector('.outputOnlyProgramTypeIdNotice').remove(); submitForm.querySelector(".error__submittedProblemIndex").remove(); let submitButInput = submitTable.querySelector(".submit"); let buttonElement = document.createElement("button"); buttonElement.id = submitButInput.id; buttonElement.type = submitButInput.type; buttonElement.className = submitButInput.className; buttonElement.innerHTML = `<i class="fas fa-cloud-upload-alt"></i> Submit `; // submitTable.replaceChild(buttonElement, submitButInput); buttonElement.classList.add('btn'); buttonElement.classList.add('btn-success'); const allowedLanguage = ["43", "89", "87", "31"]; const languageName = ["C", "CPP", "JAVA", "PYTHON3"]; const selectElement = submitForm.querySelector('select[name="programTypeId"]'); Array.from(selectElement.options).forEach(option => { if (!allowedLanguage.includes(option.value)) { option.remove(); } else{ for(let i = 0; i < allowedLanguage.length; i++){ if(allowedLanguage[i] == option.value){ option.innerHTML = languageName[i]; option.removeAttribute('selected'); break; } } } }); const noLanguageOption = document.createElement('option'); noLanguageOption.value = "0"; noLanguageOption.text = "Select a language"; noLanguageOption selectElement.insertBefore(noLanguageOption, selectElement.firstChild); // console.log(submitForm.outerHTML); // <span class="close">×</span> submitForm.querySelector('select[name="submittedProblemIndex"]').querySelector('option[value=""]').remove(); let submit_problem_option = submitForm.querySelector('select[name="submittedProblemIndex"]').innerHTML; let csrf_token_input = submitForm.querySelector('input[name="csrf_token"]').outerHTML; // console.log(submit_problem_option); const modalHTML = `<div id="myModal" class="modal fade show" tabindex="-1" role="dialog" aria-modal="true" style="display: none;"> <div class="modal-dialog modal-lg" role="document"><div class="modal-content"><div class="modal-header"><h5 class="modal-title">Submit</h5><button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button></div> <form class="submit-form" name="csrf_token" method="post" action="/team/submit" enctype="multipart/form-data">` + csrf_token_input + `<input type="hidden" name="ftaa" value=""> <input type="hidden" name="bfaa" value=""> <input type="hidden" name="action" value="submitSolutionFormSubmitted"> <div class="modal-body"> <div class="form-group"><label for="submit_problem_code" class="required">Source files</label><div class="custom-file"><input type="file" id="submit_problem_code" name="sourceFile" required="required" class="custom-file-input custom-file-input"><label class="custom-file-label text-truncate text-muted" for="submit_problem_code">No file selected</label></div></div> <div class="alert alert-warning" id="files_not_modified" style="display:none;"></div> <div class="form-group"><label class="required" for="submit_problem_problem">Problem</label><select id="submit_problem_problem" name="submittedProblemIndex" required="required" class="form-control custom-select form-control"><option value="" selected="selected">Select a problem</option>` + submit_problem_option + `</select></div> <div class="form-group"><label class="required" for="submit_problem_language">Language</label><select id="submit_problem_language" name="programTypeId" required="required" class="form-control custom-select form-control"><option value="" selected="selected">Select a language</option><option value="43">C</option><option value="89">C++</option><option value="87">Java</option><option value="31">Python 3</option></select></div></div> <div class="modal-footer"><button id="cancelBtn" type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button><button type="submit" class="btn-success btn"><i class="fas fa-cloud-upload-alt"></i> Submit </button></div><input type="hidden" name="_tta" value="396"></form></div></div> </div>`; // 插入模態框到頁面中 document.body.insertAdjacentHTML('beforeend', modalHTML); $(function () { $('body').on('change', '.custom-file-input', function () { var files = this.files; var fileNames = []; for (var i = 0; i < files.length; i++) { fileNames.push(files.item(i).name); } $(this).next('.custom-file-label').html(fileNames.join(", ")); $(this).next('.custom-file-label').removeClass('text-muted'); }); }); const fileInput = document.getElementById('submit_problem_code'); fileInput.addEventListener('change', (event) => { const five_minutes_in_ms = 5 * 60 * 1000; const now = Date.now(); const filesNotModified = document.getElementById('files_not_modified'); filesNotModified.style.display = 'none'; var atLeastOneFileRecent = false; var fileInfoHtml = ''; const files = event.target.files; for (let file of files) { const date = new Date(file.lastModified); const ago = humanReadableTimeDiff((now - date)/1000) + ' ago'; if (date > now - five_minutes_in_ms) { atLeastOneFileRecent = true; } let size = humanReadableBytes(file.size); fileInfoHtml += `<li><span class="filename">${file.name}</span>, ${size}, last modified ${ago}</li>`; } if (!atLeastOneFileRecent) { filesNotModified.style.display = 'block'; filesNotModified.innerHTML = 'None of the selected files has been recently modified:' + '<ul>' + fileInfoHtml + '</ul>'; } }); const modal_backdrop_html = `<div class="modal-backdrop fade show" style="display:none;"></div>`; document.body.insertAdjacentHTML('beforeend', modal_backdrop_html); // 把 input 按鈕換成 button // submitButInput = document.getElementById("singlePageSubmitButton"); // submitButInput.parentNode.insertBefore(buttonElement, submitButInput); // submitButInput.remove(); // 獲取模態框和觸發連結 const modal = document.getElementById('myModal'); const openModal = document.getElementById('submitbut'); const closeModal = document.querySelector('.close'); const cancelModal = document.getElementById('cancelBtn'); const modal_backdrop = document.querySelector('.modal-backdrop'); const filesNotModified = document.getElementById('files_not_modified'); // 當用戶點擊連結時,顯示模態框 openModal.addEventListener('click', function(event) { event.preventDefault(); // 防止連結跳轉 modal.style.display = 'block'; modal_backdrop.style.display = 'block'; }); // 當用戶點擊關閉按鈕時,隱藏模態框 closeModal.addEventListener('click', function() { modal.style.display = 'none'; modal_backdrop.style.display = 'none'; filesNotModified.style.display = 'none'; }); // 當用戶點擊模態框外部時,隱藏模態框 window.addEventListener('click', function(event) { if (event.target === modal) { modal.style.display = 'none'; modal_backdrop.style.display = 'none'; filesNotModified.style.display = 'none'; } }); cancelModal.addEventListener('click', function() { modal.style.display = 'none'; modal_backdrop.style.display = 'none'; filesNotModified.style.display = 'none'; }); } function getMainExtension(ext) { switch (ext) { case 'c': return '43'; case 'cpp': return '89'; case 'cc': return '89'; case 'cxx': return '89'; case 'c++': return '89'; case 'java': return '87'; case 'py': return '31'; default: return ''; } } function submitButtomJquery(){ $(document).ready(function () { { } var processFile = function () { var filename = $('#submit_problem_code').val(); if (filename !== '' && filename !== undefined) { filename = filename.replace(/^.*[\\\/]/, ''); var parts = filename.split('.').reverse(); if (parts.length < 2) return; var lcParts = [parts[0].toLowerCase(), parts[1].toLowerCase()]; // language ID var language = document.getElementById('submit_problem_language'); // the "autodetect" option has empty value if (language.value !== '') return; var langid = getMainExtension(lcParts[0]); for (i = 0; i < language.length; i++) { if (language.options[i].value === langid) { language.selectedIndex = i; } } // Problem ID var problem = document.getElementById('submit_problem_problem'); // the "autodetect" option has empty value if (problem.value !== '') { return; } for (var i = 0; i < problem.length; i++) { if (problem.options[i].text.split(/ - /)[0].toLowerCase() === lcParts[1]) { problem.selectedIndex = i; } } } }; var $body = $('body'); $body.on('change', '#submit_problem_code', processFile); }); const form = document.querySelector('.submit-form'); form.addEventListener('submit', function(event) { event.preventDefault(); const formData = new FormData(document.querySelector('.submit-form')); // for (const [key, value] of formData.entries()) { // console.log(key, value); // } var langelt = document.getElementById("submit_problem_language"); var language = langelt.options[langelt.selectedIndex].value; var languagetxt = langelt.options[langelt.selectedIndex].text; var fileelt = document.getElementById("submit_problem_code"); var filenames = fileelt.files; var filename = filenames[0].name; var probelt = document.getElementById("submit_problem_problem"); var problem = probelt.options[probelt.selectedIndex].value; var problemtxt = probelt.options[probelt.selectedIndex].text; var error = false; if (language === "") { langelt.focus(); langelt.className = langelt.className + " errorfield"; error = true; } if (problem === "") { probelt.focus(); probelt.className = probelt.className + " errorfield"; error = true; } if (filename === "") { error = true; } if (error) return false; var auxfileno = 0; // start at one; skip maincode file field for (var i = 1; i < filenames.length; i++) { if (filenames[i].value !== "") { auxfileno++; } } var extrafiles = ''; if (auxfileno > 0) { extrafiles = "Additional source files: " + auxfileno + '\n'; } var question = 'Main source file: ' + filename + '\n' + extrafiles + '\n' + 'Problem: ' + problemtxt + '\n' + 'Language: ' + languagetxt + '\n' + '\nMake submission?'; if(confirm(question)){ fetch(getCurrentURL().split('/').slice(0, 5).join('/')+'/submit?csrf_token='+formData.get('csrf_token'), { method: form.method, body: formData, }) .then(response => { if (response.ok) { location.reload(); } else { console.error('submit fail'); } }); } // .catch(error => { // console.error('error: ', error); // }); }); }
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址