Updated electron paths

This commit is contained in:
David Benson 2017-06-07 17:10:08 +01:00
parent e44c27fcce
commit 022cc17f50
3 changed files with 961 additions and 7 deletions

186
war/electron.js Normal file
View file

@ -0,0 +1,186 @@
const fs = require('fs')
const path = require('path')
const url = require('url')
const electron = require('electron')
const ipcMain = electron.ipcMain
const dialog = electron.dialog
const app = electron.app
const BrowserWindow = electron.BrowserWindow
const autoUpdater = require('electron-updater').autoUpdater
const log = require('electron-log')
autoUpdater.logger = log
autoUpdater.logger.transports.file.level = 'info'
// autoUpdater.autoDownload = false
autoUpdater.autoDownload = true
const __DEV__ = process.env.NODE_ENV === 'development'
let windowsRegistry = []
function createWindow (opt = {}) {
let options = Object.assign({
width: 1600,
height: 1200,
'web-security': false,
webPreferences: {
// preload: path.resolve('./preload.js'),
},
}, opt)
let mainWindow = new BrowserWindow(options)
windowsRegistry.push(mainWindow)
console.log('createWindow', opt)
let wurl = url.format({
pathname: `${__dirname}/index.html`,
protocol: 'file:',
query: {
'dev': __DEV__ ? 1 : 0,
'test': 1,
'db': 0,
'gapi': 0,
'od': 0,
'gh': 0,
'analytics': 0,
'picker': 0,
'mode': 'device',
'browser': 0,
'p': 'electron',
},
slashes: true,
})
//`file://${__dirname}/index.html?dev=1&test=1&db=0&gapi=0&od=0&analytics=0&picker=0&mode=device&browser=0&p=electron`
// and load the index.html of the app.
mainWindow.loadURL(wurl)
// Open the DevTools.
mainWindow.webContents.openDevTools()
mainWindow.on('close', (event/*:WindowEvent*/) => {
const win = event.sender
const index = windowsRegistry.indexOf(win)
console.log('Window on close idx:%d', index)
const contents = win.webContents
if (contents != null) {
contents.executeJavaScript(`global.__emt_isModified()`, true,
isModified => {
console.log('__emt_isModified', isModified)
if (isModified) {
var choice = dialog.showMessageBox(
win,
{
type: 'question',
buttons: ['Cancel', 'Discard Changes'],
title: 'Confirm',
message: 'The document has unsaved changes. Do you really want to quit without saving?' //mxResources.get('allChangesLost')
})
if (choice === 1) {
win.destroy()
}
} else {
win.destroy()
}
})
event.preventDefault()
}
})
// Emitted when the window is closed.
mainWindow.on('closed', (event/*:WindowEvent*/) => {
const index = windowsRegistry.indexOf(event.sender)
console.log('Window closed idx:%d', index)
windowsRegistry.splice(index, 1)
})
return mainWindow.id
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', e => {
//asynchronous
ipcMain.on('asynchronous-message', (event, arg) => {
console.log(arg) // prints "ping"
event.sender.send('asynchronous-reply', 'pong')
})
//synchronous
ipcMain.on('winman', (event, arg) => {
console.log('ipcMain.on winman', arg)
if (arg.action === 'newfile') {
event.returnValue = createWindow(arg.opt)
return
}
event.returnValue = 'pong'
})
createWindow()
// checkUpdate()
if (!__DEV__)
{
autoUpdater.checkForUpdates()
}
})
// Quit when all windows are closed.
app.on('window-all-closed', function () {
console.log('window-all-closed', windowsRegistry.length)
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
console.log('app on activate', windowsRegistry.length)
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (windowsRegistry.length === 0) {
createWindow()
}
})
function checkUpdate () {
autoUpdater.checkForUpdates().then(UpdateCheckResult => {
if (UpdateCheckResult) {
let idx = dialog.showMessageBox({
type: 'question',
buttons: ['Ok', 'Cancel'],
title: 'Confirm Update',
message: 'Update available.\n\nWould you like to download and install new version?',
detail: 'Application will automatically restart to apply update after download',
})
if (idx === 0) return autoUpdater.downloadUpdate()
}
}).then((a, b) => {
log.info('@cfu update-downloaded@\n', a, b)
}).catch(e => {
log.error('@cfu then error@\n', e)
})
}
autoUpdater.on('error', e => log.error('@error@\n', e))
autoUpdater.on('update-available',
(a, b) => log.info('@update-available@\n', a, b))
/**/
autoUpdater.on('update-downloaded', (event, info) => {
log.info('@update-downloaded@\n', info, event)
// Ask user to update the app
dialog.showMessageBox({
type: 'question',
buttons: ['Install and Relaunch', 'Later'],
defaultId: 0,
message: 'A new version of ' + app.getName() + ' has been downloaded',
detail: 'It will be installed the next time you restart the application',
}, response => {
if (response === 0) {
setTimeout(() => autoUpdater.quitAndInstall(), 1)
}
})
})
/**/

View file

@ -13,8 +13,9 @@
circuit and social network diagrams.">
<meta itemprop="image" content="https://lh4.googleusercontent.com/-cLKEldMbT_E/Tx8qXDuw6eI/AAAAAAAAAAs/Ke0pnlk8Gpg/w500-h344-k/BPMN%2Bdiagram%2Brc2f.png">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="msapplication-config" content="images/browserconfig.xml">
<meta name="mobile-web-app-capable" content="yes">
<link rel="canonical" href="https://www.draw.io">
<meta name="theme-color" content="#d89000">
<script type="text/javascript">
/**
* URL Parameters and protocol description are here:
@ -101,18 +102,50 @@
}
})();
}
/**
* Adds meta tags with application name (depends on offline URL parameter)
*/
(function()
{
function addMeta(name, content)
{
try
{
var s = document.createElement('meta');
s.setAttribute('name', name);
s.setAttribute('content', content);
var t = document.getElementsByTagName('meta')[0];
t.parentNode.insertBefore(s, t);
}
catch (e)
{
// ignore
}
};
var name = 'draw.io';
if (urlParams['offline'] === '1')
{
name += ' app';
}
addMeta('apple-mobile-web-app-title', name);
addMeta('application-name', name);
})();
</script>
<link rel="chrome-webstore-item" href="https://chrome.google.com/webstore/detail/plgmlhohecdddhbmmkncjdmlhcmaachm">
<link rel="apple-touch-icon" sizes="180x180" href="images/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="images/favicon-16x16.png">
<link rel="mask-icon" href="images/safari-pinned-tab.svg" color="#d89000">
<meta name="msapplication-config" content="images/browserconfig.xml">
<link rel="manifest" href="images/manifest.json">
<meta name="application-name" content="draw.io">
<link rel="shortcut icon" href="favicon.ico">
<meta name="theme-color" content="#d89000">
<link rel="stylesheet" type="text/css" href="styles/grapheditor.css">
<link rel="canonical" href="https://www.draw.io">
<link rel="manifest" href="images/manifest.json">
<link rel="shortcut icon" href="favicon.ico">
<style type="text/css">
body { overflow:hidden; }
.geSidebarContainer .geTitle { color:#505050; }
@ -312,7 +345,7 @@
if (window && window.process && window.process.type)
{
// Electron
mxscript('../etc/electron/ElectronApp.js');
mxscript('js/diagramly/ElectronApp.js');
}
// Adds basic error handling

View file

@ -0,0 +1,735 @@
window.OPEN_URL = 'https://www.draw.io/open';
window.TEMPLATE_PATH = 'templates';
FeedbackDialog.feedbackUrl = 'https://log.draw.io/email';
(function()
{
// Overrides default mode
App.mode = App.MODE_DEVICE;
// Disables new window option in edit diagram dialog
EditDiagramDialog.showNewWindowOption = false;
// Redirects printing to iframe to avoid document.write
var printDialogCreatePrintPreview = PrintDialog.createPrintPreview;
PrintDialog.createPrintPreview = function()
{
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
var result = printDialogCreatePrintPreview.apply(this, arguments);
result.wnd = iframe.contentWindow;
result.iframe = iframe;
// Workaround for lost gradients in print output
result.previousGetBaseUrl = mxSvgCanvas2D.prototype.getBaseUrl;
mxSvgCanvas2D.prototype.getBaseUrl = function()
{
return '';
};
return result;
};
var oldWindowOpen = window.open;
window.open = function(url)
{
if (url != null && url.startsWith('http'))
{
const {shell} = require('electron');
shell.openExternal(url);
}
else
{
return oldWindowOpen(url);
}
}
mxPrintPreview.prototype.addPageBreak = function(doc)
{
// Do nothing
};
mxPrintPreview.prototype.closeDocument = function()
{
var doc = this.wnd.document;
// Removes all event handlers in the print output
mxEvent.release(doc.body);
};
PrintDialog.printPreview = function(preview)
{
if (preview.iframe != null)
{
preview.iframe.contentWindow.print();
preview.iframe.parentNode.removeChild(preview.iframe);
mxSvgCanvas2D.prototype.getBaseUrl = preview.previousGetBaseUrl;
preview.iframe = null;
}
};
PrintDialog.previewEnabled = false;
// Enables PDF export via print
EditorUi.prototype.printPdfExport = true;
var menusInit = Menus.prototype.init;
Menus.prototype.init = function()
{
menusInit.apply(this, arguments);
var editorUi = this.editorUi;
// Replaces file menu to replace openFrom menu with open and rename downloadAs to export
this.put('file', new Menu(mxUtils.bind(this, function(menu, parent)
{
this.addMenuItems(menu, ['new', 'open', '-', 'save', 'saveAs', '-', 'import'], parent);
this.addSubmenu('exportAs', menu, parent);
this.addSubmenu('embed', menu, parent);
this.addMenuItems(menu, ['-', 'newLibrary', 'openLibrary', '-', 'documentProperties', 'print'], parent);
})));
this.put('extras', new Menu(mxUtils.bind(this, function(menu, parent)
{
this.addMenuItems(menu, ['copyConnect', 'collapseExpand', '-', 'mathematicalTypesetting', 'autosave', '-',
'createShape', 'editDiagram', '-', 'tags', '-', 'online'], parent);
})));
};
// Initializes the user interface
var editorUiInit = EditorUi.prototype.init;
EditorUi.prototype.init = function()
{
editorUiInit.apply(this, arguments);
var editorUi = this;
var graph = this.editor.graph;
this.editor.autosave = false;
global.__emt_isModified = e => {
if (this.getCurrentFile())
return this.getCurrentFile().isModified()
return false
}
// global.__emt_getCurrentFile = e => {
// return this.getCurrentFile()
// }
// Adds support for libraries
this.actions.addAction('newLibrary...', mxUtils.bind(this, function()
{
editorUi.showLibraryDialog(null, null, null, null, App.MODE_DEVICE);
}));
this.actions.addAction('openLibrary...', mxUtils.bind(this, function()
{
editorUi.pickLibrary(App.MODE_DEVICE);
}));
// Replaces import action
this.actions.addAction('import...', mxUtils.bind(this, function()
{
if (editorUi.getCurrentFile() != null)
{
const electron = require('electron');
var remote = electron.remote;
var dialog = remote.dialog;
var paths = dialog.showOpenDialog({properties: ['openFile']});
if (paths !== undefined && paths[0] != null)
{
var fs = require('fs');
var path = paths[0];
var index = path.lastIndexOf('.png');
var isPng = index > -1 && index == path.length - 4;
var encoding = (isPng || /\.gif$/i.test(path) || /\.jpe?g$/i.test(path) ||
/\.vsdx$/i.test(path)) ? 'base64' : 'utf-8'
if (editorUi.spinner.spin(document.body, mxResources.get('loading')))
{
fs.readFile(path, encoding, mxUtils.bind(this, function (e, data)
{
if (e)
{
editorUi.spinner.stop();
editorUi.handleError(e);
}
else
{
try
{
if (isPng)
{
var tmp = editorUi.extractGraphModelFromPng(data);
if (tmp != null)
{
data = tmp;
}
}
if (!editorUi.isOffline() && new XMLHttpRequest().upload && editorUi.isRemoteFileFormat(data, path))
{
// Asynchronous parsing via server
editorUi.parseFile(editorUi.base64ToBlob(data, 'application/octet-stream'), mxUtils.bind(this, function(xhr)
{
if (xhr.readyState == 4)
{
editorUi.spinner.stop();
if (xhr.status >= 200 && xhr.status <= 299)
{
editorUi.editor.graph.setSelectionCells(editorUi.insertTextAt(xhr.responseText, 0, 0, true));
}
}
}), path);
}
else if (isPng || /\.gif$/i.test(path) || /\.jpe?g$/i.test(path))
{
var img = new Image();
img.onload = function()
{
editorUi.resizeImage(img, img.src, function(data2, w, h)
{
editorUi.spinner.stop();
var pt = graph.getInsertPoint();
graph.setSelectionCell(graph.insertVertex(null, null, '', pt.x, pt.y, w, h,
'shape=image;aspect=fixed;image=' + editorUi.convertDataUri(data2) + ';'));
}, true);
};
img.src = 'data:image/png;base64,' + data;
}
else if (data != null)
{
editorUi.spinner.stop();
graph.setSelectionCells(editorUi.importXml(data));
}
}
catch(e)
{
editorUi.spinner.stop();
editorUi.handleError(e);
}
}
}));
}
}
}
}));
// Replaces new action
var oldNew = this.actions.get('new').funct;
this.actions.addAction('new...', mxUtils.bind(this, function()
{
mxLog.debug(this.getCurrentFile());
if (this.getCurrentFile() == null)
{
oldNew();
}
else {
const ipc = require('electron').ipcRenderer
ipc.sendSync('winman', {action: 'newfile', opt: {width: 1600}})
}
}), null, null, 'Ctrl+N');
this.actions.get('open').shortcut = 'Ctrl+O';
// Adds shortcut keys for file operations
editorUi.keyHandler.bindAction(78, true, 'new'); // Ctrl+N
editorUi.keyHandler.bindAction(79, true, 'open'); // Ctrl+O
editorUi.actions.addAction('keyboardShortcuts...', function()
{
const electron = require('electron');
const remote = electron.remote;
const BrowserWindow = remote.BrowserWindow;
keyboardWindow = new BrowserWindow({width: 1200, height: 1000});
// and load the index.html of the app.
keyboardWindow.loadURL(`file://${__dirname}/shortcuts.svg`);
// Emitted when the window is closed.
keyboardWindow.on('closed', function()
{
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
keyboardWindow = null;
});
});
}
// Uses local picker
App.prototype.pickFile = function()
{
var doPickFile = mxUtils.bind(this, function()
{
this.chooseFileEntry(mxUtils.bind(this, function(fileEntry, data)
{
var file = new LocalFile(this, data, '');
file.fileObject = fileEntry;
this.fileLoaded(file);
}));
});
var file = this.getCurrentFile();
if (file != null && file.isModified())
{
this.confirm(mxResources.get('allChangesLost'), null, doPickFile,
mxResources.get('cancel'), mxResources.get('discardChanges'));
}
else
{
doPickFile();
}
};
/**
* Selects a library to load from a picker
*
* @param mode the device mode, ignored in this case
*/
App.prototype.pickLibrary = function(mode)
{
this.chooseFileEntry(mxUtils.bind(this, function(fileEntry, data)
{
try
{
var library = new LocalLibrary(this, data, fileEntry.name);
library.fileObject = fileEntry;
this.loadLibrary(library);
}
catch (e)
{
this.handleError(e, mxResources.get('errorLoadingFile'));
}
}));
};
// Uses local picker
App.prototype.chooseFileEntry = function(fn)
{
const electron = require('electron');
var remote = electron.remote;
var dialog = remote.dialog;
var paths = dialog.showOpenDialog({properties: ['openFile']});
if (paths !== undefined && paths[0] != null)
{
var fs = require('fs');
var path = paths[0];
var index = path.lastIndexOf('.png');
var isPng = index > -1 && index == path.length - 4;
var encoding = isPng ? 'base64' : 'utf-8'
fs.readFile(path, encoding, mxUtils.bind(this, function (e, data)
{
if (e)
{
this.handleError(e);
}
else
{
if (isPng)
{
// Detecting png by extension. Would need https://github.com/mscdex/mmmagic
// to do it by inspection
data = this.extractGraphModelFromPng(data, true);
}
var fileEntry = new Object();
fileEntry.path = path;
fileEntry.name = path.replace(/^.*[\\\/]/, '');
fileEntry.type = encoding;
fn(fileEntry, data);
}
}));
}
};
// Disables temp files in Electron
var LocalFileCtor = LocalFile;
LocalFile = function(ui, data, title, temp)
{
LocalFileCtor.call(this, ui, data, title, false);
};
mxUtils.extend(LocalFile, LocalFileCtor);
LocalFile.prototype.isAutosave = function()
{
return this.ui.editor.autosave && this.fileObject != null;
};
LocalFile.prototype.isAutosaveOptional = function()
{
return true;
};
LocalLibrary.prototype.isAutosave = function()
{
return this.fileObject != null;
};
LocalFile.prototype.getTitle = function()
{
return (this.fileObject != null) ? this.fileObject.name : this.title;
};
LocalFile.prototype.isRenamable = function()
{
return false;
};
// Restores default implementation of open with autosave
LocalFile.prototype.open = DrawioFile.prototype.open;
LocalFile.prototype.save = function(revision, success, error)
{
DrawioFile.prototype.save.apply(this, arguments);
this.saveFile(revision, success, error);
};
LocalFile.prototype.saveFile = function(revision, success, error)
{
var fn = mxUtils.bind(this, function()
{
var doSave = mxUtils.bind(this, function(data, enc)
{
if (!this.savingFile)
{
this.savingFile = true;
// Makes sure no changes get lost while the file is saved
var prevModified = this.isModified;
var modified = this.isModified();
this.setModified(false);
var fs = require('fs');
fs.writeFile(this.fileObject.path, data, enc || this.fileObject.encoding, mxUtils.bind(this, function (e)
{
if (e)
{
this.savingFile = false;
this.isModified = prevModified;
this.setModified(modified || this.isModified());
if (error != null)
{
error();
}
}
else
{
this.savingFile = false;
this.isModified = prevModified;
this.contentChanged();
this.lastData = data;
if (success != null)
{
success();
}
}
}));
}
else
{
// TODO, already saving. Need a better error
if (error != null)
{
error();
}
}
});
if (!/(\.png)$/i.test(this.fileObject.name))
{
doSave(this.getData());
}
else
{
var graph = this.ui.editor.graph;
// Exports PNG for first page while other page is visible by creating a graph
// LATER: Add caching for the graph or SVG while not on first page
if (this.ui.pages != null && this.ui.currentPage != this.ui.pages[0])
{
graph = this.ui.createTemporaryGraph(graph.getStylesheet());
var graphGetGlobalVariable = graph.getGlobalVariable;
var page = this.ui.pages[0];
graph.getGlobalVariable = function(name)
{
if (name == 'page')
{
return page.getName();
}
else if (name == 'pagenumber')
{
return 1;
}
return graphGetGlobalVariable.apply(this, arguments);
};
document.body.appendChild(graph.container);
graph.model.setRoot(page.root);
}
this.ui.exportToCanvas(mxUtils.bind(this, function(canvas)
{
try
{
var data = canvas.toDataURL('image/png');
data = this.ui.writeGraphModelToPng(data, 'zTXt', 'mxGraphModel',
atob(this.ui.editor.graph.compress(this.ui.getFileData(true))));
doSave(atob(data.substring(data.lastIndexOf(',') + 1)), 'binary');
// Removes temporary graph from DOM
if (graph != this.ui.editor.graph)
{
graph.container.parentNode.removeChild(graph.container);
}
}
catch (e)
{
if (error != null)
{
error(e);
}
}
}), null, null, null, mxUtils.bind(this, function(e)
{
if (error != null)
{
error(e);
}
}), null, null, null, null, null, null, graph);
}
});
if (this.fileObject == null)
{
const electron = require('electron');
var remote = electron.remote;
var dialog = remote.dialog;
var path = dialog.showSaveDialog({defaultPath: this.title});
if (path != null)
{
this.fileObject = new Object();
this.fileObject.path = path;
this.fileObject.name = path.replace(/^.*[\\\/]/, '');
this.fileObject.type = 'utf-8';
fn();
}
else if (error != null)
{
error();
}
}
else
{
fn();
}
};
LocalLibrary.prototype.save = function(revision, success, error)
{
LocalFile.prototype.saveFile.apply(this, arguments);
};
LocalFile.prototype.saveAs = function(title, success, error)
{
const electron = require('electron');
var remote = electron.remote;
var dialog = remote.dialog;
var filename = this.title;
// Adds default extension
if (filename.length > 0 && (!/(\.xml)$/i.test(filename) && !/(\.html)$/i.test(filename) &&
!/(\.svg)$/i.test(filename) && !/(\.png)$/i.test(filename)))
{
filename += '.xml';
}
var path = dialog.showSaveDialog({defaultPath: filename});
if (path != null)
{
this.fileObject = new Object();
this.fileObject.path = path;
this.fileObject.name = path.replace(/^.*[\\\/]/, '');
this.fileObject.type = 'utf-8';
this.save(false, success, error);
}
else if (error != null)
{
error();
}
};
App.prototype.saveFile = function(forceDialog)
{
var file = this.getCurrentFile();
if (file != null)
{
if (!forceDialog && file.getTitle() != null)
{
file.save(true, mxUtils.bind(this, function(resp)
{
this.spinner.stop();
this.editor.setStatus(mxUtils.htmlEntities(mxResources.get('allChangesSaved')));
}), mxUtils.bind(this, function(resp)
{
this.editor.setStatus('');
this.handleError(resp, (resp != null) ? mxResources.get('errorSavingFile') : null);
}));
}
else
{
file.saveAs(null, mxUtils.bind(this, function(resp)
{
this.spinner.stop();
this.editor.setStatus(mxUtils.htmlEntities(mxResources.get('allChangesSaved')));
}), mxUtils.bind(this, function(resp)
{
this.editor.setStatus('');
this.handleError(resp, (resp != null) ? mxResources.get('errorSavingFile') : null);
}));
}
}
};
/**
* Translates this point by the given vector.
*
* @param {number} dx X-coordinate of the translation.
* @param {number} dy Y-coordinate of the translation.
*/
App.prototype.saveLibrary = function(name, images, file, mode, noSpin, noReload, fn)
{
mode = (mode != null) ? mode : this.mode;
noSpin = (noSpin != null) ? noSpin : false;
noReload = (noReload != null) ? noReload : false;
var xml = this.createLibraryDataFromImages(images);
var error = mxUtils.bind(this, function(resp)
{
this.spinner.stop();
if (fn != null)
{
fn();
}
// Null means cancel by user and is ignored
if (resp != null)
{
this.handleError(resp, mxResources.get('errorSavingFile'));
}
});
// Handles special case for local libraries
if (file == null)
{
file = new LocalLibrary(this, xml, name);
}
if (noSpin || this.spinner.spin(document.body, mxResources.get('saving')))
{
file.setData(xml);
var doSave = mxUtils.bind(this, function()
{
file.save(true, mxUtils.bind(this, function(resp)
{
this.spinner.stop();
this.hideDialog(true);
if (!noReload)
{
this.libraryLoaded(file, images)
}
if (fn != null)
{
fn();
}
}), error);
});
if (name != file.getTitle())
{
var oldHash = file.getHash();
file.rename(name, mxUtils.bind(this, function(resp)
{
// Change hash in stored settings
if (file.constructor != LocalLibrary && oldHash != file.getHash())
{
mxSettings.removeCustomLibrary(oldHash);
mxSettings.addCustomLibrary(file.getHash());
}
// Workaround for library files changing hash so
// the old library cannot be removed from the
// sidebar using the updated file in libraryLoaded
this.removeLibrarySidebar(oldHash);
doSave();
}), error)
}
else
{
doSave();
}
}
};
EditorUi.prototype.saveData = function(filename, format, data, mimeType, base64Encoded)
{
const electron = require('electron');
var remote = electron.remote;
var dialog = remote.dialog;
var path = dialog.showSaveDialog({defaultPath: filename});
if (path != null)
{
this.fileObject = new Object();
this.fileObject.path = path;
this.fileObject.name = path.replace(/^.*[\\\/]/, '');
var isImage = mimeType != null && mimeType.startsWith('image');
this.fileObject.type = base64Encoded ? 'base64' : 'utf-8';
var fs = require('fs');
fs.writeFile(this.fileObject.path, data, this.fileObject.type, mxUtils.bind(this, function (e)
{
if (e)
{
this.handleError({message: mxResources.get('errorSavingFile')});
}
}));
}
};
EditorUi.prototype.addBeforeUnloadListener = function() {};
})();