AtCoder Dropdown Tasks

AtCoder のコンテストページにおいて、問題タブをホバーするとドロップダウンリストを表示するようにします。

  1. // ==UserScript==
  2. // @name AtCoder Dropdown Tasks
  3. // @namespace https://atcoder.jp/
  4. // @version 2025-03-10
  5. // @description AtCoder のコンテストページにおいて、問題タブをホバーするとドロップダウンリストを表示するようにします。
  6. // @author magurofly
  7. // @match https://atcoder.jp/contests/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=atcoder.jp
  9. // @grant unsafeWindow
  10. // @license CC0-1.0 Universal
  11. // ==/UserScript==
  12.  
  13. (async function() {
  14. 'use strict';
  15.  
  16. if (typeof unsafeWindow.contestScreenName !== "string") return;
  17. const contestScreenName = unsafeWindow.contestScreenName;
  18.  
  19. const styleSheet = new CSSStyleSheet();
  20. styleSheet.insertRule(`
  21. .atcoder-dropdown-tasks:hover .dropdown-menu {
  22. display: block;
  23. }
  24. `);
  25. document.adoptedStyleSheets.push(styleSheet);
  26.  
  27. const tasksDropdown = unsafeWindow.document.querySelector("#contest-nav-tabs > ul > li:nth-child(2)");
  28. tasksDropdown.classList.add("atcoder-dropdown-tasks");
  29.  
  30. const tasksDropdownButton = tasksDropdown.querySelector("a");
  31. tasksDropdownButton.insertAdjacentHTML("beforeend", `<span class="caret"></span>`);
  32.  
  33. const tasksDropdownContents = document.createElement("ul");
  34. tasksDropdownContents.className = "dropdown-menu";
  35. tasksDropdown.appendChild(tasksDropdownContents);
  36.  
  37. const tasksHTML = await (await fetch(`/contests/${contestScreenName}/tasks`)).text();
  38. const tasksDoc = new DOMParser().parseFromString(tasksHTML, "text/html");
  39. for (const row of tasksDoc.querySelectorAll("#main-container > div.row > div:nth-child(2) > div.panel.panel-default.table-responsive > table > tbody > tr")) {
  40. const taskNum = row.cells[0].textContent;
  41. const taskName = row.cells[1].textContent;
  42. const taskURL = row.cells[0].children[0].href;
  43. const link = document.createElement("a");
  44. link.href = taskURL;
  45. link.textContent = `${taskNum} - ${taskName}`;
  46. link.style.fontFamily = "monospace";
  47. const li = document.createElement("li");
  48. li.appendChild(link);
  49. tasksDropdownContents.appendChild(li);
  50. }
  51. })();