|
@@ -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() {};
|
|
|
+})();
|