AtCoder Save Buffer

コードを自動的に保存して予期せぬ喪失から守ります

// ==UserScript==
// @name         AtCoder Save Buffer
// @namespace    http://atcoder.jp/
// @version      0.1
// @description  コードを自動的に保存して予期せぬ喪失から守ります
// @author       magurofly
// @match        https://atcoder.jp/contests/*/tasks/*
// @grant        none
// ==/UserScript==

// getSourceCode()
// $

(async function() {
    'use strict';

    const QUEUE_MAX = 12;
    const STORAGE = sessionStorage;

    function setSourceCode(code) {
        if ($(".btn-toggle-editor").hasClass("active")) {
            $(".plain-textarea").val(code);
        } else {
            $(".editor").data("editor").doc.setValue(code);
        }
    }

    if (!("atcoder_save_buffer_queue" in STORAGE)) {
        STORAGE.atcoder_save_buffer_queue = "[]";
    }

    const digest = [...new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(location.pathname)))].map(byte => byte.toString(16).padStart(2, "0")).join("");
    const id = "atcoder_save_buffer_" + digest;

    addEventListener("beforeunload", () => {
        const queue = JSON.parse(localStorage.atcoder_save_buffer_queue);
        const i = queue.indexOf(id);
        if (i != -1) queue.splice(i, 1);
        if (queue.length >= QUEUE_MAX) {
            const prev = queue.shift();
            delete STORAGE[prev];
        }
        queue.push(id);
        STORAGE[id] = getSourceCode();
        STORAGE.atcoder_save_buffer_queue = JSON.stringify(queue);
    });

    $(() => {
        if (id in localStorage) {
            setSourceCode(localStorage[id]);
            console.info("restored saved buffer");
        }
    });
})();