Remember open files in Electron

main
Isaiah Odhner 2019-02-16 13:18:30 -05:00
parent 6c1b5845eb
commit b40af7310a
3 changed files with 99 additions and 55 deletions

View File

@ -47,6 +47,7 @@ var redos = []; //array of <canvas>
//var frames = []; //array of {delay: N, undos: [<canvas>], redos: [<canvas>], canvas: <canvas>}? array of Frames?
var file_name;
var document_file_path;
var saved = true;
@ -92,17 +93,19 @@ var $toolbox = $ToolBox(tools);
// so it can display names of the tools, and maybe authors and previews (and not necessarily icons)
var $colorbox = $ColorBox();
// TODO: open from file path in Electron
// and set this via program arguments
// if(window.document_file_path){
// open_from_file_path(window.document_file_path);
// }
reset_file();
reset_colors();
reset_canvas(); // (with newly reset colors)
reset_magnification();
if(window.document_file_path_to_open){
open_from_file_path(document_file_path_to_open, function(err){
if(err){
return show_error_message("Failed to open file " + document_file_path_to_open, err);
}
});
}
$canvas.on("user-resized", function(e, _x, _y, width, height){
undoable(0, function(){
canvas.width = Math.max(1, width);

View File

@ -6,13 +6,78 @@ global.module = undefined;
var dialog = require("electron").remote.dialog;
var fs = require("fs");
var path = require("path");
var argv = require("electron").remote.process.argv;
if (process.platform == "win32" && argv.length >= 2) {
if (argv[1] === ".") { // in development, "path/to/electron.exe" "." "maybe/a/file.png" ...maybe?
window.document_file_path_to_open = argv[2];
} else { // in production, "path/to/JS Paint.exe" "maybe/a/file.png"
window.document_file_path_to_open = argv[1];
}
}
window.open_from_file_path = function(file_path, callback, canceled){
fs.readFile(file_path, function(err, buffer) {
if(err){
return callback(err);
}
var file = new File([new Uint8Array(buffer)], path.basename(file_path));
// can't set file.path directly, but we can do this:
Object.defineProperty(file, 'path', {
value: file_path,
});
open_from_File(file, callback, canceled);
});
};
window.save_to_file_path = function(filePath, formatName, savedCallback){
var mimeType = {
"JPEG": "image/jpeg",
"PNG": "image/png",
"GIF": "image/gif",
"WebP": "image/webp",
// "Monochrome Bitmap": "image/bitmap",
// "16 Color Bitmap": "image/bitmap",
// "256 Color Bitmap": "image/bitmap",
// "24-bit Bitmap": "image/bitmap",
}[formatName];
if(!mimeType){
return show_error_message("Can't save as " + formatName + ". Format is not supported.");
}
// if(mimeType === "image/gif"){
// new GIF();
// }
canvas.toBlob(function(blob){
if(blob.type !== mimeType){
return show_error_message("Failed to save as " + formatName + " (your browser doesn't support exporting a canvas as \"" + mimeType + "\")");
}
sanity_check_blob(blob, function(){
blob_to_buffer(blob, function(err, buffer){
if(err){
return show_error_message("Failed to save! (Technically, failed to convert a Blob to a Buffer.)", err);
}
fs.writeFile(filePath, buffer, function(err){
if(err){
return show_error_message("Failed to save file!", err);
}
var fileName = path.basename(filePath);
savedCallback(filePath, fileName);
});
});
});
}, mimeType);
};
// TODO: window.platform.saveCanvasAs etc. or platformIntegration or system or something
window.systemSaveCanvasAs = function(canvas, fileName, savedCallback){
window.systemSaveCanvasAs = function(canvas, suggestedFileName, savedCallback){
var getExtension = function(filePathOrName){
var splitByDots = filePathOrName.split(/\./g);
return splitByDots[splitByDots.length - 1].toLowerCase();
};
var extension = getExtension(fileName);
// TODO: default to existing extension, except it would be awkward to rearrange the list...
// var suggestedExtension = getExtension(suggestedFileName);
var filters = [
// top one is considered default by electron
{name: "PNG", extensions: ["png"]},
@ -28,10 +93,9 @@ window.systemSaveCanvasAs = function(canvas, fileName, savedCallback){
{name: "WebP", extensions: ["webp"]},
];
// TODO: pass BrowserWindow to make dialog modal?
// TODO: pass defaultPath of last opened file (w/ different file name)?
// also maybe sanitize fileName?
// TODO: should suggestedFileName be sanitized in some way?
dialog.showSaveDialog({
defaultPath: fileName,
defaultPath: suggestedFileName,
filters: filters,
}, function(filePath) {
if(!filePath){
@ -42,45 +106,12 @@ window.systemSaveCanvasAs = function(canvas, fileName, savedCallback){
// TODO: Linux/Unix?? you're not supposed to need file extensions
return show_error_message("Missing file extension - try adding .png to the file name");
}
var typeNameMatched = ((filters.find(function(filter){return filter.extensions.indexOf(extension) > -1})) || {}).name;
if(!typeNameMatched){
var formatNameMatched = ((filters.find(function(filter){return filter.extensions.indexOf(extension) > -1})) || {}).name;
if(!formatNameMatched){
return show_error_message("Can't save as *." +extension + " - try adding .png to the file name");
}
var mimeType = {
"JPEG": "image/jpeg",
"PNG": "image/png",
"GIF": "image/gif",
"WebP": "image/webp",
// "Monochrome Bitmap": "image/bitmap",
// "16 Color Bitmap": "image/bitmap",
// "256 Color Bitmap": "image/bitmap",
// "24-bit Bitmap": "image/bitmap",
}[typeNameMatched];
if(!mimeType){
return show_error_message("Can't save as " + typeNameMatched + ". Format is not supported.");
}
// if(mimeType === "image/gif"){
// new GIF();
// }
canvas.toBlob(function(blob){
if(blob.type !== mimeType){
return show_error_message("Failed to save as " + typeNameMatched + " (your browser doesn't support exporting a canvas as \"" + mimeType + "\")");
}
sanity_check_blob(blob, function(){
blob_to_buffer(blob, function(err, buffer){
if(err){
return show_error_message("Failed to save! (Technically, failed to convert a Blob to a Buffer.)", err);
}
fs.writeFile(filePath, buffer, function(err){
if(err){
return show_error_message("Failed to save file!", err);
}
savedCallback();
});
});
});
}, mimeType);
save_to_file_path(filePath, formatNameMatched, savedCallback);
});
};

View File

@ -24,7 +24,7 @@ function reset_colors(){
}
function reset_file(){
// document_file_path = null;
document_file_path = null;
file_name = "untitled";
update_title();
saved = true;
@ -121,6 +121,7 @@ function open_from_File(file, callback, canceled){
open_from_Image(img, function(){
file_name = file.name;
document_file_path = file.path; // available in Electron
update_title();
saved = true;
callback();
@ -165,7 +166,6 @@ function file_new(){
// there's this little thing called Inversion of Control...
// also paste_from_file_select_dialog
function file_open(){
// TODO: remember file as "open" in electron
get_FileList_from_file_select_dialog(function(files){
open_from_FileList(files, "selected");
});
@ -200,19 +200,29 @@ function file_load_from_url(){
function file_save(){
deselect();
if(file_name.match(/\.svg$/)){
//TODO: only affect suggested name in save dialog, don't change file_name
file_name = file_name.replace(/\.svg$/, "") + ".png";
//TODO: update_title();?
return file_save_as();
}
// TODO: save over "open" file in electron
if(document_file_path){
// TODO: save as JPEG by default if the previously opened/saved file was a JPEG?
return save_to_file_path(document_file_path, "PNG", function(saved_file_path, saved_file_name){
saved = true;
document_file_path = saved_file_path;
file_name = saved_file_name;
update_title();
});
}
file_save_as();
}
function file_save_as(){
deselect();
// TODO: remember file as "open", i.e. name in title bar and have File > Save save over the file
save_canvas_as(canvas, file_name.replace(/\.(bmp|dib|a?png|gif|jpe?g|jpe|jfif|tiff?|webp|raw)$/, "") + ".png", function(){
save_canvas_as(canvas, file_name.replace(/\.(bmp|dib|a?png|gif|jpe?g|jpe|jfif|tiff?|webp|raw)$/, "") + ".png", function(saved_file_path, saved_file_name){
saved = true;
document_file_path = saved_file_path;
file_name = saved_file_name;
update_title();
});
}
@ -983,10 +993,10 @@ function image_stretch_and_skew(){
}
// TODO: establish a better pattern for this (platform-specific functions, with browser-generic fallbacks)
// Note: we can't just poke in a different save_canvas_as function in electron-injected.js because electron-injected.js is loaded first
function save_canvas_as(canvas, fileName, savedCallbackUnreliable){
// Note: we can't just poke in a different save_canvas_as function in electron-injected.js because electron-injected.js is loaded first
if(window.systemSaveCanvasAs){
return window.systemSaveCanvasAs(canvas, fileName, savedCallbackUnreliable);
return systemSaveCanvasAs(canvas, fileName, savedCallbackUnreliable);
}
// TODO: file name + type dialog