From 3f68f8a7a3bb96b52d331a8c6681feb83953a6ef Mon Sep 17 00:00:00 2001 From: Alexander Bass Date: Sun, 4 Sep 2022 23:55:34 -0400 Subject: [PATCH] add extension --- content_scripts/saveload.js | 118 ++++++++++++++++++++++++++++++++++++ icons/icon-32-light.png | Bin 0 -> 343 bytes icons/icon-32.png | Bin 0 -> 357 bytes inject_scripts/load.js | 5 ++ inject_scripts/save.js | 7 +++ manifest.json | 38 ++++++++++++ popup/DSMsaveload.css | 5 ++ popup/DSMsaveload.html | 21 +++++++ popup/DSMsaveload.js | 15 +++++ 9 files changed, 209 insertions(+) create mode 100644 content_scripts/saveload.js create mode 100644 icons/icon-32-light.png create mode 100644 icons/icon-32.png create mode 100644 inject_scripts/load.js create mode 100644 inject_scripts/save.js create mode 100644 manifest.json create mode 100644 popup/DSMsaveload.css create mode 100644 popup/DSMsaveload.html create mode 100644 popup/DSMsaveload.js diff --git a/content_scripts/saveload.js b/content_scripts/saveload.js new file mode 100644 index 0000000..b7aca94 --- /dev/null +++ b/content_scripts/saveload.js @@ -0,0 +1,118 @@ +(function () { + + if (window.hasRun) { + return; + } + window.hasRun = true; + //Status checking code commented out because chrome does things differently and I don't want to make two implementations + // var STATUS = "loading..."; + // updateStatus(); + + + checkIfReady(); + function checkIfReady() { + + console.log("DSMsaveload trying to attach to desmos..."); + if (document.getElementById("dcg-header-container").querySelector(".align-right-container")) { + console.log("DSMsaveload attached!"); + // STATUS = "running"; + // updateStatus(); + return makeButtonContainers(); + } + setTimeout(checkIfReady, 200); + } + + const expressionExport = document.createElement("div"); + expressionExport.id = "EXPORTEXPRESSION"; + const expressionImport = document.createElement("div"); + expressionImport.id = "IMPORTEXPRESSION"; + + document.body.appendChild(expressionImport); + document.body.appendChild(expressionExport); + + function download(filename, textInput) { + var element = document.createElement('a'); + element.setAttribute('href', 'data:text/plain;charset=utf-8, ' + encodeURIComponent(textInput)); + element.setAttribute('download', filename); + document.body.appendChild(element); + element.click(); + } + + + + + function makeButtonContainers() { + const buttonContainer = document.createElement("span"); + buttonContainer.style = "display: inline-block; position: relative; font-size: 90%;"; + const saveButton = document.createElement("div"); + saveButton.classList.add("dcg-btn-primary"); + saveButton.style = "line-height: 34px; display: inline-block;"; + saveButton.textContent = "Save JSON"; + saveButton.addEventListener("click", () => { saveExpr(); }); + const loadContainer = document.createElement("div"); + loadContainer.classList.add("dcg-btn-primary"); + loadContainer.style = "lineHeight: 34px; postion: relative; display: inline-block; margin-left: 3px;"; + const loadButtonLabel = document.createElement("label"); + loadButtonLabel.for = "loadJSON"; + loadButtonLabel.textContent = "Load JSON"; + const loadButton = document.createElement("input"); + loadButton.type = "file"; + loadButton.style = "opacity: 0.0; position: absolute; top:0; left: 0; bottom: 0; right:0; width: 100%; height:100%; "; + loadButton.id = "loadJSON"; + loadButton.onchange = () => { + const selectedFile = loadButton.files[0]; + new Response(selectedFile).json().then(json => { + console.log(json); + loadExpr(json); + }, err => { + alert("Invalid JSON file"); + }); + }; + + loadContainer.appendChild(loadButtonLabel); + loadContainer.appendChild(loadButton); + const buttonContainer2 = document.createElement("span"); + buttonContainer2.style = "display: inline-block; position: relative; font-size: 90%;"; + + buttonContainer.appendChild(saveButton); + buttonContainer2.appendChild(loadContainer); + document.getElementById("dcg-header-container").querySelector(".align-right-container").appendChild(buttonContainer).appendChild(buttonContainer2); + } + + // creates a script in the document to interact with the page variables. + // the IMPORTEXPRESSION div is used as an interface to carry the data from this script to the injected script + function loadExpr(json) { + const expressions = JSON.stringify(json); + var scriptTag = document.createElement('script'); + scriptTag.src = chrome.extension.getURL('inject_scripts/load.js'); + scriptTag.onload = function () { this.parentNode.removeChild(this); }; + document.getElementById("IMPORTEXPRESSION").textContent = expressions; + document.body.append(scriptTag); + } + + function saveExpr() { + var scriptTag = document.createElement('script'); + scriptTag.src = chrome.extension.getURL('inject_scripts/save.js'); + scriptTag.onload = function () { this.parentNode.removeChild(this); }; + document.body.append(scriptTag); + document.addEventListener("updatedExpression", () => { + const expressionsString = document.getElementById("EXPORTEXPRESSION").textContent; + download("Desmos Graph.json", expressionsString); + document.getElementById("EXPORTEXPRESSION").textContent = ""; + }); + } + + // chrome.runtime.onMessage.addListener((message) => { + // if (message.command === "DSMstatus") { + // updateStatus(); + // } + // }); + + // function updateStatus() { + // chrome.runtime.sendMessage({ + // command: "DSMstatusReport", + // status: STATUS + // }); + // } + +})(); diff --git a/icons/icon-32-light.png b/icons/icon-32-light.png new file mode 100644 index 0000000000000000000000000000000000000000..9810749df45614fd6076d167e39125e4803774cc GIT binary patch literal 343 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzwj^(N7l!{JxM1({$v_d#0*}aI z1_nK45N51cYF`Evlq_+LC~?lu%}vcKVQ?-=O)N=GQ7F$W$xv|j^bH7arki_Zp4%3b;Ecc!Gw>CEi555dN= z3bz@bo?<*+_j%c|%a+G)UGa`$XJU2{bygH`P^oKga5%xR%A$1w!wQQ=j^7U6d!9bJ zX3ko}v7oCzPsXu?am5a9!M27Ym!n>ntiQ&hy7c?X#4TTKK5Vo5CEzQn%}!_6A+qJg-mQ4r%M%dynQe3Mu8pNprX;__3I| xB-q6WbnG~!D*V~(!2k6#y$;=8^I!6jxb_=aotz_A%7K1m@O1TaS?83{1OOw1jsXAw literal 0 HcmV?d00001 diff --git a/inject_scripts/load.js b/inject_scripts/load.js new file mode 100644 index 0000000..1708603 --- /dev/null +++ b/inject_scripts/load.js @@ -0,0 +1,5 @@ +(function () { + const expressions = JSON.parse(document.getElementById("IMPORTEXPRESSION").textContent); + Calc.setExpressions(expressions); + document.getElementById("IMPORTEXPRESSION").textContent = ""; +})(); \ No newline at end of file diff --git a/inject_scripts/save.js b/inject_scripts/save.js new file mode 100644 index 0000000..26e3c22 --- /dev/null +++ b/inject_scripts/save.js @@ -0,0 +1,7 @@ +(function () { + const expressions = Calc.getExpressions(); + const expressionBox = document.getElementById("EXPORTEXPRESSION"); + expressionBox.textContent = JSON.stringify(expressions); + const updateEvent = new Event("updatedExpression"); + document.dispatchEvent(updateEvent); +})(); diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..3be3c06 --- /dev/null +++ b/manifest.json @@ -0,0 +1,38 @@ +{ + "description": "Allows importing and exporting of Desmos.com graphs as json files.", + "manifest_version": 2, + "name": "DSMsaveload", + "version": "1.0", + "homepage_url": "https://alexanderbass.com/showcase/desmossaveload", + "permissions": [ + "activeTab" + ], + "content_scripts": [ + { + "matches": [ + "*://*.desmos.com/*" + ], + "js": [ + "content_scripts/saveload.js" + ] + } + ], + "host_permissions": [ + "https://www.desmos.com/" + ], + "web_accessible_resources": [ + "inject_scripts/*.js" + ], + "browser_action": { + "default_icon": "icons/icon-32.png", + "theme_icons": [ + { + "light": "icons/icon-32-light.png", + "dark": "icons/icon-32.png", + "size": 32 + } + ], + "default_title": "Desmos Save Load", + "default_popup": "popup/DSMsaveload.html" + } +} \ No newline at end of file diff --git a/popup/DSMsaveload.css b/popup/DSMsaveload.css new file mode 100644 index 0000000..4c4bcd0 --- /dev/null +++ b/popup/DSMsaveload.css @@ -0,0 +1,5 @@ +html, +body { + width: 250px; + text-align: center; +} \ No newline at end of file diff --git a/popup/DSMsaveload.html b/popup/DSMsaveload.html new file mode 100644 index 0000000..651f041 --- /dev/null +++ b/popup/DSMsaveload.html @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/popup/DSMsaveload.js b/popup/DSMsaveload.js new file mode 100644 index 0000000..2338e7d --- /dev/null +++ b/popup/DSMsaveload.js @@ -0,0 +1,15 @@ + +// Commented out because chrome does things differently and I don't want to make 2 implementations. +// getStatus(); +// function getStatus() { +// browser.tabs.query({ active: true, currentWindow: true }).then((tabs) => { +// browser.tabs.sendMessage(tabs[0].id, { +// command: "DSMstatus" +// }); +// }); +// } +// browser.runtime.onMessage.addListener((message) => { +// if (message.command === "DSMstatusReport") { +// document.getElementById("status").textContent = message.status; +// } +// }); \ No newline at end of file