AtCoder: すべての入出力を一度でコピー

サンプル入出力を一度にコピーできるボタンを追加します

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

You will need to install an extension such as Tampermonkey to install this script.

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         AtCoder: All Samples At Once
// @namespace    https://atcoder.jp/
// @version      2.2
// @name:ja      AtCoder: すべての入出力を一度でコピー
// @license MIT
// @description  Adds buttons to copy sample inputs/outputs
// @description:ja サンプル入出力を一度にコピーできるボタンを追加します
// @match        https://atcoder.jp/contests/*/tasks/*
// @grant        GM_setClipboard
// ==/UserScript==

(() => {
  'use strict';

  function g(t) {
    return [...document.querySelectorAll("h3")]
      .filter(h => h.textContent.includes(t))
      .map(h => {
        const p = h.parentElement.querySelector("pre");
        return p ? p.innerText.trim() : "";
      })
      .filter(Boolean);
  }

  function c(text) {
    if (typeof GM_setClipboard !== "undefined") {
      GM_setClipboard(text);
    } else {
      navigator.clipboard.writeText(text);
    }
  }

  function btn(title, text) {
    const b = document.createElement("button");
    b.textContent = title + " Copy";
    b.className = "btn btn-default btn-sm";
    b.onclick = () => {
      c(text);
      b.textContent = "Copied!";
      setTimeout(() => (b.textContent = title + " Copy"), 1000);
    };
    return b;
  }

  function findInsertPoint() {
    const headers = [...document.querySelectorAll("h3")];
    const inputHeader = headers.find(h => h.textContent.trim() === "入力");
    const outputHeader = headers.find(h => h.textContent.trim() === "出力");

    return outputHeader
      ? outputHeader.nextElementSibling
      : (inputHeader ? inputHeader.nextElementSibling : document.querySelector("#task-statement"));
  }

  const target = document.querySelector("#task-statement");
  if (!target || document.querySelector("#sample-copy-buttons")) return;

  const ins = g("入力例");
  const outs = g("出力例");

  const allIn = ins.length + "\n" + ins.join("\n");
  const allOut = "==========\n" + outs.join("\n==========\n") + "\n==========";

  const wrap = document.createElement("div");
  wrap.id = "sample-copy-buttons";
  wrap.style.margin = "10px 0";
  wrap.style.padding = "8px";
  wrap.style.border = "1px solid #ddd";
  wrap.style.background = "#fff";
  wrap.style.display = "flex";
  wrap.style.gap = "10px";
  wrap.style.alignItems = "center";

  wrap.appendChild(btn("Inputs", allIn));
  wrap.appendChild(btn("Outputs", allOut));

  // ----------------------------
  // Submit button (fixed)
  // ----------------------------

  const submit = document.createElement("a");
  submit.textContent = "Submit";
  submit.className = "btn btn-default btn-sm";
  submit.style.textDecoration = "none";
  submit.style.display = "inline-flex";
  submit.style.alignItems = "center";

  const contestMatch = location.href.match(/contests\/([^/]+)\//);
  const contest = contestMatch ? contestMatch[1] : "";

  // Reliable task detection (FIX)
  const taskInput = document.querySelector('input[name="data.TaskScreenName"]');
  const task = taskInput ? taskInput.value : "";

  submit.href = `https://atcoder.jp/contests/${contest}/submit?taskScreenName=${task}`;

  wrap.appendChild(submit);

  const insertPoint = findInsertPoint();

  if (insertPoint && insertPoint.parentNode) {
    insertPoint.parentNode.insertBefore(wrap, insertPoint.nextSibling);
  } else {
    target.appendChild(wrap);
  }

  // ----------------------------
  // Ctrl + Enter shortcut
  // ----------------------------

  document.addEventListener("keydown", (e) => {
    if (e.ctrlKey && e.key === "Enter") {
      const active = document.activeElement;
      const isTyping =
        active &&
        (active.tagName === "TEXTAREA" || active.tagName === "INPUT");

      if (isTyping) return;

      e.preventDefault();
      location.href = submit.href;
    }
  });

})();