From ecdbd0f2c96e33e707424c0c2029310082a87be1 Mon Sep 17 00:00:00 2001 From: Dominik Korsa Date: Fri, 13 Jan 2023 16:47:54 +0100 Subject: [PATCH 1/9] Add links to problems in results --- ext/js/background.js | 16 ++++++++++++++++ ext/js/common.js | 18 ++++++++++++++++++ ext/js/problems.js | 26 ++++++++++++++++++++------ ext/js/results-list.js | 2 ++ ext/js/results.js | 1 + ext/manifest.json | 7 ++++++- 6 files changed, 63 insertions(+), 7 deletions(-) diff --git a/ext/js/background.js b/ext/js/background.js index b6d7457..21294b9 100644 --- a/ext/js/background.js +++ b/ext/js/background.js @@ -281,6 +281,18 @@ }); } + function saveContestProblemList(contestID, problems) { + storage.set({ + [`contest-problems/${contestID}`]: problems + }); + console.log(storage.get()); + } + + async function getProblemList(contestID) { + const key = `contest-problems/${contestID}`; + return (await storage.get(key))[key] ?? {}; + } + retrieveLastContestID(); setUpLastContestRedirect(); setUpSubmitRedirect(); @@ -307,6 +319,10 @@ }); } else if (request.action === 'injectHighlightJsCss') { injectHighlightJsCss(sender.tab); + } else if (request.action === 'saveContestProblemList') { + saveContestProblemList(request.contestID, request.problems); + } else if (request.action === 'getContestProblemList') { + return getProblemList(request.contestID); } return new Promise(resolve => resolve(null)); }); diff --git a/ext/js/common.js b/ext/js/common.js index 9cdf175..bee5b7f 100644 --- a/ext/js/common.js +++ b/ext/js/common.js @@ -12,3 +12,21 @@ if (typeof module !== 'undefined') { getContestID }; } + +function updateProblemList(column) { + browser.runtime.sendMessage({ + action: 'getContestProblemList', + contestID: getContestID(document.location.href), + }).then((problems) => { + console.log(getContestID(document.location.href), problems); + for (const el of $(`table.results > tbody > tr:not(:first-of-type) > td:nth-child(${column})`)) { + const code = $(el).text(); + const problem = problems[code]; + if (!problem) continue; + const link = $(''); + link.attr('href', problem.href); + link.text(`${code} - ${problem.title}`) + $(el).empty().append(link); + } + }); +} diff --git a/ext/js/problems.js b/ext/js/problems.js index 65414f7..34c4148 100644 --- a/ext/js/problems.js +++ b/ext/js/problems.js @@ -257,16 +257,30 @@ }); } - hideProblemGroups(); - connectGroupHideLinks(); - const table = $('table.results'); - table.each((index, table) => processProblemGroup($(table))); - - // "Results" constants const contestID = getContestID(document.location.href); const resultsURL = `${SATORI_URL_HTTPS}contest/${contestID}/results`; + function saveProblemList() { + const problems = Object.fromEntries($.find('#content table.results tr:not(:first-of-type)').map((el) => [ + $(el).find('td:nth-child(1)').text(), + { + href: $(el).find('td:nth-child(2) a').attr('href'), + title: $(el).find('td:nth-child(2)').text(), + } + ])); + browser.runtime.sendMessage({ + action: 'saveContestProblemList', + contestID, + problems, + }); + } + + saveProblemList(); + hideProblemGroups(); + connectGroupHideLinks(); + const table = $('table.results'); + table.each((index, table) => processProblemGroup($(table))); // "Results" button const submitUrlRegex = /submit\?select=(\d+)/; diff --git a/ext/js/results-list.js b/ext/js/results-list.js index 075e1ae..34dc279 100644 --- a/ext/js/results-list.js +++ b/ext/js/results-list.js @@ -9,4 +9,6 @@ 'tr:nth-child(2) > td:first > a').attr('href'); } }); + + updateProblemList(2); })(); diff --git a/ext/js/results.js b/ext/js/results.js index 17b04bc..2f2645a 100644 --- a/ext/js/results.js +++ b/ext/js/results.js @@ -85,4 +85,5 @@ } initializeSyntaxHighlighter(); + updateProblemList(3); })(); diff --git a/ext/manifest.json b/ext/manifest.json index 2ee7fbf..8d3cdf2 100644 --- a/ext/manifest.json +++ b/ext/manifest.json @@ -104,10 +104,14 @@ "css": ["css/problems.css"] }, { - "matches": ["*://satori.tcs.uj.edu.pl/contest/*/results"], + "matches": [ + "*://satori.tcs.uj.edu.pl/contest/*/results", + "*://satori.tcs.uj.edu.pl/contest/*/results?*" + ], "js": [ "vendor/browser-polyfill.js", "vendor/bower/jquery.min.js", + "js/common.js", "js/results-list.js" ], "run_at": "document_end" @@ -119,6 +123,7 @@ "vendor/bower/jquery.min.js", "vendor/bower/highlight.pack.min.js", "vendor/bower/highlightjs-line-numbers.min.js", + "js/common.js", "js/results.js" ], "run_at": "document_end", From 87e9d10495d0505978fc300e81d85368f53f34ef Mon Sep 17 00:00:00 2001 From: Dominik Korsa Date: Fri, 13 Jan 2023 18:10:21 +0100 Subject: [PATCH 2/9] Don't persist problem list --- ext/js/background.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/ext/js/background.js b/ext/js/background.js index 21294b9..82e2672 100644 --- a/ext/js/background.js +++ b/ext/js/background.js @@ -22,6 +22,8 @@ */ let contestResultsRedirects = new Set(); + const contestProblemList = {}; + function displayStatusNotification(submitID, problemCode, status) { browser.notifications.create({ type: 'basic', @@ -282,15 +284,11 @@ } function saveContestProblemList(contestID, problems) { - storage.set({ - [`contest-problems/${contestID}`]: problems - }); - console.log(storage.get()); + contestProblemList[contestID] = problems; } async function getProblemList(contestID) { - const key = `contest-problems/${contestID}`; - return (await storage.get(key))[key] ?? {}; + return contestProblemList[contestID]; } retrieveLastContestID(); From 4a3e101b9fed38addee275e2b131137e22d9dedb Mon Sep 17 00:00:00 2001 From: Dominik Korsa Date: Fri, 13 Jan 2023 19:18:45 +0100 Subject: [PATCH 3/9] Fix problem link when there is no statement --- ext/js/background.js | 3 ++- ext/js/common.js | 13 +++++++++---- ext/js/problems.js | 6 ++++-- ext/js/results-list.js | 2 +- ext/js/results.js | 2 +- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/ext/js/background.js b/ext/js/background.js index 82e2672..d90f097 100644 --- a/ext/js/background.js +++ b/ext/js/background.js @@ -288,7 +288,8 @@ } async function getProblemList(contestID) { - return contestProblemList[contestID]; + // TODO: Fetch problem list + return contestProblemList[contestID] ?? {}; } retrieveLastContestID(); diff --git a/ext/js/common.js b/ext/js/common.js index bee5b7f..a64e287 100644 --- a/ext/js/common.js +++ b/ext/js/common.js @@ -13,19 +13,24 @@ if (typeof module !== 'undefined') { }; } -function updateProblemList(column) { +function updateProblemList(isResultList) { + const column = isResultList ? 2 : 3; browser.runtime.sendMessage({ action: 'getContestProblemList', contestID: getContestID(document.location.href), }).then((problems) => { - console.log(getContestID(document.location.href), problems); for (const el of $(`table.results > tbody > tr:not(:first-of-type) > td:nth-child(${column})`)) { const code = $(el).text(); const problem = problems[code]; if (!problem) continue; + const statementHref = problem.href || problem.pdfHref; + if (!statementHref) { + $(el).text(`${code} - ${problem.title}`); + return; + } const link = $(''); - link.attr('href', problem.href); - link.text(`${code} - ${problem.title}`) + link.attr('href', statementHref); + link.text(`${code} - ${problem.title}`); $(el).empty().append(link); } }); diff --git a/ext/js/problems.js b/ext/js/problems.js index 34c4148..68aa80f 100644 --- a/ext/js/problems.js +++ b/ext/js/problems.js @@ -265,8 +265,10 @@ const problems = Object.fromEntries($.find('#content table.results tr:not(:first-of-type)').map((el) => [ $(el).find('td:nth-child(1)').text(), { - href: $(el).find('td:nth-child(2) a').attr('href'), - title: $(el).find('td:nth-child(2)').text(), + title: $(el).find('td:nth-child(2)').text(), + href: $(el).find('td:nth-child(2) a').attr('href'), + pdfHref: $(el).find('td:nth-child(3) a').attr('href'), + submitHref: $(el).find('td:nth-child(5) a').attr('href'), } ])); browser.runtime.sendMessage({ diff --git a/ext/js/results-list.js b/ext/js/results-list.js index 34dc279..43b4d09 100644 --- a/ext/js/results-list.js +++ b/ext/js/results-list.js @@ -10,5 +10,5 @@ } }); - updateProblemList(2); + updateProblemList(true); })(); diff --git a/ext/js/results.js b/ext/js/results.js index 2f2645a..6d9a3fb 100644 --- a/ext/js/results.js +++ b/ext/js/results.js @@ -85,5 +85,5 @@ } initializeSyntaxHighlighter(); - updateProblemList(3); + updateProblemList(false); })(); From 2f1d4f154b46d1e63e773e1c6860195876c07469 Mon Sep 17 00:00:00 2001 From: Dominik Korsa Date: Fri, 13 Jan 2023 19:51:24 +0100 Subject: [PATCH 4/9] Add results button to problem page --- ext/js/common.js | 18 ++++++++++++++++-- ext/js/config.js | 5 ++++- ext/js/problem.js | 9 +++++++++ ext/manifest.json | 13 +++++++++++++ ext/scss/problem.scss | 5 +++++ 5 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 ext/js/problem.js create mode 100644 ext/scss/problem.scss diff --git a/ext/js/common.js b/ext/js/common.js index a64e287..5272be6 100644 --- a/ext/js/common.js +++ b/ext/js/common.js @@ -4,12 +4,26 @@ * @returns {string} contest ID */ function getContestID(url) { - return PROBLEM_URL_REGEX.exec(url)[1]; + return CONTEST_URL_REGEX.exec(url)[1]; +} + +/** + * Parse given problem URL and return the contest and problem ID. + * @param {string} url URL to parse + * @returns {object} contest and problem ID + */ +function getContestAndProblemID(url) { + const match = PROBLEM_URL_REGEX.exec(url); + return { + contestID: match[1], + problemID: match[2], + } } if (typeof module !== 'undefined') { module.exports = { - getContestID + getContestID, + getContestAndProblemID, }; } diff --git a/ext/js/config.js b/ext/js/config.js index 7567322..88fd584 100644 --- a/ext/js/config.js +++ b/ext/js/config.js @@ -1,8 +1,10 @@ const SATORI_URL = 'satori.tcs.uj.edu.pl/'; const SATORI_URL_HTTP = 'http://' + SATORI_URL; const SATORI_URL_HTTPS = 'https://' + SATORI_URL; -const PROBLEM_URL_REGEX = +const CONTEST_URL_REGEX = /https:\/\/satori\.tcs\.uj\.edu\.pl\/contest\/(\d+)\//; +const PROBLEM_URL_REGEX = + /https:\/\/satori\.tcs\.uj\.edu\.pl\/contest\/(\d+)\/problems\/(\d+)/; const CHOSEN_LOGO_PRIMARY_KEY = 'chosenLogo_primary'; const CHOSEN_LOGO_SECONDARY_KEY = 'chosenLogo_secondary'; @@ -42,6 +44,7 @@ if (typeof module !== 'undefined') { SATORI_URL, SATORI_URL_HTTP, SATORI_URL_HTTPS, + CONTEST_URL_REGEX, PROBLEM_URL_REGEX, CHOSEN_LOGO_PRIMARY_KEY, diff --git a/ext/js/problem.js b/ext/js/problem.js new file mode 100644 index 0000000..7a82b2b --- /dev/null +++ b/ext/js/problem.js @@ -0,0 +1,9 @@ +(function () { + 'use strict'; + + const { contestID, problemID } = getContestAndProblemID(document.location.href); + console.log(contestID, problemID); + $('Results') + .attr('href', `${SATORI_URL_HTTPS}contest/${contestID}/results?results_filter_problem=${problemID}`) + .appendTo('#content > .buttton_bar') +})(); diff --git a/ext/manifest.json b/ext/manifest.json index 8d3cdf2..044a829 100644 --- a/ext/manifest.json +++ b/ext/manifest.json @@ -103,6 +103,19 @@ "run_at": "document_end", "css": ["css/problems.css"] }, + { + "matches": ["*://satori.tcs.uj.edu.pl/contest/*/problems/*"], + "js": [ + "vendor/browser-polyfill.js", + "vendor/bower/jquery.min.js", + "js/common.js", + "js/problem.js" + ], + "run_at": "document_end", + "css": [ + "css/problem.css" + ] + }, { "matches": [ "*://satori.tcs.uj.edu.pl/contest/*/results", diff --git a/ext/scss/problem.scss b/ext/scss/problem.scss new file mode 100644 index 0000000..fa82782 --- /dev/null +++ b/ext/scss/problem.scss @@ -0,0 +1,5 @@ +#content { + .buttton_bar { + margin-top: 1em; + } +} From 3ab34aa1318c670bffcd56a8a6d458556bcd6d4a Mon Sep 17 00:00:00 2001 From: Dominik Korsa Date: Fri, 13 Jan 2023 19:56:24 +0100 Subject: [PATCH 5/9] Fix problem list resetting --- ext/js/problem.js | 1 - ext/manifest.json | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ext/js/problem.js b/ext/js/problem.js index 7a82b2b..096581c 100644 --- a/ext/js/problem.js +++ b/ext/js/problem.js @@ -2,7 +2,6 @@ 'use strict'; const { contestID, problemID } = getContestAndProblemID(document.location.href); - console.log(contestID, problemID); $('Results') .attr('href', `${SATORI_URL_HTTPS}contest/${contestID}/results?results_filter_problem=${problemID}`) .appendTo('#content > .buttton_bar') diff --git a/ext/manifest.json b/ext/manifest.json index 044a829..8de01a8 100644 --- a/ext/manifest.json +++ b/ext/manifest.json @@ -93,7 +93,10 @@ ] }, { - "matches": ["*://satori.tcs.uj.edu.pl/contest/*/problems*"], + "matches": [ + "*://satori.tcs.uj.edu.pl/contest/*/problems", + "*://satori.tcs.uj.edu.pl/contest/*/problems?*" + ], "js": [ "vendor/browser-polyfill.js", "vendor/bower/jquery.min.js", From 24c978048a679db03bd169072a5df5c80bf12480 Mon Sep 17 00:00:00 2001 From: Dominik Korsa Date: Fri, 13 Jan 2023 20:28:25 +0100 Subject: [PATCH 6/9] And "Submit other" and "All submissions" buttons to result page --- ext/js/common.js | 37 ++++++++++++++++++++----------------- ext/js/results.js | 16 +++++++++++++++- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/ext/js/common.js b/ext/js/common.js index 5272be6..6de9b53 100644 --- a/ext/js/common.js +++ b/ext/js/common.js @@ -27,25 +27,28 @@ if (typeof module !== 'undefined') { }; } -function updateProblemList(isResultList) { +async function updateProblemList(isResultList) { const column = isResultList ? 2 : 3; - browser.runtime.sendMessage({ + const problems = await browser.runtime.sendMessage({ action: 'getContestProblemList', contestID: getContestID(document.location.href), - }).then((problems) => { - for (const el of $(`table.results > tbody > tr:not(:first-of-type) > td:nth-child(${column})`)) { - const code = $(el).text(); - const problem = problems[code]; - if (!problem) continue; - const statementHref = problem.href || problem.pdfHref; - if (!statementHref) { - $(el).text(`${code} - ${problem.title}`); - return; - } - const link = $(''); - link.attr('href', statementHref); - link.text(`${code} - ${problem.title}`); - $(el).empty().append(link); - } }); + + let submitHref; + for (const el of $(`table.results > tbody > tr:not(:first-of-type) > td:nth-child(${column})`)) { + const code = $(el).text(); + const problem = problems[code]; + if (!problem) continue; + if (problem.submitHref) submitHref = problem.submitHref; + const statementHref = problem.href || problem.pdfHref; + if (!statementHref) { + $(el).text(`${code} - ${problem.title}`); + continue; + } + const link = $(''); + link.attr('href', statementHref); + link.text(`${code} - ${problem.title}`); + $(el).empty().append(link); + } + return submitHref; } diff --git a/ext/js/results.js b/ext/js/results.js index 6d9a3fb..4d8aaaa 100644 --- a/ext/js/results.js +++ b/ext/js/results.js @@ -17,6 +17,7 @@ let problemStatus = tr.find('td:last').text(); let url = document.location.href; + const contestID = getContestID(url); /** * Parse given HTML and return problem status code if it's found. @@ -84,6 +85,19 @@ }); } + const submitUrlRegex = /submit\?select=(\d+)/; + initializeSyntaxHighlighter(); - updateProblemList(false); + updateProblemList(false).then((submitUrl) => { + if (!submitUrl) return; + const submitID = submitUrlRegex.exec(submitUrl)[1]; + const submitButton = $('Submit another') + .attr('href', submitUrl); + const resultsButton = $('All submissions') + .attr('href', `${SATORI_URL_HTTPS}contest/${contestID}/results?results_filter_problem=${submitID}`); + $('
') + .append(submitButton) + .append(resultsButton) + .insertAfter('#content .results') + }); })(); From e969a96d571c9da8abda3e45bd86d78ebe30a4b9 Mon Sep 17 00:00:00 2001 From: Dominik Korsa Date: Fri, 13 Jan 2023 21:31:36 +0100 Subject: [PATCH 7/9] Load problem list on demand --- ext/js/background.js | 10 +++++++++- ext/js/common.js | 18 +++++++++++++++++- ext/js/problems.js | 22 +++++----------------- ext/js/results-list.js | 2 +- ext/js/results.js | 2 +- ext/manifest.json | 1 + 6 files changed, 34 insertions(+), 21 deletions(-) diff --git a/ext/js/background.js b/ext/js/background.js index d90f097..f5eaed8 100644 --- a/ext/js/background.js +++ b/ext/js/background.js @@ -288,7 +288,15 @@ } async function getProblemList(contestID) { - // TODO: Fetch problem list + if (!contestProblemList[contestID]) { + try { + const response = await fetch(`${SATORI_URL_HTTPS}contest/${contestID}/problems`); + if (!response.ok) throw new Error(`HTTP Status ${response.status}`); + contestProblemList[contestID] = parseProblemList($.parseHTML(await response.text())); + } catch (error) { + console.error(error); + } + } return contestProblemList[contestID] ?? {}; } diff --git a/ext/js/common.js b/ext/js/common.js index 6de9b53..fc442f6 100644 --- a/ext/js/common.js +++ b/ext/js/common.js @@ -27,7 +27,23 @@ if (typeof module !== 'undefined') { }; } -async function updateProblemList(isResultList) { +function parseProblemList(jqueryHandles) { + return Object.fromEntries(jqueryHandles.flatMap( + (el) => [...$(el).find('#content table.results tr:not(:first-of-type)')].map( + (tr) => [ + $(tr).find('td:nth-child(1)').text(), + { + title: $(tr).find('td:nth-child(2)').text(), + href: $(tr).find('td:nth-child(2) a').attr('href'), + pdfHref: $(tr).find('td:nth-child(3) a').attr('href'), + submitHref: $(tr).find('td:nth-child(5) a').attr('href'), + } + ] + )) + ); +} + +async function insertProblemLinks(isResultList) { const column = isResultList ? 2 : 3; const problems = await browser.runtime.sendMessage({ action: 'getContestProblemList', diff --git a/ext/js/problems.js b/ext/js/problems.js index 68aa80f..124ef5f 100644 --- a/ext/js/problems.js +++ b/ext/js/problems.js @@ -261,24 +261,12 @@ const contestID = getContestID(document.location.href); const resultsURL = `${SATORI_URL_HTTPS}contest/${contestID}/results`; - function saveProblemList() { - const problems = Object.fromEntries($.find('#content table.results tr:not(:first-of-type)').map((el) => [ - $(el).find('td:nth-child(1)').text(), - { - title: $(el).find('td:nth-child(2)').text(), - href: $(el).find('td:nth-child(2) a').attr('href'), - pdfHref: $(el).find('td:nth-child(3) a').attr('href'), - submitHref: $(el).find('td:nth-child(5) a').attr('href'), - } - ])); - browser.runtime.sendMessage({ - action: 'saveContestProblemList', - contestID, - problems, - }); - } + browser.runtime.sendMessage({ + action: 'saveContestProblemList', + contestID, + problems: parseProblemList([$]), + }); - saveProblemList(); hideProblemGroups(); connectGroupHideLinks(); const table = $('table.results'); diff --git a/ext/js/results-list.js b/ext/js/results-list.js index 43b4d09..ccabc95 100644 --- a/ext/js/results-list.js +++ b/ext/js/results-list.js @@ -10,5 +10,5 @@ } }); - updateProblemList(true); + insertProblemLinks(true); })(); diff --git a/ext/js/results.js b/ext/js/results.js index 4d8aaaa..9daa500 100644 --- a/ext/js/results.js +++ b/ext/js/results.js @@ -88,7 +88,7 @@ const submitUrlRegex = /submit\?select=(\d+)/; initializeSyntaxHighlighter(); - updateProblemList(false).then((submitUrl) => { + insertProblemLinks(false).then((submitUrl) => { if (!submitUrl) return; const submitID = submitUrlRegex.exec(submitUrl)[1]; const submitButton = $('Submit another') diff --git a/ext/manifest.json b/ext/manifest.json index 8de01a8..783abf3 100644 --- a/ext/manifest.json +++ b/ext/manifest.json @@ -43,6 +43,7 @@ "background": { "scripts": [ "vendor/browser-polyfill.js", + "vendor/bower/jquery.min.js", "js/config.js", "js/common.js", "js/background.js" From d01fbd1cc4c4024eccf2edc4ecb06515a371ed09 Mon Sep 17 00:00:00 2001 From: Dominik Korsa Date: Fri, 13 Jan 2023 22:19:24 +0100 Subject: [PATCH 8/9] Add Submit another button to filtered result list page --- ext/js/results-list.js | 11 +++++++++++ ext/js/results.js | 6 +++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/ext/js/results-list.js b/ext/js/results-list.js index ccabc95..b28c210 100644 --- a/ext/js/results-list.js +++ b/ext/js/results-list.js @@ -10,5 +10,16 @@ } }); + const contestID = getContestID(document.location.href); + + function addCompareSubmitsButton() { + const problemID = new URLSearchParams(document.location.search).get('results_filter_problem'); + if (!problemID || !/^\d+$/.test(problemID)) return; + $(`Submit another`) + .attr('href', `${SATORI_URL_HTTPS}contest/${contestID}/submit?select=${problemID}`) + .appendTo('#content .button_bar') + } + + addCompareSubmitsButton(); insertProblemLinks(true); })(); diff --git a/ext/js/results.js b/ext/js/results.js index 9daa500..c0c0c64 100644 --- a/ext/js/results.js +++ b/ext/js/results.js @@ -91,13 +91,13 @@ insertProblemLinks(false).then((submitUrl) => { if (!submitUrl) return; const submitID = submitUrlRegex.exec(submitUrl)[1]; - const submitButton = $('Submit another') - .attr('href', submitUrl); const resultsButton = $('All submissions') .attr('href', `${SATORI_URL_HTTPS}contest/${contestID}/results?results_filter_problem=${submitID}`); + const submitButton = $('Submit another') + .attr('href', submitUrl); $('
') - .append(submitButton) .append(resultsButton) + .append(submitButton) .insertAfter('#content .results') }); })(); From 65958aae5e69135df00330f25fd29c82eb848f24 Mon Sep 17 00:00:00 2001 From: Dominik Korsa Date: Sat, 14 Jan 2023 11:57:04 +0100 Subject: [PATCH 9/9] Add results sidebar to problem page --- ext/js/problem.js | 43 ++++++++++++++++++++++++++++++++++++++++++- ext/scss/problem.scss | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 73 insertions(+), 4 deletions(-) diff --git a/ext/js/problem.js b/ext/js/problem.js index 096581c..34b235d 100644 --- a/ext/js/problem.js +++ b/ext/js/problem.js @@ -2,7 +2,48 @@ 'use strict'; const { contestID, problemID } = getContestAndProblemID(document.location.href); + const resultsUrl = `${SATORI_URL_HTTPS}contest/${contestID}/results?results_filter_problem=${problemID}`; $('Results') - .attr('href', `${SATORI_URL_HTTPS}contest/${contestID}/results?results_filter_problem=${problemID}`) + .attr('href', resultsUrl) .appendTo('#content > .buttton_bar') + + function parseResultsPage(html) { + for (const x of $.parseHTML(html)) { + const content = $(x).find('#content'); + if (content.length > 0) return content; + } + } + + async function loadResults() { + const response = await fetch(`${resultsUrl}&results_limit=20`); + if (!response.ok) throw Error(`Results request failed with HTTP status code ${response.status}`); + const content = parseResultsPage(await response.text()); + const table = content.find('> table.results'); + if (!table) return; + table.find('td:nth-child(2), th:nth-child(2)').remove(); + + if (table.find('tr:not(:first-child)').length === 0) { + $('No submissions yet') + .appendTo(table); + } + + // Page selector has more than one page - show link to see all submissions + if (content.find('> .wheel > a.wheelitem').length > 0) { + const row = $('See more submissions'); + row.find('a').attr('href', resultsUrl); + table.append(row); + } + + $( + '
' + + '

Recent submission results

' + + '
' + ) + .append(table) + .insertAfter('#content'); + } + + loadResults().catch((error) => { + console.error('Failed to load recent submissions', error); + }); })(); diff --git a/ext/scss/problem.scss b/ext/scss/problem.scss index fa82782..1f26e83 100644 --- a/ext/scss/problem.scss +++ b/ext/scss/problem.scss @@ -1,5 +1,33 @@ -#content { - .buttton_bar { - margin-top: 1em; +#container > .colmask > .colmid > .colleft > .col1 { + display: grid; + grid-template-columns: 1fr 300px; + + #content { + grid-column: 1; + + .buttton_bar { + margin-top: 1em; + } + } + + #results-sidebar { + grid-column: 2; + margin-top: -1em; + } + + @media screen and (max-width: 1200px) { + grid-template-columns: 1fr; + grid-template-rows: auto auto; + + #content { + grid-row: 1; + } + + #results-sidebar { + border-top: 1px dotted #A1A39D; + grid-column: 1; + grid-row: 2; + margin: 0 1em 1em; + } } }