View All Editorials

View all editorials of the AtCoder contest in one page.

Verzia zo dňa 16.10.2022. Pozri najnovšiu verziu.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==UserScript==
// @name            View All Editorials
// @name:ja         解説ぜんぶ見る
// @description     View all editorials of the AtCoder contest in one page.
// @description:ja  AtCoderコンテストの解説ページに、すべての問題の解説をまとめて表示します。
// @version         1.3.1
// @icon            https://www.google.com/s2/favicons?domain=atcoder.jp
// @match           https://atcoder.jp/contests/*/editorial
// @match           https://atcoder.jp/contests/*/editorial?*
// @grant           GM_addStyle
// @namespace       https://gitlab.com/w0mbat/user-scripts
// @author          w0mbat
// ==/UserScript==

(async function () {
  'use strict';
  console.log(`🐻 "View All Editorials" start execution. 🐻`)

  const appendHeadChild = (tagName, options) =>
    Object.assign(document.head.appendChild(document.createElement(tagName)), options);
  const addScript = (src) => new Promise((resolve) => {
    appendHeadChild('script', { src, type: 'text/javascript', onload: resolve });
  });
  const addStyleSheet = (src) => new Promise((resolve) => {
    appendHeadChild('link', { rel: 'stylesheet', href: src, onload: resolve });
  });

  const loadKaTex = async () => {
    await addStyleSheet("https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css");
    await addScript("https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.js");
    await addScript("https://cdn.jsdelivr.net/npm/[email protected]/dist/contrib/auto-render.min.js");
    const kaTexOptions = {
      delimiters: [
        { left: "$$", right: "$$", display: true },
        { left: "$", right: "$", display: false },
        { left: "\\(", right: "\\)", display: false },
        { left: "\\[", right: "\\]", display: true }
      ],
      ignoredTags: ["script", "noscript", "style", "textarea", "code", "option"],
      ignoredClasses: ["prettyprint", "source-code-for-copy"],
      throwOnError: false
    };
    /* global renderMathInElement */
    renderMathInElement && renderMathInElement(document.body, kaTexOptions);
  };

  const loadPrettifier = async () =>
    await addScript("https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js");

  const scrape = (doc) =>
    doc.querySelector("#main-container > div.row > div:nth-child(2) > div:nth-of-type(1)");
  const loadEditorial = async (link) => {
    link.parentNode.classList.add('🐻-editorial-item');
    const response = await fetch(link.href);
    if (!response.ok) throw "Fetch failed";
    const dom = scrape(new DOMParser().parseFromString(await response.text(), 'text/html'));
    if (!dom) throw "Scraping failed";
    link.parentNode.appendChild(dom).classList.add('🐻-editorial-content');
  };

  const filter4InternalEditorialLink = (link) => link.href.match(/\/contests\/.+\/editorial\//);
  const loadAllEditorials = () => Promise.all(
    Array.prototype.filter.call(document.getElementsByTagName('a'), filter4InternalEditorialLink)
      .map(e => loadEditorial(e).catch(ex => console.warn(`🐻 Something wrong: "${e.href}", ${ex}`))));

  GM_addStyle(`
    pre code { tab-size: 2; }
    .🐻-editorial-item { margin-bottom: 1.5em; font-size: larger; }
    .🐻-editorial-content { font-size: smaller; }
  `);
  await loadAllEditorials();
  await loadKaTex();
  await loadPrettifier();

  console.log(`🐻 "View All Editorials" end execution. 🐻`)
})();