Skip to content

Instantly share code, notes, and snippets.

@shibukawa
Last active April 10, 2019 13:28
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shibukawa/9d235a1a78441b1e0d60 to your computer and use it in GitHub Desktop.
Save shibukawa/9d235a1a78441b1e0d60 to your computer and use it in GitHub Desktop.
Electron - Mithril連係
var fs = require("fs");
var path = require("path");
var app = require("app");
var dialog = require('dialog');
var BrowserWindow = require('browser-window');
var ipc = require("ipc");
function ApplicationContext(title, defaultRoute, filter) {
this.title = title;
this.filter = filter;
this.defaultRoute = defaultRoute;
this.documents = {};
this.updateMenu = function(context, focusedWindow, presetMenu) {};
var self = this;
function modified(event, json, task, oldRoute, newRoute) {
var senderWindow = BrowserWindow.fromWebContents(event.sender);
var document = self.documents[senderWindow.id];
document.history = document.history.slice(0, document.current + 1);
document.history.push({
json: json,
oldRoute: oldRoute,
newRoute: newRoute,
task: task
});
document.current = document.history.length - 1;
self.updateState(senderWindow);
}
ipc.on("modified", modified);
if (process.platform === "darwin") {}
}
ApplicationContext.prototype.registerWindow = function(newWindow) {
var self = this;
this._clear(newWindow);
newWindow.once("page-title-updated", function(event) {
self.updateState(newWindow);
event.preventDefault();
});
function close(event) {
var document = self.documents[newWindow.id];
if (document && document.current !== 0) {
event.preventDefault();
self._saveIfModified(newWindow, "保存しないで閉じる")
.then(function() {
newWindow.removeListener("close", close);
newWindow.close();
self._afterClose(newWindow.id);
});
} else {
self._afterClose(newWindow.id);
}
}
newWindow.on("close", close);
};
ApplicationContext.prototype._afterClose = function(windowId) {
delete this.documents[windowId];
};
ApplicationContext.prototype.updateTitle = function(targetWindow) {
if (!targetWindow) {
return;
}
var document = this.documents[targetWindow.id];
var modified = document.current !== 0;
var title;
var fileName = document.filePath ? path.basename(document.filePath) : "新規ファイル";
if (modified) {
title = this.title + " - * " + fileName + " *";
} else {
title = this.title + " - " + fileName;
}
targetWindow.setTitle(title);
};
ApplicationContext.prototype.updateState = function(focusedWindow) {
var self = this;
this.updateTitle(focusedWindow);
if (!this.updateMenu) {
return;
}
var document = this.documents[focusedWindow.id];
var modified = document.current !== 0;
var presetMenu = {
fileNew: {
label: "新規作成",
accelerator: "CmdOrCtrl+N",
click: function() {
self._fileNew();
}
},
fileOpen: {
label: "開く",
accelerator: "CmdOrCtrl+O",
click: function() {
self._fileOpen();
}
},
fileSave: {
label: "保存",
accelerator: "CmdOrCtrl+S",
click: function() {
self._fileSave();
}
},
fileSaveAs: {
label: "名前をつけて保存",
accelerator: "CmdOrCtrl+Shift+S",
click: function() {
self._fileSaveAs();
}
},
fileQuit: {
label: "終了",
accelerator: "CmdOrCtrl+Q",
click: function() {
self._fileQuit();
}
},
editUndo: {
label: "元に戻す",
accelerator: "CmdOrCtrl+Z",
click: function() {
self._editUndo();
}
},
editRedo: {
label: "やり直し",
accelerator: "CmdOrCtrl+Y",
click: function() {
self._editRedo();
}
}
};
if (modified) {
presetMenu.editUndo.enabled = true;
presetMenu.editUndo.label = "元に戻す " + document.history[document.current].task;
} else {
presetMenu.editUndo.enabled = false;
presetMenu.editUndo.label = "元に戻す";
}
if (document.current !== (document.history.length - 1)) {
presetMenu.editRedo.enabled = true;
presetMenu.editRedo.label = "やり直し " + document.history[document.current + 1].task;
} else {
presetMenu.editRedo.enabled = false;
presetMenu.editRedo.label = "やり直し";
}
this.updateMenu(this, focusedWindow, presetMenu);
};
ApplicationContext.prototype._clear = function(focusedWindow) {
this.documents[focusedWindow.id] = {
filePath: "",
history: [{
json: {},
oldRoute: this.defaultRoute,
newRoute: this.defaultRoute,
task: ""
}],
current: 0
};
};
ApplicationContext.prototype._updateRenderer = function(focusedWindow, redo) {
var document = this.documents[focusedWindow.id];
var current = document.history[document.current];
var route = redo ? current.newRoute : current.oldRoute;
focusedWindow.webContents.send("load", current.json, route);
};
// メニュー
/*
File - New
*/
ApplicationContext.prototype._fileNew = function() {
console.log("file new");
var focusedWindow = BrowserWindow.getFocusedWindow();
var self = this;
this._saveIfModified(focusedWindow, "保存しない")
.then(function() {
self._clear(focusedWindow);
self._updateRenderer(focusedWindow);
self.updateState(focusedWindow);
});
}
/*
File - Open
*/
ApplicationContext.prototype._fileOpen = function() {
var focusedWindow = BrowserWindow.getFocusedWindow();
var self = this;
this._saveIfModified(focusedWindow, "保存しない")
.then(function() {
dialog.showOpenDialog(focusedWindow, {
title: "ファイルを開く",
properties: ["openFile"],
filters: [self.filter]
}, function(filenames) {
if (filenames && filenames.length > 0) {
fs.readFile(filenames[0], "utf8", function(err, text) {
self._clear(focusedWindow);
var document = self.documents[focusedWindow.id];
document.history[0].json = JSON.parse(text);
document.filePath = filenames[0];
self._updateRenderer(focusedWindow);
self.updateState(focusedWindow);
});
}
});
});
}
/*
File - Save
*/
ApplicationContext.prototype._fileSave = function() {
var focusedWindow = BrowserWindow.getFocusedWindow();
this._save(focusedWindow, false);
}
/*
File - SaveAs
*/
ApplicationContext.prototype._fileSaveAs = function() {
var focusedWindow = BrowserWindow.getFocusedWindow();
this._save(focusedWindow, true);
}
/*
File - Quit
*/
ApplicationContext.prototype._fileQuit = function() {
var focusedWindow = BrowserWindow.getFocusedWindow();
if (focusedWindow) {
this._saveIfModified(focusedWindow, "保存しないで閉じる")
.then(function() {
app.quit();
});
} else {
app.quit();
}
}
/*
Undo
*/
ApplicationContext.prototype._editUndo = function() {
var focusedWindow = BrowserWindow.getFocusedWindow();
var document = this.documents[focusedWindow.id];
if (document.current === 0) {
console.log("history error: can't undo");
return;
}
document.current--;
this._updateRenderer(focusedWindow);
this.updateState(focusedWindow);
};
/*
リドゥ
*/
ApplicationContext.prototype._editRedo = function() {
var focusedWindow = BrowserWindow.getFocusedWindow();
var document = this.documents[focusedWindow.id];
if (document.current === document.history.length - 1) {
console.log("history error: can't redo");
return;
}
document.current++;
this._updateRenderer(focusedWindow);
this.updateState(focusedWindow, true);
};
/*
Save/SaveAsのバックエンド
*/
ApplicationContext.prototype._save = function(focusedWindow, alwaysOpenDialog) {
var self = this;
var document = this.documents[focusedWindow.id];
return new Promise(function(resolved, rejected) {
if (document.filePath && !alwaysOpenDialog) {
self._rawSave(focusedWindow).then(resolved, rejected);
} else {
dialog.showSaveDialog(focusedWindow, {
title: "ファイルの保存",
filters: [self.filter]
}, function(filePath) {
if (filePath) {
document.filePath = filePath;
self._rawSave(focusedWindow).then(resolved, rejected);
} else {
rejected();
}
});
}
});
};
/*
変更されていたら保存処理を行う(新規やオープンから呼ばれる)
*/
ApplicationContext.prototype._saveIfModified = function(focusedWindow, ignoreLabel) {
var self = this;
var document = this.documents[focusedWindow.id];
return new Promise(function(resolved, rejected) {
if (document.current !== 0) {
var buttons = ["保存", "キャンセル", ignoreLabel];
dialog.showMessageBox(focusedWindow, {
type: "question",
buttons: buttons,
message: "ファイルが変更されています。保存しますか?"
}, function(buttonIndex) {
console.log("buttonIndex", buttonIndex);
switch (buttonIndex) {
case 0:
self._save(focusedWindow, false).then(resolved, rejected);
break;
case 1:
rejected();
break;
case 2:
resolved();
break;
}
});
} else {
resolved();
}
});
};
/*
最終的な保存処理
*/
ApplicationContext.prototype._rawSave = function(focusedWindow) {
var self = this;
var document = this.documents[focusedWindow.id];
return new Promise(function(resolved, rejected) {
var last = document.history[document.current];
var content = JSON.stringify(last.json, null, " ");
fs.writeFile(document.filePath, content, {
"encoding": "utf8"
}, function(err) {
if (err) {
return rejected(err);
}
document.history = [last];
document.current = 0;
self.updateState(focusedWindow);
resolved();
});
});
};
module.exports = ApplicationContext;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment