aboutsummaryrefslogtreecommitdiff
/**
 * Copyright 2021 Wojtek Kosior
 *
 * This program is free software; you can redistribute it
 * and/or modify it under the terms of either:
 * - the GNU General Public License as published by the Free
 *   Software Foundation; either version 3 of the License, or (at
 *   your option) any later version, or
 * - the "A" license: <https://koszko.org/alicense.txt>; explained
 *   at: <https://koszko.org/en/articles/my-new-license.html>
 *
 * As additional permission under GNU GPL version 3 section 7, you
 * may distribute forms of that code without the copy of the GNU
 * GPL normally required by section 4, provided you include this
 * license notice and, in case of non-source distribution, a URL
 * through which recipients can access the Corresponding Source.
 * If you modify file(s) with this exception, you may extend this
 * exception to your version of the file(s), but you are not
 * obligated to do so. If you do not wish to do so, delete this
 * exception statement from your version. If you delete this
 * exception statement from all source files in the program, then
 * also delete it here.
 *
 * As a special exception to the GPL, any HTML file which merely
 * makes function calls to this code, and for that purpose
 * includes it by reference shall be deemed a separate work for
 * copyright law purposes. If you modify this code, you may extend
 * this exception to your version of the code, but you are not
 * obligated to do so. If you do not wish to do so, delete this
 * exception statement from your version.
 */


/* Make the view scrollable. */

document.body.setAttribute("style",
			   "width: 100vw; height: 100vh; overflow: scroll;" +
			   (document.body.getAttribute("style") || ""));

let container = document.querySelectorAll(".waffle")[0];
let main_gid = null;

while (container) {
    container = container.parentElement;
    console.log(container);
    if (container === document.body || !container)
	break;

    const match = /([0-9]+)-grid-container/.exec(container.id);
    if (match)
	main_gid = match[1];

    container.setAttribute("style",
			   "width: fit-content; width: -moz-fit-content;");
}


/* Remove editor toolbars and bottom bar - these don't work anyway. */

const docs_chrome = document.getElementById("docs-chrome");
if (docs_chrome)
    docs_chrome.remove()
const grid_bottom_bar = document.getElementById("grid-bottom-bar");
if (grid_bottom_bar)
    grid_bottom_bar.remove()


/* Remove no Javascript warning. */

for (const no_js_warning of document.querySelectorAll("noscript"))
    no_js_warning.remove();


/* Get opengraph data. */

const og = {};

for (const node of document.head.childNodes) {
    if (node.tagName === "STYLE") {
	document.head.removeChild(node);
	continue;
    }

    if (node.tagName !== "META")
	continue;

    const match = /^og:(.+)/.exec(node.getAttribute("property"));
    if (!match)
	continue;

    og[match[1]] = node.getAttribute("content");
}


/* Construct download link. */

let download_link = null;

const match = new RegExp("/spreadsheets/d/([^/]+)").exec(document.URL);
if (match)
    download_link = `https://docs.google.com/spreadsheets/d/${match[1]}/export`;


/* Add title bar with sheet name and download button. */

const title_bar = document.createElement("div");
const title_heading = document.createElement("h1");
const title_text = document.createElement("span");
const main_download_button = document.createElement("a");

main_download_button.textContent = "download";
main_download_button.setAttribute("style", "border-radius: 10px; padding: 20px; color: #333; background-color: lightgreen; text-decoration: none; box-shadow: -4px 8px 8px #888; display: inline-block;");

if (og.title) {
    title_text.textContent = og.title;
    title_heading.appendChild(title_text);
}

title_text.setAttribute("style", "margin-right: 10px;");

if (download_link) {
    main_download_button.setAttribute("href", download_link);
    title_heading.appendChild(main_download_button);
}

title_bar.setAttribute("style", "padding: 0 20px; color: #555;");

title_bar.appendChild(title_heading);

document.body.insertBefore(title_bar, document.body.firstElementChild);


/* Extract sheet data from a script that sets the `bootstrapData' variable. */

let data = null;
for (const script of document.scripts) {
    const match = /bootstrapData = ({([^;]|[^}];)+})/.exec(script.textContent);
    if (!match)
	continue;
    data = JSON.parse(match[1]);
}

/*
 * Add download buttons for individual sheets belonging to this spreadsheet.
 * Data schema has been observed by looking at various spreadsheets.
 */

function add_sheet_download(data)
{
    if (!Array.isArray(data))
	return;

    const gid = data[2];
    if (!["string", "number"].includes(typeof gid))
	return;

    const sheet_download_link = `${download_link}?gid=${gid}`;
    const sheet_download_button = document.createElement("a");

    sheet_download_button.setAttribute("style", "border-radius: 5px; padding: 10px; color: #333; background-color: lightgreen; text-decoration: none; box-shadow: -4px 8px 8px #888; display: inline-block; margin: 0 5px 5px 0;");
    sheet_download_button.setAttribute("href", sheet_download_link);

    let sheet_name = null;
    if (Array.isArray(data[3]) &&
	data[3][0] && typeof data[3][0] === "object"
	&& Array.isArray(data[3][0][1]) &&
	Array.isArray(data[3][0][1][0]) &&
	typeof data[3][0][1][0][2] === "string") {

	const sheet_name = data[3][0][1][0][2];
	sheet_download_button.textContent = sheet_name;
        if (gid == main_gid)
	    title_text.textContent = `${title_text.textContent} - ${sheet_name}`;
    } else {
	sheet_download_button.textContent = `<sheet gid=${gid}>`;
    }

    title_bar.appendChild(sheet_download_button);
}

if (download_link) {
    for (const entry of data.changes.topsnapshot) {
	if (!Array.isArray(entry) || entry[0] !== 21350203 ||
	    typeof entry[1] !== "string")
	    continue;

	let entry_data = null;

	try {
	    entry_data = JSON.parse(entry[1]);
	} catch (e) {
	    console.log(e);
	    continue;
	}

	add_sheet_download(entry_data);
    }
}