Tabbed AtCoder Editorial

display atcoder editorial in tabs

От 26.06.2022. Виж последната версия.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name         Tabbed AtCoder Editorial
// @version      0.1
// @description  display atcoder editorial in tabs
// @match        https://atcoder.jp/contests/*/editorial
// @grant        GM_addStyle
// @license      MIT
// @namespace https://greasyfork.org/users/808669
// ==/UserScript==

/* jshint esversion:8 */
(async function () {
  'use strict';
  async function addScript(src) {
    return new Promise((resolve) => {
      const script = document.createElement("script");
      script.type = "text/javascript";
      script.src = src;
      script.onload = resolve;
      document.getElementsByTagName("head")[0].appendChild(script);
    });
  }

  async function addLink(href) {
    return new Promise((resolve) => {
      const link = document.createElement("link");
      link.rel = "stylesheet";
      link.href = href;
      link.onload = resolve;
      document.getElementsByTagName("head")[0].appendChild(link);
    });
  }

  async function getEditorial(link) {
    return new Promise((resolve) => {
      const xhr = new XMLHttpRequest();
      xhr.responseType = "document";
      xhr.onload = (response) => {
        const editorial = response.target.responseXML.querySelector("#main-container > div.row > div:nth-child(2) > div:nth-child(3)");
        if (editorial) link.parentNode.appendChild(editorial);
        resolve();
      };
      xhr.open("GET", link.href);
      xhr.send();
    });
  }

  async function getAllEditorials() {
    return Promise.all(Array.prototype.filter.call(document.getElementsByTagName('a'), e => e.href.match(/\/editorial\//))
      .map(e => getEditorial(e)));
  }

  async function createTab() {
    const parser = new DOMParser();
    const parse = s => parser.parseFromString(s, "text/html").body.firstChild;
    const nav = document.querySelector("#main-container > div.row > div:nth-child(2)");
    const dummy = document.createElement("div");
    const navul = parse(`<ul class="nav nav-tabs" role="tablist"></ul>`);
    const navdiv = parse(`<div class="tab-content"></div>`);

    let previd = "dummy";
    let isactive = true;
    let prevhead = -1;
    let kaisetsu = -1;

    while (nav.children.length > 0) {
      const e = nav.firstChild;
      const summary = e.textContent.trimStart().split(/\s+/)[0];
      if (e.tagName === "DIV" && summary === "解説") {
        kaisetsu = dummy.children.length;
        dummy.appendChild(e);
      } else if (e.tagName === "DIV" || e.tagName === "H3") {
        console.log(e);
        const cond = e.textContent === "コンテスト全体の解説";
        const name = cond ? "全体" : e.textContent.trimStart().split(/\s+/)[0];
        const id = cond ? "all" : e.textContent.trimStart().split(/\s+/)[0];
        const li = parse(`<li role="presentation">
          <a href="#editorial-${id}" aria-controls="editorial-${id}" role="tab" data-toggle="tab">${name}</a>
        </li>`);
        if (isactive) li.classList.add("active");
        navul.appendChild(li);
        previd = id;
        prevhead = dummy.children.length;
        dummy.appendChild(e);
      } else if (e.tagName === "UL" || e.tagName == "P") {
        const div = document.createElement("div");
        div.role = "tabpanel";
        div.classList.add("tab-pane");
        if (isactive) div.classList.add("active");
        div.id = "editorial-" + previd;
        console.log(prevhead, dummy);
        div.appendChild(dummy.children[prevhead]);
        div.appendChild(e);
        navdiv.appendChild(div);
        isactive = false;
      } else {
        dummy.appendChild(e);
      }
    }

    if (kaisetsu >= 0) nav.appendChild(dummy.children[kaisetsu]);
    nav.appendChild(navul);
    nav.appendChild(navdiv);
    return Promise.all(Array.prototype.filter.call(navdiv.getElementsByTagName('a'), e => e.href.match(/\/editorial\//))
      .map(e => getEditorial(e)));
  }

  GM_addStyle("pre code { tab-size: 4; }");
  await createTab();
  await addLink("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");
  await addScript("https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js");
  renderMathInElement(document.body);
})();