David Benson 4 лет назад
Родитель
Сommit
418951e7c5
89 измененных файлов с 4326 добавлено и 3517 удалено
  1. 2 0
      .github/workflows/build-release.yml
  2. 19 0
      ChangeLog
  3. 1 1
      VERSION
  4. 79 0
      src/main/webapp/electron-preload.js
  5. 484 44
      src/main/webapp/electron.js
  6. 0 124
      src/main/webapp/electronFilesWorker.js
  7. 1102 1090
      src/main/webapp/js/app.min.js
  8. 4 4
      src/main/webapp/js/diagramly/App.js
  9. 2 2
      src/main/webapp/js/diagramly/Devel.js
  10. 4 4
      src/main/webapp/js/diagramly/Dialogs.js
  11. 1 1
      src/main/webapp/js/diagramly/DriveClient.js
  12. 18 2
      src/main/webapp/js/diagramly/Editor.js
  13. 35 10
      src/main/webapp/js/diagramly/EditorUi.js
  14. 557 578
      src/main/webapp/js/diagramly/ElectronApp.js
  15. 1 1
      src/main/webapp/js/diagramly/Init.js
  16. 1 1
      src/main/webapp/js/diagramly/Menus.js
  17. 2 15
      src/main/webapp/js/diagramly/Minimal.js
  18. 1 1
      src/main/webapp/js/diagramly/OneDriveClient.js
  19. 4 0
      src/main/webapp/js/diagramly/Pages.js
  20. 52 26
      src/main/webapp/js/export.js
  21. 12 10
      src/main/webapp/js/grapheditor/Format.js
  22. 8 6
      src/main/webapp/js/grapheditor/Graph.js
  23. 301 53
      src/main/webapp/js/grapheditor/Shapes.js
  24. 5 5
      src/main/webapp/js/grapheditor/Sidebar.js
  25. 772 759
      src/main/webapp/js/viewer-static.min.js
  26. 772 759
      src/main/webapp/js/viewer.min.js
  27. 23 13
      src/main/webapp/mxgraph/mxClient.js
  28. 1 0
      src/main/webapp/resources/dia.txt
  29. 1 0
      src/main/webapp/resources/dia_am.txt
  30. 1 0
      src/main/webapp/resources/dia_ar.txt
  31. 1 0
      src/main/webapp/resources/dia_bg.txt
  32. 1 0
      src/main/webapp/resources/dia_bn.txt
  33. 1 0
      src/main/webapp/resources/dia_bs.txt
  34. 1 0
      src/main/webapp/resources/dia_ca.txt
  35. 1 0
      src/main/webapp/resources/dia_cs.txt
  36. 1 0
      src/main/webapp/resources/dia_da.txt
  37. 1 0
      src/main/webapp/resources/dia_de.txt
  38. 1 0
      src/main/webapp/resources/dia_el.txt
  39. 1 0
      src/main/webapp/resources/dia_eo.txt
  40. 1 0
      src/main/webapp/resources/dia_es.txt
  41. 1 0
      src/main/webapp/resources/dia_et.txt
  42. 1 0
      src/main/webapp/resources/dia_eu.txt
  43. 1 0
      src/main/webapp/resources/dia_fa.txt
  44. 1 0
      src/main/webapp/resources/dia_fi.txt
  45. 1 0
      src/main/webapp/resources/dia_fil.txt
  46. 1 0
      src/main/webapp/resources/dia_fr.txt
  47. 1 0
      src/main/webapp/resources/dia_gl.txt
  48. 1 0
      src/main/webapp/resources/dia_gu.txt
  49. 1 0
      src/main/webapp/resources/dia_he.txt
  50. 1 0
      src/main/webapp/resources/dia_hi.txt
  51. 1 0
      src/main/webapp/resources/dia_hr.txt
  52. 1 0
      src/main/webapp/resources/dia_hu.txt
  53. 1 0
      src/main/webapp/resources/dia_i18n.txt
  54. 1 0
      src/main/webapp/resources/dia_id.txt
  55. 1 0
      src/main/webapp/resources/dia_it.txt
  56. 1 0
      src/main/webapp/resources/dia_ja.txt
  57. 1 0
      src/main/webapp/resources/dia_kn.txt
  58. 1 0
      src/main/webapp/resources/dia_ko.txt
  59. 1 0
      src/main/webapp/resources/dia_lt.txt
  60. 1 0
      src/main/webapp/resources/dia_lv.txt
  61. 1 0
      src/main/webapp/resources/dia_ml.txt
  62. 1 0
      src/main/webapp/resources/dia_mr.txt
  63. 1 0
      src/main/webapp/resources/dia_ms.txt
  64. 1 0
      src/main/webapp/resources/dia_my.txt
  65. 1 0
      src/main/webapp/resources/dia_nl.txt
  66. 1 0
      src/main/webapp/resources/dia_no.txt
  67. 1 0
      src/main/webapp/resources/dia_pl.txt
  68. 1 0
      src/main/webapp/resources/dia_pt-br.txt
  69. 1 0
      src/main/webapp/resources/dia_pt.txt
  70. 1 0
      src/main/webapp/resources/dia_ro.txt
  71. 1 0
      src/main/webapp/resources/dia_ru.txt
  72. 1 0
      src/main/webapp/resources/dia_si.txt
  73. 1 0
      src/main/webapp/resources/dia_sk.txt
  74. 1 0
      src/main/webapp/resources/dia_sl.txt
  75. 1 0
      src/main/webapp/resources/dia_sr.txt
  76. 1 0
      src/main/webapp/resources/dia_sv.txt
  77. 1 0
      src/main/webapp/resources/dia_sw.txt
  78. 1 0
      src/main/webapp/resources/dia_ta.txt
  79. 1 0
      src/main/webapp/resources/dia_te.txt
  80. 1 0
      src/main/webapp/resources/dia_th.txt
  81. 1 0
      src/main/webapp/resources/dia_tr.txt
  82. 1 0
      src/main/webapp/resources/dia_uk.txt
  83. 1 0
      src/main/webapp/resources/dia_vi.txt
  84. 1 0
      src/main/webapp/resources/dia_zh-tw.txt
  85. 1 0
      src/main/webapp/resources/dia_zh.txt
  86. 1 1
      src/main/webapp/service-worker.js
  87. 1 1
      src/main/webapp/service-worker.js.map
  88. 1 1
      src/main/webapp/templates/basic/cross.xml
  89. 3 5
      src/main/webapp/vsdxImporter.html

+ 2 - 0
.github/workflows/build-release.yml

@@ -2,6 +2,8 @@ name: Build & Release
 
 
 on:
 on:
   push:
   push:
+    paths:
+      - VERSION
       
       
 jobs:
 jobs:
   build:
   build:

+ 19 - 0
ChangeLog

@@ -1,3 +1,22 @@
+30-DEC-2021: 16.1.2
+
+- Adds fillStyle dropdown for image background
+
+29-DEC-2021: 16.1.1
+
+- Avoids creating Blob for parseFile
+- Fixes dimension shape with large stroke size https://github.com/jgraph/drawio/issues/271
+- Hides foreign object warnings in background pages
+- Fixes overflows in minimal and sketch theme https://github.com/jgraph/drawio/issues/2509
+- Fixes freehand mode for Apple pencil on iOS https://github.com/jgraph/drawio/issues/2510
+- Adds tableRow shape, fixes events for merged cells
+- Uses clip path attribute for SVG image clipping
+- Fixes default label background for imported images
+- Fits image to clipPath bounding box
+- Fixes collapsed table foreground https://github.com/jgraph/drawio/issues/2512
+- Fixes overflow in LinkDialog
+- Disables child layout for collapsed cells
+
 23-DEC-2021: 16.1.0
 23-DEC-2021: 16.1.0
 
 
 - Fixes inconsistent event cursors on table lines
 - Fixes inconsistent event cursors on table lines

+ 1 - 1
VERSION

@@ -1 +1 @@
-16.1.0
+16.1.2

+ 79 - 0
src/main/webapp/electron-preload.js

@@ -0,0 +1,79 @@
+const {
+    contextBridge,
+    ipcRenderer
+} = require("electron");
+
+let reqId = 1;
+let reqInfo = {};
+let fileChangedListeners = {};
+
+ipcRenderer.on('mainResp', (event, resp) => 
+{
+	var callbacks = reqInfo[resp.reqId];
+	
+	if (resp.error)
+	{
+		callbacks.error(resp.msg, resp.e);
+	}
+	else
+	{
+		callbacks.callback(resp.data);
+	}
+	
+	delete reqInfo[resp.reqId];
+});
+
+ipcRenderer.on('fileChanged', (event, resp) => 
+{
+	var listener = fileChangedListeners[resp.path];
+	
+	if (listener)
+	{
+		listener(resp.curr, resp.prev);
+	}
+});
+
+contextBridge.exposeInMainWorld(
+    'electron', {
+        request: (msg, callback, error) => 
+		{
+			msg.reqId = reqId++;
+			reqInfo[msg.reqId] = {callback: callback, error: error};
+
+			//TODO Maybe a special function for this better than this hack?
+			//File watch special case where the callback is called multiple times
+			if (msg.action == 'watchFile')
+			{
+				fileChangedListeners[msg.path] = msg.listener;
+				delete msg.listener;
+			}
+
+			ipcRenderer.send('rendererReq', msg);
+        },
+		registerMsgListener: function(action, callback)
+		{
+			ipcRenderer.on(action, function(event, args)
+			{
+				callback(args);
+			});
+		},
+		sendMessage: function(action, args)
+		{
+			ipcRenderer.send(action, args);
+		},
+		listenOnce: function(action, callback)
+		{
+			ipcRenderer.once(action, function(event, args)
+			{
+				callback(args);
+			});
+		}
+    }
+);
+
+contextBridge.exposeInMainWorld(
+    'process', {
+		type: process.type,
+		versions: process.versions
+	}
+);

+ 484 - 44
src/main/webapp/electron.js

@@ -2,12 +2,8 @@ const fs = require('fs')
 const os = require('os');
 const os = require('os');
 const path = require('path')
 const path = require('path')
 const url = require('url')
 const url = require('url')
-const electron = require('electron')
-const {Menu: menu, shell} = require('electron')
-const ipcMain = electron.ipcMain
-const dialog = electron.dialog
-const app = electron.app
-const BrowserWindow = electron.BrowserWindow
+const {Menu: menu, shell, dialog,
+		clipboard, nativeImage, ipcMain, app, BrowserWindow} = require('electron')
 const crc = require('crc');
 const crc = require('crc');
 const zlib = require('zlib');
 const zlib = require('zlib');
 const log = require('electron-log')
 const log = require('electron-log')
@@ -17,8 +13,6 @@ const PDFDocument = require('pdf-lib').PDFDocument;
 const Store = require('electron-store');
 const Store = require('electron-store');
 const store = new Store();
 const store = new Store();
 const ProgressBar = require('electron-progressbar');
 const ProgressBar = require('electron-progressbar');
-const remoteMain = require("@electron/remote/main")
-remoteMain.initialize()
 const disableUpdate = require('./disableUpdate').disableUpdate() || 
 const disableUpdate = require('./disableUpdate').disableUpdate() || 
 						process.env.DRAWIO_DISABLE_UPDATE === 'true' || 
 						process.env.DRAWIO_DISABLE_UPDATE === 'true' || 
 						fs.existsSync('/.flatpak-info'); //This file indicates running in flatpak sandbox
 						fs.existsSync('/.flatpak-info'); //This file indicates running in flatpak sandbox
@@ -89,17 +83,14 @@ function createWindow (opt = {})
 		webViewTag: false,
 		webViewTag: false,
 		'web-security': true,
 		'web-security': true,
 		webPreferences: {
 		webPreferences: {
-			// preload: path.resolve('./preload.js'),
-			nodeIntegration: true,
-			nodeIntegrationInWorker: true,
+			preload: `${__dirname}/electron-preload.js`,
 			spellcheck: enableSpellCheck,
 			spellcheck: enableSpellCheck,
-			contextIsolation: false,
+			contextIsolation: true,
 			nativeWindowOpen: true
 			nativeWindowOpen: true
 		}
 		}
 	}, opt)
 	}, opt)
 
 
 	let mainWindow = new BrowserWindow(options)
 	let mainWindow = new BrowserWindow(options)
-	remoteMain.enable(mainWindow.webContents)
 	windowsRegistry.push(mainWindow)
 	windowsRegistry.push(mainWindow)
 
 
 	if (__DEV__) 
 	if (__DEV__) 
@@ -107,6 +98,9 @@ function createWindow (opt = {})
 		console.log('createWindow', opt)
 		console.log('createWindow', opt)
 	}
 	}
 
 
+	//Cannot be read before app is ready
+	queryObj['appLang'] = app.getLocale();
+
 	let ourl = url.format(
 	let ourl = url.format(
 	{
 	{
 		pathname: `${__dirname}/index.html`,
 		pathname: `${__dirname}/index.html`,
@@ -123,6 +117,21 @@ function createWindow (opt = {})
 		mainWindow.webContents.openDevTools()
 		mainWindow.webContents.openDevTools()
 	}
 	}
 
 
+	mainWindow.on('maximize', function()
+	{
+		mainWindow.webContents.send('maximize')
+	});
+
+	mainWindow.on('unmaximize', function()
+	{
+		mainWindow.webContents.send('unmaximize')
+	});
+
+	mainWindow.on('resize', function()
+	{
+		mainWindow.webContents.send('resize')
+	});
+
 	mainWindow.on('close', (event) =>
 	mainWindow.on('close', (event) =>
 	{
 	{
 		const win = event.sender
 		const win = event.sender
@@ -137,7 +146,7 @@ function createWindow (opt = {})
 
 
 		if (contents != null)
 		if (contents != null)
 		{
 		{
-			contents.executeJavaScript('if(typeof global.__emt_isModified === \'function\'){global.__emt_isModified()}', true)
+			contents.executeJavaScript('if(typeof window.__emt_isModified === \'function\'){window.__emt_isModified()}', true)
 				.then((isModified) =>
 				.then((isModified) =>
 				{
 				{
 					if (__DEV__) 
 					if (__DEV__) 
@@ -159,7 +168,7 @@ function createWindow (opt = {})
 						if (choice === 1)
 						if (choice === 1)
 						{
 						{
 							//If user chose not to save, remove the draft
 							//If user chose not to save, remove the draft
-							contents.executeJavaScript('global.__emt_removeDraft()', true);
+							contents.executeJavaScript('window.__emt_removeDraft()', true);
 							win.destroy()
 							win.destroy()
 						}
 						}
 						else
 						else
@@ -198,28 +207,9 @@ function createWindow (opt = {})
 // Some APIs can only be used after this event occurs.
 // Some APIs can only be used after this event occurs.
 app.on('ready', e =>
 app.on('ready', e =>
 {
 {
-	//asynchronous
-	ipcMain.on('asynchronous-message', (event, arg) =>
+	ipcMain.on('newfile', (event, arg) =>
 	{
 	{
-		console.log(arg)  // prints "ping"
-		event.sender.send('asynchronous-reply', 'pong')
-	})
-	//synchronous
-	ipcMain.on('winman', (event, arg) =>
-	{
-		if (__DEV__) 
-		{
-			console.log('ipcMain.on winman', arg)
-		}
-		
-		if (arg.action === 'newfile')
-		{
-			event.returnValue = createWindow(arg.opt).id
-			
-			return
-		}
-		
-		event.returnValue = 'pong'
+		createWindow(arg)
 	})
 	})
 	
 	
     let argv = process.argv
     let argv = process.argv
@@ -256,7 +246,9 @@ app.on('ready', e =>
 			.option('-t, --transparent',
 			.option('-t, --transparent',
 				'set transparent background for PNG')
 				'set transparent background for PNG')
 			.option('-e, --embed-diagram',
 			.option('-e, --embed-diagram',
-				'includes a copy of the diagram (for PNG and PDF formats only)')
+				'includes a copy of the diagram (for PNG, SVG and PDF formats only)')
+			.option('--embed-svg-images',
+				'Embed Images in SVG file (for SVG format only)')
 			.option('-b, --border <border>',
 			.option('-b, --border <border>',
 				'sets the border width around the diagram (default: 0)', parseInt)
 				'sets the border width around the diagram (default: 0)', parseInt)
 			.option('-s, --scale <scale>',
 			.option('-s, --scale <scale>',
@@ -291,8 +283,8 @@ app.on('ready', e =>
     	var dummyWin = new BrowserWindow({
     	var dummyWin = new BrowserWindow({
 			show : false,
 			show : false,
 			webPreferences: {
 			webPreferences: {
-				nodeIntegration: true,
-				contextIsolation: false,
+				preload: `${__dirname}/electron-preload.js`,
+				contextIsolation: true,
 				nativeWindowOpen: true
 				nativeWindowOpen: true
 			}
 			}
 		});
 		});
@@ -362,6 +354,7 @@ app.on('ready', e =>
 				allPages: format == 'pdf' && options.allPages,
 				allPages: format == 'pdf' && options.allPages,
 				scale: (options.crop && (options.scale == null || options.scale == 1)) ? 1.00001: (options.scale || 1), //any value other than 1 crops the pdf
 				scale: (options.crop && (options.scale == null || options.scale == 1)) ? 1.00001: (options.scale || 1), //any value other than 1 crops the pdf
 				embedXml: options.embedDiagram? '1' : '0',
 				embedXml: options.embedDiagram? '1' : '0',
+				embedImages: options.embedSvgImages? '1' : '0',
 				jpegQuality: options.quality,
 				jpegQuality: options.quality,
 				uncompressed: options.uncompressed
 				uncompressed: options.uncompressed
 			};
 			};
@@ -492,7 +485,8 @@ app.on('ready', e =>
 												{
 												{
 													if (outType.isDir)
 													if (outType.isDir)
 													{
 													{
-														outFileName = path.join(options.output, path.basename(curFile)) + '.' + format;
+														outFileName = path.join(options.output, path.basename(curFile,
+															path.extname(curFile))) + '.' + format;
 													}
 													}
 													else
 													else
 													{
 													{
@@ -527,7 +521,7 @@ app.on('ready', e =>
 													}
 													}
 													
 													
 													fs.writeFileSync(realFileName, data, format == 'vsdx'? 'base64' : null, { flag: 'wx' });
 													fs.writeFileSync(realFileName, data, format == 'vsdx'? 'base64' : null, { flag: 'wx' });
-													console.log(curFile + ' -> ' + outFileName);
+													console.log(curFile + ' -> ' + realFileName);
 												}
 												}
 												catch(e)
 												catch(e)
 												{
 												{
@@ -582,6 +576,7 @@ app.on('ready', e =>
 	}
 	}
     else if (program.rawArgs.indexOf('-h') > -1 || program.rawArgs.indexOf('--help') > -1 || program.rawArgs.indexOf('-V') > -1 || program.rawArgs.indexOf('--version') > -1) //To prevent execution when help/version arg is used
     else if (program.rawArgs.indexOf('-h') > -1 || program.rawArgs.indexOf('--help') > -1 || program.rawArgs.indexOf('-V') > -1 || program.rawArgs.indexOf('--version') > -1) //To prevent execution when help/version arg is used
 	{
 	{
+		app.quit();
     	return;
     	return;
 	}
 	}
     
     
@@ -1219,9 +1214,9 @@ function exportDiagram(event, args, directFinalize)
 	{
 	{
 		browser = new BrowserWindow({
 		browser = new BrowserWindow({
 			webPreferences: {
 			webPreferences: {
+				preload: `${__dirname}/electron-preload.js`,
 				backgroundThrottling: false,
 				backgroundThrottling: false,
-				nodeIntegration: true,
-				contextIsolation: false,
+				contextIsolation: true,
 				nativeWindowOpen: true
 				nativeWindowOpen: true
 			},
 			},
 			show : false,
 			show : false,
@@ -1267,6 +1262,12 @@ function exportDiagram(event, args, directFinalize)
 
 
 			function renderingFinishHandler(evt, renderInfo)
 			function renderingFinishHandler(evt, renderInfo)
 			{
 			{
+				if (renderInfo == null)
+				{
+					event.reply('export-error');
+					return;
+				}
+
 				var pageCount = renderInfo.pageCount, bounds = null;
 				var pageCount = renderInfo.pageCount, bounds = null;
 				//For some reason, Electron 9 doesn't send this object as is without stringifying. Usually when variable is external to function own scope
 				//For some reason, Electron 9 doesn't send this object as is without stringifying. Usually when variable is external to function own scope
 				try
 				try
@@ -1462,4 +1463,443 @@ function exportDiagram(event, args, directFinalize)
 	}
 	}
 };
 };
 
 
-ipcMain.on('export', exportDiagram);
+ipcMain.on('export', exportDiagram);
+
+//================================================================
+// Renderer Helper functions
+//================================================================
+
+const { COPYFILE_EXCL } = fs.constants;
+const DRAFT_PREFEX = '~$';
+const DRAFT_EXT = '.dtmp';
+const BKP_PREFEX = '~$';
+const BKP_EXT = '.bkp';
+
+function isConflict(origStat, stat)
+{
+	return stat != null && origStat != null && stat.mtimeMs != origStat.mtimeMs;
+};
+
+function getDraftFileName(fileObject)
+{
+	let filePath = fileObject.path;
+	let draftFileName = '', counter = 1, uniquePart = '';
+
+	do
+	{
+		draftFileName = path.join(path.dirname(filePath), DRAFT_PREFEX + path.basename(filePath) + uniquePart + DRAFT_EXT);
+		uniquePart = '_' + counter++;
+	} while (fs.existsSync(draftFileName));
+
+	return draftFileName;
+};
+
+function getFileDrafts(fileObject)
+{
+	let filePath = fileObject.path;
+	let draftsPaths = [], drafts = [], draftFileName, counter = 1, uniquePart = '';
+
+	do
+	{
+		draftsPaths.push(draftFileName);
+		draftFileName = path.join(path.dirname(filePath), DRAFT_PREFEX + path.basename(filePath) + uniquePart + DRAFT_EXT);
+		uniquePart = '_' + counter++;
+	} while (fs.existsSync(draftFileName)); //TODO this assume continuous drafts names
+
+	//Skip the first null element
+	for (let i = 1; i < draftsPaths.length; i++)
+	{
+		try
+		{
+			let stat = fs.lstatSync(draftsPaths[i]);
+			drafts.push({data: fs.readFileSync(draftsPaths[i], 'utf8'), 
+						created: stat.ctimeMs,
+						modified: stat.mtimeMs,
+						path: draftsPaths[i]});
+		}
+		catch (e){} // Ignore
+	}
+
+	return drafts;
+};
+
+function saveDraft(fileObject, data)
+{
+	if (data == null || data.length == 0)
+	{
+		throw new Error('empty data'); 
+	}
+	else
+	{
+		var draftFileName = fileObject.draftFileName || getDraftFileName(fileObject);
+		fs.writeFileSync(draftFileName, data, 'utf8');
+		return draftFileName;
+	}
+}
+
+function saveFile(fileObject, data, origStat, overwrite, defEnc)
+{
+	var retryCount = 0;
+	var backupCreated = false;
+	var bkpPath = path.join(path.dirname(fileObject.path), BKP_PREFEX + path.basename(fileObject.path) + BKP_EXT);
+
+	var writeFile = function()
+	{
+		if (data == null || data.length == 0)
+		{
+			throw new Error('empty data');
+		}
+		else
+		{
+			var writeEnc = defEnc || fileObject.encoding;
+			
+			fs.writeFileSync(fileObject.path, data, writeEnc);
+			let stat2 = fs.statSync(fileObject.path);
+			// Workaround for possible writing errors is to check the written
+			// contents of the file and retry 3 times before showing an error
+			let writtenData = fs.readFileSync(fileObject.path, writeEnc);
+			
+			if (data != writtenData)
+			{
+				retryCount++;
+				
+				if (retryCount < 3)
+				{
+					return writeFile();
+				}
+				else
+				{
+					throw new Error('all saving trials failed');
+				}
+			}
+			else
+			{
+				if (backupCreated)
+				{
+					fs.unlink(bkpPath, (err) => {}); //Ignore errors!
+				}
+
+				return stat2;
+			}
+		}
+	};
+	
+	function doSaveFile()
+	{
+		//Copy file to backup file (after conflict and stat is checked)
+		try
+		{
+			fs.copyFileSync(fileObject.path, bkpPath, COPYFILE_EXCL);
+			backupCreated = true;
+		}
+		catch (e) {} //Ignore
+					
+		return writeFile();
+	};
+	
+	if (overwrite)
+	{
+		return doSaveFile();
+	}
+	else
+	{
+		let stat = fs.existsSync(fileObject.path)?
+				 fs.statSync(fileObject.path) : null;
+
+		if (stat && isConflict(origStat, stat))
+		{
+			new Error('conflict');
+		}
+		else
+		{
+			return doSaveFile();
+		}
+	}
+};
+
+function writeFile(path, data, enc)
+{
+	return fs.writeFileSync(path, data, enc);
+};
+
+function getAppDataFolder()
+{
+	try
+	{
+		var appDataDir = app.getPath('appData');
+		var drawioDir = appDataDir + '/draw.io';
+		
+		if (!fs.existsSync(drawioDir)) //Usually this dir already exists
+		{
+			fs.mkdirSync(drawioDir);
+		}
+		
+		return drawioDir;
+	}
+	catch(e) {}
+	
+	return '.';
+};
+
+function getDocumentsFolder()
+{
+	//On windows, misconfigured Documents folder cause an exception
+	try
+	{
+		return app.getPath('documents');
+	}
+	catch(e) {}
+	
+	return '.';
+};
+
+function checkFileExists(pathParts)
+{
+	return fs.existsSync(path.join(...pathParts));
+};
+
+function showOpenDialog(defaultPath, filters, properties)
+{
+	return dialog.showOpenDialogSync({
+		defaultPath: defaultPath,
+		filters: filters,
+		properties: properties
+	});
+};
+
+function showSaveDialog(defaultPath, filters)
+{
+	return dialog.showSaveDialogSync({
+		defaultPath: defaultPath,
+		filters: filters
+	});
+};
+
+function installPlugin(filePath)
+{
+	var pluginsDir = path.join(getAppDataFolder(), '/plugins');
+	
+	if (!fs.existsSync(pluginsDir))
+	{
+		fs.mkdirSync(pluginsDir);
+	}
+	
+	var pluginName = path.basename(filePath);
+	var dstFile = path.join(pluginsDir, pluginName);
+	
+	if (fs.existsSync(dstFile))
+	{
+		throw new Error('fileExists');
+	}
+	else
+	{
+		fs.copyFileSync(filePath, dstFile);
+	}
+
+	return {pluginName: pluginName, selDir: path.dirname(filePath)};
+}
+
+function uninstallPlugin(plugin)
+{
+	var pluginsFile = path.join(getAppDataFolder(), '/plugins', plugin);
+	        	
+	if (fs.existsSync(pluginsFile))
+	{
+		fs.unlinkSync(pluginsFile);
+	}
+}
+
+function dirname(path_p)
+{
+	return path.dirname(path_p);
+}
+
+function readFile(filename, encoding)
+{
+	return fs.readFileSync(filename, encoding);
+}
+
+function fileStat(file)
+{
+	return fs.statSync(file);
+}
+
+function isFileWritable(file)
+{
+	try 
+	{
+		fs.accessSync(file, fs.constants.W_OK);
+		return true;
+	}
+	catch (e)
+	{
+		return false;
+	}
+}
+
+function clipboardAction(method, data)
+{
+	if (method == 'writeText')
+	{
+		clipboard.writeText(data);
+	}
+	else if (method == 'readText')
+	{
+		return clipboard.readText();
+	}
+	else if (method == 'writeImage')
+	{
+		clipboard.write({image: 
+			nativeImage.createFromDataURL(data.dataUrl), html: '<img src="' +
+			data.dataUrl + '" width="' + data.w + '" height="' + data.h + '">'});
+	}
+}
+
+function deleteFile(file) 
+{
+	fs.unlinkSync(file);
+}
+
+function windowAction(method)
+{
+	let win = BrowserWindow.getFocusedWindow();
+
+	if (win)
+	{
+		if (method == 'minimize')
+		{
+			win.minimize();
+		}
+		else if (method == 'maximize')
+		{
+			win.maximize();
+		}
+		else if (method == 'unmaximize')
+		{
+			win.unmaximize();
+		}
+		else if (method == 'close')
+		{
+			win.close();
+		}
+		else if (method == 'isMaximized')
+		{
+			return win.isMaximized();
+		}
+		else if (method == 'removeAllListeners')
+		{
+			win.removeAllListeners();
+		}
+	}
+}
+
+function openExternal(url)
+{
+	shell.openExternal(url);
+}
+
+function watchFile(path)
+{
+	let win = BrowserWindow.getFocusedWindow();
+
+	if (win)
+	{
+		fs.watchFile(path, (curr, prev) => {
+			try
+			{
+				win.webContents.send('fileChanged', {
+					path: path,
+					curr: curr,
+					prev: prev
+				});
+			}
+			catch (e) {} // Ignore
+		});
+	}
+}
+
+function unwatchFile(path)
+{
+	fs.unwatchFile(path);
+}
+
+ipcMain.on("rendererReq", async (event, args) => 
+{
+	try
+	{
+		let ret = null;
+
+		switch(args.action)
+		{
+		case 'saveFile':
+			ret = saveFile(args.fileObject, args.data, args.origStat, args.overwrite, args.defEnc);
+			break;
+		case 'writeFile':
+			ret = writeFile(args.path, args.data, args.enc);
+			break;
+		case 'saveDraft':
+			ret = saveDraft(args.fileObject, args.data);
+			break;
+		case 'getFileDrafts':
+			ret = getFileDrafts(args.fileObject);
+			break;
+		case 'getAppDataFolder':
+			ret = getAppDataFolder();
+			break;
+		case 'getDocumentsFolder':
+			ret = getDocumentsFolder();
+			break;
+		case 'checkFileExists':
+			ret = checkFileExists(args.pathParts);
+			break;
+		case 'showOpenDialog':
+			ret = showOpenDialog(args.defaultPath, args.filters, args.properties);
+			break;
+		case 'showSaveDialog':
+			ret = showSaveDialog(args.defaultPath, args.filters);
+			break;
+		case 'installPlugin':
+			ret = installPlugin(args.filePath);
+			break;
+		case 'uninstallPlugin':
+			ret = uninstallPlugin(args.plugin);
+			break;
+		case 'dirname':
+			ret = dirname(args.path);
+			break;
+		case 'readFile':
+			ret = readFile(args.filename, args.encoding);
+			break;
+		case 'clipboardAction':
+			ret = clipboardAction(args.method, args.data);
+			break;
+		case 'deleteFile':
+			ret = deleteFile(args.file);
+			break;
+		case 'fileStat':
+			ret = fileStat(args.file);
+			break;
+		case 'isFileWritable':
+			ret = isFileWritable(args.file);
+			break;
+		case 'windowAction':
+			ret = windowAction(args.method);
+			break;
+		case 'openExternal':
+			ret = openExternal(args.url);
+			break;
+		case 'watchFile':
+			ret = watchFile(args.path);
+			break;
+		case 'unwatchFile':	
+			ret = unwatchFile(args.path);
+			break;
+		};
+
+		event.reply('mainResp', {success: true, data: ret, reqId: args.reqId});
+	}
+	catch (e)
+	{
+		event.reply('mainResp', {error: true, msg: e.message, e: e, reqId: args.reqId});
+	}
+});

+ 0 - 124
src/main/webapp/electronFilesWorker.js

@@ -1,124 +0,0 @@
-const fs = require('fs');
-const path = require('path');
-const { COPYFILE_EXCL } = fs.constants;
-
-function isConflict(origStat, stat)
-{
-	return stat != null && origStat != null && stat.mtimeMs != origStat.mtimeMs;
-};
-
-function saveFile(fileObject, data, origStat, overwrite, defEnc, reqId)
-{
-	var retryCount = 0;
-	var backupCreated = false;
-	
-	var writeFile = function()
-	{
-		if (data == null || data.length == 0)
-		{
-			postMessage({error: true, msg: 'empty data', reqId: reqId});
-		}
-		else
-		{
-			var writeEnc = defEnc || fileObject.encoding;
-			
-			fs.writeFile(fileObject.path, data, writeEnc,
-			function (e)
-		    {
-        		if (e)
-        		{
-        			postMessage({error: true, msg: 'saving failed', e: e, reqId: reqId});
-        		}
-        		else
-        		{
-					fs.stat(fileObject.path, function(e2, stat2)
-					{
-						if (e2)
-		        		{
-		        			postMessage({error: true, msg: 'stat failed', e: e2, reqId: reqId});
-		        		}
-						else
-						{
-							// Workaround for possible writing errors is to check the written
-							// contents of the file and retry 3 times before showing an error
-							fs.readFile(fileObject.path, writeEnc, (err, writtenData) => 
-							{
-								if (data != writtenData)
-								{
-									retryCount++;
-									
-									if (retryCount < 3)
-									{
-										writeFile();
-									}
-									else
-									{
-					        			postMessage({error: true, msg: 'all saving trials failed', e: e, reqId: reqId});
-									}
-								}
-								else
-								{
-				        			postMessage({success: true, data: {stat: stat2}, reqId: reqId});
-				        			
-				        			if (backupCreated)
-			        				{
-				        				fs.unlink(fileObject.bkpPath, (err) => {}); //Ignore errors!
-			        				}
-								}
-							});							
-						}
-					});
-        		}
-        	});
-		}
-	};
-	
-	function doSaveFile()
-	{
-		//Copy file to backup file (after conflict and stat is checked)
-		fs.copyFile(fileObject.path, fileObject.bkpPath, COPYFILE_EXCL, (err) => 
-		{
-			if (!err)
-			{
-				backupCreated = true;
-			}
-			
-			writeFile();
-		});	
-	};
-	
-	if (overwrite)
-	{
-		doSaveFile();
-	}
-	else
-	{
-		//TODO Using stat before write is not recommended, we can check the error code from writeFile
-		fs.stat(fileObject.path, function(err, stat)
-		{
-			if (isConflict(origStat, stat))
-			{
-    			postMessage({error: true, msg: 'conflict', e: {isConflicted: true}, reqId: reqId});
-			}
-			else if (err != null && err.code !== 'ENOENT')
-			{
-    			postMessage({error: true, msg: 'stat failed', e: err, reqId: reqId});
-			}
-			else
-			{
-				doSaveFile();
-			}
-		});
-	}
-};
-
-//TODO handle reqId better
-onmessage = function(e) 
-{
-  switch(e.data.action)
-  {
-  case 'saveFile':
-	  saveFile(e.data.fileObject, e.data.data, e.data.origStat, e.data.overwrite, e.data.defEnc, e.data.reqId);
-	  break;
-  };
-};

Разница между файлами не показана из-за своего большого размера
+ 1102 - 1090
src/main/webapp/js/app.min.js


+ 4 - 4
src/main/webapp/js/diagramly/App.js

@@ -3372,7 +3372,7 @@ App.prototype.start = function()
 						}), null, null, null, null, urlParams['browser'] == '1',
 						}), null, null, null, null, urlParams['browser'] == '1',
 							null, null, true, rowLimit, null, null, null,
 							null, null, true, rowLimit, null, null, null,
 							this.editor.fileExtensions);
 							this.editor.fileExtensions);
-						this.showDialog(dlg.container, 400, (serviceCount > rowLimit) ? 390 : 270,
+						this.showDialog(dlg.container, 420, (serviceCount > rowLimit) ? 390 : 270,
 							true, false, mxUtils.bind(this, function(cancel)
 							true, false, mxUtils.bind(this, function(cancel)
 						{
 						{
 							if (cancel && this.getCurrentFile() == null)
 							if (cancel && this.getCurrentFile() == null)
@@ -4561,7 +4561,7 @@ App.prototype.saveFile = function(forceDialog, success)
 				this.hideDialog();
 				this.hideDialog();
 			}), mxResources.get('saveAs'), mxResources.get('download'), null, null, allowTab,
 			}), mxResources.get('saveAs'), mxResources.get('download'), null, null, allowTab,
 				null, true, rowLimit, null, null, null, this.editor.fileExtensions, false);
 				null, true, rowLimit, null, null, null, this.editor.fileExtensions, false);
-			this.showDialog(dlg.container, 400, (serviceCount > rowLimit) ? 390 : 270, true, true);
+			this.showDialog(dlg.container, 420, (serviceCount > rowLimit) ? 390 : 270, true, true);
 			dlg.init();
 			dlg.init();
 		}
 		}
 	}
 	}
@@ -4620,7 +4620,7 @@ App.prototype.loadTemplate = function(url, onload, onerror, templateFilename, as
 			else if (!this.isOffline() && new XMLHttpRequest().upload && this.isRemoteFileFormat(data, filterFn))
 			else if (!this.isOffline() && new XMLHttpRequest().upload && this.isRemoteFileFormat(data, filterFn))
 			{
 			{
 				// Asynchronous parsing via server
 				// Asynchronous parsing via server
-				this.parseFile(new Blob([data], {type: 'application/octet-stream'}), mxUtils.bind(this, function(xhr)
+				this.parseFileData(data, mxUtils.bind(this, function(xhr)
 				{
 				{
 					if (xhr.readyState == 4 && xhr.status >= 200 && xhr.status <= 299 &&
 					if (xhr.readyState == 4 && xhr.status >= 200 && xhr.status <= 299 &&
 						xhr.responseText.substring(0, 13) == '<mxGraphModel')
 						xhr.responseText.substring(0, 13) == '<mxGraphModel')
@@ -6640,7 +6640,7 @@ App.prototype.convertFile = function(url, filename, mimeType, extension, success
 				}
 				}
 				else if (Graph.fileSupport && new XMLHttpRequest().upload && this.isRemoteFileFormat(data, url))
 				else if (Graph.fileSupport && new XMLHttpRequest().upload && this.isRemoteFileFormat(data, url))
 				{
 				{
-					this.parseFile(new Blob([data], {type: 'application/octet-stream'}), mxUtils.bind(this, function(xhr)
+					this.parseFileData(data, mxUtils.bind(this, function(xhr)
 					{
 					{
 						if (xhr.readyState == 4)
 						if (xhr.readyState == 4)
 						{
 						{

+ 2 - 2
src/main/webapp/js/diagramly/Devel.js

@@ -34,8 +34,8 @@ if (!mxIsElectron && location.protocol !== 'http:')
 			'; ';
 			'; ';
 
 
 		var styleHashes = '\'sha256-JjkxVHHCCVO0nllPD6hU8bBYSlsikA8TM/o3fhr0bas=\' ' + // index.html
 		var styleHashes = '\'sha256-JjkxVHHCCVO0nllPD6hU8bBYSlsikA8TM/o3fhr0bas=\' ' + // index.html
-			'\'sha256-VTG4NbRCx30lYCdLPlgZTrdTopzcdviOjAbS7nk+KbI=\' ' + // Minimal.js/Light
-			'\'sha256-mbkyvR7KVIpvb+DU65TAGUt3LYuyF2kUg8Ktoee8eY4=\' ' + // Minimal.js/Dark
+			'\'sha256-AmGry6TX9+7jq8dDe3fV57YLyCZkhoLUqLMFLkDHngQ=\' ' + // Minimal.js/Light
+			'\'sha256-9mIrMmC05PfyiKHe8Cf98PvG7wJ8gXtJv+bX221nLpk=\' ' + // Minimal.js/Dark
 			'\'sha256-7kY8ozVqKLIIBwZ24dhdmZkM26PsOlZmEi72RhmZKoM=\' ' + // mxTooltipHandler.js
 			'\'sha256-7kY8ozVqKLIIBwZ24dhdmZkM26PsOlZmEi72RhmZKoM=\' ' + // mxTooltipHandler.js
 			'\'sha256-01chdey79TzZe4ihnvvUXXI5y8MklIcKH+vzDdQvsuU=\' ' + // Editor.js/mathJaxWebkitCss
 			'\'sha256-01chdey79TzZe4ihnvvUXXI5y8MklIcKH+vzDdQvsuU=\' ' + // Editor.js/mathJaxWebkitCss
 			'\'sha256-fGbXK7EYpvNRPca81zPnqJHi2y+34KSgAcZv8mhaSzI=\' ' + // MathJax.js
 			'\'sha256-fGbXK7EYpvNRPca81zPnqJHi2y+34KSgAcZv8mhaSzI=\' ' + // MathJax.js

+ 4 - 4
src/main/webapp/js/diagramly/Dialogs.js

@@ -4070,7 +4070,7 @@ var CreateDialog = function(editorUi, title, createFn, cancelFn, dlgTitle, btnLa
 		{
 		{
 			var typeSelect = FilenameDialog.createFileTypes(editorUi, nameInput, editorUi.editor.diagramFileTypes);
 			var typeSelect = FilenameDialog.createFileTypes(editorUi, nameInput, editorUi.editor.diagramFileTypes);
 			typeSelect.style.marginLeft = '6px';
 			typeSelect.style.marginLeft = '6px';
-			typeSelect.style.width = '80px';
+			typeSelect.style.width = '90px';
 			div.appendChild(typeSelect);
 			div.appendChild(typeSelect);
 		}
 		}
 		
 		
@@ -5013,7 +5013,7 @@ var LinkDialog = function(editorUi, initialValue, btnLabel, fn, showPages, showN
 	linkInput.setAttribute('placeholder', mxResources.get('dragUrlsHere'));
 	linkInput.setAttribute('placeholder', mxResources.get('dragUrlsHere'));
 	linkInput.setAttribute('type', 'text');
 	linkInput.setAttribute('type', 'text');
 	linkInput.style.marginTop = '6px';
 	linkInput.style.marginTop = '6px';
-	linkInput.style.width = '100%';
+	linkInput.style.width = '97%';
 	linkInput.style.boxSizing = 'border-box';
 	linkInput.style.boxSizing = 'border-box';
 	linkInput.style.backgroundImage = 'url(\'' + Dialog.prototype.clearImage + '\')';
 	linkInput.style.backgroundImage = 'url(\'' + Dialog.prototype.clearImage + '\')';
 	linkInput.style.backgroundRepeat = 'no-repeat';
 	linkInput.style.backgroundRepeat = 'no-repeat';
@@ -8275,7 +8275,7 @@ var PluginsDialog = function(editorUi, addFn, delFn)
 	var div = document.createElement('div');
 	var div = document.createElement('div');
 	var inner = document.createElement('div');
 	var inner = document.createElement('div');
 	
 	
-	inner.style.height = '120px';
+	inner.style.height = '180px';
 	inner.style.overflow = 'auto';
 	inner.style.overflow = 'auto';
 
 
 	var plugins = mxSettings.getPlugins().slice();
 	var plugins = mxSettings.getPlugins().slice();
@@ -8332,7 +8332,7 @@ var PluginsDialog = function(editorUi, addFn, delFn)
 	div.appendChild(inner);
 	div.appendChild(inner);
 	refresh();
 	refresh();
 
 
-	var addBtn = mxUtils.button(mxResources.get('add') + '...', addFn != null? function()
+	var addBtn = mxUtils.button(mxResources.get('add'), addFn != null? function()
 	{
 	{
 		addFn(function(newPlugin)
 		addFn(function(newPlugin)
 		{
 		{

+ 1 - 1
src/main/webapp/js/diagramly/DriveClient.js

@@ -1179,7 +1179,7 @@ DriveClient.prototype.getXmlFile = function(resp, success, error, ignoreMime, re
 							
 							
 							if (Graph.fileSupport && new XMLHttpRequest().upload && this.ui.isRemoteFileFormat(data, url))
 							if (Graph.fileSupport && new XMLHttpRequest().upload && this.ui.isRemoteFileFormat(data, url))
 							{
 							{
-								this.ui.parseFile(new Blob([data], {type: 'application/octet-stream'}), mxUtils.bind(this, function(xhr)
+								this.ui.parseFileData(data, mxUtils.bind(this, function(xhr)
 								{
 								{
 									try
 									try
 									{
 									{

+ 18 - 2
src/main/webapp/js/diagramly/Editor.js

@@ -1257,7 +1257,18 @@
 				return shapeCreateHandJiggle.apply(this, arguments);
 				return shapeCreateHandJiggle.apply(this, arguments);
 			}
 			}
 		};
 		};
-		
+
+		// Avoids duplicate painting of images
+		var imageShapePaintVertexShape = mxImageShape.prototype.paintVertexShape;
+
+		mxImageShape.prototype.paintVertexShape = function(c, x, y, w, h)
+		{
+			if (c.handJiggle == null || !c.handJiggle.passThrough)
+			{
+				imageShapePaintVertexShape.apply(this, arguments);
+			}
+		};
+
 		// Overrides for event handling on transparent background for sketch style
 		// Overrides for event handling on transparent background for sketch style
 		var shapePaint = mxShape.prototype.paint;
 		var shapePaint = mxShape.prototype.paint;
 		mxShape.prototype.paint = function(c)
 		mxShape.prototype.paint = function(c)
@@ -4243,7 +4254,12 @@
 			{name: 'fixedRows', dispName: 'Fixed Rows', type: 'bool', defVal: false},
 			{name: 'fixedRows', dispName: 'Fixed Rows', type: 'bool', defVal: false},
 			{name: 'resizeLast', dispName: 'Resize Last Column', type: 'bool', defVal: false},
 			{name: 'resizeLast', dispName: 'Resize Last Column', type: 'bool', defVal: false},
 			{name: 'resizeLastRow', dispName: 'Resize Last Row', type: 'bool', defVal: false}].
 			{name: 'resizeLastRow', dispName: 'Resize Last Row', type: 'bool', defVal: false}].
-			concat(mxCellRenderer.defaultShapes['swimlane'].prototype.customProperties);
+			concat(mxCellRenderer.defaultShapes['swimlane'].prototype.customProperties).
+			concat(mxCellRenderer.defaultShapes['partialRectangle'].prototype.customProperties);
+
+		mxCellRenderer.defaultShapes['tableRow'].prototype.customProperties =
+			mxCellRenderer.defaultShapes['swimlane'].prototype.customProperties.
+			concat(mxCellRenderer.defaultShapes['partialRectangle'].prototype.customProperties);
 		
 		
 		mxCellRenderer.defaultShapes['doubleEllipse'].prototype.customProperties = [
 		mxCellRenderer.defaultShapes['doubleEllipse'].prototype.customProperties = [
 	        {name: 'margin', dispName: 'Indent', type: 'float', min:0, defVal:4}
 	        {name: 'margin', dispName: 'Indent', type: 'float', min:0, defVal:4}

+ 35 - 10
src/main/webapp/js/diagramly/EditorUi.js

@@ -5210,7 +5210,8 @@
 		}
 		}
 		
 		
 		var editSelect = document.createElement('select');
 		var editSelect = document.createElement('select');
-		editSelect.style.width = '120px';
+		editSelect.style.maxWidth = '200px';
+		editSelect.style.width = 'auto';
 		editSelect.style.marginLeft = '8px';
 		editSelect.style.marginLeft = '8px';
 		editSelect.style.marginRight = '10px';
 		editSelect.style.marginRight = '10px';
 		editSelect.className = 'geBtn';
 		editSelect.className = 'geBtn';
@@ -5289,6 +5290,7 @@
 
 
 		var linkSelect = document.createElement('select');
 		var linkSelect = document.createElement('select');
 		linkSelect.style.width = '100px';
 		linkSelect.style.width = '100px';
+		linkSelect.style.padding = '0px';
 		linkSelect.style.marginLeft = '8px';
 		linkSelect.style.marginLeft = '8px';
 		linkSelect.style.marginRight = '10px';
 		linkSelect.style.marginRight = '10px';
 		linkSelect.className = 'geBtn';
 		linkSelect.className = 'geBtn';
@@ -7804,7 +7806,7 @@
 			if (Graph.fileSupport && !this.isOffline() && new XMLHttpRequest().upload && this.isRemoteFileFormat(text))
 			if (Graph.fileSupport && !this.isOffline() && new XMLHttpRequest().upload && this.isRemoteFileFormat(text))
 			{
 			{
 				// Fixes possible parsing problems with ASCII 160 (non-breaking space)
 				// Fixes possible parsing problems with ASCII 160 (non-breaking space)
-				this.parseFile(new Blob([text.replace(/\s+/g,' ')], {type: 'application/octet-stream'}), mxUtils.bind(this, function(xhr)
+				this.parseFileData(text.replace(/\s+/g,' '), mxUtils.bind(this, function(xhr)
 				{
 				{
 					if (xhr.readyState == 4 && xhr.status >= 200 && xhr.status <= 299)
 					if (xhr.readyState == 4 && xhr.status >= 200 && xhr.status <= 299)
 					{
 					{
@@ -7881,7 +7883,7 @@
 						this.resizeImage(img, text, mxUtils.bind(this, function(data2, w2, h2)
 						this.resizeImage(img, text, mxUtils.bind(this, function(data2, w2, h2)
 	    				{
 	    				{
 							graph.setSelectionCell(graph.insertVertex(null, null, '', graph.snap(dx), graph.snap(dy),
 							graph.setSelectionCell(graph.insertVertex(null, null, '', graph.snap(dx), graph.snap(dy),
-									w2, h2, 'shape=image;verticalLabelPosition=bottom;labelBackgroundColor=#ffffff;' +
+									w2, h2, 'shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;' +
 									'verticalAlign=top;aspect=fixed;imageAspect=0;image=' + this.convertDataUri(data2) + ';'));
 									'verticalAlign=top;aspect=fixed;imageAspect=0;image=' + this.convertDataUri(data2) + ';'));
 	    				}), resizeImages, this.maxImageSize);
 	    				}), resizeImages, this.maxImageSize);
 					}
 					}
@@ -7892,7 +7894,7 @@
 						var h = Math.round(img.height * s);
 						var h = Math.round(img.height * s);
 						
 						
 						graph.setSelectionCell(graph.insertVertex(null, null, '', graph.snap(dx), graph.snap(dy),
 						graph.setSelectionCell(graph.insertVertex(null, null, '', graph.snap(dx), graph.snap(dy),
-								w, h, 'shape=image;verticalLabelPosition=bottom;labelBackgroundColor=#ffffff;' +
+								w, h, 'shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;' +
 								'verticalAlign=top;aspect=fixed;imageAspect=0;image=' + text + ';'));
 								'verticalAlign=top;aspect=fixed;imageAspect=0;image=' + text + ';'));
 					}
 					}
 				}), mxUtils.bind(this, function()
 				}), mxUtils.bind(this, function()
@@ -8230,7 +8232,7 @@
 		                	{
 		                	{
 		                		if (!ui.isOffline() && new XMLHttpRequest().upload && ui.isRemoteFileFormat(data, file.name))
 		                		if (!ui.isOffline() && new XMLHttpRequest().upload && ui.isRemoteFileFormat(data, file.name))
 		                		{
 		                		{
-		                			ui.parseFile(new Blob([data], {type: 'application/octet-stream'}), mxUtils.bind(this, function(xhr)
+		                			ui.parseFileData(data, mxUtils.bind(this, function(xhr)
 		                			{
 		                			{
 		                				if (xhr.readyState == 4)
 		                				if (xhr.readyState == 4)
 		                				{
 		                				{
@@ -8342,7 +8344,7 @@
 				}
 				}
 
 
 				cells = [graph.insertVertex(null, null, '', dx, dy, w, h,
 				cells = [graph.insertVertex(null, null, '', dx, dy, w, h,
-					'shape=image;verticalLabelPosition=bottom;labelBackgroundColor=#ffffff;' +
+					'shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;' +
 					'verticalAlign=top;aspect=fixed;imageAspect=0;image=' + data + ';')];
 					'verticalAlign=top;aspect=fixed;imageAspect=0;image=' + data + ';')];
 			}
 			}
 		}
 		}
@@ -8365,7 +8367,7 @@
 			async = true;
 			async = true;
 
 
 			// Returns empty cells array as it is aysynchronous
 			// Returns empty cells array as it is aysynchronous
-			this.parseFile((file != null) ? file : new Blob([data], {type: 'application/octet-stream'}), mxUtils.bind(this, function(xhr)
+			var parseCallback = mxUtils.bind(this, function(xhr)
 			{
 			{
 				if (xhr.readyState == 4)
 				if (xhr.readyState == 4)
 				{
 				{
@@ -8378,7 +8380,16 @@
 						done(null);
 						done(null);
 					}
 					}
 				}
 				}
-			}), filename);
+			});
+
+			if (data != null)
+			{
+				this.parseFileData(data, parseCallback, filename);
+			}
+			else
+			{
+				this.parseFile(file, parseCallback, filename);
+			}
 		}
 		}
 		else if (data.indexOf('PK') == 0 && file != null)
 		else if (data.indexOf('PK') == 0 && file != null)
 		{
 		{
@@ -9046,6 +9057,20 @@
 			graph.view.defaultGridColor = mxGraphView.prototype.defaultDarkGridColor;
 			graph.view.defaultGridColor = mxGraphView.prototype.defaultDarkGridColor;
 		}
 		}
 		
 		
+		// Stops panning while freehand is active
+		if (Graph.touchStyle)
+		{
+			graph.panningHandler.isPanningTrigger = function(me)
+			{
+				var evt = me.getEvent();
+				
+			 	return (me.getState() == null && (!mxEvent.isMouseEvent(evt) &&
+					!graph.freehand.isDrawing())) ||
+			 		(mxEvent.isPopupTrigger(evt) && (me.getState() == null ||
+			 		mxEvent.isControlDown(evt) || mxEvent.isShiftDown(evt)));
+			};
+		}		
+
 		// Starts editing PlantUML data
 		// Starts editing PlantUML data
 		graph.cellEditor.editPlantUmlData = function(cell, trigger, data)
 		graph.cellEditor.editPlantUmlData = function(cell, trigger, data)
 		{
 		{
@@ -9908,7 +9933,7 @@
 			    				var s = Math.min(1, Math.min(maxSize / Math.max(1, w)), maxSize / Math.max(1, h));
 			    				var s = Math.min(1, Math.min(maxSize / Math.max(1, w)), maxSize / Math.max(1, h));
 
 
 			    				graph.setSelectionCell(graph.insertVertex(null, null, '', x, y, w * s, h * s,
 			    				graph.setSelectionCell(graph.insertVertex(null, null, '', x, y, w * s, h * s,
-			    					'shape=image;verticalLabelPosition=bottom;labelBackgroundColor=#ffffff;' +
+			    					'shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;' +
 			    					'verticalAlign=top;aspect=fixed;imageAspect=0;image=' + uri + ';'));
 			    					'verticalAlign=top;aspect=fixed;imageAspect=0;image=' + uri + ';'));
 			    			}), mxUtils.bind(this, function(img)
 			    			}), mxUtils.bind(this, function(img)
 			    			{
 			    			{
@@ -12663,7 +12688,7 @@
 			else if (data != null && typeof data.substring === 'function' && !this.isOffline() && new XMLHttpRequest().upload && this.isRemoteFileFormat(data, ''))
 			else if (data != null && typeof data.substring === 'function' && !this.isOffline() && new XMLHttpRequest().upload && this.isRemoteFileFormat(data, ''))
 			{
 			{
 				// Asynchronous parsing via server
 				// Asynchronous parsing via server
-				this.parseFile(new Blob([data], {type: 'application/octet-stream'}), mxUtils.bind(this, function(xhr)
+				this.parseFileData(data, mxUtils.bind(this, function(xhr)
 				{
 				{
 					if (xhr.readyState == 4 && xhr.status >= 200 && xhr.status <= 299 &&
 					if (xhr.readyState == 4 && xhr.status >= 200 && xhr.status <= 299 &&
 						xhr.responseText.substring(0, 13) == '<mxGraphModel')
 						xhr.responseText.substring(0, 13) == '<mxGraphModel')

Разница между файлами не показана из-за своего большого размера
+ 557 - 578
src/main/webapp/js/diagramly/ElectronApp.js


+ 1 - 1
src/main/webapp/js/diagramly/Init.js

@@ -83,7 +83,7 @@ window.mxLanguage = window.mxLanguage || (function()
 				
 				
 				if (!lang && window.mxIsElectron)
 				if (!lang && window.mxIsElectron)
 				{
 				{
-					lang = require('@electron/remote').app.getLocale();
+					lang = urlParams['appLang'];
 					
 					
 					if (lang != null)
 					if (lang != null)
 			    	{
 			    	{

+ 1 - 1
src/main/webapp/js/diagramly/Menus.js

@@ -2268,7 +2268,7 @@
 			{
 			{
 				editorUi.actions.addAction('plugins...', function()
 				editorUi.actions.addAction('plugins...', function()
 				{
 				{
-					editorUi.showDialog(new PluginsDialog(editorUi).container, 360, 170, true, false);
+					editorUi.showDialog(new PluginsDialog(editorUi).container, 380, 240, true, false);
 				});
 				});
 			}
 			}
 		}
 		}

+ 2 - 15
src/main/webapp/js/diagramly/Minimal.js

@@ -453,6 +453,7 @@ EditorUi.initMinimalTheme = function()
 			'html body .geToolbarButton { opacity: 0.3; }' +
 			'html body .geToolbarButton { opacity: 0.3; }' +
 			'html body .geToolbarButton:active { opacity: 0.15; }' +
 			'html body .geToolbarButton:active { opacity: 0.15; }' +
 			'html body .geStatus:active { opacity: 0.5; }' +
 			'html body .geStatus:active { opacity: 0.5; }' +
+			'.geStatus > div { box-sizing: border-box; max-width: 100%; text-overflow: ellipsis; }' +
 			'html body .geStatus { padding-top:3px !important; }' +
 			'html body .geStatus { padding-top:3px !important; }' +
 			'html body .geMenubarContainer .geStatus { margin-top: 0px !important; }' +
 			'html body .geMenubarContainer .geStatus { margin-top: 0px !important; }' +
 			'html table.mxPopupMenu tr.mxPopupMenuItemHover:active { opacity: 0.7; }' +
 			'html table.mxPopupMenu tr.mxPopupMenuItemHover:active { opacity: 0.7; }' +
@@ -477,7 +478,7 @@ EditorUi.initMinimalTheme = function()
 			'.mxWindow div button.geStyleButton { box-sizing: border-box; }' +
 			'.mxWindow div button.geStyleButton { box-sizing: border-box; }' +
 			'table.mxWindow td.mxWindowPane button.geColorBtn { padding:0px; box-sizing: border-box; }' +
 			'table.mxWindow td.mxWindowPane button.geColorBtn { padding:0px; box-sizing: border-box; }' +
 			'td.mxWindowPane .geSidebarContainer button { padding:2px; box-sizing: border-box; }' +
 			'td.mxWindowPane .geSidebarContainer button { padding:2px; box-sizing: border-box; }' +
-			'html body .geMenuItem { font-size:14px; text-decoration: none; font-weight: normal; padding: 6px 10px 6px 10px; border: none; border-radius: 5px; color: #353535; box-shadow: inset 0 0 0 1px rgba(0,0,0,.11), inset 0 -1px 0 0 rgba(0,0,0,.08), 0 1px 2px 0 rgba(0,0,0,.04); }' +
+			'html body .geMenuItem { font-size:14px; text-decoration: none; font-weight: normal; padding: 6px 10px 6px 10px; border: none; border-radius: 5px; color: #353535; box-shadow: inset 0 0 0 1px rgba(0,0,0,.11), inset 0 -1px 0 0 rgba(0,0,0,.08), 0 1px 2px 0 rgba(0,0,0,.04); ' + (EditorUi.isElectronApp? 'app-region: no-drag; ' : '') + '}' +
 			// Styling for Minimal
 			// Styling for Minimal
 			'.geTabContainer { border-bottom:1px solid lightgray; border-top:1px solid lightgray; background: ' + (Editor.isDarkMode() ? Editor.darkColor : '#fff') + ' !important; }' +
 			'.geTabContainer { border-bottom:1px solid lightgray; border-top:1px solid lightgray; background: ' + (Editor.isDarkMode() ? Editor.darkColor : '#fff') + ' !important; }' +
 			'.geToolbarContainer { background: ' + (Editor.isDarkMode() ? Editor.darkColor : '#fff') + '; }' +
 			'.geToolbarContainer { background: ' + (Editor.isDarkMode() ? Editor.darkColor : '#fff') + '; }' +
@@ -1987,20 +1988,6 @@ EditorUi.initMinimalTheme = function()
 			picker.style.display = 'none';
 			picker.style.display = 'none';
 		}));
 		}));
 
 
-		// Stops panning while freehand is active
-		if (Graph.touchStyle)
-		{
-			graph.panningHandler.isPanningTrigger = function(me)
-			{
-				var evt = me.getEvent();
-				
-			 	return (me.getState() == null && (!mxEvent.isMouseEvent(evt) &&
-					!graph.freehand.isDrawing())) ||
-			 		(mxEvent.isPopupTrigger(evt) && (me.getState() == null ||
-			 		mxEvent.isControlDown(evt) || mxEvent.isShiftDown(evt)));
-			};
-		}		
-
 		// Hides hover icons if freehand is active
 		// Hides hover icons if freehand is active
 		if (ui.hoverIcons != null)
 		if (ui.hoverIcons != null)
 		{
 		{

+ 1 - 1
src/main/webapp/js/diagramly/OneDriveClient.js

@@ -646,7 +646,7 @@ OneDriveClient.prototype.getFile = function(id, success, error, denyConvert, asL
 							
 							
 							if (Graph.fileSupport && new XMLHttpRequest().upload && this.ui.isRemoteFileFormat(data, meta['@microsoft.graph.downloadUrl']))
 							if (Graph.fileSupport && new XMLHttpRequest().upload && this.ui.isRemoteFileFormat(data, meta['@microsoft.graph.downloadUrl']))
 							{
 							{
-								this.ui.parseFile(new Blob([data], {type: 'application/octet-stream'}), mxUtils.bind(this, function(xhr)
+								this.ui.parseFileData(data, mxUtils.bind(this, function(xhr)
 								{
 								{
 									try
 									try
 									{
 									{

+ 4 - 0
src/main/webapp/js/diagramly/Pages.js

@@ -383,10 +383,14 @@ EditorUi.prototype.getImageForPage = function(page, sourcePage, sourceGraph)
 
 
 	this.updatePageRoot(page);
 	this.updatePageRoot(page);
 	graph.model.setRoot(page.root);
 	graph.model.setRoot(page.root);
+
+	var temp = Graph.foreignObjectWarningText;
+	Graph.foreignObjectWarningText = '';
 	var svgRoot = graph.getSvg(null, null, null, null, null,
 	var svgRoot = graph.getSvg(null, null, null, null, null,
 		null, null, null, null, null, null, true);
 		null, null, null, null, null, null, true);
 	var bounds = graph.getGraphBounds();
 	var bounds = graph.getGraphBounds();
 	document.body.removeChild(graph.container);
 	document.body.removeChild(graph.container);
+	Graph.foreignObjectWarningText = temp;
 
 
 	return new mxImage(Editor.createSvgDataUri(mxUtils.getXml(svgRoot)),
 	return new mxImage(Editor.createSvgDataUri(mxUtils.getXml(svgRoot)),
 		bounds.width, bounds.height, bounds.x, bounds.y);
 		bounds.width, bounds.height, bounds.x, bounds.y);

+ 52 - 26
src/main/webapp/js/export.js

@@ -83,9 +83,7 @@ function render(data)
 		//Electron pdf export
 		//Electron pdf export
 		try 
 		try 
 		{
 		{
-			const { ipcRenderer } = require('electron');
-			
-			ipcRenderer.send('render-finished', null);
+			electron.sendMessage('render-finished', null);
 		}
 		}
 		catch(e)
 		catch(e)
 		{
 		{
@@ -96,28 +94,32 @@ function render(data)
 	}
 	}
 	
 	
 	var xmlDoc = node.ownerDocument;
 	var xmlDoc = node.ownerDocument;
+	var origXmlDoc = xmlDoc;
 	var diagrams = null;
 	var diagrams = null;
 	var from = 0;
 	var from = 0;
 
 
-	if (mxIsElectron && data.format == 'xml')
+	function getFileXml(uncompressed)
 	{
 	{
-		const { ipcRenderer } = require('electron');
+		var xml = mxUtils.getXml(origXmlDoc);
+		EditorUi.prototype.createUi = function(){};
+		EditorUi.prototype.addTrees = function(){};
+		EditorUi.prototype.updateActionStates = function(){};
+		var editorUi = new EditorUi();
+		var tmpFile = new LocalFile(editorUi, xml);
+		editorUi.setCurrentFile(tmpFile);
+		editorUi.setFileData(xml);
+		return editorUi.createFileData(editorUi.getXmlFileData(null, null, uncompressed));
+	};
 
 
+	if (mxIsElectron && data.format == 'xml')
+	{
 		try
 		try
 		{
 		{
-			var xml = mxUtils.getXml(xmlDoc);
-			EditorUi.prototype.createUi = function(){};
-			EditorUi.prototype.addTrees = function(){};
-			EditorUi.prototype.updateActionStates = function(){};
-			var editorUi = new EditorUi();
-			var tmpFile = new LocalFile(editorUi, xml);
-			editorUi.setCurrentFile(tmpFile);
-			editorUi.setFileData(xml);
-			ipcRenderer.send('xml-data', mxUtils.getXml(editorUi.getXmlFileData(null, null, data.uncompressed)));
+			electron.sendMessage('xml-data', getFileXml(data.uncompressed));
 		}
 		}
 		catch(e)
 		catch(e)
 		{
 		{
-			ipcRenderer.send('xml-data-error');
+			electron.sendMessage('xml-data-error');
 		}
 		}
 		
 		
 		return;
 		return;
@@ -210,9 +212,7 @@ function render(data)
 				{
 				{
 					try 
 					try 
 					{
 					{
-						const { ipcRenderer } = require('electron');
-						
-						ipcRenderer.on('get-svg-data', (event, arg) => 
+						electron.registerMsgListener('get-svg-data', (arg) => 
 						{
 						{
 							graph.mathEnabled = math; //Enable math such that getSvg works as expected
 							graph.mathEnabled = math; //Enable math such that getSvg works as expected
 							// Returns the exported SVG for the given graph (see EditorUi.exportSvg)
 							// Returns the exported SVG for the given graph (see EditorUi.exportSvg)
@@ -238,13 +238,33 @@ function render(data)
 							{
 							{
 								Editor.prototype.addMathCss(svgRoot);
 								Editor.prototype.addMathCss(svgRoot);
 							}
 							}
-							
-							ipcRenderer.send('svg-data', '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' +
-									mxUtils.getXml(svgRoot));
+						
+							function doSend() 
+							{
+								var editable = data.embedXml == '1';
+
+								if (editable)
+								{
+									svgRoot.setAttribute('content', getFileXml());
+								}
+
+								electron.sendMessage('svg-data', Graph.xmlDeclaration + '\n' + ((editable) ? Graph.svgFileComment + '\n' : '') +
+															 Graph.svgDoctype + '\n' + mxUtils.getXml(svgRoot));
+							};
+
+							if (data.embedImages == '1')
+							{
+								var tmpEditor = new Editor();
+								tmpEditor.convertImages(svgRoot, doSend);
+							}
+							else
+							{
+								doSend();
+							}
 						});
 						});
 						
 						
 						//For some reason, Electron 9 doesn't send this object as is without stringifying. Usually when variable is external to function own scope
 						//For some reason, Electron 9 doesn't send this object as is without stringifying. Usually when variable is external to function own scope
-						ipcRenderer.send('render-finished', {bounds: JSON.stringify(bounds), pageCount: pageCount});
+						electron.sendMessage('render-finished', {bounds: JSON.stringify(bounds), pageCount: pageCount});
 					}
 					}
 					catch(e)
 					catch(e)
 					{
 					{
@@ -896,11 +916,17 @@ if (mxIsElectron)
 {
 {
 	try 
 	try 
 	{
 	{
-		const { ipcRenderer } = require('electron');
-		
-		ipcRenderer.on('render', (event, arg) => 
+		electron.registerMsgListener('render', (arg) => 
 		{
 		{
-			render(arg);
+			try
+			{
+				render(arg);
+			}
+			catch(e)
+			{
+				console.log(e);
+				electron.sendMessage('render-finished', null);
+			}
 		});
 		});
 	}
 	}
 	catch(e)
 	catch(e)

+ 12 - 10
src/main/webapp/js/grapheditor/Format.js

@@ -4168,8 +4168,8 @@ StyleFormatPanel.prototype.init = function()
 		{
 		{
 			this.container.appendChild(this.addSvgStyles(this.createPanel()));
 			this.container.appendChild(this.addSvgStyles(this.createPanel()));
 		}
 		}
-		
-		if (!ss.containsImage || ss.style.shape == 'image')
+
+		if (ss.fill)
 		{
 		{
 			this.container.appendChild(this.addFill(this.createPanel()));
 			this.container.appendChild(this.addFill(this.createPanel()));
 		}
 		}
@@ -4415,7 +4415,8 @@ StyleFormatPanel.prototype.addFill = function(container)
 		graph.stylesheet.getDefaultEdgeStyle();
 		graph.stylesheet.getDefaultEdgeStyle();
 
 
 	var gradientPanel = this.createCellColorOption(mxResources.get('gradient'), mxConstants.STYLE_GRADIENTCOLOR,
 	var gradientPanel = this.createCellColorOption(mxResources.get('gradient'), mxConstants.STYLE_GRADIENTCOLOR,
-		(defs[mxConstants.STYLE_GRADIENTCOLOR] != null) ? defs[mxConstants.STYLE_GRADIENTCOLOR] : '#ffffff', function(color)
+		(defs[mxConstants.STYLE_GRADIENTCOLOR] != null) ? defs[mxConstants.STYLE_GRADIENTCOLOR] : '#ffffff',
+		function(color)
 	{
 	{
 		if (color == null || color == mxConstants.NONE)
 		if (color == null || color == mxConstants.NONE)
 		{
 		{
@@ -4431,9 +4432,9 @@ StyleFormatPanel.prototype.addFill = function(container)
 	});
 	});
 
 
 	var fillKey = (ss.style.shape == 'image') ? mxConstants.STYLE_IMAGE_BACKGROUND : mxConstants.STYLE_FILLCOLOR;
 	var fillKey = (ss.style.shape == 'image') ? mxConstants.STYLE_IMAGE_BACKGROUND : mxConstants.STYLE_FILLCOLOR;
-	var label = (ss.style.shape == 'image') ? mxResources.get('background') : mxResources.get('fill');
-	
-	var fillPanel = this.createCellColorOption(label, fillKey, 'default', null, mxUtils.bind(this, function(color)
+
+	var fillPanel = this.createCellColorOption(mxResources.get('fill'),
+		fillKey, 'default', null, mxUtils.bind(this, function(color)
 	{
 	{
 		graph.setCellStyles(fillKey, color, ss.cells);
 		graph.setCellStyles(fillKey, color, ss.cells);
 	}), graph.shapeBackgroundColor);
 	}), graph.shapeBackgroundColor);
@@ -4483,9 +4484,9 @@ StyleFormatPanel.prototype.addFill = function(container)
 		fillStyleSelect.value = fillStyle;
 		fillStyleSelect.value = fillStyle;
 		container.style.display = (ss.fill) ? '' : 'none';
 		container.style.display = (ss.fill) ? '' : 'none';
 		
 		
-		var fillColor = mxUtils.getValue(ss.style, mxConstants.STYLE_FILLCOLOR, null);
-			
-		if (!ss.fill || ss.containsImage || fillColor == null || fillColor == mxConstants.NONE || ss.style.shape == 'filledEdge')
+		var fillColor = mxUtils.getValue(ss.style, fillKey, null);
+		
+		if (!ss.fill || fillColor == null || fillColor == mxConstants.NONE || ss.style.shape == 'filledEdge')
 		{
 		{
 			fillStyleSelect.style.display = 'none';
 			fillStyleSelect.style.display = 'none';
 			gradientPanel.style.display = 'none';
 			gradientPanel.style.display = 'none';
@@ -4493,7 +4494,8 @@ StyleFormatPanel.prototype.addFill = function(container)
 		else
 		else
 		{
 		{
 			fillStyleSelect.style.display = (ss.style.sketch == '1') ? '' : 'none';
 			fillStyleSelect.style.display = (ss.style.sketch == '1') ? '' : 'none';
-			gradientPanel.style.display = (ss.style.sketch != '1' || fillStyle == 'solid' || fillStyle == 'auto') ? '' : 'none';
+			gradientPanel.style.display = (!ss.containsImage && (ss.style.sketch != '1' ||
+				fillStyle == 'solid' || fillStyle == 'auto')) ? '' : 'none';
 		}
 		}
 	});
 	});
 	
 	

+ 8 - 6
src/main/webapp/js/grapheditor/Graph.js

@@ -3042,7 +3042,8 @@ Graph.prototype.initLayoutManager = function()
 		// Executes layouts from top to bottom except for nested layouts where
 		// Executes layouts from top to bottom except for nested layouts where
 		// child layouts are executed before and after the parent layout runs
 		// child layouts are executed before and after the parent layout runs
 		// in case the layout changes the size of the child cell
 		// in case the layout changes the size of the child cell
-		if (eventName != mxEvent.BEGIN_UPDATE || this.hasLayout(parent, eventName))
+		if (!this.graph.isCellCollapsed(cell) && (eventName != mxEvent.BEGIN_UPDATE ||
+			this.hasLayout(parent, eventName)))
 		{
 		{
 			var style = this.graph.getCellStyle(cell);
 			var style = this.graph.getCellStyle(cell);
 			
 			
@@ -5965,8 +5966,8 @@ Graph.prototype.createTable = function(rowCount, colCount, w, h, title, startSiz
 	startSize = (startSize != null) ? startSize : 30;
 	startSize = (startSize != null) ? startSize : 30;
 	tableStyle = (tableStyle != null) ? tableStyle : 'shape=table;startSize=' +
 	tableStyle = (tableStyle != null) ? tableStyle : 'shape=table;startSize=' +
 		((title != null) ? startSize : '0') + ';container=1;collapsible=0;childLayout=tableLayout;';
 		((title != null) ? startSize : '0') + ';container=1;collapsible=0;childLayout=tableLayout;';
-	rowStyle = (rowStyle != null) ? rowStyle : 'shape=partialRectangle;collapsible=0;dropTarget=0;' +
-    	'fillColor=none;top=0;left=0;bottom=0;right=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;';
+	rowStyle = (rowStyle != null) ? rowStyle : 'shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;' +
+    	'top=0;left=0;bottom=0;right=0;collapsible=0;dropTarget=0;fillColor=none;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;';
 	cellStyle = (cellStyle != null) ? cellStyle : 'shape=partialRectangle;html=1;whiteSpace=wrap;connectable=0;' +
 	cellStyle = (cellStyle != null) ? cellStyle : 'shape=partialRectangle;html=1;whiteSpace=wrap;connectable=0;' +
 		'overflow=hidden;fillColor=none;top=0;left=0;bottom=0;right=0;pointerEvents=1;';
 		'overflow=hidden;fillColor=none;top=0;left=0;bottom=0;right=0;pointerEvents=1;';
 	
 	
@@ -6019,8 +6020,8 @@ Graph.prototype.createCrossFunctionalSwimlane = function(rowCount, colCount, w,
 	var s = 'collapsible=0;recursiveResize=0;expand=0;';
 	var s = 'collapsible=0;recursiveResize=0;expand=0;';
 	tableStyle = (tableStyle != null) ? tableStyle : 'shape=table;childLayout=tableLayout;' +
 	tableStyle = (tableStyle != null) ? tableStyle : 'shape=table;childLayout=tableLayout;' +
 		((title == null) ? 'startSize=0;fillColor=none;' : 'startSize=40;') + s;
 		((title == null) ? 'startSize=0;fillColor=none;' : 'startSize=40;') + s;
-	rowStyle = (rowStyle != null) ? rowStyle : 'swimlane;horizontal=0;swimlaneHead=0;swimlaneBody=0;fontStyle=0;' +
-		'fillColor=none;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;startSize=40;' + s;
+	rowStyle = (rowStyle != null) ? rowStyle : 'shape=tableRow;horizontal=0;swimlaneHead=0;swimlaneBody=0;top=0;left=0;' +
+		'bottom=0;right=0;dropTarget=0;fontStyle=0;fillColor=none;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;startSize=40;' + s;
 	firstCellStyle = (firstCellStyle != null) ? firstCellStyle : 'swimlane;swimlaneHead=0;swimlaneBody=0;fontStyle=0;' +
 	firstCellStyle = (firstCellStyle != null) ? firstCellStyle : 'swimlane;swimlaneHead=0;swimlaneBody=0;fontStyle=0;' +
 		'connectable=0;fillColor=none;startSize=40;' + s;
 		'connectable=0;fillColor=none;startSize=40;' + s;
 	cellStyle = (cellStyle != null) ? cellStyle : 'swimlane;swimlaneHead=0;swimlaneBody=0;fontStyle=0;connectable=0;' +
 	cellStyle = (cellStyle != null) ? cellStyle : 'swimlane;swimlaneHead=0;swimlaneBody=0;fontStyle=0;connectable=0;' +
@@ -7879,7 +7880,8 @@ if (typeof mxVertexHandler != 'undefined')
 				shape = style[mxConstants.STYLE_SHAPE];
 				shape = style[mxConstants.STYLE_SHAPE];
 			}
 			}
 			
 			
-			return shape == mxConstants.SHAPE_SWIMLANE || shape == 'table';
+			return shape == mxConstants.SHAPE_SWIMLANE ||
+				shape == 'table' || shape == 'tableRow';
 		};
 		};
 		
 		
 		/**
 		/**

Разница между файлами не показана из-за своего большого размера
+ 301 - 53
src/main/webapp/js/grapheditor/Shapes.js


Разница между файлами не показана из-за своего большого размера
+ 5 - 5
src/main/webapp/js/grapheditor/Sidebar.js


Разница между файлами не показана из-за своего большого размера
+ 772 - 759
src/main/webapp/js/viewer-static.min.js


Разница между файлами не показана из-за своего большого размера
+ 772 - 759
src/main/webapp/js/viewer.min.js


Разница между файлами не показана из-за своего большого размера
+ 23 - 13
src/main/webapp/mxgraph/mxClient.js


+ 1 - 0
src/main/webapp/resources/dia.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_am.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_ar.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_bg.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_bn.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_bs.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_ca.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_cs.txt

@@ -1170,3 +1170,4 @@ website=Webové stránky
 check4Updates=Zjistit dostupnost případných aktualizací
 check4Updates=Zjistit dostupnost případných aktualizací
 attWriteFailedRetry={1}: Zapsání přílohy se nezdařilo, opětovný pokus za {2} sekund…
 attWriteFailedRetry={1}: Zapsání přílohy se nezdařilo, opětovný pokus za {2} sekund…
 confPartialPageList=Nepodařilo se získat všechny stránky kvůli chybě v Confluence. Pokračuje se pouze se {1} stránkami.
 confPartialPageList=Nepodařilo se získat všechny stránky kvůli chybě v Confluence. Pokračuje se pouze se {1} stránkami.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_da.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_de.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_el.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_eo.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_es.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_et.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_eu.txt

@@ -1170,3 +1170,4 @@ website=Webgunea
 check4Updates=Bilat eguneraketak
 check4Updates=Bilat eguneraketak
 attWriteFailedRetry={1}: Eranskinaren idazketa huts egin du, berriro saiatuko da {2} segundo barru...
 attWriteFailedRetry={1}: Eranskinaren idazketa huts egin du, berriro saiatuko da {2} segundo barru...
 confPartialPageList=Ezin izan ditugu orrialde guztiak eskuratu konfluentzia errore bat dela medio. {1} orrialde soilik erabiliko dira.
 confPartialPageList=Ezin izan ditugu orrialde guztiak eskuratu konfluentzia errore bat dela medio. {1} orrialde soilik erabiliko dira.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_fa.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_fi.txt

@@ -1170,3 +1170,4 @@ website=Verkkosivusto
 check4Updates=Tarkista päivitykset
 check4Updates=Tarkista päivitykset
 attWriteFailedRetry={1}: Liitteen kirjoitus epäonnistui, yritetään uudelleen {2} sekunnin kuluttua...
 attWriteFailedRetry={1}: Liitteen kirjoitus epäonnistui, yritetään uudelleen {2} sekunnin kuluttua...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_fil.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_fr.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_gl.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_gu.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_he.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_hi.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_hr.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_hu.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_i18n.txt

@@ -1170,3 +1170,4 @@ website=website
 check4Updates=check4Updates
 check4Updates=check4Updates
 attWriteFailedRetry=attWriteFailedRetry
 attWriteFailedRetry=attWriteFailedRetry
 confPartialPageList=confPartialPageList
 confPartialPageList=confPartialPageList
+spellCheck=spellCheck

+ 1 - 0
src/main/webapp/resources/dia_id.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_it.txt

@@ -1170,3 +1170,4 @@ website=Sito web
 check4Updates=Controlla aggiornamenti
 check4Updates=Controlla aggiornamenti
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_ja.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_kn.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_ko.txt

@@ -1170,3 +1170,4 @@ website=웹사이트
 check4Updates=업데이트 여부를 확인중입니다.
 check4Updates=업데이트 여부를 확인중입니다.
 attWriteFailedRetry={1}: 첨부파일 쓰기를 실패했습니다. {2} 초 후 재시도합니다.
 attWriteFailedRetry={1}: 첨부파일 쓰기를 실패했습니다. {2} 초 후 재시도합니다.
 confPartialPageList=Confluence에서 발생한 오류로 모든 페이지를 가져오지 못했습니다. {1} 페이지만 사용합니다.
 confPartialPageList=Confluence에서 발생한 오류로 모든 페이지를 가져오지 못했습니다. {1} 페이지만 사용합니다.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_lt.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_lv.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_ml.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_mr.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_ms.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_my.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_nl.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_no.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_pl.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_pt-br.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Verificar se há atualizações
 check4Updates=Verificar se há atualizações
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_pt.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_ro.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_ru.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_si.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_sk.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_sl.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_sr.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_sv.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_sw.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_ta.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_te.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_th.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_tr.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_uk.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_vi.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_zh-tw.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

+ 1 - 0
src/main/webapp/resources/dia_zh.txt

@@ -1170,3 +1170,4 @@ website=Website
 check4Updates=Check for updates
 check4Updates=Check for updates
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 attWriteFailedRetry={1}: Attachment write failed, trying again in {2} seconds...
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
 confPartialPageList=We couldn't fetch all pages due to an error in Confluence. Continuing using {1} pages only.
+spellCheck=Spell checker

Разница между файлами не показана из-за своего большого размера
+ 1 - 1
src/main/webapp/service-worker.js


Разница между файлами не показана из-за своего большого размера
+ 1 - 1
src/main/webapp/service-worker.js.map


Разница между файлами не показана из-за своего большого размера
+ 1 - 1
src/main/webapp/templates/basic/cross.xml


+ 3 - 5
src/main/webapp/vsdxImporter.html

@@ -19,17 +19,15 @@
 
 
   try
   try
   {
   {
-	const { ipcRenderer } = require('electron');
-	
-	ipcRenderer.on('import', (event, vsdxBuff) => 
+	electron.registerMsgListener('import', (vsdxBuff) => 
 	{
 	{
 	 	doImport(vsdxBuff, function(xml)
 	 	doImport(vsdxBuff, function(xml)
 		{
 		{
-	 		ipcRenderer.send('import-success', xml);
+			electron.sendMessage('import-success', xml);
 		},
 		},
 		function()
 		function()
 		{
 		{
-			ipcRenderer.send('import-error');
+			electron.sendMessage('import-error');
 		});
 		});
 	});
 	});
   }
   }