AtCoder のコンテストページにおいて、問題タブをホバーするとドロップダウンリストを表示するようにします。
当前为
// ==UserScript==
// @name AtCoder Dropdown Tasks
// @namespace https://atcoder.jp/
// @version 2025-03-06
// @description AtCoder のコンテストページにおいて、問題タブをホバーするとドロップダウンリストを表示するようにします。
// @author magurofly
// @match https://atcoder.jp/contests/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=atcoder.jp
// @grant unsafeWindow
// @license CC0-1.0 Universal
// ==/UserScript==
(async function() {
'use strict';
const styleSheet = new CSSStyleSheet();
styleSheet.insertRule(`
.atcoder-dropdown-tasks:hover .dropdown-menu {
display: block;
}
`);
document.adoptedStyleSheets.push(styleSheet);
if (typeof unsafeWindow.contestScreenName !== "string") return;
const contestScreenName = unsafeWindow.contestScreenName;
const tasksHTML = await (await fetch(`/contests/${contestScreenName}/tasks`)).text();
const tasksDropdown = unsafeWindow.document.querySelector("#contest-nav-tabs > ul > li:nth-child(2)");
tasksDropdown.classList.add("atcoder-dropdown-tasks");
const tasksDropdownButton = tasksDropdown.querySelector("a");
tasksDropdownButton.insertAdjacentHTML("beforeend", `<span class="caret"></span>`);
const tasksDropdownContents = document.createElement("ul");
tasksDropdownContents.className = "dropdown-menu";
tasksDropdown.appendChild(tasksDropdownContents);
const tasksDoc = new DOMParser().parseFromString(tasksHTML, "text/html");
for (const row of tasksDoc.querySelectorAll("#main-container > div.row > div:nth-child(2) > div.panel.panel-default.table-responsive > table > tbody > tr")) {
const taskNum = row.cells[0].textContent;
const taskName = row.cells[1].textContent;
const taskURL = row.cells[0].children[0].href;
tasksDropdownContents.insertAdjacentHTML("beforeend", `<li><a href="${taskURL}">${taskNum} - ${taskName}</a></li>`);
}
})();