AtCoder Copy Contest ID

Add a button to copy the contest ID to the clipboard in AtCoder contest pages

As of 2023-04-16. See the latest version.

  1. // ==UserScript==
  2. // @name AtCoder Copy Contest ID
  3. // @name:ja AtCoder Copy Contest ID
  4. // @namespace https://github.com/xe-o
  5. // @version 0.2
  6. // @description Add a button to copy the contest ID to the clipboard in AtCoder contest pages
  7. // @description:ja AtCoderコンテストページのナビゲーションバーへ、コンテストIDをコピーするためのボタンを追加します
  8. // @author XERO
  9. // @license MIT
  10. // @match https://atcoder.jp/*
  11. // @grant GM_setClipboard
  12. // @run-at document-idle
  13. // ==/UserScript==
  14.  
  15. const COPY_BUTTON_LABEL_INIT = "Copy Contest ID";
  16. const COPY_BUTTON_HTML = `
  17. <li>
  18. <a id="contest-id-copy-button" style="cursor: pointer; font-size: 12px">
  19. <span class="glyphicon glyphicon-copy" style="margin-right: 2px" aria-hidden="true"></span>
  20. <span id="copy-button-text">${COPY_BUTTON_LABEL_INIT}</span>
  21. </a>
  22. </li>`;
  23.  
  24. const copyContestId = (() => {
  25. const $ = (selector, baseElement) =>
  26. (baseElement || document).querySelector(selector);
  27. const getContestID = () => window.location.pathname.split("/")[2];
  28. return () => {
  29. const navbarElement = $(".navbar-nav");
  30. if (!navbarElement) throw new Error("Navbar element not found.");
  31. navbarElement.insertAdjacentHTML("beforeend", COPY_BUTTON_HTML);
  32.  
  33. const copyButton = $("#contest-id-copy-button");
  34. copyButton.removeEventListener("click", copyToClipboard);
  35. const copyButtonIcon = $(".glyphicon", copyButton);
  36. const copyButtonLabel = $("#copy-button-text");
  37.  
  38. async function copyToClipboard() {
  39. try {
  40. await GM_setClipboard(getContestID(), {
  41. type: "text",
  42. mimetype: "text/plain",
  43. });
  44. copyButtonIcon.classList.replace("glyphicon-copy", "glyphicon-ok");
  45. } catch (error) {
  46. console.error(`Failed to copy contest ID: ${error}`);
  47. copyButtonIcon.classList.replace("glyphicon-copy", "glyphicon-remove");
  48. } finally {
  49. const copyResultText = copyButtonIcon.classList.contains("glyphicon-ok")
  50. ? "Copied!"
  51. : "Failed to copy";
  52. copyButtonLabel.textContent = copyResultText;
  53. setTimeout(() => {
  54. copyButtonLabel.textContent = COPY_BUTTON_LABEL_INIT;
  55. copyButtonIcon.classList.replace(
  56. "glyphicon-ok",
  57. "glyphicon-copy",
  58. "glyphicon-remove"
  59. );
  60. }, 1800);
  61. }
  62. }
  63.  
  64. copyButton.addEventListener("click", copyToClipboard);
  65. };
  66. })();
  67.  
  68. copyContestId();