Skip to content

Commit

Permalink
Merge pull request #390 from RAIRLab/388-firefox-cannot-save-files
Browse files Browse the repository at this point in the history
388 firefox cannot save or load files fix
  • Loading branch information
James-Oswald committed May 6, 2024
2 parents 217ff50 + 5c7f07b commit 8d21575
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 130 deletions.
1 change: 1 addition & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"recommendations": [
"dbaeumer.vscode-eslint",
"firefox-devtools.vscode-firefox-debug",
"streetsidesoftware.code-spell-checker"
]
}
19 changes: 13 additions & 6 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,27 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "Chrome Vite Debug",
"url": "http://localhost:5173/",
"webRoot": "${workspaceRoot}/src",
//"sourceMaps": true,
},
{
"type": "msedge",
"name": "Edge Vite Debug",
"request": "launch",
"name": "Edge Vite Debug",
"url": "http://localhost:5173/",
"webRoot": "${workspaceFolder}/src"
},
{
"type": "chrome",
"type": "firefox",
"request": "launch",
"name": "Chrome Vite Debug",
"name": "Firefox Vite Debug",
"url": "http://localhost:5173/",
"webRoot": "${workspaceRoot}/src",
//"sourceMaps": true,
}
"webRoot": "${workspaceFolder}/src"
},
]
}
13 changes: 13 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
},
"homepage": "https://github.com/RAIRLab/PeirceMyHeart#readme",
"devDependencies": {
"@types/file-saver": "^2.0.7",
"@types/node": "20.12.8",
"@types/wicg-file-system-access": "^2023.10.5",
"gts": "^5.3.0",
Expand All @@ -43,6 +44,7 @@
"vitest": "^1.6.0"
},
"dependencies": {
"file-saver": "^2.0.5",
"fork-awesome": "^1.2.0",
"theme-change": "^2.5.0"
}
Expand Down
124 changes: 123 additions & 1 deletion src/AEG-IO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,20 @@
* @author Anusha Tiwari
*/

import {TreeContext} from "./TreeContext";
import {redrawProof, redrawTree} from "./SharedToolUtils/DrawUtils";
import {appendStep} from "./ProofHistory/ProofHistory";

import {AEGTree} from "./AEG/AEGTree";
import {AtomNode} from "./AEG/AtomNode";
import {CutNode} from "./AEG/CutNode";
import {Ellipse} from "./AEG/Ellipse";
import {Point} from "./AEG/Point";
import {ProofModeMove, ProofModeNode} from "./ProofHistory/ProofModeNode";

//Cross-browser file saving library.
import FileSaver from "file-saver";

/**
* Describes The Sheet of Assertion in JSON files.
*/
Expand Down Expand Up @@ -146,7 +153,7 @@ function toCut(cutData: cutObj): CutNode {
}

/**
* Parses the incoming AtomObject and returns and equivalent AtomNode.
* Parses the incoming AtomObject and returns an equivalent AtomNode.
*
* @param atomData Incoming AtomObject.
* @returns AtomNode equivalent of atomData.
Expand All @@ -158,3 +165,118 @@ function toAtom(atomData: atomObj): AtomNode {

return new AtomNode(identifier, origin, atomData.internalWidth, atomData.internalHeight);
}

/**
* Creates and returns the json string of the given AEG Tree object.
* Uses tab characters as delimiters.
*
* @param treeData An AEG Tree object.
* @returns json string of treeData.
*/
export function aegJsonString(treeData: AEGTree | ProofModeNode[]): string {
return JSON.stringify(treeData, null, "\t");
}

/**
* Calls appropriate methods to save the current AEGTree as a file.
*/
export async function saveMode(): Promise<void> {
let name: string;
let data: AEGTree | ProofModeNode[];

if (TreeContext.modeState === "Draw") {
name = TreeContext.tree.toString();
data = TreeContext.tree;
} else {
if (TreeContext.proof.length === 1) {
name = "One-Step Proof";
} else {
name =
TreeContext.proof[0].tree.toString() +
" PROVES " +
TreeContext.getLastProofStep().tree.toString();
}
data = TreeContext.proof;
}

//Errors caused by file handler or HTML download element should not be displayed.
try {
//Dialog based download
if ("showSaveFilePicker" in window) {
const saveHandle = await window.showSaveFilePicker({
excludeAcceptAllOption: true,
suggestedName: name,
startIn: "downloads",
types: [{accept: {"text/json": [".json"]}}],
});
saveFile(saveHandle, data);
} else {
//Fallback to immediate download if showSaveFilePicker is not supported.
const blob = new Blob([aegJsonString(data)], {type: "text/json"});
FileSaver(blob, name + ".json");
}
} catch (error) {
//Catch error but do nothing. Discussed in Issue #247.
}
}

function readFile(file: File) {
const reader = new FileReader();
reader.addEventListener("load", () => {
const aegData = reader.result;
if (typeof aegData === "string") {
const loadData = loadFile(TreeContext.modeState, aegData);
if (TreeContext.modeState === "Draw") {
//Loads data.
TreeContext.tree = loadData as AEGTree;
//Redraws tree which is now the parsed loadData.
redrawTree(TreeContext.tree);
} else if (TreeContext.modeState === "Proof") {
//Clears current proof.
TreeContext.clearProof();
//Loads data for the new proof.
TreeContext.proof = loadData as ProofModeNode[];
//Removes default start step.
document.getElementById("Row: 1")?.remove();
//Adds button for each step of the loaded proof to the history bar.
for (let i = 0; i < TreeContext.proof.length; i++) {
appendStep(TreeContext.proof[i], i + 1);
}
TreeContext.currentProofStep = TreeContext.proof[TreeContext.proof.length - 1];
redrawProof();
}
} else {
console.log("Loading failed because reading the file was unsuccessful.");
}
});
reader.readAsText(file);
}

/**
* Calls the appropriate methods to load files and convert them to equivalent AEGTrees.
*/
export async function loadMode(): Promise<void> {
try {
if ("showOpenFilePicker" in window) {
const [fileHandle] = await window.showOpenFilePicker({
excludeAcceptAllOption: true,
multiple: false,
startIn: "downloads",
types: [{accept: {"text/json": [".json"]}}],
});
const file = await fileHandle.getFile();
readFile(file);
} else {
const fileInput = document.createElement("input");
fileInput.type = "file";
fileInput.accept = ".json";
fileInput.addEventListener("change", () => {
const file = fileInput.files?.item(0);
readFile(file!);
});
fileInput.click();
}
} catch (error) {
//Do nothing.
}
}
4 changes: 2 additions & 2 deletions src/SharedToolUtils/DrawUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* @author Anusha Tiwari
*/

import {aegStringify} from "../index";
import {aegJsonString} from "../AEG-IO";
import {AEGTree} from "../AEG/AEGTree";
import {AtomNode} from "../AEG/AtomNode";
import {CutNode} from "../AEG/CutNode";
Expand Down Expand Up @@ -174,7 +174,7 @@ export function redrawTree(tree: AEGTree, color?: string): void {
cutDisplay.innerHTML = tree.toString();
cleanCanvas();
redrawCut(tree.sheet, color);
window.treeString = aegStringify(tree);
window.treeString = aegJsonString(tree);
}

/**
Expand Down
Loading

0 comments on commit 8d21575

Please sign in to comment.