Browse Source

10.3.6 release

Gaudenz Alder 6 years ago
parent
commit
e03605002c

+ 5 - 0
ChangeLog

@@ -1,3 +1,8 @@
+07-MAR-2019: 10.3.6
+
+- Improves error handling for Google Drive
+- Adds realtime file conversion tool
+
 05-MAR-2019: 10.3.5
 
 - Reduces possible number 403 errors in Drive

+ 1 - 1
VERSION

@@ -1 +1 @@
-10.3.5
+10.3.6

+ 1 - 1
src/main/webapp/cache.manifest

@@ -1,7 +1,7 @@
 CACHE MANIFEST
 
 # THIS FILE WAS GENERATED. DO NOT MODIFY!
-# 03/05/2019 06:52 PM
+# 03/07/2019 12:33 PM
 
 app.html
 index.html?offline=1

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


+ 249 - 214
src/main/webapp/js/diagramly/App.js

@@ -17,16 +17,19 @@ App = function(editor, container, lightbox)
 		urlParams['chrome'] != '0')));
 	
 	// Logs unloading of window with modifications for Google Drive file
-	window.onunload = mxUtils.bind(this, function()
+	if (!mxClient.IS_CHROMEAPP && !EditorUi.isElectronApp)
 	{
-		var file = this.getCurrentFile();
-		
-		if (file != null && file.constructor == DriveFile && file.isModified() && this.drive != null)
+		window.onunload = mxUtils.bind(this, function()
 		{
-			EditorUi.logEvent({category: 'Unload-Modified', action: file.getId(), label:
-				(this.drive.user != null) ? this.drive.user.id : 'unknown-user'});	
-		}
-	});
+			var file = this.getCurrentFile();
+			
+			if (file != null && file.constructor == DriveFile && file.isModified() && this.drive != null)
+			{
+				EditorUi.logEvent({category: 'Unload-Modified', action: file.getId(), label:
+					(this.drive.user != null) ? this.drive.user.id : 'unknown-user'});	
+			}
+		});
+	}
 	
 	// Pre-fetches images
 	if (mxClient.IS_SVG)
@@ -1125,27 +1128,30 @@ App.prototype.init = function()
 			this.mode = App.mode;
 		}
 		
-		// Checks if the cache is alive
-		var acceptResponse = true;
-		
-		var timeoutThread = window.setTimeout(mxUtils.bind(this, function()
+		if (!mxClient.IS_CHROMEAPP && !EditorUi.isElectronApp)
 		{
-			acceptResponse = false;
-			EditorUi.logEvent({category: 'Cache', action: 'alive', label: 408});
-		}), this.timeout);
-		
-		var t0 = new Date().getTime();
-		
-		mxUtils.get(EditorUi.cacheUrl + '?alive', mxUtils.bind(this, function(req)
-		{
-			window.clearTimeout(timeoutThread);
+			// Checks if the cache is alive
+			var acceptResponse = true;
 			
-			if (acceptResponse)
+			var timeoutThread = window.setTimeout(mxUtils.bind(this, function()
 			{
-				EditorUi.logEvent({category: 'Cache', action: 'alive', label:
-					req.getStatus() + '.' + (new Date().getTime() - t0)});
-			}
-		}));
+				acceptResponse = false;
+				EditorUi.logEvent({category: 'Cache', action: 'alive', label: 408});
+			}), this.timeout);
+			
+			var t0 = new Date().getTime();
+			
+			mxUtils.get(EditorUi.cacheUrl + '?alive', mxUtils.bind(this, function(req)
+			{
+				window.clearTimeout(timeoutThread);
+				
+				if (acceptResponse)
+				{
+					EditorUi.logEvent({category: 'Cache', action: 'alive', label:
+						req.getStatus() + '.' + (new Date().getTime() - t0)});
+				}
+			}));
+		}
 	}
 	else if (this.menubar != null)
 	{
@@ -2060,7 +2066,22 @@ App.prototype.load = function()
 				{
 					this.loadGapi(mxUtils.bind(this, function()
 					{
-						this.start();
+						if (urlParams['convert-realtime'] == '1')
+						{
+							this.spinner.stop();
+							
+							this.confirm('You are about to convert realtime files', mxUtils.bind(this, function()
+							{
+								this.drive.convertRealtimeFiles();
+							}), mxUtils.bind(this, function()
+							{
+								this.start();
+							}));
+						}
+						else
+						{
+							this.start();
+						}
 					}));
 				}
 			}
@@ -2638,86 +2659,93 @@ App.prototype.addLanguageMenu = function(elt, addLabel)
  */
 App.prototype.pickFile = function(mode)
 {
-	mode = (mode != null) ? mode : this.mode;
-	
-	if (mode == App.MODE_GOOGLE)
-	{
-		if (this.drive != null && typeof(google) != 'undefined' && typeof(google.picker) != 'undefined')
-		{
-			this.drive.pickFile();
-		}
-		else
-		{
-			this.openLink('https://drive.google.com');
-		}
-	}
-	else
+	try
 	{
-		var peer = this.getPeerForMode(mode);
+		mode = (mode != null) ? mode : this.mode;
 		
-		if (peer != null)
-		{
-			peer.pickFile();
-		}
-		// input.click does not work in IE on Windows 7
-		else if (mode == App.MODE_DEVICE && Graph.fileSupport && ((!mxClient.IS_IE && !mxClient.IS_IE11) ||
-			navigator.appVersion.indexOf('Windows NT 6.1') < 0))
+		if (mode == App.MODE_GOOGLE)
 		{
-			var input = document.createElement('input');
-			input.setAttribute('type', 'file');
-			
-			mxEvent.addListener(input, 'change', mxUtils.bind(this, function()
+			if (this.drive != null && typeof(google) != 'undefined' && typeof(google.picker) != 'undefined')
 			{
-				if (input.files != null)
-				{
-					this.openFiles(input.files);
-				}
-			}));
-	
-			input.click();
+				this.drive.pickFile();
+			}
+			else
+			{
+				this.openLink('https://drive.google.com');
+			}
 		}
 		else
 		{
-			this.hideDialog();
-			window.openNew = this.getCurrentFile() != null && !this.isDiagramEmpty();
-			window.baseUrl = this.getUrl();
-			window.openKey = 'open';
-			var prevValue = Editor.useLocalStorage;
-			Editor.useLocalStorage = (mode == App.MODE_BROWSER);
-			this.openFile();
+			var peer = this.getPeerForMode(mode);
 			
-			// Installs local handler for opened files in same window
-			window.openFile.setConsumer(mxUtils.bind(this, function(xml, filename)
+			if (peer != null)
+			{
+				peer.pickFile();
+			}
+			// input.click does not work in IE on Windows 7
+			else if (mode == App.MODE_DEVICE && Graph.fileSupport && ((!mxClient.IS_IE && !mxClient.IS_IE11) ||
+				navigator.appVersion.indexOf('Windows NT 6.1') < 0))
 			{
-				// Replaces PNG with XML extension
-				var dot = !this.useCanvasForExport && filename.substring(filename.length - 4) == '.png';
+				var input = document.createElement('input');
+				input.setAttribute('type', 'file');
 				
-				if (dot)
+				mxEvent.addListener(input, 'change', mxUtils.bind(this, function()
 				{
-					filename = filename.substring(0, filename.length - 4) + '.xml';
-				}
-				
-				this.fileLoaded((mode == App.MODE_BROWSER) ?
-					new StorageFile(this, xml, filename) :
-					new LocalFile(this, xml, filename));
-			}));
-			
-			// Extends dialog close to show splash screen
-			var dlg = this.dialog;
-			var dlgClose = dlg.close;
-			
-			this.dialog.close = mxUtils.bind(this, function(cancel)
+					if (input.files != null)
+					{
+						this.openFiles(input.files);
+					}
+				}));
+		
+				input.click();
+			}
+			else
 			{
-				Editor.useLocalStorage = prevValue;
-				dlgClose.apply(dlg, arguments);
-	
-				if (this.getCurrentFile() == null)
+				this.hideDialog();
+				window.openNew = this.getCurrentFile() != null && !this.isDiagramEmpty();
+				window.baseUrl = this.getUrl();
+				window.openKey = 'open';
+				var prevValue = Editor.useLocalStorage;
+				Editor.useLocalStorage = (mode == App.MODE_BROWSER);
+				this.openFile();
+				
+				// Installs local handler for opened files in same window
+				window.openFile.setConsumer(mxUtils.bind(this, function(xml, filename)
 				{
-					this.showSplash();
-				}
-			});
+					// Replaces PNG with XML extension
+					var dot = !this.useCanvasForExport && filename.substring(filename.length - 4) == '.png';
+					
+					if (dot)
+					{
+						filename = filename.substring(0, filename.length - 4) + '.xml';
+					}
+					
+					this.fileLoaded((mode == App.MODE_BROWSER) ?
+						new StorageFile(this, xml, filename) :
+						new LocalFile(this, xml, filename));
+				}));
+				
+				// Extends dialog close to show splash screen
+				var dlg = this.dialog;
+				var dlgClose = dlg.close;
+				
+				this.dialog.close = mxUtils.bind(this, function(cancel)
+				{
+					Editor.useLocalStorage = prevValue;
+					dlgClose.apply(dlg, arguments);
+		
+					if (this.getCurrentFile() == null)
+					{
+						this.showSplash();
+					}
+				});
+			}
 		}
 	}
+	catch (e)
+	{
+		this.handleError(e);
+	}
 };
 
 /**
@@ -2858,156 +2886,163 @@ App.prototype.pickLibrary = function(mode)
  */
 App.prototype.saveLibrary = function(name, images, file, mode, noSpin, noReload, fn)
 {
-	mode = (mode != null) ? mode : this.mode;
-	noSpin = (noSpin != null) ? noSpin : false;
-	noReload = (noReload != null) ? noReload : false;
-	var xml = this.createLibraryDataFromImages(images);
-	
-	var error = mxUtils.bind(this, function(resp)
+	try
 	{
-		this.spinner.stop();
+		mode = (mode != null) ? mode : this.mode;
+		noSpin = (noSpin != null) ? noSpin : false;
+		noReload = (noReload != null) ? noReload : false;
+		var xml = this.createLibraryDataFromImages(images);
 		
-		if (fn != null)
+		var error = mxUtils.bind(this, function(resp)
 		{
-			fn();
+			this.spinner.stop();
+			
+			if (fn != null)
+			{
+				fn();
+			}
+			
+			this.handleError(resp, (resp != null) ? mxResources.get('errorSavingFile') : null);
+		});
+	
+		// Handles special case for local libraries
+		if (file == null && mode == App.MODE_DEVICE)
+		{
+			file = new LocalLibrary(this, xml, name);
 		}
 		
-		this.handleError(resp, (resp != null) ? mxResources.get('errorSavingFile') : null);
-	});
-
-	// Handles special case for local libraries
-	if (file == null && mode == App.MODE_DEVICE)
-	{
-		file = new LocalLibrary(this, xml, name);
-	}
-	
-	if (file == null)
-	{
-		this.pickFolder(mode, mxUtils.bind(this, function(folderId)
+		if (file == null)
 		{
-			if (mode == App.MODE_GOOGLE && this.drive != null && this.spinner.spin(document.body, mxResources.get('inserting')))
+			this.pickFolder(mode, mxUtils.bind(this, function(folderId)
 			{
-				this.drive.insertFile(name, xml, folderId, mxUtils.bind(this, function(newFile)
+				if (mode == App.MODE_GOOGLE && this.drive != null && this.spinner.spin(document.body, mxResources.get('inserting')))
 				{
-					this.spinner.stop();
-					this.hideDialog(true);
-					this.libraryLoaded(newFile, images);
-				}), error, this.drive.libraryMimeType);
-			}
-			else if (mode == App.MODE_GITHUB && this.gitHub != null && this.spinner.spin(document.body, mxResources.get('inserting')))
-			{
-				this.gitHub.insertLibrary(name, xml, mxUtils.bind(this, function(newFile)
-				{
-					this.spinner.stop();
-					this.hideDialog(true);
-					this.libraryLoaded(newFile, images);
-				}), error, folderId);
-			}
-			else if (mode == App.MODE_TRELLO && this.trello != null && this.spinner.spin(document.body, mxResources.get('inserting')))
-			{
-				this.trello.insertLibrary(name, xml, mxUtils.bind(this, function(newFile)
+					this.drive.insertFile(name, xml, folderId, mxUtils.bind(this, function(newFile)
+					{
+						this.spinner.stop();
+						this.hideDialog(true);
+						this.libraryLoaded(newFile, images);
+					}), error, this.drive.libraryMimeType);
+				}
+				else if (mode == App.MODE_GITHUB && this.gitHub != null && this.spinner.spin(document.body, mxResources.get('inserting')))
 				{
-					this.spinner.stop();
-					this.hideDialog(true);
-					this.libraryLoaded(newFile, images);
-				}), error, folderId);
-			}
-			else if (mode == App.MODE_DROPBOX && this.dropbox != null && this.spinner.spin(document.body, mxResources.get('inserting')))
-			{
-				this.dropbox.insertLibrary(name, xml, mxUtils.bind(this, function(newFile)
+					this.gitHub.insertLibrary(name, xml, mxUtils.bind(this, function(newFile)
+					{
+						this.spinner.stop();
+						this.hideDialog(true);
+						this.libraryLoaded(newFile, images);
+					}), error, folderId);
+				}
+				else if (mode == App.MODE_TRELLO && this.trello != null && this.spinner.spin(document.body, mxResources.get('inserting')))
 				{
-					this.spinner.stop();
-					this.hideDialog(true);
-					this.libraryLoaded(newFile, images);
-				}), error, folderId);
-			}
-			else if (mode == App.MODE_ONEDRIVE && this.oneDrive != null && this.spinner.spin(document.body, mxResources.get('inserting')))
-			{
-				this.oneDrive.insertLibrary(name, xml, mxUtils.bind(this, function(newFile)
+					this.trello.insertLibrary(name, xml, mxUtils.bind(this, function(newFile)
+					{
+						this.spinner.stop();
+						this.hideDialog(true);
+						this.libraryLoaded(newFile, images);
+					}), error, folderId);
+				}
+				else if (mode == App.MODE_DROPBOX && this.dropbox != null && this.spinner.spin(document.body, mxResources.get('inserting')))
 				{
-					this.spinner.stop();
-					this.hideDialog(true);
-					this.libraryLoaded(newFile, images);
-				}), error, folderId);
-			}
-			else if (mode == App.MODE_BROWSER)
-			{
-				var fn = mxUtils.bind(this, function()
+					this.dropbox.insertLibrary(name, xml, mxUtils.bind(this, function(newFile)
+					{
+						this.spinner.stop();
+						this.hideDialog(true);
+						this.libraryLoaded(newFile, images);
+					}), error, folderId);
+				}
+				else if (mode == App.MODE_ONEDRIVE && this.oneDrive != null && this.spinner.spin(document.body, mxResources.get('inserting')))
 				{
-					var file = new StorageLibrary(this, xml, name);
-					
-					// Inserts data into local storage
-					file.saveFile(name, false, mxUtils.bind(this, function()
+					this.oneDrive.insertLibrary(name, xml, mxUtils.bind(this, function(newFile)
 					{
+						this.spinner.stop();
 						this.hideDialog(true);
-						this.libraryLoaded(file, images);
-					}), error);
-				});
-				
-				if (localStorage.getItem(name) == null)
+						this.libraryLoaded(newFile, images);
+					}), error, folderId);
+				}
+				else if (mode == App.MODE_BROWSER)
 				{
-					fn();
+					var fn = mxUtils.bind(this, function()
+					{
+						var file = new StorageLibrary(this, xml, name);
+						
+						// Inserts data into local storage
+						file.saveFile(name, false, mxUtils.bind(this, function()
+						{
+							this.hideDialog(true);
+							this.libraryLoaded(file, images);
+						}), error);
+					});
+					
+					if (localStorage.getItem(name) == null)
+					{
+						fn();
+					}
+					else
+					{
+						this.confirm(mxResources.get('replaceIt', [name]), fn);
+					}
 				}
 				else
 				{
-					this.confirm(mxResources.get('replaceIt', [name]), fn);
+					this.handleError({message: mxResources.get('serviceUnavailableOrBlocked')});
 				}
-			}
-			else
-			{
-				this.handleError({message: mxResources.get('serviceUnavailableOrBlocked')});
-			}
-		}));
-	}
-	else if (noSpin || this.spinner.spin(document.body, mxResources.get('saving')))
-	{
-		file.setData(xml);
-		
-		var doSave = mxUtils.bind(this, function()
+			}));
+		}
+		else if (noSpin || this.spinner.spin(document.body, mxResources.get('saving')))
 		{
-			file.save(true, mxUtils.bind(this, function(resp)
+			file.setData(xml);
+			
+			var doSave = mxUtils.bind(this, function()
 			{
-				this.spinner.stop();
-				this.hideDialog(true);
-				
-				if (!noReload)
-				{
-					this.libraryLoaded(file, images);
-				}
-				
-				if (fn != null)
+				file.save(true, mxUtils.bind(this, function(resp)
 				{
-					fn();
-				}
-			}), error);
-		});
-		
-		if (name != file.getTitle())
-		{
-			var oldHash = file.getHash();
+					this.spinner.stop();
+					this.hideDialog(true);
+					
+					if (!noReload)
+					{
+						this.libraryLoaded(file, images);
+					}
+					
+					if (fn != null)
+					{
+						fn();
+					}
+				}), error);
+			});
 			
-			file.rename(name, mxUtils.bind(this, function(resp)
+			if (name != file.getTitle())
 			{
-				// Change hash in stored settings
-				if (file.constructor != LocalLibrary && oldHash != file.getHash())
+				var oldHash = file.getHash();
+				
+				file.rename(name, mxUtils.bind(this, function(resp)
 				{
-					mxSettings.removeCustomLibrary(oldHash);
-					mxSettings.addCustomLibrary(file.getHash());
-				}
-
-				// Workaround for library files changing hash so
-				// the old library cannot be removed from the
-				// sidebar using the updated file in libraryLoaded
-				this.removeLibrarySidebar(oldHash);
-
+					// Change hash in stored settings
+					if (file.constructor != LocalLibrary && oldHash != file.getHash())
+					{
+						mxSettings.removeCustomLibrary(oldHash);
+						mxSettings.addCustomLibrary(file.getHash());
+					}
+	
+					// Workaround for library files changing hash so
+					// the old library cannot be removed from the
+					// sidebar using the updated file in libraryLoaded
+					this.removeLibrarySidebar(oldHash);
+	
+					doSave();
+				}), error)
+			}
+			else
+			{
 				doSave();
-			}), error)
-		}
-		else
-		{
-			doSave();
+			}
 		}
 	}
+	catch (e)
+	{
+		this.handleError(e);
+	}
 };
 
 /**

File diff suppressed because it is too large
+ 1195 - 792
src/main/webapp/js/diagramly/DriveClient.js


+ 148 - 93
src/main/webapp/js/diagramly/DriveFile.js

@@ -12,11 +12,6 @@ DriveFile = function(ui, data, desc)
 //Extends mxEventSource
 mxUtils.extend(DriveFile, DrawioFile);
 
-/**
- * Slower autosave delay to avoid rate limite exceeded.
- */
-DriveFile.prototype.autosaveDelay = 2000;
-
 /**
  * Delay for last save in ms.
  */
@@ -151,116 +146,176 @@ DriveFile.prototype.save = function(revision, success, error, unloading, overwri
  */
 DriveFile.prototype.saveFile = function(title, revision, success, error, unloading, overwrite)
 {
-	if (!this.isEditable())
+	try
 	{
-		if (success != null)
+		if (!this.isEditable())
 		{
-			success();
+			if (success != null)
+			{
+				success();
+			}
 		}
-	}
-	else if (!this.savingFile)
-	{
-		var doSave = mxUtils.bind(this, function(realOverwrite, realRevision)
+		else if (!this.savingFile)
 		{
-			var lastDesc = this.desc;
-			
-			// Makes sure no changes get lost while the file is saved
-			var modified = this.isModified();
-			this.setModified(false);
-			this.savingFile = true;
-
-			// Waits for success for modified state to be visible
-			var prevModified = this.isModified;
-			
-			this.isModified = function()
-			{
-				return true;
-			};
-
-			this.ui.drive.saveFile(this, realRevision, mxUtils.bind(this, function(resp, savedData)
+			var doSave = mxUtils.bind(this, function(realOverwrite, realRevision)
 			{
-				this.isModified = prevModified;
-				this.savingFile = false;
-				
-				// Handles special case where resp is false eg
-				// if the old file was converted to realtime
-				if (resp != false)
+				try
 				{
-					if (revision)
-					{
-						this.lastAutosaveRevision = new Date().getTime();
-					}
-
-					// Adaptive autosave delay
-					this.autosaveDelay = Math.min(8000,
-						Math.max(this.saveDelay + 500,
-						DriveFile.prototype.autosaveDelay));
-					this.desc = resp;
+					var lastDesc = this.desc;
 					
-					this.fileSaved(savedData, lastDesc, mxUtils.bind(this, function()
-					{
-						this.contentChanged();
-						
-						if (success != null)
-						{
-							success(resp);
-						}
-					}), error);
-				}
-				else
-				{
-					this.setModified(modified || this.isModified());
+					// Makes sure no changes get lost while the file is saved
+					var modified = this.isModified();
+					this.setModified(false);
+					this.savingFile = true;
+		
+					// Waits for success for modified state to be visible
+					var prevModified = this.isModified;
 					
-					if (error != null)
+					this.isModified = function()
 					{
-						error(resp);
-					}
-				}
-			}), mxUtils.bind(this, function(err, desc)
-			{
-				this.savingFile = false;
-				this.isModified = prevModified;
-				this.setModified(modified || this.isModified());
-			
-				if (this.isConflict(err))
-				{
-					this.inConflictState = true;
-					
-					if (this.sync != null)
+						return true;
+					};
+		
+					this.ui.drive.saveFile(this, realRevision, mxUtils.bind(this, function(resp, savedData)
 					{
-						this.savingFile = true;
-						
-						this.sync.fileConflict(desc, mxUtils.bind(this, function()
+						try
+						{
+							this.isModified = prevModified;
+							this.savingFile = false;
+							
+							// Handles special case where resp is false eg
+							// if the old file was converted to realtime
+							if (resp != false)
+							{
+								if (revision)
+								{
+									this.lastAutosaveRevision = new Date().getTime();
+								}
+			
+								// Adaptive autosave delay
+								this.autosaveDelay = Math.min(8000,
+									Math.max(this.saveDelay + 500,
+									DriveFile.prototype.autosaveDelay));
+								this.desc = resp;
+								
+								this.fileSaved(savedData, lastDesc, mxUtils.bind(this, function()
+								{
+									this.contentChanged();
+									
+									if (success != null)
+									{
+										success(resp);
+									}
+								}), error);
+							}
+							else
+							{
+								this.setModified(modified || this.isModified());
+								
+								if (error != null)
+								{
+									error(resp);
+								}
+							}
+						}
+						catch (e)
 						{
-							// Adds random cool-off
-							window.setTimeout(mxUtils.bind(this, function()
+							this.setModified(modified || this.isModified());
+							
+							if (error != null)
+							{
+								error(e);
+							}
+							else
 							{
-								this.updateFileData();
-								doSave(realOverwrite, true);
-							}), 100 + Math.random() * 500);
-						}), mxUtils.bind(this, function()
+								throw e;
+							}
+						}
+					}), mxUtils.bind(this, function(err, desc)
+					{
+						try
 						{
 							this.savingFile = false;
+							this.isModified = prevModified;
+							this.setModified(modified || this.isModified());
+						
+							if (this.isConflict(err))
+							{
+								this.inConflictState = true;
+								
+								if (this.sync != null)
+								{
+									this.savingFile = true;
+									
+									this.sync.fileConflict(desc, mxUtils.bind(this, function()
+									{
+										// Adds random cool-off
+										window.setTimeout(mxUtils.bind(this, function()
+										{
+											this.updateFileData();
+											doSave(realOverwrite, true);
+										}), 100 + Math.random() * 500);
+									}), mxUtils.bind(this, function()
+									{
+										this.savingFile = false;
+										
+										if (error != null)
+										{
+											error();
+										}
+									}));
+								}
+								else if (error != null)
+								{
+									error();
+								}
+							}
+							else if (error != null)
+							{
+								error(err);
+							}
+						}
+						catch (e)
+						{
+							this.setModified(modified || this.isModified());
 							
 							if (error != null)
 							{
-								error();
+								error(e);
 							}
-						}));
+							else
+							{
+								throw e;
+							}
+						}
+					}), unloading, unloading, realOverwrite);
+				}
+				catch (e)
+				{
+					if (error != null)
+					{
+						error(e);
 					}
-					else if (error != null)
+					else
 					{
-						error();
+						throw e;
 					}
 				}
-				else if (error != null)
-				{
-					error(err);
-				}
-			}), unloading, unloading, realOverwrite);
-		});
-		
-		doSave(overwrite, revision);
+			});
+			
+			doSave(overwrite, revision);
+		}
+	}
+	catch (e)
+	{
+		if (error != null)
+		{
+			error(e);
+		}
+		else
+		{
+			throw e;
+		}
 	}
 };
 

+ 76 - 65
src/main/webapp/js/diagramly/EditorUi.js

@@ -488,7 +488,8 @@
 						mxUtils.setPrefixedStyle(status.style, 'boxShadow', '2px 2px 3px 0px #ddd');
 					}
 					
-					if (label.substring(label.length - 3, label.length) != '...')
+					if (label.substring(label.length - 3, label.length) != '...' &&
+						label.charAt(label.length - 1) != '!')
 					{
 						label = label + '...';
 					}
@@ -5696,77 +5697,87 @@
 	 */
 	EditorUi.prototype.getEmbeddedPng = function(success, error, optionalData)
 	{
-		var graph = this.editor.graph;
-		var diagramData = null;
-		
-		// Exports PNG for given optional data
-		if (optionalData != null && optionalData.length > 0)
-		{
-			graph = this.createTemporaryGraph(this.editor.graph.getStylesheet());
-			document.body.appendChild(graph.container);
-			this.decodeNodeIntoGraph(this.editor.extractGraphModel(
-				mxUtils.parseXml(optionalData).documentElement, true), graph);
-			diagramData = optionalData;
-		}
-		// Exports PNG for first page while other page is showing
-		else if (this.pages != null && this.currentPage != this.pages[0])
+		try
 		{
-			graph = this.createTemporaryGraph(graph.getStylesheet());
-			var graphGetGlobalVariable = graph.getGlobalVariable;
-			var page = this.pages[0];
-	
-			graph.getGlobalVariable = function(name)
+			var graph = this.editor.graph;
+			var diagramData = null;
+			
+			// Exports PNG for given optional data
+			if (optionalData != null && optionalData.length > 0)
 			{
-				if (name == 'page')
-				{
-					return page.getName();
-				}
-				else if (name == 'pagenumber')
+				graph = this.createTemporaryGraph(this.editor.graph.getStylesheet());
+				document.body.appendChild(graph.container);
+				this.decodeNodeIntoGraph(this.editor.extractGraphModel(
+					mxUtils.parseXml(optionalData).documentElement, true), graph);
+				diagramData = optionalData;
+			}
+			// Exports PNG for first page while other page is showing
+			else if (this.pages != null && this.currentPage != this.pages[0])
+			{
+				graph = this.createTemporaryGraph(graph.getStylesheet());
+				var graphGetGlobalVariable = graph.getGlobalVariable;
+				var page = this.pages[0];
+		
+				graph.getGlobalVariable = function(name)
 				{
-					return 1;
-				}
-				
-				return graphGetGlobalVariable.apply(this, arguments);
-			};
-	
-			document.body.appendChild(graph.container);
-			graph.model.setRoot(page.root);
-		}
+					if (name == 'page')
+					{
+						return page.getName();
+					}
+					else if (name == 'pagenumber')
+					{
+						return 1;
+					}
+					
+					return graphGetGlobalVariable.apply(this, arguments);
+				};
+		
+				document.body.appendChild(graph.container);
+				graph.model.setRoot(page.root);
+			}
+		
+		   	this.exportToCanvas(mxUtils.bind(this, function(canvas)
+		   	{
+		   		try
+		   		{
+		   			if (diagramData == null)
+		   			{
+		   				diagramData = this.getFileData(true);
+		   			}
+		   			
+		   	   	    var data = canvas.toDataURL('image/png');
+	   	   	   		data = this.writeGraphModelToPng(data, 'zTXt', 'mxGraphModel',
+	   	   	   			atob(Graph.compress(diagramData)));
+	   	   	   		success(data.substring(data.lastIndexOf(',') + 1));
 	
-	   	this.exportToCanvas(mxUtils.bind(this, function(canvas)
-	   	{
-	   		try
-	   		{
-	   			if (diagramData == null)
-	   			{
-	   				diagramData = this.getFileData(true);
-	   			}
-	   			
-	   	   	    var data = canvas.toDataURL('image/png');
-   	   	   		data = this.writeGraphModelToPng(data, 'zTXt', 'mxGraphModel',
-   	   	   			atob(Graph.compress(diagramData)));
-   	   	   		success(data.substring(data.lastIndexOf(',') + 1));
-
-				// Removes temporary graph from DOM
-   	   	   		if (graph != this.editor.graph)
-				{
-					graph.container.parentNode.removeChild(graph.container);
-				}
-	   		}
-	   		catch (e)
-	   		{
-	   			if (error != null)
+					// Removes temporary graph from DOM
+	   	   	   		if (graph != this.editor.graph)
+					{
+						graph.container.parentNode.removeChild(graph.container);
+					}
+		   		}
+		   		catch (e)
+		   		{
+		   			if (error != null)
+		   			{
+		   				error(e);
+		   			}
+		   		}
+		   	}), null, null, null, mxUtils.bind(this, function(e)
+		   	{
+		   		if (error != null)
 	   			{
 	   				error(e);
 	   			}
-	   		}
-	   	}), null, null, null, mxUtils.bind(this, function(e)
-	   	{
-	   		if (error != null)
-   			{
-   				error(e);
-   			}
-	   	}), null, null, null, null, graph.shadowVisible, null, graph);
+		   	}), null, null, null, null, graph.shadowVisible, null, graph);
+		}
+		catch (e)
+		{
+			if (error != null)
+			{
+				error(e);
+			}
+		}
 	}
 	
 	/**

+ 12 - 5
src/main/webapp/js/diagramly/Menus.js

@@ -1883,7 +1883,7 @@
 			
 			if (editorUi.gitHub != null)
 			{
-				menu.addItem(mxResources.get('gh') + '...', null, function()
+				menu.addItem(mxResources.get('github') + '...', null, function()
 				{
 					pickFileFromService(editorUi.gitHub);
 				}, parent);
@@ -2185,11 +2185,18 @@
 
 		this.editorUi.actions.addAction('share...', mxUtils.bind(this, function()
 		{
-			var file = this.editorUi.getCurrentFile();
-			
-			if (file != null)
+			try
+			{
+				var file = editorUi.getCurrentFile();
+				
+				if (file != null)
+				{
+					editorUi.drive.showPermissions(file.getId());
+				}
+			}
+			catch (e)
 			{
-				this.editorUi.drive.showPermissions(file.getId());
+				editorUi.handleError(e);
 			}
 		}));
 

+ 1 - 1
src/main/webapp/js/mxgraph/EditorUi.js

@@ -3701,7 +3701,7 @@ EditorUi.prototype.showDataDialog = function(cell)
 	if (cell != null)
 	{
 		var dlg = new EditDataDialog(this, cell);
-		this.showDialog(dlg.container, 340, 340, true, false, null, false);
+		this.showDialog(dlg.container, 480, 420, true, false, null, false);
 		dlg.init();
 	}
 };

+ 1 - 1
src/main/webapp/js/mxgraph/Format.js

@@ -358,7 +358,7 @@ Format.prototype.refresh = function()
 	label.style.textAlign = 'center';
 	label.style.fontWeight = 'bold';
 	label.style.paddingTop = '8px';
-	label.style.fontSize = '14px';
+	label.style.fontSize = '13px';
 	label.style.borderWidth = '0px 0px 1px 1px';
 	label.style.borderStyle = 'solid';
 	label.style.display = (mxClient.IS_QUIRKS) ? 'inline' : 'inline-block';

+ 1 - 1
src/main/webapp/js/mxgraph/Graph.js

@@ -948,7 +948,7 @@ Graph.zapGremlins = function(text)
 		var code = text.charCodeAt(i);
 		
 		// Removes all control chars except TAB, LF and CR
-		if (code >= 32 || code == 9 || code == 10 || code == 13)
+		if ((code >= 32 || code == 9 || code == 10 || code == 13) && code != 0xFFFF)
 		{
 			checked.push(text.charAt(i));
 		}

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


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

@@ -400,7 +400,7 @@ layers=‫طبقات‬
 landscape=‫طباعة بالعرض‬
 language=‫لغة‬
 leanMapping=Lean Mapping
-lastChange=‫آخر تعديل قبل {1} يوم(ا)
+lastChange=‫آخر تعديل قبل {1}‬
 lessThanAMinute=‫أقل من دقيقة‬
 licensingError=Licensing Error
 licenseHasExpired=The license for {1} has expired on {2}. Click here.