aboutsummaryrefslogtreecommitdiff
path: root/content/sgoogle_sheets_download/google_sheets_download.js
diff options
context:
space:
mode:
Diffstat (limited to 'content/sgoogle_sheets_download/google_sheets_download.js')
-rw-r--r--content/sgoogle_sheets_download/google_sheets_download.js198
1 files changed, 198 insertions, 0 deletions
diff --git a/content/sgoogle_sheets_download/google_sheets_download.js b/content/sgoogle_sheets_download/google_sheets_download.js
new file mode 100644
index 0000000..dc959e1
--- /dev/null
+++ b/content/sgoogle_sheets_download/google_sheets_download.js
@@ -0,0 +1,198 @@
+/**
+ * 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);
+ }
+}