Browse Source

16.0.0 release

David Benson 3 years ago
parent
commit
c02986677e
37 changed files with 4699 additions and 4788 deletions
  1. 15 0
      ChangeLog
  2. 1 1
      VERSION
  3. 8 0
      src/main/webapp/electron.js
  4. 1061 1068
      src/main/webapp/js/app.min.js
  5. 49 38
      src/main/webapp/js/diagramly/App.js
  6. 3 3
      src/main/webapp/js/diagramly/Devel.js
  7. 1 0
      src/main/webapp/js/diagramly/DrawioFile.js
  8. 12 41
      src/main/webapp/js/diagramly/Editor.js
  9. 13 9
      src/main/webapp/js/diagramly/EditorUi.js
  10. 56 60
      src/main/webapp/js/diagramly/ElectronApp.js
  11. 2 0
      src/main/webapp/js/diagramly/GraphViewer.js
  12. 2 2
      src/main/webapp/js/diagramly/Minimal.js
  13. 8 2
      src/main/webapp/js/diagramly/Settings.js
  14. 1 1
      src/main/webapp/js/grapheditor/Actions.js
  15. 0 2
      src/main/webapp/js/grapheditor/Editor.js
  16. 291 87
      src/main/webapp/js/grapheditor/EditorUi.js
  17. 120 534
      src/main/webapp/js/grapheditor/Format.js
  18. 98 0
      src/main/webapp/js/grapheditor/Graph.js
  19. 1 1
      src/main/webapp/js/grapheditor/Shapes.js
  20. 1433 1424
      src/main/webapp/js/viewer-static.min.js
  21. 1433 1424
      src/main/webapp/js/viewer.min.js
  22. 74 74
      src/main/webapp/mxgraph/mxClient.js
  23. 1 1
      src/main/webapp/resources/dia_ar.txt
  24. 3 3
      src/main/webapp/resources/dia_eu.txt
  25. 1 1
      src/main/webapp/service-worker.js
  26. 1 1
      src/main/webapp/service-worker.js.map
  27. 1 1
      src/main/webapp/shortcuts.svg
  28. 1 1
      src/main/webapp/templates/cloud/aws/aws_1.xml
  29. 1 1
      src/main/webapp/templates/cloud/aws/aws_10.xml
  30. 1 1
      src/main/webapp/templates/cloud/aws/aws_2.xml
  31. 1 1
      src/main/webapp/templates/cloud/aws/aws_3.xml
  32. 1 1
      src/main/webapp/templates/cloud/aws/aws_4.xml
  33. 1 1
      src/main/webapp/templates/cloud/aws/aws_5.xml
  34. 1 1
      src/main/webapp/templates/cloud/aws/aws_6.xml
  35. 1 1
      src/main/webapp/templates/cloud/aws/aws_7.xml
  36. 1 1
      src/main/webapp/templates/cloud/aws/aws_8.xml
  37. 1 1
      src/main/webapp/templates/cloud/aws/aws_9.xml

+ 15 - 0
ChangeLog

@@ -1,3 +1,18 @@
+17-DEC-2021: 16.0.0
+
+The reason for going to version 16 is there is a breaking change in the docker image. The 
+default base image used has been changed because the previous image was not supported. There 
+is no breaking change in the editor codebase, but the docker images follow the same numbering.
+
+- Fixes clipping on initial arrow drop down https://github.com/jgraph/drawio/issues/2482
+- Fixes table and template icon in sketch mode
+- Restores sync problem icon
+- Hides Cmd+R keyboard shortcut in Safari https://github.com/jgraph/drawio/issues/1757
+- Moves selection state to EditorUi
+- Added scrollbar to layersDialog in GraphViewer https://github.com/jgraph/drawio/issues/1347
+- Added dark mode support for Mermaid https://github.com/jgraph/drawio-desktop/issues/785
+- [conf cloud] Added minorEdit for page changes just in case it is effective
+
 13-DEC-2021: 15.9.6
 
 - Fixes NPE for wheel event in outline window

+ 1 - 1
VERSION

@@ -1 +1 @@
-15.9.6
+16.0.0

+ 8 - 0
src/main/webapp/electron.js

@@ -26,6 +26,12 @@ autoUpdater.logger = log
 autoUpdater.logger.transports.file.level = 'info'
 autoUpdater.autoDownload = false
 
+//Command option to disable hardware acceleration
+if (process.argv.indexOf('--disable-acceleration') !== -1)
+{
+	app.disableHardwareAcceleration();
+}
+
 const __DEV__ = process.env.DRAWIO_ENV === 'dev'
 		
 let windowsRegistry = []
@@ -149,6 +155,8 @@ function createWindow (opt = {})
 							
 						if (choice === 1)
 						{
+							//If user chose not to save, remove the draft
+							contents.executeJavaScript('global.__emt_removeDraft()', true);
 							win.destroy()
 						}
 						else

File diff suppressed because it is too large
+ 1061 - 1068
src/main/webapp/js/app.min.js


+ 49 - 38
src/main/webapp/js/diagramly/App.js

@@ -3266,7 +3266,6 @@ App.prototype.start = function()
 						{
 							var id = this.getDiagramId();
 							
-							
 							if (EditorUi.enableDrafts && (urlParams['mode'] == null || EditorUi.isElectronApp) &&
 								this.getServiceName() == 'draw.io' && (id == null || id.length == 0) &&
 								!this.editor.isChromelessView())
@@ -3505,6 +3504,54 @@ App.prototype.loadDraft = function(xml, success)
 	}), null, null, true);
 };
 
+App.prototype.filterDrafts = function(filePath, guid, callback)
+{
+	var drafts = [];
+
+	function result()
+	{
+		callback(drafts);
+	};
+
+	try
+	{
+		this.getDatabaseItems(mxUtils.bind(this, function(items)
+		{
+			// Collects orphaned drafts
+			for (var i = 0; i < items.length; i++)
+			{
+				try
+				{
+					var key = items[i].key;
+					
+					if (key != null && key.substring(0, 7) == '.draft_')
+					{
+						var obj = JSON.parse(items[i].data);
+						
+						if (obj != null && obj.type == 'draft' && obj.aliveCheck != guid && 
+							((filePath == null && obj.fileObject == null) ||
+								(obj.fileObject != null && obj.fileObject.path == filePath)))	
+						{
+							obj.key = key;
+							drafts.push(obj);
+						}
+					}
+				}
+				catch (e)
+				{
+					// ignore
+				}
+			}
+
+			result();
+		}, result));
+	}
+	catch (e)
+	{
+		result();
+	}
+};
+
 /**
  * Checks for orphaned drafts.
  */
@@ -3520,34 +3567,8 @@ App.prototype.checkDrafts = function()
 		{
 			localStorage.removeItem('.draft-alive-check');
 
-			this.getDatabaseItems(mxUtils.bind(this, function(items)
+			this.filterDrafts(null, guid, mxUtils.bind(this, function(drafts)
 			{
-				// Collects orphaned drafts
-				var drafts = [];
-				
-				for (var i = 0; i < items.length; i++)
-				{
-					try
-					{
-						var key = items[i].key;
-						
-						if (key != null && key.substring(0, 7) == '.draft_')
-						{
-							var obj = JSON.parse(items[i].data);
-							
-							if (obj != null && obj.type == 'draft' && obj.aliveCheck != guid)
-							{
-								obj.key = key;
-								drafts.push(obj);
-							}
-						}
-					}
-					catch (e)
-					{
-						// ignore
-					}
-				}
-				
 				if (drafts.length == 1)
 				{
 					this.loadDraft(drafts[0].data, mxUtils.bind(this, function()
@@ -3606,16 +3627,6 @@ App.prototype.checkDrafts = function()
 				{
 					this.createFile(this.defaultFilename, this.getFileData(), null, null, null, null, null, true);
 				}
-			}), mxUtils.bind(this, function()
-			{
-				if (urlParams['splash'] != '0')
-				{
-					this.loadFile();
-				}
-				else
-				{
-					this.createFile(this.defaultFilename, this.getFileData(), null, null, null, null, null, true);
-				}
 			}));
 		}), 0);
 	}

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

@@ -66,6 +66,9 @@ if (!mxIsElectron && location.protocol !== 'http:')
 			'style-src %style-src% \'self\'  https://fonts.googleapis.com ' +
 			// Replaces unsafe-inline style-src with hashes with safe-style-src URL parameter
 			((urlParams['safe-style-src'] == '1') ? styleHashes : '\'unsafe-inline\'; ') +
+			'form-action \'none\';' +
+			'base-uri \'none\';' +
+			'child-src \'none\';' +
 			'object-src \'none\';';
 			
 		var csp = hashes + directives;
@@ -99,9 +102,6 @@ if (!mxIsElectron && location.protocol !== 'http:')
 				'frame-src \'self\' https://viewer.diagrams.net https://*.google.com; ' +
 				'style-src \'self\' https://fonts.googleapis.com ' + styleHashes + ' ' +
 				'object-src \'none\';' +
-				'form-action \'none\';' +
-				'base-uri \'none\';' +
-				'child-src \'none\';' +
 				'frame-src \'none\';' +
 				'worker-src https://se.diagrams.net/service-worker.js;'
 			console.log('se.diagrams.net:', se_diagrams_net);

+ 1 - 0
src/main/webapp/js/diagramly/DrawioFile.js

@@ -1444,6 +1444,7 @@ DrawioFile.prototype.saveDraft = function()
 			modified: new Date().getTime(),
 			data: this.ui.getFileData(),
 			title: this.getTitle(),
+			fileObject: this.fileObject,
 			aliveCheck: this.ui.draftAliveCheck};
 		this.ui.setDatabaseItem('.draft_' + this.draftId,
 			JSON.stringify(draft));

File diff suppressed because it is too large
+ 12 - 41
src/main/webapp/js/diagramly/Editor.js


+ 13 - 9
src/main/webapp/js/diagramly/EditorUi.js

@@ -92,7 +92,7 @@
 	/**
 	 * Specifies if drafts should be saved in IndexedDB.
 	 */
-	EditorUi.enableDrafts = !mxClient.IS_CHROMEAPP && !EditorUi.isElectronApp &&
+	EditorUi.enableDrafts = !mxClient.IS_CHROMEAPP &&
 		isLocalStorage && urlParams['drafts'] != '0';
 	
 	/**
@@ -7514,9 +7514,14 @@
 			{
 				this.loadingMermaid = false;
 				
-				config = (config != null) ? config : EditorUi.defaultMermaidConfig;
+				config = (config != null) ? config : mxUtils.clone(EditorUi.defaultMermaidConfig);
 				config.securityLevel = 'strict';
 				config.startOnLoad = false;
+
+				if (Editor.isDarkMode())
+				{
+					config.theme = 'dark';
+				}
 				
 				mermaid.mermaidAPI.initialize(config);
 	    		
@@ -13811,21 +13816,19 @@
 
 		var graph = this.editor.graph;
 		var file = this.getCurrentFile();
+		var ss = this.getSelectionState();
 		var active = this.isDiagramActive();
-		var editable = graph.getEditableCells(graph.getSelectionCells());
-		var enabled = file != null || urlParams['embed'] == '1';
 
 		this.actions.get('pageSetup').setEnabled(active);
 		this.actions.get('autosave').setEnabled(file != null && file.isEditable() && file.isAutosaveOptional());
 		this.actions.get('guides').setEnabled(active);
-		this.actions.get('editData').setEnabled(editable.length > 0 || graph.isSelectionEmpty());
+		this.actions.get('editData').setEnabled(graph.isEnabled());
 		this.actions.get('shadowVisible').setEnabled(active);
 		this.actions.get('connectionArrows').setEnabled(active);
 		this.actions.get('connectionPoints').setEnabled(active);
 		this.actions.get('copyStyle').setEnabled(active && !graph.isSelectionEmpty());
-		this.actions.get('pasteStyle').setEnabled(active && editable.length > 0);
-		this.actions.get('editGeometry').setEnabled(editable.length > 0 &&
-			graph.getModel().isVertex(editable[0]));
+		this.actions.get('pasteStyle').setEnabled(active && ss.cells.length > 0);
+		this.actions.get('editGeometry').setEnabled(ss.vertices.length >  0);
 		this.actions.get('createShape').setEnabled(active);
 		this.actions.get('createRevision').setEnabled(active);
 		this.actions.get('moveToFolder').setEnabled(file != null);
@@ -13845,7 +13848,8 @@
 			'/' + mxResources.get('replace') : '') + '...';
 		
 		var state = graph.view.getState(graph.getSelectionCell());
-		this.actions.get('editShape').setEnabled(active && state != null && state.shape != null && state.shape.stencil != null);
+		this.actions.get('editShape').setEnabled(active && state != null &&
+			state.shape != null && state.shape.stencil != null);
 	};
 
 	/**

+ 56 - 60
src/main/webapp/js/diagramly/ElectronApp.js

@@ -309,6 +309,15 @@ mxStencilRegistry.allowEval = false;
 			return false
 		}
 		
+		global.__emt_removeDraft = function()
+		{
+			var currentFile = editorUi.getCurrentFile();
+
+			if (currentFile != null)
+			{
+				currentFile.removeDraft();
+			}
+		};
 		// global.__emt_getCurrentFile = e => {
 		// 	return this.getCurrentFile()
 		// }
@@ -1029,22 +1038,52 @@ mxStencilRegistry.allowEval = false;
 		var isPng = index > -1 && index == path.length - 4;
 		var isVsdx = /\.vsdx$/i.test(path) || /\.vssx$/i.test(path);
 		var encoding = isVsdx? null : ((isPng || /\.pdf$/i.test(path)) ? 'base64' : 'utf-8');
-		var isModified = false, fileLoaded = false;
+		var fileEntry = new Object(), stat = null;
+		fileEntry.path = path;
+		fileEntry.name = path.replace(/^.*[\\\/]/, '');
+		fileEntry.type = encoding;
+
+		var checkDrafts = mxUtils.bind(this, function()
+		{
+			this.filterDrafts(fileEntry.path, 'dummy', mxUtils.bind(this, function(drafts)
+			{
+				if (drafts.length > 0)
+				{
+					var dlg = new DraftDialog(this, mxResources.get('unsavedChanges'),
+								(drafts.length > 1) ? null : drafts[0].data, mxUtils.bind(this, function(index)
+					{
+						index = index || 0;
+						this.hideDialog();
+						fn(fileEntry, drafts[index].data, stat, null, true);
+						this.removeDatabaseItem(drafts[index].key);
+					}), mxUtils.bind(this, function(index)
+					{
+						index = index || 0;
+					
+						// Discard draft
+						this.confirm(mxResources.get('areYouSure'), null, mxUtils.bind(this, function()
+						{
+							this.removeDatabaseItem(drafts[index].key);
+							this.hideDialog();
+						}), mxResources.get('no'), mxResources.get('yes'));
+					}), null, null, null, (drafts.length > 1) ? drafts : null);
+					
+					this.showDialog(dlg.container, 640, 480, true, false);
+					
+					dlg.init();
+				}
+			}));
+		});
 
 		var readData = mxUtils.bind(this, function (e, data)
 		{
 			if (e)
 			{
 				fnErr(e);
-				fileLoaded = true;
+				checkDrafts();
 			}
 			else
 			{
-				var fileEntry = new Object();
-				fileEntry.path = path;
-				fileEntry.name = path.replace(/^.*[\\\/]/, '');
-				fileEntry.type = encoding;
-
 				// VSDX and PDF files are imported instead of being opened
 				if (isVsdx)
 				{
@@ -1084,10 +1123,10 @@ mxStencilRegistry.allowEval = false;
 						}
 						else
 						{
-							fn(null, xml, null, name, isModified);
+							fn(null, xml, null, name, false);
 						}
-						
-						fileLoaded = true;
+
+						checkDrafts();
 					}), null, name);
 					
 					return;
@@ -1099,9 +1138,8 @@ mxStencilRegistry.allowEval = false;
 					if (tmp != null)
 					{
 						var name = fileEntry.name;
-						fn(null, tmp, null, name.substring(0, name.lastIndexOf('.')) + '.drawio', isModified);
-						fileLoaded = true;
-
+						fn(null, tmp, null, name.substring(0, name.lastIndexOf('.')) + '.drawio', false);
+						checkDrafts();
 						return;
 					}
 	    		}
@@ -1112,7 +1150,7 @@ mxStencilRegistry.allowEval = false;
 					data = this.extractGraphModelFromPng('data:image/png;base64,' + data);
 				}
 
-				fs.stat(path, function(err, stat)
+				fs.stat(path, function(err, stat_p)
 				{
 					if (err)
 					{
@@ -1120,58 +1158,16 @@ mxStencilRegistry.allowEval = false;
 					}
 					else
 					{
-						fn(fileEntry, data, stat, null, isModified);
+						stat = stat_p;
+						fn(fileEntry, data, stat, null, false);
 					}
-					
-					fileLoaded = true;
+
+					checkDrafts();
 				});
 			}
 		});
  
 		fs.readFile(path, encoding, readData);
-
-    	//Check if a bkp file exists, if one exists, ask user to restore/ignore
-		var checkBkpFile = mxUtils.bind(this, function (e, data)
-		{
-			//Backup file must be loaded after actual file
-			if (!fileLoaded)
-			{
-				setTimeout(function()
-				{
-					checkBkpFile(e, data);
-				}, 10);
-				return;
-			}
-			
-			if (!e)
-			{
-				var dlg = new DraftDialog(this, mxResources.get('backupFound'),
-						data, mxUtils.bind(this, function()
-				{
-					this.hideDialog();
-					isModified = true;
-					readData(null, data);
-					fs.unlink(bkpFile, (err) => {}); //Ignore errors!
-				}), mxUtils.bind(this, function()
-				{
-					this.hideDialog();
-					fs.unlink(bkpFile, (err) => {}); //Ignore errors!
-				}));
-				
-				this.showDialog(dlg.container, 640, 480, true, false, mxUtils.bind(this, function(cancel)
-				{
-					if (cancel)
-					{
-						//TODO Rename backup file?
-					}
-				}));
-				
-				dlg.init();
-			}
-		});
-		
-		var bkpFile = getBkpFilePath(path);
-		fs.readFile(bkpFile, encoding, checkBkpFile);		
 	};
 
 	// Disables temp files in Electron

+ 2 - 0
src/main/webapp/js/diagramly/GraphViewer.js

@@ -1460,6 +1460,8 @@ GraphViewer.prototype.addToolbar = function()
 						layersDialog.style.backgroundColor = '#eee';
 						layersDialog.style.fontFamily = Editor.defaultHtmlFont;
 						layersDialog.style.fontSize = '11px';
+						layersDialog.style.overflowY = 'auto';
+						layersDialog.style.maxHeight = (this.graph.container.clientHeight - this.toolbarHeight - 10) + 'px'
 						layersDialog.style.zIndex = this.toolbarZIndex + 1;
 						mxUtils.setOpacity(layersDialog, 80);
 						var origin = mxUtils.getDocumentScrollOrigin(document);

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

@@ -2233,7 +2233,7 @@ EditorUi.initMinimalTheme = function()
 					var toggleShapesAction = ui.actions.get('toggleShapes');
 					addAction(toggleShapesAction, mxResources.get('shapes') + ' (' + toggleShapesAction.shortcut + ')', insertImage);
 
-					elt = addMenu('table', null, Editor.tableImage);
+					elt = addMenu('table', null, Editor.calendarImage);
 					elt.style.boxShadow = 'none';
 					elt.style.opacity = '0.7';
 					elt.style.padding = '6px';
@@ -2241,7 +2241,7 @@ EditorUi.initMinimalTheme = function()
 					elt.style.width = '37px';
 					addElt(elt, null, 'pointer');
 
-					addAction(ui.actions.get('insertTemplate'), mxResources.get('template'), Editor.templateImage);
+					addAction(ui.actions.get('insertTemplate'), mxResources.get('template'), Editor.addImage);
 				}
 
 				if (urlParams['embedInline'] != '1')

+ 8 - 2
src/main/webapp/js/diagramly/Settings.js

@@ -233,7 +233,7 @@ var mxSettings =
 			showStartScreen: true,
 			gridColor: mxGraphView.prototype.defaultGridColor,
 			darkGridColor: mxGraphView.prototype.defaultDarkGridColor,
-			autosave: true,
+			autosave: !EditorUi.isElectronApp,
 			resizeImages: null,
 			openCounter: 0,
 			version: mxSettings.currentVersion,
@@ -361,7 +361,13 @@ var mxSettings =
 			
 			if (mxSettings.settings.autosave == null)
 			{
-				mxSettings.settings.autosave = true;
+				mxSettings.settings.autosave = !EditorUi.isElectronApp;
+			}
+			else if (EditorUi.isElectronApp && localStorage.getItem('._autoSaveTrans_') == null) //Transition to no autosave
+			{
+				localStorage.setItem('._autoSaveTrans_', '1');
+				mxSettings.settings.autosave = false;
+				mxSettings.save();
 			}
 			
 			if (mxSettings.settings.scratchpadSeen != null)

+ 1 - 1
src/main/webapp/js/grapheditor/Actions.js

@@ -485,7 +485,7 @@ Actions.prototype.init = function()
 
 		graph.turnShapes(graph.getResizableCells(graph.getSelectionCells()),
 			(evt != null) ? mxEvent.isShiftDown(evt) : false);
-	}, null, null, Editor.ctrlKey + '+R'));
+	}, null, null, (mxClient.IS_SF) ? null : Editor.ctrlKey + '+R'));
 	this.put('selectConnections', new Action(mxResources.get('selectEdges'), function(evt)
 	{
 		var cell = graph.getSelectionCell();

File diff suppressed because it is too large
+ 0 - 2
src/main/webapp/js/grapheditor/Editor.js


+ 291 - 87
src/main/webapp/js/grapheditor/EditorUi.js

@@ -58,7 +58,19 @@ EditorUi = function(editor, container, lightbox)
 	{
 		new Image().src = mxConnectionHandler.prototype.connectImage.src;
 	}
+
+	// Installs selection state listener
+	this.selectionStateListener = mxUtils.bind(this, function(sender, evt)
+	{
+		this.clearSelectionState();
+	});
 	
+	graph.getSelectionModel().addListener(mxEvent.CHANGE, this.selectionStateListener);
+	graph.getModel().addListener(mxEvent.CHANGE, this.selectionStateListener);
+	graph.addListener(mxEvent.EDITING_STARTED, this.selectionStateListener);
+	graph.addListener(mxEvent.EDITING_STOPPED, this.selectionStateListener);
+	graph.getView().addListener('unitChanged', this.selectionStateListener);
+
 	// Disables graph and forced panning in chromeless mode
 	if (this.editor.chromeless && !this.editor.editable)
 	{
@@ -1231,6 +1243,220 @@ EditorUi.prototype.init = function()
 	}
 };
 
+/**
+ * Returns information about the current selection.
+ */
+EditorUi.prototype.clearSelectionState = function()
+{
+	this.selectionState = null;
+};
+
+/**
+ * Returns information about the current selection.
+ */
+EditorUi.prototype.getSelectionState = function()
+{
+	if (this.selectionState == null)
+	{
+		this.selectionState = this.createSelectionState();
+	}
+	
+	return this.selectionState;
+};
+
+/**
+ * Returns information about the current selection.
+ */
+EditorUi.prototype.createSelectionState = function()
+{
+	var graph = this.editor.graph;
+	var cells = graph.getSelectionCells();
+	var result = this.initSelectionState();
+	var initial = true;
+	
+	for (var i = 0; i < cells.length; i++)
+	{
+		var style = graph.getCurrentCellStyle(cells[i]);
+	
+		if (mxUtils.getValue(style, mxConstants.STYLE_EDITABLE, '1') != '0')
+		{
+			this.updateSelectionStateForCell(result, cells[i], cells, initial);
+			initial = false;
+		}
+	}
+
+	this.updateSelectionStateForTableCells(result);
+	
+	return result;
+};
+
+/**
+ * Returns information about the current selection.
+ */
+EditorUi.prototype.initSelectionState = function()
+{
+	return {vertices: [], edges: [], cells: [], x: null, y: null, width: null, height: null,
+		style: {}, containsImage: false, containsLabel: false, fill: true, glass: true,
+		rounded: true, autoSize: false, image: true, shadow: true, lineJumps: true, resizable: true,
+		table: false, cell: false, row: false, movable: true, rotatable: true, stroke: true,
+		unlocked: this.editor.graph.isEnabled(), connections: false};
+};
+
+/**
+ * Adds information about current selected table cells range.
+ */
+EditorUi.prototype.updateSelectionStateForTableCells = function(result)
+{
+	// Updates rowspan/colspan for table cell merging
+	// if (result.cells.length > 1 && result.cell)
+	// {
+		//var cells = mxUtils.sortCells(result.cells);
+		// var row = graph.model.getParent(cells[0]);
+		// var table = graph.model.getParent(row);
+		// var colIndex = row.getIndex(cells[0]);
+		// var rowIndex = table.getIndex(row);
+		// var colCount = 1;
+
+		// while (colCount < cells.length && graph.model.getParent(cells[colCount]) == row)
+		// {
+		// 	colCount++;
+		// }
+
+		// var index = 1;
+		// var rowCount = 1;
+		// row = table.getChildAt(rowIndex + rowCount);
+
+		// while (cells[rowCount * colCount + index] == row.getChildAt(index))
+		// {
+		// 	index++;
+		// }
+
+		// row = graph.model.getParent(cells[rowCount * colCount + index]);
+
+		// var rowCount = 1;
+
+
+
+		// for (var i = 1; i < cells.length; i++)
+		// {
+
+		// }
+
+		// var colIndex = graph.getColumnIndex(cells[0]);
+		// var rowIndex = graph.getRowIndex(cells[0]);
+
+	// }
+};
+
+/**
+ * Returns information about the current selection.
+ */
+EditorUi.prototype.updateSelectionStateForCell = function(result, cell, cells, initial)
+{
+	var graph = this.editor.graph;
+	result.cells.push(cell);
+	
+	if (graph.getModel().isVertex(cell))
+	{
+		result.connections = graph.model.getEdgeCount(cell) > 0;
+		result.unlocked = result.unlocked && !graph.isCellLocked(cell);
+		result.resizable = result.resizable && graph.isCellResizable(cell);
+		result.rotatable = result.rotatable && graph.isCellRotatable(cell);
+		result.movable = result.movable && graph.isCellMovable(cell) &&
+			!graph.isTableRow(cell) && !graph.isTableCell(cell);
+		result.table = result.table || graph.isTable(cell);
+		result.cell = result.cell || graph.isTableCell(cell);
+		result.row = result.row || graph.isTableRow(cell);
+		result.vertices.push(cell);
+		var geo = graph.getCellGeometry(cell);
+		
+		if (geo != null)
+		{
+			if (geo.width > 0)
+			{
+				if (result.width == null)
+				{
+					result.width = geo.width;
+				}
+				else if (result.width != geo.width)
+				{
+					result.width = '';
+				}
+			}
+			else
+			{
+				result.containsLabel = true;
+			}
+			
+			if (geo.height > 0)
+			{
+				if (result.height == null)
+				{
+					result.height = geo.height;
+				}
+				else if (result.height != geo.height)
+				{
+					result.height = '';
+				}
+			}
+			else
+			{
+				result.containsLabel = true;
+			}
+			
+			if (!geo.relative || geo.offset != null)
+			{
+				var x = (geo.relative) ? geo.offset.x : geo.x;
+				var y = (geo.relative) ? geo.offset.y : geo.y;
+				
+				if (result.x == null)
+				{
+					result.x = x;
+				}
+				else if (result.x != x)
+				{
+					result.x = '';
+				}
+				
+				if (result.y == null)
+				{
+					result.y = y;
+				}
+				else if (result.y != y)
+				{
+					result.y = '';
+				}
+			}
+		}
+	}
+	else if (graph.getModel().isEdge(cell))
+	{
+		result.edges.push(cell);
+		result.connections = true;
+		result.resizable = false;
+		result.rotatable = false;
+		result.movable = false;
+	}
+
+	var state = graph.view.getState(cell);
+	
+	if (state != null)
+	{
+		result.autoSize = result.autoSize || graph.isAutoSizeState(state);
+		result.glass = result.glass && graph.isGlassState(state);
+		result.rounded = result.rounded && graph.isRoundedState(state);
+		result.lineJumps = result.lineJumps && graph.isLineJumpState(state);
+		result.image = result.image && graph.isImageState(state);
+		result.shadow = result.shadow && graph.isShadowState(state);
+		result.fill = result.fill && graph.isFillState(state);
+		result.stroke = result.stroke && graph.isStrokeState(state);
+		
+		var shape = mxUtils.getValue(state.style, mxConstants.STYLE_SHAPE, null);
+		result.containsImage = result.containsImage || shape == 'image';
+		graph.mergeStyle(state.style, result.style, initial);
+	}
+};
+
 /**
  * Returns true if the given event should start editing. This implementation returns true.
  */
@@ -3803,51 +4029,9 @@ EditorUi.prototype.addUndoListener = function()
 EditorUi.prototype.updateActionStates = function()
 {
 	var graph = this.editor.graph;
-	var vertexSelected = false;
-	var groupSelected = false;
-	var edgeSelected = false;
-	var tableSelected = false;
-	var rowSelected = false;
-	var cellSelected = false;
-	var selected = false;
-	var editable = [];
-
-	var cells = graph.getSelectionCells();
-	
-	if (cells != null)
-	{
-    	for (var i = 0; i < cells.length; i++)
-    	{
-    		var cell = cells[i];
+	var ss = this.getSelectionState();
+    var unlocked = graph.isEnabled() && !graph.isCellLocked(graph.getDefaultParent());
 
-			tableSelected = tableSelected || graph.isTable(cell);
-			cellSelected = cellSelected || graph.isTableCell(cell);
-			rowSelected = rowSelected || graph.isTableRow(cell);
- 
-			if (graph.isCellEditable(cell))
-			{
-				editable.push(cell);
-				selected = true;
-					
-	    		if (graph.getModel().isEdge(cell))
-	    		{
-	    			edgeSelected = true;
-	    		}
-	    		
-	    		if (graph.getModel().isVertex(cell))
-	    		{
-	    			vertexSelected = true;
-	    			
-		    		if (graph.getModel().getChildCount(cell) > 0 ||
-		    			graph.isContainer(cell))
-		    		{
-		    			groupSelected = true;
-		    		}
-	    		}
-			}
-		}
-	}
-	
 	// Updates action states
 	var actions = ['cut', 'copy', 'bold', 'italic', 'underline', 'delete', 'duplicate',
 	               'editStyle', 'editTooltip', 'editLink', 'backgroundColor', 'borderColor',
@@ -3857,57 +4041,65 @@ EditorUi.prototype.updateActionStates = function()
 	
 	for (var i = 0; i < actions.length; i++)
 	{
-		this.actions.get(actions[i]).setEnabled(selected);
+		this.actions.get(actions[i]).setEnabled(ss.cells.length > 0);
 	}
 
-	this.actions.get('lockUnlock').setEnabled(!graph.isSelectionEmpty());	
+	this.actions.get('grid').setEnabled(!this.editor.chromeless || this.editor.editable);
+	this.actions.get('pasteSize').setEnabled(this.copiedSize != null && ss.vertices.length > 0);
+	this.actions.get('pasteData').setEnabled(this.copiedValue != null && ss.cells.length > 0);
 	this.actions.get('setAsDefaultStyle').setEnabled(graph.getSelectionCount() == 1);
-	this.actions.get('clearWaypoints').setEnabled(selected);
 	this.actions.get('copySize').setEnabled(graph.getSelectionCount() == 1);
-	this.actions.get('bringForward').setEnabled(editable.length == 1);
-	this.actions.get('sendBackward').setEnabled(editable.length == 1);
-	this.actions.get('turn').setEnabled(graph.getResizableCells(graph.getSelectionCells()).length > 0);
-	this.actions.get('curved').setEnabled(edgeSelected);
-	this.actions.get('rotation').setEnabled(vertexSelected);
-	this.actions.get('wordWrap').setEnabled(vertexSelected);
-	this.actions.get('autosize').setEnabled(vertexSelected);
-   	var oneVertexSelected = vertexSelected && graph.getSelectionCount() == 1;
-	this.actions.get('group').setEnabled((graph.getSelectionCount() > 1 ||
-		(oneVertexSelected && !graph.isContainer(graph.getSelectionCell()) &&
-		graph.model.getChildCount(graph.getSelectionCell()) == 0)) &&
-		!rowSelected && !cellSelected);
-	this.actions.get('ungroup').setEnabled(groupSelected && !rowSelected && !cellSelected);
-   	this.actions.get('removeFromGroup').setEnabled(oneVertexSelected &&
-   		graph.getModel().isVertex(graph.getModel().getParent(editable[0])));
-
-	// Updates menu states
-   	var state = graph.view.getState(graph.getSelectionCell());
-    this.menus.get('navigation').setEnabled(selected || graph.view.currentRoot != null);
-    this.actions.get('collapsible').setEnabled(vertexSelected &&
-    	(graph.isContainer(graph.getSelectionCell()) || graph.model.getChildCount(graph.getSelectionCell()) > 0));
-    this.actions.get('home').setEnabled(graph.view.currentRoot != null);
-    this.actions.get('exitGroup').setEnabled(graph.view.currentRoot != null);
-    this.actions.get('enterGroup').setEnabled(graph.getSelectionCount() == 1 && graph.isValidRoot(graph.getSelectionCell()));
-    var foldable = graph.getSelectionCount() == 1 && graph.isCellFoldable(graph.getSelectionCell()); // TODO
-    this.actions.get('expand').setEnabled(foldable);
-    this.actions.get('collapse').setEnabled(foldable);
-    this.actions.get('editLink').setEnabled(editable.length == 1);
-    this.actions.get('openLink').setEnabled(graph.getSelectionCount() == 1 &&
-    	graph.getLinkForCell(graph.getSelectionCell()) != null);
-    this.actions.get('guides').setEnabled(graph.isEnabled());
-    this.actions.get('grid').setEnabled(!this.editor.chromeless || this.editor.editable);
-
-    var unlocked = graph.isEnabled() && !graph.isCellLocked(graph.getDefaultParent());
-    this.menus.get('layout').setEnabled(unlocked);
-    this.menus.get('insert').setEnabled(unlocked);
-    this.menus.get('direction').setEnabled(unlocked && vertexSelected);
-    this.menus.get('align').setEnabled(unlocked && vertexSelected && graph.getSelectionCount() > 1);
-    this.menus.get('distribute').setEnabled(unlocked && vertexSelected && graph.getSelectionCount() > 1);
+	this.actions.get('lockUnlock').setEnabled(!graph.isSelectionEmpty());
+	this.actions.get('bringForward').setEnabled(ss.cells.length == 1);
+	this.actions.get('sendBackward').setEnabled(ss.cells.length == 1);
+	this.actions.get('rotation').setEnabled(ss.vertices.length == 1);
+	this.actions.get('wordWrap').setEnabled(ss.vertices.length == 1);
+	this.actions.get('autosize').setEnabled(ss.vertices.length == 1);
+	this.actions.get('clearWaypoints').setEnabled(ss.connections);
+	this.actions.get('curved').setEnabled(ss.edges.length > 0);
+	this.actions.get('turn').setEnabled(ss.resizable);
+	this.actions.get('group').setEnabled(!ss.row && !ss.cell &&
+		(ss.cells.length > 1 || (ss.vertices.length == 1 &&
+		graph.model.getChildCount(ss.cells[0]) == 0 &&
+		!graph.isContainer(ss.vertices[0]))));
+	this.actions.get('ungroup').setEnabled(!ss.row && !ss.cell && !ss.table &&
+		ss.vertices.length > 0 && (graph.isContainer(ss.vertices[0]) ||
+		graph.getModel().getChildCount(ss.vertices[0]) > 0));
+   	this.actions.get('removeFromGroup').setEnabled(ss.cells.length == 1 &&
+   		graph.getModel().isVertex(graph.getModel().getParent(ss.cells[0])));
+	this.actions.get('collapsible').setEnabled(ss.vertices.length == 1 &&
+		(graph.model.getChildCount(ss.vertices[0]) > 0 ||
+		graph.isContainer(ss.vertices[0])));
+		this.actions.get('exitGroup').setEnabled(graph.view.currentRoot != null);
+	this.actions.get('home').setEnabled(graph.view.currentRoot != null);
+	this.actions.get('enterGroup').setEnabled(ss.cells.length == 1 &&
+		graph.isValidRoot(ss.cells[0]));
+	this.actions.get('editLink').setEnabled(ss.cells.length == 1);
+	this.actions.get('openLink').setEnabled(ss.cells.length == 1 &&
+		graph.getLinkForCell(ss.cells[0]) != null);
+	this.actions.get('guides').setEnabled(graph.isEnabled());
     this.actions.get('selectVertices').setEnabled(unlocked);
     this.actions.get('selectEdges').setEnabled(unlocked);
     this.actions.get('selectAll').setEnabled(unlocked);
     this.actions.get('selectNone').setEnabled(unlocked);
-    
+
+	var foldable = ss.vertices.length == 1 &&
+		graph.isCellFoldable(ss.vertices[0]);
+	this.actions.get('expand').setEnabled(foldable);
+	this.actions.get('collapse').setEnabled(foldable);
+
+	// Updates menu states
+    this.menus.get('navigation').setEnabled(ss.cells.length > 0 ||
+		graph.view.currentRoot != null);
+    this.menus.get('layout').setEnabled(unlocked);
+    this.menus.get('insert').setEnabled(unlocked);
+    this.menus.get('direction').setEnabled(ss.unlocked &&
+		ss.vertices.length == 1);
+    this.menus.get('distribute').setEnabled(ss.unlocked &&
+		ss.vertices.length > 1);
+    this.menus.get('align').setEnabled(ss.unlocked &&
+		ss.vertices.length > 1);
+
     this.updatePasteActionStates();
 };
 
@@ -5505,6 +5697,18 @@ EditorUi.prototype.createKeyHandler = function(editor)
  */
 EditorUi.prototype.destroy = function()
 {
+	var graph = this.editor.graph;
+
+	if (graph != null && this.selectionStateListener != null)
+	{
+		graph.getSelectionModel().removeListener(mxEvent.CHANGE, this.selectionStateListener);
+		graph.getModel().removeListener(mxEvent.CHANGE, this.selectionStateListener);
+		graph.removeListener(mxEvent.EDITING_STARTED, this.selectionStateListener);
+		graph.removeListener(mxEvent.EDITING_STOPPED, this.selectionStateListener);
+		graph.getView().removeListener('unitChanged', this.selectionStateListener);
+		this.selectionStateListener = null;
+	}
+	
 	if (this.editor != null)
 	{
 		this.editor.destroy();

File diff suppressed because it is too large
+ 120 - 534
src/main/webapp/js/grapheditor/Format.js


+ 98 - 0
src/main/webapp/js/grapheditor/Graph.js

@@ -2058,6 +2058,14 @@ Graph.prototype.standalone = false;
  */
 Graph.prototype.enableFlowAnimation = false;
 
+/**
+ * Background color for inactive tabs.
+ */
+Graph.prototype.roundableShapes = ['label', 'rectangle', 'internalStorage', 'corner',
+	'parallelogram', 'swimlane', 'triangle', 'trapezoid', 'ext', 'step', 'tee', 'process',
+	'link', 'rhombus', 'offPageConnector', 'loopLimit', 'hexagon', 'manualInput', 'card',
+	'curlyBracket', 'singleArrow', 'callout', 'doubleArrow', 'flexArrow', 'umlLifeline'];
+
 /**
  * Installs child layout styles.
  */
@@ -2183,6 +2191,96 @@ Graph.prototype.init = function(container)
 	 * Contains the offset.
 	 */
 	Graph.prototype.currentTranslate = new mxPoint(0, 0);
+
+	/**
+	 * Returns information about the current selection.
+	 */
+	Graph.prototype.isFillState = function(state)
+	{
+		return !this.isSpecialColor(state.style[mxConstants.STYLE_FILLCOLOR]) && (this.model.isVertex(state.cell) ||
+			mxUtils.getValue(state.style, mxConstants.STYLE_SHAPE, null) == 'arrow' ||
+			mxUtils.getValue(state.style, mxConstants.STYLE_SHAPE, null) == 'filledEdge' ||
+			mxUtils.getValue(state.style, mxConstants.STYLE_SHAPE, null) == 'flexArrow');
+	};
+	
+	/**
+	 * Returns information about the current selection.
+	 */
+	Graph.prototype.isStrokeState = function(state)
+	{
+		return !this.isSpecialColor(state.style[mxConstants.STYLE_STROKECOLOR]);
+	};
+	
+	/**
+	 * Returns information about the current selection.
+	 */
+	Graph.prototype.isSpecialColor = function(color)
+	{
+		return mxUtils.indexOf([mxConstants.STYLE_STROKECOLOR,
+			mxConstants.STYLE_FILLCOLOR, 'inherit', 'swimlane',
+			'indicated'], color) >= 0;
+	};
+	
+	/**
+	 * Returns information about the current selection.
+	 */
+	Graph.prototype.isGlassState = function(state)
+	{
+		var shape = mxUtils.getValue(state.style, mxConstants.STYLE_SHAPE, null);
+		
+		return (shape == 'label' || shape == 'rectangle' || shape == 'internalStorage' ||
+				shape == 'ext' || shape == 'umlLifeline' || shape == 'swimlane' ||
+				shape == 'process');
+	};
+	
+	/**
+	 * Returns information about the current selection.
+	 */
+	Graph.prototype.isRoundedState = function(state)
+	{
+		return (state.shape != null) ? state.shape.isRoundable() :
+			mxUtils.indexOf(this.roundableShapes, mxUtils.getValue(state.style,
+			mxConstants.STYLE_SHAPE, null)) >= 0;
+	};
+	
+	/**
+	 * Returns information about the current selection.
+	 */
+	Graph.prototype.isLineJumpState = function(state)
+	{
+		var shape = mxUtils.getValue(state.style, mxConstants.STYLE_SHAPE, null);
+		var curved = mxUtils.getValue(state.style, mxConstants.STYLE_CURVED, false);
+		
+		return !curved && (shape == 'connector' || shape == 'filledEdge');
+	};
+	
+	/**
+	 * Returns information about the current selection.
+	 */
+	Graph.prototype.isAutoSizeState = function(state)
+	{
+		return mxUtils.getValue(state.style, mxConstants.STYLE_AUTOSIZE, null) == '1';
+	};
+	
+	/**
+	 * Returns information about the current selection.
+	 */
+	Graph.prototype.isImageState = function(state)
+	{
+		var shape = mxUtils.getValue(state.style, mxConstants.STYLE_SHAPE, null);
+		
+		return (shape == 'label' || shape == 'image');
+	};
+	
+	/**
+	 * Returns information about the current selection.
+	 */
+	Graph.prototype.isShadowState = function(state)
+	{
+		var shape = mxUtils.getValue(state.style, mxConstants.STYLE_SHAPE, null);
+		
+		return (shape != 'image');
+	};
 	
 	/**
 	 * 

+ 1 - 1
src/main/webapp/js/grapheditor/Shapes.js

@@ -5125,7 +5125,7 @@
 			
 			StyleFormatPanel.prototype.getCustomColors = function()
 			{
-				var ss = this.format.getSelectionState();
+				var ss = this.editorUi.getSelectionState();
 				var result = styleFormatPanelGetCustomColors.apply(this, arguments);
 				
 				if (ss.style.shape == 'umlFrame')

File diff suppressed because it is too large
+ 1433 - 1424
src/main/webapp/js/viewer-static.min.js


File diff suppressed because it is too large
+ 1433 - 1424
src/main/webapp/js/viewer.min.js


File diff suppressed because it is too large
+ 74 - 74
src/main/webapp/mxgraph/mxClient.js


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

@@ -97,7 +97,7 @@ chatWindowTitle=‫دردشة‬
 chooseAnOption=‫اختر خيارا‬
 chromeApp=‫تطبيق Chrome‬
 collaborativeEditingNotice=‫ملاحظات مهمة عن مشاركة التعديل‬
-compare=‫يقارن‬
+compare=‫قارن‬
 compressed=‫مضغوط‬
 commitMessage=‫أكد علي تسجيل الرسالة‬
 configLinkWarn=‫هذة الوصلة تقوم بتغيرات علي draw.io . اضغط علي موافق لو كنت تثق فيمن ارسله اليك‬

+ 3 - 3
src/main/webapp/resources/dia_eu.txt

@@ -352,7 +352,7 @@ fullscreen=Pantaila osoa
 gap=Tartea
 gcp=GCP
 general=Orokorra
-getNotionChromeExtension=Eskuratu Notion Chrome gehigarria
+getNotionChromeExtension=Get the Notion Chrome Extension
 github=GitHub
 gitlab=GitLab
 gliffy=Gliffy
@@ -1168,5 +1168,5 @@ contactOwner=Contact Owner
 viewerOnlyMsg=Ezin dituzu diagramak editatu plataforma mugikorrean, mesedez erabili mahaigaineko bezeroa edo web arakatzailea.
 website=Webgunea
 check4Updates=Bilat eguneraketak
-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.
+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.

File diff suppressed because it is too large
+ 1 - 1
src/main/webapp/service-worker.js


File diff suppressed because it is too large
+ 1 - 1
src/main/webapp/service-worker.js.map


File diff suppressed because it is too large
+ 1 - 1
src/main/webapp/shortcuts.svg


File diff suppressed because it is too large
+ 1 - 1
src/main/webapp/templates/cloud/aws/aws_1.xml


File diff suppressed because it is too large
+ 1 - 1
src/main/webapp/templates/cloud/aws/aws_10.xml


File diff suppressed because it is too large
+ 1 - 1
src/main/webapp/templates/cloud/aws/aws_2.xml


File diff suppressed because it is too large
+ 1 - 1
src/main/webapp/templates/cloud/aws/aws_3.xml


File diff suppressed because it is too large
+ 1 - 1
src/main/webapp/templates/cloud/aws/aws_4.xml


File diff suppressed because it is too large
+ 1 - 1
src/main/webapp/templates/cloud/aws/aws_5.xml


File diff suppressed because it is too large
+ 1 - 1
src/main/webapp/templates/cloud/aws/aws_6.xml


File diff suppressed because it is too large
+ 1 - 1
src/main/webapp/templates/cloud/aws/aws_7.xml


File diff suppressed because it is too large
+ 1 - 1
src/main/webapp/templates/cloud/aws/aws_8.xml


File diff suppressed because it is too large
+ 1 - 1
src/main/webapp/templates/cloud/aws/aws_9.xml