فهرست منبع

10.9.0 release

Gaudenz Alder 6 سال پیش
والد
کامیت
2b8e70de16
36فایلهای تغییر یافته به همراه40838 افزوده شده و 11417 حذف شده
  1. 7 0
      ChangeLog
  2. 1 1
      VERSION
  3. 24 22
      etc/mxgraph/mxClient.js
  4. 1 1
      src/main/webapp/cache.manifest
  5. 481 478
      src/main/webapp/js/app.min.js
  6. 44 50
      src/main/webapp/js/diagramly/App.js
  7. 7 7
      src/main/webapp/js/diagramly/DriveClient.js
  8. 21 7
      src/main/webapp/js/diagramly/DriveFile.js
  9. 93 63
      src/main/webapp/js/diagramly/DropboxFile.js
  10. 56 54
      src/main/webapp/js/diagramly/Editor.js
  11. 18 2
      src/main/webapp/js/diagramly/EditorUi.js
  12. 5 4
      src/main/webapp/js/diagramly/ElectronApp.js
  13. 93 62
      src/main/webapp/js/diagramly/GitHubFile.js
  14. 129 111
      src/main/webapp/js/diagramly/OneDriveClient.js
  15. 114 87
      src/main/webapp/js/diagramly/OneDriveFile.js
  16. 2 1
      src/main/webapp/js/diagramly/sidebar/Sidebar-Rack.js
  17. 14 4
      src/main/webapp/js/mxgraph/Dialogs.js
  18. 7 4
      src/main/webapp/js/mxgraph/Editor.js
  19. 2 2
      src/main/webapp/js/mxgraph/EditorUi.js
  20. 35 12
      src/main/webapp/js/mxgraph/Format.js
  21. 78 0
      src/main/webapp/js/mxgraph/Graph.js
  22. 10 0
      src/main/webapp/js/mxgraph/Menus.js
  23. 6 6
      src/main/webapp/js/mxgraph/Toolbar.js
  24. 1 1
      src/main/webapp/js/shapes.min.js
  25. 8 8
      src/main/webapp/js/stencils.min.js
  26. 399 395
      src/main/webapp/js/viewer.min.js
  27. 10 4
      src/main/webapp/shapes/rack/mxRack.js
  28. 276 116
      src/main/webapp/stencils/rack/apc.xml
  29. 16372 4127
      src/main/webapp/stencils/rack/cisco.xml
  30. 1730 421
      src/main/webapp/stencils/rack/dell.xml
  31. 7464 1927
      src/main/webapp/stencils/rack/f5.xml
  32. 3476 1001
      src/main/webapp/stencils/rack/general.xml
  33. 2056 524
      src/main/webapp/stencils/rack/hp.xml
  34. 2656 604
      src/main/webapp/stencils/rack/ibm.xml
  35. 5139 1311
      src/main/webapp/stencils/rack/oracle.xml
  36. 3 0
      src/main/webapp/styles/grapheditor.css

+ 7 - 0
ChangeLog

@@ -1,3 +1,10 @@
+08-JUL-2019: 10.9.0
+
+- Fixes custom link execution for visibility changes
+- Fixes format panel CSS in Firefox for Linux
+- Fixes inconsistent text editing alignment
+- Uses mxGraph 4.0.2 beta 2
+
 04-JUL-2019: 10.8.9
 
 - Uses mxGraph 4.0.2 beta 1

+ 1 - 1
VERSION

@@ -1 +1 @@
-10.8.9
+10.9.0

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 24 - 22
etc/mxgraph/mxClient.js


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

@@ -1,7 +1,7 @@
 CACHE MANIFEST
 
 # THIS FILE WAS GENERATED. DO NOT MODIFY!
-# 07/04/2019 05:30 PM
+# 07/08/2019 02:53 PM
 
 app.html
 index.html?offline=1

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 481 - 478
src/main/webapp/js/app.min.js


+ 44 - 50
src/main/webapp/js/diagramly/App.js

@@ -23,40 +23,30 @@ App = function(editor, container, lightbox)
 		{
 			var file = this.getCurrentFile();
 			
-			if (file != null && file.constructor == DriveFile && file.isModified() && this.drive != null)
+			if (file != null && file.isModified())
 			{
-				EditorUi.logEvent({category: 'DISCARD-FILE-' + file.getHash() + '.' +
-					file.desc.headRevisionId + '.' + file.desc.modifiedDate + '-size_' + file.getSize(),
-					action: 'open_' + ((file.opened != null) ? Math.round((Date.now() - file.opened.getTime()) / 1000) : 'x') +
-					'-save_' + ((file.lastSaved != null) ?  Math.round((Date.now() - file.lastSaved.getTime()) / 1000) : 'x') +
-					'-change_' + ((file.lastChanged != null) ?  Math.round((Date.now() - file.lastChanged.getTime()) / 1000) : 'x') +
-					((this.editor.autosave) ? '' : '-nosave') +
-					((file.isAutosave()) ? '' : '-noauto') +
-					((file.changeListenerEnabled) ? '' : '-nolisten') +
-					((file.inConflictState) ? '-conflict' : '') +
-					((file.invalidChecksum) ? '-invalid' : '') +
-					((file.savingFile) ? '-saving' : '') +
+				var evt = {category: 'DISCARD-FILE-' + file.getHash(),
+					action: ((file.savingFile) ? 'saving' : '') +
 					((file.savingFile && file.savingFileTime != null) ? '_' +
 						Math.round((Date.now() - file.savingFileTime) / 1000) : '') +
-					((file.autosaveThread != null) ? '-thread' : ''),
-					label: ((this.drive.user != null) ? 'user_' + this.drive.user.id : 'unknown') +
-					((file.sync != null) ? ('-client_' + file.sync.clientId) : '-nosync')});
-			}
-			else if (file != null && file.isModified())
-			{
-				EditorUi.logEvent({category: 'DISCARD-FILE-' + file.getHash() + '-size_' + file.getSize(),
-					action: 'open_' + ((file.opened != null) ? Math.round((Date.now() - file.opened.getTime()) / 1000) : 'x') +
-					'-save_' + ((file.lastSaved != null) ?  Math.round((Date.now() - file.lastSaved.getTime()) / 1000) : 'x') +
-					'-change_' + ((file.lastChanged != null) ?  Math.round((Date.now() - file.lastChanged.getTime()) / 1000) : 'x') +
+					((file.autosaveThread != null) ? '-thread' : '') +
 					((this.editor.autosave) ? '' : '-nosave') +
 					((file.isAutosave()) ? '' : '-noauto') +
 					((file.changeListenerEnabled) ? '' : '-nolisten') +
 					((file.inConflictState) ? '-conflict' : '') +
 					((file.invalidChecksum) ? '-invalid' : '') +
-					((file.savingFile) ? '-saving' : '') +
-					((file.savingFile && file.savingFileTime != null) ? '_' +
-						Math.round((Date.now() - file.savingFileTime) / 1000) : '') +
-					((file.autosaveThread != null) ? '-thread' : '')});
+					'-open_' + ((file.opened != null) ? Math.round((Date.now() - file.opened.getTime()) / 1000) : 'x') +
+					'-save_' + ((file.lastSaved != null) ?  Math.round((Date.now() - file.lastSaved.getTime()) / 1000) : 'x') +
+					'-change_' + ((file.lastChanged != null) ?  Math.round((Date.now() - file.lastChanged.getTime()) / 1000) : 'x'),
+					label: (file.sync != null) ? ('client_' + file.sync.clientId) : 'nosync'};
+					
+				if (file.constructor == DriveFile && file.desc != null && this.drive != null)
+				{
+					evt.label += ((this.drive.user != null) ? '-user_' + this.drive.user.id : '-nouser') + '-rev_' +
+						file.desc.headRevisionId + '-mod_' + file.desc.modifiedDate + '-size_' + file.getSize();
+				}
+
+				EditorUi.logEvent(evt);
 			}
 		});
 	}
@@ -1514,6 +1504,29 @@ App.prototype.sanityCheck = function()
 		(Date.now() - ((file.lastSaved != null) ? file.lastSaved.getTime() :
 		file.opened.getTime())) >= this.warnInterval)
 	{
+		var evt = {category: 'WARN-FILE-' + file.getHash(),
+			action: ((file.savingFile) ? 'saving' : '') +
+			((file.savingFile && file.savingFileTime != null) ? '_' +
+				Math.round((Date.now() - file.savingFileTime) / 1000) : '') +
+			((file.autosaveThread != null) ? '-thread' : '') +
+			((this.editor.autosave) ? '' : '-nosave') +
+			((file.isAutosave()) ? '' : '-noauto') +
+			((file.changeListenerEnabled) ? '' : '-nolisten') +
+			((file.inConflictState) ? '-conflict' : '') +
+			((file.invalidChecksum) ? '-invalid' : '') +
+			'-open_' + ((file.opened != null) ? Math.round((Date.now() - file.opened.getTime()) / 1000) : 'x') +
+			'-save_' + ((file.lastSaved != null) ?  Math.round((Date.now() - file.lastSaved.getTime()) / 1000) : 'x') +
+			'-change_' + ((file.lastChanged != null) ?  Math.round((Date.now() - file.lastChanged.getTime()) / 1000) : 'x'),
+			label: (file.sync != null) ? ('client_' + file.sync.clientId) : 'nosync'};
+			
+		if (file.constructor == DriveFile && file.desc != null && this.drive != null)
+		{
+			evt.label += ((this.drive.user != null) ? '-user_' + this.drive.user.id : '-nouser') + '-rev_' +
+				file.desc.headRevisionId + '-mod_' + file.desc.modifiedDate + '-size_' + file.getSize();
+		}
+			
+		EditorUi.logEvent(evt);
+
 		var msg = mxResources.get('ensureDataSaved');
 		
 		if (file.lastSaved != null)
@@ -1527,21 +1540,7 @@ App.prototype.sanityCheck = function()
 
 			msg = mxResources.get('lastSaved', [str]);
 		}
-		
-		EditorUi.logEvent({category: 'WARN-FILE-' + file.getHash(),
-			action: 'open_' + ((file.opened != null) ? Math.round((Date.now() - file.opened.getTime()) / 1000) : 'x') +
-			'-save_' + ((file.lastSaved != null) ?  Math.round((Date.now() - file.lastSaved.getTime()) / 1000) : 'x') +
-			'-change_' + ((file.lastChanged != null) ?  Math.round((Date.now() - file.lastChanged.getTime()) / 1000) : 'x') +
-			((this.editor.autosave) ? '' : '-nosave') +
-			((file.isAutosave()) ? '' : '-noauto') +
-			((file.changeListenerEnabled) ? '' : '-nolisten') +
-			((file.inConflictState) ? '-conflict' : '') +
-			((file.invalidChecksum) ? '-invalid' : '') +
-			((file.savingFile) ? '-saving' : '') +
-			((file.savingFile && file.savingFileTime != null) ? '_' +
-				Math.round((Date.now() - file.savingFileTime) / 1000) : '') +
-			((file.autosaveThread != null) ? '-thread' : '')});
-		
+
 		this.showError(mxResources.get('unsavedChanges'), msg, mxResources.get('ignore'),
 			mxUtils.bind(this, function()
 			{
@@ -4212,7 +4211,6 @@ App.prototype.loadFile = function(id, sameWindow, file, success, force)
 						this.fileLoaded(file);
 						var currentFile = this.getCurrentFile();
 						
-						// Keeps ID even for converted files in chromeless mode for refresh to work
 						if (currentFile == null)
 						{
 							window.location.hash = '';
@@ -4220,6 +4218,7 @@ App.prototype.loadFile = function(id, sameWindow, file, success, force)
 						}
 						else if (this.editor.chromeless && !this.editor.editable)
 						{
+							// Keeps ID even for converted files in chromeless mode for refresh to work
 							currentFile.getHash = function()
 							{
 								return peerChar + id;
@@ -4227,15 +4226,10 @@ App.prototype.loadFile = function(id, sameWindow, file, success, force)
 							
 							window.location.hash = '#' + currentFile.getHash();
 						}
-						else
-						{
-							window.location.hash = currentFile.getHash();
-						}
-						
-						// Shows a warning if a copy was opened which happens
-						// eg. for .png files in IE as they cannot be written
-						if (file.mode == null)
+						else if (file == currentFile && file.getMode() == null)
 						{
+							// Shows a warning if a copy was opened which happens
+							// eg. for .png files in IE as they cannot be written
 							var status = mxResources.get('browserUnsupportedFiletype');
 							this.editor.setStatus('<div title="'+ status + '" class="geStatusAlert" style="overflow:hidden;">' + status + '</div>');
 						}

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

@@ -1287,7 +1287,8 @@ DriveClient.prototype.saveFile = function(file, revision, success, errFn, noChec
 										null, 'from-' + head0 + '.' + mod0 + '-' + this.ui.hashValue(etag0) +
 										'-to-' + resp.headRevisionId + '.' + resp.modifiedDate + '-' +
 										this.ui.hashValue(resp.etag) + ((temp.length > 0) ? '-errors-' + temp : ''),
-										(this.user != null) ? this.user.id : 'unknown');
+										'user-' + ((this.user != null) ? this.user.id : 'unknown') +
+									 	((file.sync != null) ? '-client_' + file.sync.clientId : '-nosync'));
 								}
 								catch (e)
 								{
@@ -2602,12 +2603,11 @@ DriveClient.prototype.convertRealtimeFiles = function()
 					
 					// Logs conversion
 					EditorUi.logEvent({category: 'AUTO-CONVERT',
-						action: 'total-' + total + '-xml-' + fromXml +
-						'-json-' + fromJson + '-done-' + converted +
-						'-fail-' + failed + '-load-' + loadFail +
-						'-save-' + saveFail + '-invalid-' + invalid +
-						'-dt-' + Math.round(dt / 1000),
-						label: (this.user != null) ? this.user.id : 'unknown-user'});
+						action: 'total_' + total + '-done_' + converted +
+						'-fail_' + '-xml_' + fromXml + '-json_' + fromJson +
+						'-load_' + loadFail + '-save_' + saveFail +
+						'-invalid_' + invalid + '-dt-' + Math.round(dt / 1000),
+						label: (this.user != null) ? 'user_' + this.user.id : '-nouser'});
 				}
 				catch (e)
 				{

+ 21 - 7
src/main/webapp/js/diagramly/DriveFile.js

@@ -160,24 +160,26 @@ DriveFile.prototype.saveFile = function(title, revision, success, error, unloadi
 		{
 			var doSave = mxUtils.bind(this, function(realOverwrite, realRevision)
 			{
+				var prevModified = null;
+				var modified = null;
+				
 				try
 				{
-					var lastDesc = this.desc;
-					
 					// Makes sure no changes get lost while the file is saved
-					var modified = this.isModified();
+					prevModified = this.isModified;
+					modified = this.isModified();
 					this.setModified(false);
-					this.savingFile = true;
 					this.savingFileTime = new Date();
+					this.savingFile = true;
 					
 					// Waits for success for modified state to be visible
-					var prevModified = this.isModified;
-					
 					this.isModified = function()
 					{
 						return true;
 					};
-		
+
+					var lastDesc = this.desc;
+
 					this.ui.drive.saveFile(this, realRevision, mxUtils.bind(this, function(resp, savedData)
 					{
 						try
@@ -295,6 +297,18 @@ DriveFile.prototype.saveFile = function(title, revision, success, error, unloadi
 				}
 				catch (e)
 				{
+					this.savingFile = false;
+					
+					if (prevModified != null)
+					{
+						this.isModified = prevModified;
+					}
+					
+					if (modified != null)
+					{
+						this.setModified(modified || this.isModified());
+					}
+					
 					if (error != null)
 					{
 						error(e);

+ 93 - 63
src/main/webapp/js/diagramly/DropboxFile.js

@@ -159,9 +159,9 @@ DropboxFile.prototype.updateDescriptor = function(newFile)
  * @param {number} dx X-coordinate of the translation.
  * @param {number} dy Y-coordinate of the translation.
  */
-DropboxFile.prototype.save = function(revision, success, error)
+DropboxFile.prototype.save = function(revision, success, error, unloading, overwrite)
 {
-	this.doSave(this.getTitle(), success, error);
+	this.doSave(this.getTitle(), revision, success, error, unloading, overwrite);
 };
 
 /**
@@ -172,7 +172,7 @@ DropboxFile.prototype.save = function(revision, success, error)
  */
 DropboxFile.prototype.saveAs = function(title, success, error)
 {
-	this.doSave(title, success, error);
+	this.doSave(title, false, success, error);
 };
 
 /**
@@ -181,15 +181,17 @@ DropboxFile.prototype.saveAs = function(title, success, error)
  * @param {number} dx X-coordinate of the translation.
  * @param {number} dy Y-coordinate of the translation.
  */
-DropboxFile.prototype.doSave = function(title, success, error)
+DropboxFile.prototype.doSave = function(title, revision, success, error, unloading, overwrite)
 {
 	// Forces update of data for new extensions
 	var prev = this.stat.name;
 	this.stat.name = title;
-	DrawioFile.prototype.save.apply(this, arguments);
-	this.stat.name = prev;
 	
-	this.saveFile(title, false, success, error);
+	DrawioFile.prototype.save.apply(this, [null, mxUtils.bind(this, function()
+	{
+		this.stat.name = prev;
+		this.saveFile(title, revision, success, error, unloading, overwrite);
+	}), error, unloading, overwrite]);
 };
 
 /**
@@ -213,76 +215,104 @@ DropboxFile.prototype.saveFile = function(title, revision, success, error)
 		{
 			if (checked)
 			{
-				this.savingFile = true;
-				this.savingFileTime = new Date();
+				var prevModified = null;
+				var modified = null;
 				
-				// Makes sure no changes get lost while the file is saved
-				var prevModified = this.isModified;
-				var modified = this.isModified();
-
-				var prepare = mxUtils.bind(this, function()
+				try
 				{
-					this.setModified(false);
-					
-					this.isModified = function()
-					{
-						return modified;
-					};
-				});
-				
-				prepare();
-				
-				var doSave = mxUtils.bind(this, function(data)
-				{
-					var index = this.stat.path_display.lastIndexOf('/');
-					var folder = (index > 1) ? this.stat.path_display.substring(1, index + 1) : null;
-					
-					this.ui.dropbox.saveFile(title, data, mxUtils.bind(this, function(stat)
+					// Makes sure no changes get lost while the file is saved
+					prevModified = this.isModified;
+					modified = this.isModified();
+					this.savingFile = true;
+					this.savingFileTime = new Date();
+	
+					var prepare = mxUtils.bind(this, function()
 					{
-						this.savingFile = false;
-						this.isModified = prevModified;
-						this.stat = stat;
-						this.contentChanged();
+						this.setModified(false);
 						
-						if (success != null)
+						this.isModified = function()
 						{
-							success();
-						}
-					}), mxUtils.bind(this, function(err)
+							return modified;
+						};
+					});
+					
+					prepare();
+					
+					var doSave = mxUtils.bind(this, function(data)
 					{
-						this.savingFile = false;
-						this.isModified = prevModified;
-						this.setModified(modified || this.isModified());
+						var index = this.stat.path_display.lastIndexOf('/');
+						var folder = (index > 1) ? this.stat.path_display.substring(1, index + 1) : null;
 						
-						if (error != null)
+						this.ui.dropbox.saveFile(title, data, mxUtils.bind(this, function(stat)
 						{
-							// Handles modified state for retries
-							if (err != null && err.retry != null)
+							this.savingFile = false;
+							this.isModified = prevModified;
+							this.stat = stat;
+							this.contentChanged();
+							
+							if (success != null)
 							{
-								var retry = err.retry;
-								
-								err.retry = function()
-								{
-									prepare();
-									retry();
-								};
+								success();
 							}
+						}), mxUtils.bind(this, function(err)
+						{
+							this.savingFile = false;
+							this.isModified = prevModified;
+							this.setModified(modified || this.isModified());
 							
-							error(err);
-						}
-					}), folder);
-				});
-				
-				if (this.ui.useCanvasForExport && /(\.png)$/i.test(this.getTitle()))
-				{
-					this.ui.getEmbeddedPng(mxUtils.bind(this, function(data)
+							if (error != null)
+							{
+								// Handles modified state for retries
+								if (err != null && err.retry != null)
+								{
+									var retry = err.retry;
+									
+									err.retry = function()
+									{
+										prepare();
+										retry();
+									};
+								}
+								
+								error(err);
+							}
+						}), folder);
+					});
+					
+					if (this.ui.useCanvasForExport && /(\.png)$/i.test(this.getTitle()))
+					{
+						this.ui.getEmbeddedPng(mxUtils.bind(this, function(data)
+						{
+							doSave(this.ui.base64ToBlob(data, 'image/png'));
+						}), error, (this.ui.getCurrentFile() != this) ? this.getData() : null);
+					}
+					else
 					{
-						doSave(this.ui.base64ToBlob(data, 'image/png'));
-					}), error, (this.ui.getCurrentFile() != this) ? this.getData() : null);
+						doSave(this.getData());
+					}
 				}
-				else
+				catch (e)
 				{
-					doSave(this.getData());
+					this.savingFile = false;
+					
+					if (prevModified != null)
+					{
+						this.isModified = prevModified;
+					}
+					
+					if (modified != null)
+					{
+						this.setModified(modified || this.isModified());
+					}
+					
+					if (error != null)
+					{
+						error(e);
+					}
+					else
+					{
+						throw e;
+					}
 				}
 			}
 			else if (error != null)

+ 56 - 54
src/main/webapp/js/diagramly/Editor.js

@@ -3713,88 +3713,90 @@
 		if (href.substring(0, 17) == 'data:action/json,')
 		{
 			// Some actions are stateless and must be handled before the transaction
-			var action = JSON.parse(href.substring(17));
+			var link = JSON.parse(href.substring(17));
 
-			if (action.actions != null)
+			if (link.actions != null)
 			{
 				// Executes open actions before starting transaction
-				for (var i = 0; i < action.actions.length; i++)
+				for (var i = 0; i < link.actions.length; i++)
 				{
-					if (action.actions[i].open != null)
+					var action = link.actions[i];
+					
+					if (action.open != null)
 					{
-						if (this.isCustomLink(action.actions[i].open))
+						if (this.isCustomLink(action.open))
 						{
-							if (!this.customLinkClicked(action.actions[i].open))
+							if (!this.customLinkClicked(action.open))
 							{
 								return;
 							}
 						}
 						else
 						{
-							this.openLink(action.actions[i].open);
+							this.openLink(action.open);
 						}
 					}
 				}
 
+				// Executes all actions that change cell states
 	    		this.model.beginUpdate();
 	    		try
 	    		{
-					for (var i = 0; i < action.actions.length; i++)
+					for (var i = 0; i < link.actions.length; i++)
 					{
-						this.handleLinkAction(action.actions[i]);
+						var action = link.actions[i];
+						
+						if (action.toggle != null)
+						{
+							this.toggleCells(this.getCellsForAction(action.toggle, true));
+						}
+						
+						if (action.show != null)
+						{
+							this.setCellsVisible(this.getCellsForAction(action.show, true), true);
+						}
+						
+						if (action.hide != null)
+						{
+							this.setCellsVisible(this.getCellsForAction(action.hide, true), false);
+						}
 					}
 				}
 	    		finally
 	    		{
 	    			this.model.endUpdate();
 	    		}
-			}
-		}
-	};
-
-	/**
-	 * Executes the given action if it must be executed inside of a transaction.
-	 */
-	Graph.prototype.handleLinkAction = function(action)
-	{
-		var cells = [];
-		
-		if (action.select != null && this.isEnabled())
-		{
-			cells = this.getCellsForAction(action.select);
-			this.setSelectionCells(cells);
-		}
-
-		if (action.highlight != null)
-		{
-			cells = this.getCellsForAction(action.highlight);
-			this.highlightCells(cells, action.highlight.color,
-				action.highlight.duration, action.highlight.opacity);
-		}
+	    		
+				// Executes stateless actions on cells
+				for (var i = 0; i < link.actions.length; i++)
+				{
+					var action = link.actions[i];
+					var cells = [];
+					
+					if (action.select != null && this.isEnabled())
+					{
+						cells = this.getCellsForAction(action.select);
+						this.setSelectionCells(cells);
+					}
 
-		if (action.toggle != null)
-		{
-			this.toggleCells(this.getCellsForAction(action.toggle, true));
-		}
-		
-		if (action.show != null)
-		{
-			this.setCellsVisible(this.getCellsForAction(action.show, true), true);
-		}
-		
-		if (action.hide != null)
-		{
-			this.setCellsVisible(this.getCellsForAction(action.hide, true), false);
-		}
+					if (action.highlight != null)
+					{
+						cells = this.getCellsForAction(action.highlight);
+						this.highlightCells(cells, action.highlight.color,
+							action.highlight.duration, action.highlight.opacity);
+					}
 
-		if (action.scroll != null)
-		{
-			cells = this.getCellsForAction(action.scroll);
-		}
-		
-		if (cells.length > 0)
-		{
-			this.scrollCellToVisible(cells[0]);
+					if (action.scroll != null)
+					{
+						cells = this.getCellsForAction(action.scroll);
+					}
+					
+					if (cells.length > 0)
+					{
+						this.scrollCellToVisible(cells[0]);
+					}
+				}
+			}
 		}
 	};
 

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

@@ -5321,7 +5321,7 @@
 			mxUtils.br(div);
 			height += 26;
 		}
-		
+
 		var dlg = new CustomDialog(this, div, mxUtils.bind(this, function()
 		{
 			this.lastExportBorder = borderInput.value;
@@ -5331,7 +5331,7 @@
 				include.checked, cb5.checked, borderInput.value, cb6.checked, !allPages.checked,
 				linkSelect.value);
 		}), null, btnLabel, helpLink);
-		this.showDialog(dlg.container, 340, height, true, true);
+		this.showDialog(dlg.container, 340, height, true, true, null, null, null, null, true);
 		zoomInput.focus();
 		
 		if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5 || mxClient.IS_QUIRKS)
@@ -11856,6 +11856,22 @@
 		// do nothing
 	};
 	
+	/**
+	 * Hook for subclassers
+	 */
+	EditorUi.prototype.scheduleSanityCheck = function()
+	{
+		// do nothing
+	};
+	
+	/**
+	 * Hook for subclassers
+	 */
+	EditorUi.prototype.stopSanityCheck = function()
+	{
+		// do nothing
+	};
+
 	/**
 	 * Returns true if a diagram is cative and editable.
 	 */

+ 5 - 4
src/main/webapp/js/diagramly/ElectronApp.js

@@ -823,12 +823,13 @@ mxStencilRegistry.allowEval = false;
 	
 	// Restores default implementation of open with autosave
 	LocalFile.prototype.open = DrawioFile.prototype.open;
-
+	
 	LocalFile.prototype.save = function(revision, success, error, unloading, overwrite)
 	{
-		DrawioFile.prototype.save.apply(this, arguments);
-		
-		this.saveFile(revision, success, error, unloading, overwrite);
+		DrawioFile.prototype.save.apply(this, [revision, mxUtils.bind(this, function()
+		{
+			this.saveFile(null, revision, success, error, unloading, overwrite);
+		}), error, unloading, overwrite]);
 	};
 
 	LocalFile.prototype.isConflict = function(stat)

+ 93 - 62
src/main/webapp/js/diagramly/GitHubFile.js

@@ -181,10 +181,12 @@ GitHubFile.prototype.doSave = function(title, success, error, unloading, overwri
 	// Forces update of data for new extensions
 	var prev = this.meta.name;
 	this.meta.name = title;
-	DrawioFile.prototype.save.apply(this, arguments);
-	this.meta.name = prev;
 	
-	this.saveFile(title, false, success, error, unloading, overwrite, message);
+	DrawioFile.prototype.save.apply(this, [null, mxUtils.bind(this, function()
+	{
+		this.meta.name = prev;
+		this.saveFile(title, false, success, error, unloading, overwrite, message);
+	}), error, unloading, overwrite]);
 };
 
 /**
@@ -208,80 +210,109 @@ GitHubFile.prototype.saveFile = function(title, revision, success, error, unload
 		{
 			if (this.getTitle() == title)
 			{
-				var savedEtag = this.getCurrentEtag();
-				var savedData = this.data;
-
-				// Makes sure no changes get lost while the file is saved
-				var prevModified = this.isModified;
-				var modified = this.isModified();
-				this.savingFile = true;
-				this.savingFileTime = new Date();
-					
-				var prepare = mxUtils.bind(this, function()
-				{
-					this.setModified(false);
-					
-					this.isModified = function()
-					{
-						return modified;
-					};
-				});
-				
-				prepare();
+				var prevModified = null;
+				var modified = null;
 				
-				this.ui.gitHub.saveFile(this, mxUtils.bind(this, function(commit)
+				try
 				{
-					this.isModified = prevModified;
-					this.savingFile = false;
-					
-					this.meta.sha = commit.content.sha;
-					this.meta.html_url = commit.content.html_url;
-					this.meta.download_url = commit.content.download_url;
-
-					this.fileSaved(savedData, savedEtag, mxUtils.bind(this, function()
+					// Makes sure no changes get lost while the file is saved
+					prevModified = this.isModified;
+					modified = this.isModified();
+					this.savingFile = true;
+					this.savingFileTime = new Date();
+						
+					// Makes sure no changes get lost while the file is saved
+					var prepare = mxUtils.bind(this, function()
 					{
-						this.contentChanged();
+						this.setModified(false);
 						
-						if (success != null)
+						this.isModified = function()
 						{
-							success();
-						}
-					}), error);
-				}),
-				mxUtils.bind(this, function(err)
-				{
-					this.savingFile = false;
-					this.isModified = prevModified;
-					this.setModified(modified || this.isModified());
+							return modified;
+						};
+					});
+					
+					var savedEtag = this.getCurrentEtag();
+					var savedData = this.data;
+					prepare();
 
-					if (this.isConflict(err))
+					this.ui.gitHub.saveFile(this, mxUtils.bind(this, function(commit)
 					{
-						this.inConflictState = true;
+						this.isModified = prevModified;
+						this.savingFile = false;
 						
-						if (error != null)
+						this.meta.sha = commit.content.sha;
+						this.meta.html_url = commit.content.html_url;
+						this.meta.download_url = commit.content.download_url;
+	
+						this.fileSaved(savedData, savedEtag, mxUtils.bind(this, function()
 						{
-							// Passes current commit message to avoid
-							// multiple dialogs after synchronize
-							error({commitMessage: message});
-						}
-					}
-					else if (error != null)
+							this.contentChanged();
+							
+							if (success != null)
+							{
+								success();
+							}
+						}), error);
+					}),
+					mxUtils.bind(this, function(err)
 					{
-						// Handles modified state for retries
-						if (err != null && err.retry != null)
+						this.savingFile = false;
+						this.isModified = prevModified;
+						this.setModified(modified || this.isModified());
+	
+						if (this.isConflict(err))
 						{
-							var retry = err.retry;
+							this.inConflictState = true;
 							
-							err.retry = function()
+							if (error != null)
 							{
-								prepare();
-								retry();
-							};
+								// Passes current commit message to avoid
+								// multiple dialogs after synchronize
+								error({commitMessage: message});
+							}
 						}
-						
-						error(err);
+						else if (error != null)
+						{
+							// Handles modified state for retries
+							if (err != null && err.retry != null)
+							{
+								var retry = err.retry;
+								
+								err.retry = function()
+								{
+									prepare();
+									retry();
+								};
+							}
+							
+							error(err);
+						}
+					}), overwrite, message);
+				}
+				catch (e)
+				{
+					this.savingFile = false;
+					
+					if (prevModified != null)
+					{
+						this.isModified = prevModified;
+					}
+					
+					if (modified != null)
+					{
+						this.setModified(modified || this.isModified());
+					}
+					
+					if (error != null)
+					{
+						error(e);
+					}
+					else
+					{
+						throw e;
 					}
-				}), overwrite, message);
+				}
 			}
 			else
 			{

+ 129 - 111
src/main/webapp/js/diagramly/OneDriveClient.js

@@ -809,51 +809,55 @@ OneDriveClient.prototype.saveFile = function(file, success, error, etag)
 
 		this.writeFile(url + '/content/', data, 'PUT', null, mxUtils.bind(this, function(resp)
 		{
-			// Workaround for truncated files in OneDrive is to check if file size is correct
-			try
-			{
-				// Returns string length in bytes instead of chars to check returned file size
-				function byteCount(str)
-				{
-					try
-					{
-						return new Blob([str]).size
-					}
-					catch (e)
-					{
-						// ignore
-					}
-					
-					return null;
-				};
-				
-				if (typeof window.Blob !== 'undefined')
-				{
-					var exp = (typeof data === 'string') ? byteCount(data) : data.size;
-					
-					if (resp != null && exp != null && resp.size != exp)
-					{
-						// Logs failed save
-						var user = this.getUser();
-						
-						EditorUi.sendReport('Critical: Truncated OneDrive File ' +
-							new Date().toISOString() + ':' + '\n\nBrowser=' + navigator.userAgent +
-							'\nFile=' + file.getId() + '\nMime=' + file.meta.file.mimeType +
-							'\nUser=' + ((user != null) ? user.id : 'unknown') +
-							 	'.' + ((file.sync != null) ? file.sync.clientId : 'nosync') +
-							'\nExpected=' + exp + ' Actual=' + resp.size)
-						EditorUi.logError('Critical: Truncated OneDrive File ' + file.getId(),
-							null, 'expected_' + exp + '-actual_' + resp.size +
-							'-mime_' + file.meta.file.mimeType,
-							((user != null) ? user.id : 'unknown') + '.' +
-							((file.sync != null) ? file.sync.clientId : 'nosync'));
-					}
-				}
-			}
-			catch (e)
-			{
-				// ignore
-			}
+			// Checks for truncated files in OneDrive by comparing expected and actual file size
+			// Apparently in some cases the file is not truncated but the expected and actual
+			// file size do still defer and cases with truncated files have not been detected
+			// ie. there were no cases where the file size was significantly off.
+//			try
+//			{
+//				if (typeof window.Blob !== 'undefined')
+//				{
+//
+//					// Returns string length in bytes instead of chars to check returned file size
+//					function byteCount(str)
+//					{
+//						try
+//						{
+//							return new Blob([str]).size
+//						}
+//						catch (e)
+//						{
+//							// ignore
+//						}
+//						
+//						return null;
+//					};
+//					
+//					var exp = (typeof data === 'string') ? byteCount(data) : data.size;
+//					
+//					if (resp != null && exp != null && resp.size != exp)
+//					{
+//						// Logs failed save
+//						var user = this.getUser();
+//						
+//						EditorUi.sendReport('Critical: Truncated OneDrive File ' +
+//							new Date().toISOString() + ':' + '\n\nBrowser=' + navigator.userAgent +
+//							'\nFile=' + file.getId() + '\nMime=' + file.meta.file.mimeType +
+//							'\nUser=' + ((user != null) ? user.id : 'unknown') +
+//							 	'-client_' + ((file.sync != null) ? file.sync.clientId : 'nosync') +
+//							'\nExpected=' + exp + ' Actual=' + resp.size)
+//						EditorUi.logError('Critical: Truncated OneDrive File ' + file.getId(),
+//							null, 'expected_' + exp + '-actual_' + resp.size +
+//							'-mime_' + file.meta.file.mimeType,
+//							'user-' + ((user != null) ? user.id : 'unknown') +
+//						 	((file.sync != null) ? '-client_' + file.sync.clientId : '-nosync'));
+//					}
+//				}
+//			}
+//			catch (e)
+//			{
+//				// ignore
+//			}
 			
 			success(resp, savedData);
 		}), error, etag);
@@ -880,89 +884,103 @@ OneDriveClient.prototype.saveFile = function(file, success, error, etag)
  */
 OneDriveClient.prototype.writeFile = function(url, data, method, contentType, success, error, etag)
 {
-	if (url != null && data != null)
+	try
 	{
-		var doExecute = mxUtils.bind(this, function(failOnAuth)
+		if (url != null && data != null)
 		{
-			var acceptResponse = true;
-			
-			var timeoutThread = window.setTimeout(mxUtils.bind(this, function()
+			var doExecute = mxUtils.bind(this, function(failOnAuth)
 			{
-				acceptResponse = false;
-				error({code: App.ERROR_TIMEOUT, retry: doExecute});
-			}), this.ui.timeout);
-
-			var req = new mxXmlRequest(url, data, method);
-			
-			req.setRequestHeaders = mxUtils.bind(this, function(request, params)
-			{
-				// Space deletes content type header. Specification says "text/plain"
-				// should work but returns an 415 Unsupported Media Type error
-				request.setRequestHeader('Content-Type', contentType || ' ');
-				//TODO This header is needed for moving a file between two different drives. 
-				//		Note: the response is empty when this header is used, also the server may take some time to really execute the request (i.e. async) 
-				//request.setRequestHeader('Prefer', 'respond-async');
-				request.setRequestHeader('Authorization', 'Bearer ' + this.token);
-				
-				if (etag != null)
+				try
 				{
-					request.setRequestHeader('If-Match', etag);
-				}
-			});
-			
-			req.send(mxUtils.bind(this, function(req)
-			{
-		    	window.clearTimeout(timeoutThread);
-		    	
-		    	if (acceptResponse)
-		    	{
-			    	if (req.getStatus() >= 200 && req.getStatus() <= 299)
+					var acceptResponse = true;
+					
+					var timeoutThread = window.setTimeout(mxUtils.bind(this, function()
+					{
+						acceptResponse = false;
+						error({code: App.ERROR_TIMEOUT, retry: doExecute});
+					}), this.ui.timeout);
+		
+					var req = new mxXmlRequest(url, data, method);
+					
+					req.setRequestHeaders = mxUtils.bind(this, function(request, params)
 					{
-			    		if (this.user == null)
+						// Space deletes content type header. Specification says "text/plain"
+						// should work but returns an 415 Unsupported Media Type error
+						request.setRequestHeader('Content-Type', contentType || ' ');
+						//TODO This header is needed for moving a file between two different drives. 
+						//		Note: the response is empty when this header is used, also the server may take some time to really execute the request (i.e. async) 
+						//request.setRequestHeader('Prefer', 'respond-async');
+						request.setRequestHeader('Authorization', 'Bearer ' + this.token);
+						
+						if (etag != null)
 						{
-							this.updateUser(this.emptyFn, this.emptyFn, true);
+							request.setRequestHeader('If-Match', etag);
 						}
-			    		
-						success(JSON.parse(req.getText()));
-					}
-					else if (!failOnAuth && req.getStatus() === 401)
+					});
+					
+					req.send(mxUtils.bind(this, function(req)
 					{
-						this.authenticate(function()
-						{
-							doExecute(true);
-						}, error, failOnAuth);
-					}
-					else
+				    	window.clearTimeout(timeoutThread);
+				    	
+				    	if (acceptResponse)
+				    	{
+					    	if (req.getStatus() >= 200 && req.getStatus() <= 299)
+							{
+					    		if (this.user == null)
+								{
+									this.updateUser(this.emptyFn, this.emptyFn, true);
+								}
+					    		
+								success(JSON.parse(req.getText()));
+							}
+							else if (!failOnAuth && req.getStatus() === 401)
+							{
+								this.authenticate(function()
+								{
+									doExecute(true);
+								}, error, failOnAuth);
+							}
+							else
+							{
+								error(this.parseRequestText(req), req);
+							}
+				    	}
+					}), mxUtils.bind(this, function(req)
 					{
-						error(this.parseRequestText(req), req);
-					}
-		    	}
-			}), mxUtils.bind(this, function(req)
+				    	window.clearTimeout(timeoutThread);
+				    	
+				    	if (acceptResponse)
+				    	{
+							error(this.parseRequestText(req));
+				    	}
+					}));
+				}
+				catch (e)
+				{
+					error(e);
+				}
+			});
+			
+			if (this.token == null || this.tokenExpiresOn - Date.now() < 60000) //60 sec tolerance window
 			{
-		    	window.clearTimeout(timeoutThread);
-		    	
-		    	if (acceptResponse)
-		    	{
-					error(this.parseRequestText(req));
-		    	}
-			}));
-		});
-		
-		if (this.token == null || this.tokenExpiresOn - Date.now() < 60000) //60 sec tolerance window
-		{
-			this.authenticate(function()
+				this.authenticate(function()
+				{
+					doExecute(true);
+				}, error);
+			}
+			else
 			{
-				doExecute(true);
-			}, error);
+				doExecute(false);
+			}
 		}
 		else
 		{
-			doExecute(false);
+			error({message: mxResources.get('unknownError')});
 		}
 	}
-	else
+	catch (e)
 	{
-		error({message: mxResources.get('unknownError')});
+		error(e);
 	}
 };
 

+ 114 - 87
src/main/webapp/js/diagramly/OneDriveFile.js

@@ -263,10 +263,7 @@ OneDriveFile.prototype.getLastModifiedDate = function()
  */
 OneDriveFile.prototype.save = function(revision, success, error, unloading, overwrite)
 {
-	DrawioFile.prototype.save.apply(this, [revision, mxUtils.bind(this, function()
-	{
-		this.saveFile(this.getTitle(), false, success, error, unloading, overwrite);
-	}), error, unloading, overwrite]);
+	this.doSave(this.getTitle(), revision, success, error, unloading, overwrite);
 };
 
 /**
@@ -277,13 +274,7 @@ OneDriveFile.prototype.save = function(revision, success, error, unloading, over
  */
 OneDriveFile.prototype.saveAs = function(title, success, error)
 {
-	// Forces update of data for new extension
-	var prev = this.meta.name;
-	this.meta.name = title;
-	DrawioFile.prototype.save.apply(this, arguments);
-	this.meta.name = prev;
-	
-	this.saveFile(title, false, success, error);
+	this.doSave(title, false, success, error);
 };
 
 /**
@@ -292,9 +283,17 @@ OneDriveFile.prototype.saveAs = function(title, success, error)
  * @param {number} dx X-coordinate of the translation.
  * @param {number} dy Y-coordinate of the translation.
  */
-OneDriveFile.prototype.doSave = function(title, success, error, unloading, overwrite)
+OneDriveFile.prototype.doSave = function(title, revision, success, error, unloading, overwrite)
 {
-	this.saveFile(title, false, success, error, unloading, overwrite);
+	// Forces update of data for new extensions
+	var prev = this.meta.name;
+	this.meta.name = title;
+	
+	DrawioFile.prototype.save.apply(this, [null, mxUtils.bind(this, function()
+	{
+		this.meta.name = prev;
+		this.saveFile(title, revision, success, error, unloading, overwrite);
+	}), error, unloading, overwrite]);
 };
 
 /**
@@ -318,100 +317,128 @@ OneDriveFile.prototype.saveFile = function(title, revision, success, error, unlo
 		{
 			var doSave = mxUtils.bind(this, function()
 			{
-				var etag = (!overwrite && this.constructor == OneDriveFile &&
-						(DrawioFile.SYNC == 'manual' || DrawioFile.SYNC == 'auto')) ?
-						this.getCurrentEtag() : null;
-				var lastDesc = this.meta;
+				var prevModified = null;
+				var modified = null;
 				
-				// Makes sure no changes get lost while the file is saved
-				var prevModified = this.isModified;
-				var modified = this.isModified();
-				this.savingFile = true;
-				this.savingFileTime = new Date();
-				
-				var prepare = mxUtils.bind(this, function()
+				try
 				{
-					this.setModified(false);
+					// Makes sure no changes get lost while the file is saved
+					prevModified = this.isModified;
+					modified = this.isModified();
+					this.savingFile = true;
+					this.savingFileTime = new Date();
 					
-					this.isModified = function()
-					{
-						return modified;
-					};
-				});
-				
-				prepare();
-				
-				this.ui.oneDrive.saveFile(this, mxUtils.bind(this, function(meta, savedData)
-				{
-					this.isModified = prevModified;
-					this.savingFile = false;
-					this.meta = meta;
-
-					this.fileSaved(savedData, lastDesc, mxUtils.bind(this, function()
+					var prepare = mxUtils.bind(this, function()
 					{
-						this.contentChanged();
+						this.setModified(false);
 						
-						if (success != null)
+						this.isModified = function()
 						{
-							success();
-						}
-					}), error);
-				}),
-				mxUtils.bind(this, function(err, req)
-				{
-					this.savingFile = false;
-					this.isModified = prevModified;
-					this.setModified(modified || this.isModified());
+							return modified;
+						};
+					});
+						
+					var etag = (!overwrite && this.constructor == OneDriveFile &&
+							(DrawioFile.SYNC == 'manual' || DrawioFile.SYNC == 'auto')) ?
+							this.getCurrentEtag() : null;
+					var lastDesc = this.meta;
+					prepare();
 					
-					if (this.isConflict(req))
-			    	{
-						this.inConflictState = true;
-
-						if (this.sync != null)
+					this.ui.oneDrive.saveFile(this, mxUtils.bind(this, function(meta, savedData)
+					{
+						this.isModified = prevModified;
+						this.savingFile = false;
+						this.meta = meta;
+	
+						this.fileSaved(savedData, lastDesc, mxUtils.bind(this, function()
 						{
-							this.savingFile = true;
-							this.savingFileTime = new Date();
+							this.contentChanged();
 							
-							this.sync.fileConflict(null, mxUtils.bind(this, function()
+							if (success != null)
 							{
-								// Adds random cool-off
-								window.setTimeout(mxUtils.bind(this, function()
-								{
-									this.updateFileData();
-									doSave();
-								}), 100 + Math.random() * 500);
-							}), mxUtils.bind(this, function()
+								success();
+							}
+						}), error);
+					}),
+					mxUtils.bind(this, function(err, req)
+					{
+						this.savingFile = false;
+						this.isModified = prevModified;
+						this.setModified(modified || this.isModified());
+						
+						if (this.isConflict(req))
+				    	{
+							this.inConflictState = true;
+	
+							if (this.sync != null)
 							{
-								this.savingFile = false;
+								this.savingFile = true;
+								this.savingFileTime = new Date();
 								
-								if (error != null)
+								this.sync.fileConflict(null, mxUtils.bind(this, function()
 								{
-									error();
-								}
-							}));
+									// Adds random cool-off
+									window.setTimeout(mxUtils.bind(this, function()
+									{
+										this.updateFileData();
+										doSave();
+									}), 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();
+							// Handles modified state for retries
+							if (err != null && err.retry != null)
+							{
+								var retry = err.retry;
+								
+								err.retry = function()
+								{
+									prepare();
+									retry();
+								};
+							}
+							
+							error(err);
 						}
+					}), etag);
+				}
+				catch (e)
+				{
+					this.savingFile = false;
+					
+					if (prevModified != null)
+					{
+						this.isModified = prevModified;
 					}
-					else if (error != null)
+					
+					if (modified != null)
 					{
-						// Handles modified state for retries
-						if (err != null && err.retry != null)
-						{
-							var retry = err.retry;
-							
-							err.retry = function()
-							{
-								prepare();
-								retry();
-							};
-						}
-						
-						error(err);
+						this.setModified(modified || this.isModified());
 					}
-				}), etag);
+					
+					if (error != null)
+					{
+						error(e);
+					}
+					else
+					{
+						throw e;
+					}
+				}
 			});
 			
 			doSave();

+ 2 - 1
src/main/webapp/js/diagramly/sidebar/Sidebar-Rack.js

@@ -5,6 +5,7 @@
 	{
 		var s = 'strokeColor=#666666;html=1;verticalLabelPosition=bottom;labelBackgroundColor=#ffffff;verticalAlign=top;outlineConnect=0;shadow=0;dashed=0;';
 		var sr = 'strokeColor=#666666;html=1;labelPosition=right;align=left;spacingLeft=15;shadow=0;dashed=0;fillColor=#ffffff;outlineConnect=0;';
+		var sr2 = 'strokeColor=#666666;html=1;labelPosition=right;align=left;spacingLeft=15;shadow=0;dashed=0;outlineConnect=0;';
 		
 		//default tags
 		var dt = 'rack equipment ';
@@ -16,7 +17,7 @@
 			this.createVertexTemplateEntry(s + 'shape=mxgraph.rackGeneral.container;container=1;collapsible=0;childLayout=rack;allowGaps=1;marginLeft=9;marginRight=9;marginTop=21;marginBottom=22;textColor=#666666;numDisp=off;', 180, 228.6, '', 'Rack Cabinet', null, null, dt + 'cabinet'),
 			this.createVertexTemplateEntry(s + 'shape=mxgraph.rackGeneral.container;container=1;collapsible=0;childLayout=rack;allowGaps=1;marginLeft=33;marginRight=9;marginTop=21;marginBottom=22;textColor=#666666;numDisp=ascend;', 210, 228.6, '', 'Numbered Rack Cabinet', null, null, dt + 'cabinet numbered'),
 			this.createVertexTemplateEntry(sr + 'text;', 160, 15, '', 'Spacing', null, null, dt + 'spacing'),
-			this.createVertexTemplateEntry(sr + 'shape=mxgraph.rackGeneral.plate;fillColor=#e8e8e8;', 160, 15, '', 'Cover Plate', null, null, dt + 'cover plate'),
+			this.createVertexTemplateEntry(sr2 + 'shape=mxgraph.rackGeneral.plate;fillColor=#e8e8e8;', 160, 15, '', 'Cover Plate', null, null, dt + 'cover plate'),
 			this.createVertexTemplateEntry(sr + 'shape=mxgraph.rack.general.1u_rack_server;', 160, 15, '', 'Server', null, null, dt + 'server'),
 			this.createVertexTemplateEntry(sr + 'shape=mxgraph.rackGeneral.horCableDuct;', 160, 15, '', 'Horizontal Cable Duct', null, null, dt + 'horizontal cable duct'),
 			this.createVertexTemplateEntry(sr + 'shape=mxgraph.rackGeneral.horRoutingBank;', 160, 20, '', 'Horizontal Routing Bank', null, null, dt + 'horizontal routing bank'),

+ 14 - 4
src/main/webapp/js/mxgraph/Dialogs.js

@@ -1409,7 +1409,6 @@ var EditDataDialog = function(ui, cell)
 	var id = (EditDataDialog.getDisplayIdForCell != null) ?
 		EditDataDialog.getDisplayIdForCell(ui, cell) : null;
 	
-	// FIXME: Fix remove button for quirks mode
 	var addRemoveButton = function(text, name)
 	{
 		var wrapper = document.createElement('div');
@@ -1526,15 +1525,20 @@ var EditDataDialog = function(ui, cell)
 	top.appendChild(form.table);
 
 	var newProp = document.createElement('div');
+	newProp.style.boxSizing = 'border-box';
+	newProp.style.paddingRight = '160px';
 	newProp.style.whiteSpace = 'nowrap';
 	newProp.style.marginTop = '6px';
-
+	newProp.style.width = '100%';
+	
 	var nameInput = document.createElement('input');
 	nameInput.setAttribute('placeholder', mxResources.get('enterPropertyName'));
 	nameInput.setAttribute('type', 'text');
 	nameInput.setAttribute('size', (mxClient.IS_IE || mxClient.IS_IE11) ? '36' : '40');
+	nameInput.style.boxSizing = 'border-box';
 	nameInput.style.marginLeft = '2px';
-
+	nameInput.style.width = '100%';
+	
 	newProp.appendChild(nameInput);
 	top.appendChild(newProp);
 	div.appendChild(top);
@@ -1575,6 +1579,7 @@ var EditDataDialog = function(ui, cell)
 					text.focus();
 				}
 
+				addBtn.setAttribute('disabled', 'disabled');
 				nameInput.value = '';
 			}
 			catch (e)
@@ -1600,9 +1605,14 @@ var EditDataDialog = function(ui, cell)
 		}
 	};
 	
+	addBtn.setAttribute('title', mxResources.get('addProperty'));
 	addBtn.setAttribute('disabled', 'disabled');
-	addBtn.style.marginLeft = '10px';
+	addBtn.style.textOverflow = 'ellipsis';
+	addBtn.style.position = 'absolute';
+	addBtn.style.overflow = 'hidden';
 	addBtn.style.width = '144px';
+	addBtn.style.right = '0px';
+	addBtn.className = 'geBtn';
 	newProp.appendChild(addBtn);
 
 	var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()

+ 7 - 4
src/main/webapp/js/mxgraph/Editor.js

@@ -745,7 +745,7 @@ OpenFile.prototype.cancel = function(cancel)
 /**
  * Basic dialogs that are available in the viewer (print dialog).
  */
-function Dialog(editorUi, elt, w, h, modal, closable, onClose, noScroll, transparent, onResize)
+function Dialog(editorUi, elt, w, h, modal, closable, onClose, noScroll, transparent, onResize, ignoreBgClick)
 {
 	var dx = 0;
 	
@@ -850,10 +850,13 @@ function Dialog(editorUi, elt, w, h, modal, closable, onClose, noScroll, transpa
 		document.body.appendChild(img);
 		this.dialogImg = img;
 		
-		mxEvent.addGestureListeners(this.bg, null, null, mxUtils.bind(this, function(evt)
+		if (!ignoreBgClick)
 		{
-			editorUi.hideDialog(true);
-		}));
+			mxEvent.addGestureListeners(this.bg, null, null, mxUtils.bind(this, function(evt)
+			{
+				editorUi.hideDialog(true);
+			}));
+		}
 	}
 	
 	this.resizeListener = mxUtils.bind(this, function()

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

@@ -3401,7 +3401,7 @@ EditorUi.prototype.showError = function(title, msg, btn, fn, retry, btn2, fn2, b
 /**
  * Displays a print dialog.
  */
-EditorUi.prototype.showDialog = function(elt, w, h, modal, closable, onClose, noScroll, trasparent, onResize)
+EditorUi.prototype.showDialog = function(elt, w, h, modal, closable, onClose, noScroll, trasparent, onResize, ignoreBgClick)
 {
 	this.editor.graph.tooltipHandler.hideTooltip();
 	
@@ -3410,7 +3410,7 @@ EditorUi.prototype.showDialog = function(elt, w, h, modal, closable, onClose, no
 		this.dialogs = [];
 	}
 	
-	this.dialog = new Dialog(this, elt, w, h, modal, closable, onClose, noScroll, trasparent, onResize);
+	this.dialog = new Dialog(this, elt, w, h, modal, closable, onClose, noScroll, trasparent, onResize, ignoreBgClick);
 	this.dialogs.push(this.dialog);
 };
 

+ 35 - 12
src/main/webapp/js/mxgraph/Format.js

@@ -2558,21 +2558,21 @@ TextFormatPanel.prototype.addFont = function(container)
 	
 	var left = this.editorUi.toolbar.addButton('geSprite-left', mxResources.get('left'),
 		(graph.cellEditor.isContentEditing()) ?
-		function()
+		function(evt)
 		{
-			document.execCommand('justifyleft', false, null);
+			graph.cellEditor.alignText(mxConstants.ALIGN_LEFT, evt);
 		} : callFn(this.editorUi.menus.createStyleChangeFunction([mxConstants.STYLE_ALIGN], [mxConstants.ALIGN_LEFT])), stylePanel3);
 	var center = this.editorUi.toolbar.addButton('geSprite-center', mxResources.get('center'),
 		(graph.cellEditor.isContentEditing()) ?
-		function()
+		function(evt)
 		{
-			document.execCommand('justifycenter', false, null);
+			graph.cellEditor.alignText(mxConstants.ALIGN_CENTER, evt);
 		} : callFn(this.editorUi.menus.createStyleChangeFunction([mxConstants.STYLE_ALIGN], [mxConstants.ALIGN_CENTER])), stylePanel3);
 	var right = this.editorUi.toolbar.addButton('geSprite-right', mxResources.get('right'),
 		(graph.cellEditor.isContentEditing()) ?
-		function()
+		function(evt)
 		{
-			document.execCommand('justifyright', false, null);
+			graph.cellEditor.alignText(mxConstants.ALIGN_RIGHT, evt);
 		} : callFn(this.editorUi.menus.createStyleChangeFunction([mxConstants.STYLE_ALIGN], [mxConstants.ALIGN_RIGHT])), stylePanel3);
 
 	this.styleButtons([left, center, right]);
@@ -2625,8 +2625,14 @@ TextFormatPanel.prototype.addFont = function(container)
 		full = this.editorUi.toolbar.addButton('geSprite-justifyfull', mxResources.get('block'),
 			function()
 			{
-				document.execCommand('justifyfull', false, null);
+				if (full.style.opacity == 1)
+				{
+					document.execCommand('justifyfull', false, null);
+				}
 			}, stylePanel3);
+		full.style.marginRight = '9px';
+		full.style.opacity = 1;
+
 		this.styleButtons([full,
        		sub = this.editorUi.toolbar.addButton('geSprite-subscript',
        			mxResources.get('subscript') + ' (' + Editor.ctrlKey + '+,)',
@@ -2639,7 +2645,6 @@ TextFormatPanel.prototype.addFont = function(container)
 			{
 				document.execCommand('superscript', false, null);
 			}, stylePanel3)]);
-		full.style.marginRight = '9px';
 		
 		var tmp = stylePanel3.cloneNode(false);
 		tmp.style.paddingTop = '4px';
@@ -3536,7 +3541,7 @@ TextFormatPanel.prototype.addFont = function(container)
 		setSelected(bottom, valign == mxConstants.ALIGN_BOTTOM);
 		
 		var pos = mxUtils.getValue(ss.style, mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER);
-		var vpos =  mxUtils.getValue(ss.style, mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE);
+		var vpos = mxUtils.getValue(ss.style, mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE);
 		
 		if (pos == mxConstants.ALIGN_LEFT && vpos == mxConstants.ALIGN_TOP)
 		{
@@ -3780,13 +3785,31 @@ TextFormatPanel.prototype.addFont = function(container)
 							setSelected(fontStyleItems[1], css.fontStyle == 'italic' ||
 								hasParentOrOnlyChild('I') || hasParentOrOnlyChild('EM'));
 							setSelected(fontStyleItems[2], hasParentOrOnlyChild('U'));
-							setSelected(left, isEqualOrPrefixed(css.textAlign, 'left'));
-							setSelected(center, isEqualOrPrefixed(css.textAlign, 'center'));
-							setSelected(right, isEqualOrPrefixed(css.textAlign, 'right'));
 							setSelected(full, isEqualOrPrefixed(css.textAlign, 'justify'));
 							setSelected(sup, hasParentOrOnlyChild('SUP'));
 							setSelected(sub, hasParentOrOnlyChild('SUB'));
 							
+							if (graph.cellEditor.isAllTextSelected())
+							{
+								var align = graph.cellEditor.align || mxUtils.getValue(ss.style, mxConstants.STYLE_ALIGN, mxConstants.ALIGN_CENTER);
+								setSelected(left, align == mxConstants.ALIGN_LEFT);
+								setSelected(center, align == mxConstants.ALIGN_CENTER);
+								setSelected(right, align == mxConstants.ALIGN_RIGHT);
+								
+								setSelected(full, false);
+								full.style.opacity = 0.2;
+								full.style.cursor = 'default';
+							}
+							else
+							{
+								setSelected(left, isEqualOrPrefixed(css.textAlign, 'left'));
+								setSelected(center, isEqualOrPrefixed(css.textAlign, 'center'));
+								setSelected(right, isEqualOrPrefixed(css.textAlign, 'right'));
+								
+								full.style.opacity = 1;
+								full.style.cursor = '';
+							}
+							
 							currentTable = graph.getParentByName(node, 'TABLE', graph.cellEditor.textarea);
 							tableRow = (currentTable == null) ? null : graph.getParentByName(node, 'TR', currentTable);
 							tableCell = (currentTable == null) ? null : graph.getParentByName(node, 'TD', currentTable);

+ 78 - 0
src/main/webapp/js/mxgraph/Graph.js

@@ -5438,6 +5438,19 @@ if (typeof mxVertexHandler != 'undefined')
 			span.innerHTML = elt.innerHTML;
 			elt.parentNode.replaceChild(span, elt);
 		};
+
+		/**
+		 * 
+		 */
+		Graph.prototype.processElements = function(elt, fn)
+		{
+			var elts = elt.getElementsByTagName('*');
+			
+			for (var i = 0; i < elts.length; i++)
+			{
+				fn(elts[i]);
+			}
+		};
 		
 		/**
 		 * Handles label changes for XML user objects.
@@ -7013,6 +7026,71 @@ if (typeof mxVertexHandler != 'undefined')
 			return state != null && state.style['html'] == 1;
 		};
 	
+		/**
+		 * Returns true if all selected text (or the cursor) is not
+		 * within a block element or within the only block element.
+		 */
+		mxCellEditor.prototype.isAllTextSelected = function()
+		{
+			var par = null;
+			
+			if (document.selection)
+			{
+				par = document.selection.createRange().parentElement();
+			}
+			else
+			{
+				var selection = window.getSelection();
+				
+				if (selection.rangeCount > 0)
+				{
+					par = selection.getRangeAt(0).commonAncestorContainer;
+				}
+			}
+			
+			var block = false;
+			var css = null;
+			
+			while (par != null && par != this.textarea)
+			{
+				css = (par.nodeType == mxConstants.NODETYPE_ELEMENT) ?
+					mxUtils.getCurrentStyle(par) : null;
+				block = block || (css != null && css.display === 'block');
+			
+				par = par.parentNode;
+
+				if (block && par.childNodes.length > 1)
+				{
+					return false;
+				}
+			}
+			
+			return true;
+		};
+		
+		/**
+		 * Returns true if all selected text (or the cursor) is not
+		 * within a block element or within the only block element.
+		 */
+		mxCellEditor.prototype.alignText = function(align, evt)
+		{
+			// Ignore isAllTextSelected() to produce consistent behaviour
+			// regardless of width of current selected block (if the widest
+			// block is selected the alignment changes are not visible)
+			if (evt == null || !mxEvent.isShiftDown(evt))
+			{
+				this.graph.cellEditor.setAlign(align);
+				
+				this.graph.processElements(this.textarea, function(elt)
+				{
+					elt.removeAttribute('align');
+					elt.style.textAlign = null;
+				});
+			}
+			
+			document.execCommand('justify' + align.toLowerCase(), false, null);
+		};
+		
 		/**
 		 * Creates the keyboard event handler for the current graph and history.
 		 */

+ 10 - 0
src/main/webapp/js/mxgraph/Menus.js

@@ -821,6 +821,16 @@ Menus.prototype.createStyleChangeFunction = function(keys, values)
 			for (var i = 0; i < keys.length; i++)
 			{
 				graph.setCellStyles(keys[i], values[i]);
+
+				// Removes CSS alignment to produce consistent output
+				if (keys[i] == mxConstants.STYLE_ALIGN)
+				{
+					graph.updateLabelElements(graph.getSelectionCells(), function(elt)
+					{
+						elt.removeAttribute('align');
+						elt.style.textAlign = null;
+					});
+				}
 			}
 			
 			if (post != null)

+ 6 - 6
src/main/webapp/js/mxgraph/Toolbar.js

@@ -291,21 +291,21 @@ Toolbar.prototype.createTextToolbar = function()
 	// to catch the focus on click in these browsers. NOTE: Workaround in mxPopupMenu for icon items (without text).
 	var alignMenu = this.addMenuFunction('', mxResources.get('align'), false, mxUtils.bind(this, function(menu)
 	{
-		elt = menu.addItem('', null, mxUtils.bind(this, function()
+		elt = menu.addItem('', null, mxUtils.bind(this, function(evt)
 		{
-			document.execCommand('justifyleft', false, null);
+			graph.cellEditor.alignText(mxConstants.ALIGN_LEFT, evt);
 		}), null, 'geIcon geSprite geSprite-left');
 		elt.setAttribute('title', mxResources.get('left'));
 
-		elt = menu.addItem('', null, mxUtils.bind(this, function()
+		elt = menu.addItem('', null, mxUtils.bind(this, function(evt)
 		{
-			document.execCommand('justifycenter', false, null);
+			graph.cellEditor.alignText(mxConstants.ALIGN_CENTER, evt);
 		}), null, 'geIcon geSprite geSprite-center');
 		elt.setAttribute('title', mxResources.get('center'));
 
-		elt = menu.addItem('', null, mxUtils.bind(this, function()
+		elt = menu.addItem('', null, mxUtils.bind(this, function(evt)
 		{
-			document.execCommand('justifyright', false, null);
+			graph.cellEditor.alignText(mxConstants.ALIGN_RIGHT, evt);
 		}), null, 'geIcon geSprite geSprite-right');
 		elt.setAttribute('title', mxResources.get('right'));
 

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
src/main/webapp/js/shapes.min.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 8 - 8
src/main/webapp/js/stencils.min.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 399 - 395
src/main/webapp/js/viewer.min.js


+ 10 - 4
src/main/webapp/shapes/rack/mxRack.js

@@ -178,6 +178,7 @@ mxRackPlate.prototype.paintVertexShape = function(c, x, y, w, h)
 
 mxRackPlate.prototype.background = function(c, w, h)
 {
+	c.begin();
 	c.rect(0, 0, w, h);
 	c.fillAndStroke();
 };
@@ -189,12 +190,17 @@ mxRackPlate.prototype.foreground = function(c, w, h)
 	if (w > bufferSize * 2)
 	{
 		c.save();
-		c.setFillColor('#b4b4b4');
-		c.rect(0, 0, w, h);
-		c.fillAndStroke();
+		c.setFillColor('#000000');
+		c.setAlpha(0.23);
+		c.rect(0,0, bufferSize, h);
+		c.fill();
+		c.rect(w - bufferSize,0, bufferSize, h);
+		c.fill();
 		c.restore();
+		c.rect(0, 0, w, h);
+		c.stroke();
 		c.rect(bufferSize, 0, w - bufferSize * 2, h);
-		c.fillAndStroke();
+		c.stroke();
 	}
 };
 

+ 276 - 116
src/main/webapp/stencils/rack/apc.xml

@@ -1,117 +1,277 @@
-<shapes name="mxGraph.rack.APC">
-    <shape name="APC Smart UPS 1000-3000 VA 2U" h="29.75" w="160.85">
-        <foreground>
-            <strokecolor color="#545454"/>
-            <fillcolor color="#545454"/>
-            <rect x="0" y="0" w="160.85" h="29.75"/>
-            <fillstroke/>
-            <fillcolor color="#f4f4f4"/>
-            <path>
-                <move x="7.83" y="0"/>
-                <line x="152.65" y="0"/>
-                <line x="152.65" y="11.97"/>
-                <arc rx="2.8" ry="2.8" x-axis-rotation="0" large-arc-flag="0" sweep-flag="0" x="152.65" y="17.78"/>
-                <line x="152.65" y="29.75"/>
-                <line x="7.83" y="29.75"/>
-                <line x="7.83" y="17.78"/>
-                <arc rx="2.8" ry="2.8" x-axis-rotation="0" large-arc-flag="0" sweep-flag="0" x="7.83" y="11.97"/>
-                <close/>
-            </path>
-            <fillstroke/>
-            <strokecolor color="#000000"/>
-            <rect x="91.32" y="2.45" w="53.99" h="25.21"/>
-            <stroke/>
-            <fillcolor color="#bfbfbf"/>
-            <rect x="16.33" y="2.45" w="72.33" h="2.23"/>
-            <fill/>
-            <rect x="16.33" y="5.8" w="72.33" h="2.23"/>
-            <fill/>
-            <rect x="16.33" y="8.92" w="72.33" h="2.23"/>
-            <fill/>
-            <rect x="16.33" y="12.27" w="72.33" h="2.23"/>
-            <fill/>
-            <rect x="16.33" y="15.62" w="72.33" h="2.23"/>
-            <fill/>
-            <rect x="16.33" y="18.74" w="72.33" h="2.23"/>
-            <fill/>
-            <rect x="16.33" y="22.09" w="72.33" h="2.23"/>
-            <fill/>
-            <rect x="16.33" y="25.43" w="72.33" h="2.23"/>
-            <fill/>
-        </foreground>
-    </shape>
-    <shape name="APC Smart UPS 5000 VA 5U" h="73.75" w="160.85">
-        <foreground>
-            <strokecolor color="#545454"/>
-            <fillcolor color="#545454"/>
-            <rect x="0" y="0" w="160.85" h="73.75"/>
-            <fillstroke/>
-            <fillcolor color="#f4f4f4"/>
-            <path>
-                <move x="7.83" y="0"/>
-                <line x="152.65" y="0"/>
-                <line x="152.65" y="29.69"/>
-                <arc rx="8" ry="8" x-axis-rotation="0" large-arc-flag="0" sweep-flag="0" x="152.65" y="44.06"/>
-                <line x="152.65" y="73.75"/>
-                <line x="7.83" y="73.75"/>
-                <line x="7.83" y="44.06"/>
-                <arc rx="8" ry="8" x-axis-rotation="0" large-arc-flag="0" sweep-flag="0" x="7.83" y="29.69"/>
-                <close/>
-            </path>
-            <fillstroke/>
-            <strokecolor color="#000000"/>
-            <rect x="100" y="18" w="43" h="38"/>
-            <stroke/>
-            <fillcolor color="#bfbfbf"/>
-            <rect x="16.33" y="6.08" w="127" h="5.53"/>
-            <fill/>
-            <rect x="16.33" y="14.38" w="72.33" h="5.53"/>
-            <fill/>
-            <rect x="16.33" y="22.12" w="72.33" h="5.53"/>
-            <fill/>
-            <rect x="16.33" y="30.42" w="72.33" h="5.53"/>
-            <fill/>
-            <rect x="16.33" y="38.71" w="72.33" h="5.53"/>
-            <fill/>
-            <rect x="16.33" y="46.46" w="72.33" h="5.53"/>
-            <fill/>
-            <rect x="16.33" y="54.75" w="72.33" h="5.53"/>
-            <fill/>
-            <rect x="16.33" y="63.05" w="127" h="5.53"/>
-            <fill/>
-        </foreground>
-    </shape>
-    <shape name="APC Smart UPS 750 VA 1U" h="14.95" w="160.85">
-        <foreground>
-            <strokecolor color="#545454"/>
-            <fillcolor color="#545454"/>
-            <rect x="0" y="0" w="160.85" h="14.95"/>
-            <fillstroke/>
-            <fillcolor color="#f4f4f4"/>
-            <path>
-                <move x="7.83" y="0"/>
-                <line x="152.65" y="0"/>
-                <line x="152.65" y="3.03"/>
-                <arc rx="4.2" ry="4.2" x-axis-rotation="0" large-arc-flag="0" sweep-flag="0" x="152.65" y="11.77"/>
-                <line x="152.65" y="14.95"/>
-                <line x="7.83" y="14.95"/>
-                <line x="7.83" y="11.77"/>
-                <arc rx="4.2" ry="4.2" x-axis-rotation="0" large-arc-flag="0" sweep-flag="0" x="7.83" y="3.03"/>
-                <close/>
-            </path>
-            <fillstroke/>
-            <fillcolor color="#bfbfbf"/>
-            <rect x="16" y="3.03" w="72.33" h="3.03"/>
-            <fill/>
-            <rect x="16" y="8.74" w="72.33" h="3.03"/>
-            <fill/>
-            <rect x="116.32" y="3.03" w="27.66" h="3.03"/>
-            <fill/>
-            <rect x="116.32" y="8.74" w="27.66" h="3.03"/>
-            <fill/>
-            <strokecolor color="#000000"/>
-            <rect x="91.32" y="3.36" w="23" h="8.41"/>
-            <stroke/>
-        </foreground>
-    </shape>
+<shapes name="mxgraph.rack.APC">
+<shape aspect="variable" h="30.75" name="APC Smart UPS 1000-3000 VA 2U" strokewidth="inherit" w="161.85">
+    <connections/>
+    <foreground>
+        <save/>
+        <path>
+            <move x="0" y="0"/>
+            <line x="0" y="30.75"/>
+            <line x="161.85" y="30.75"/>
+            <line x="161.85" y="0"/>
+            <close/>
+        </path>
+        <fill/>
+        <fillcolor color="#000000"/>
+        <strokewidth width="1"/>
+        <linejoin join="miter"/>
+        <linecap cap="butt"/>
+        <miterlimit limit="4"/>
+        <dashpattern pattern="none"/>
+        <dashed dashed="1"/>
+        <alpha alpha="1"/>
+        <strokealpha alpha="1"/>
+        <fillalpha alpha="0.64313725"/>
+        <fontfamily family="sans-serif"/>
+        <fontstyle style="0"/>
+        <path>
+            <move x="8.83" y="1"/>
+            <line x="152.65" y="1"/>
+            <line x="152.65" y="12.07"/>
+            <curve x1="151.81" x2="151.08" x3="150.6" y1="12.19" y2="12.51" y3="13.05"/>
+            <curve x1="150.03" x2="149.75" x3="149.75" y1="13.7" y2="14.54" y3="15.38"/>
+            <curve x1="149.75" x2="150.03" x3="150.6" y1="16.21" y2="17.05" y3="17.7"/>
+            <curve x1="151.08" x2="151.81" x3="152.65" y1="18.24" y2="18.56" y3="18.68"/>
+            <line x="152.65" y="29.75"/>
+            <line x="8.83" y="29.75"/>
+            <line x="8.83" y="18.68"/>
+            <curve x1="9.68" x2="10.4" x3="10.88" y1="18.56" y2="18.24" y3="17.7"/>
+            <curve x1="11.46" x2="11.73" x3="11.73" y1="17.05" y2="16.21" y3="15.38"/>
+            <curve x1="11.73" x2="11.46" x3="10.88" y1="14.54" y2="13.7" y3="13.05"/>
+            <curve x1="10.4" x2="9.68" x3="8.83" y1="12.51" y2="12.19" y3="12.07"/>
+            <close/>
+            <move x="0" y="0"/>
+            <line x="0" y="30.75"/>
+            <line x="161.85" y="30.75"/>
+            <line x="161.85" y="0"/>
+            <close/>
+        </path>
+        <fill/>
+        <restore/>
+        <rect/>
+        <stroke/>
+        <strokecolor color="#000000"/>
+        <rect h="25.21" w="53.99" x="91.82" y="2.95"/>
+        <stroke/>
+        <fillcolor color="#000000"/>
+        <fillalpha alpha="0.23137255"/>
+        <path>
+            <move x="16.83" y="25.93"/>
+            <line x="89.16" y="25.93"/>
+            <line x="89.16" y="28.16"/>
+            <line x="16.83" y="28.16"/>
+            <close/>
+            <move x="16.83" y="22.59"/>
+            <line x="89.16" y="22.59"/>
+            <line x="89.16" y="24.82"/>
+            <line x="16.83" y="24.82"/>
+            <close/>
+            <move x="16.83" y="19.24"/>
+            <line x="89.16" y="19.24"/>
+            <line x="89.16" y="21.47"/>
+            <line x="16.83" y="21.47"/>
+            <close/>
+            <move x="16.83" y="16.12"/>
+            <line x="89.16" y="16.12"/>
+            <line x="89.16" y="18.35"/>
+            <line x="16.83" y="18.35"/>
+            <close/>
+            <move x="16.83" y="12.77"/>
+            <line x="89.16" y="12.77"/>
+            <line x="89.16" y="15"/>
+            <line x="16.83" y="15"/>
+            <close/>
+            <move x="16.83" y="9.42"/>
+            <line x="89.16" y="9.42"/>
+            <line x="89.16" y="11.65"/>
+            <line x="16.83" y="11.65"/>
+            <close/>
+            <move x="16.83" y="6.3"/>
+            <line x="89.16" y="6.3"/>
+            <line x="89.16" y="8.53"/>
+            <line x="16.83" y="8.53"/>
+            <close/>
+            <move x="16.83" y="2.95"/>
+            <line x="89.16" y="2.95"/>
+            <line x="89.16" y="5.19"/>
+            <line x="16.83" y="5.19"/>
+            <close/>
+        </path>
+        <fill/>
+    </foreground>
+</shape>
+<shape aspect="variable" h="74.75" name="APC Smart UPS 5000 VA 5U" strokewidth="inherit" w="161.85">
+    <connections/>
+    <foreground>
+        <save/>
+        <path>
+            <move x="0" y="0"/>
+            <line x="0" y="74.75"/>
+            <line x="161.85" y="74.75"/>
+            <line x="161.85" y="0"/>
+            <close/>
+        </path>
+        <fill/>
+        <fillcolor color="#000000"/>
+        <strokewidth width="1"/>
+        <linejoin join="miter"/>
+        <linecap cap="butt"/>
+        <miterlimit limit="4"/>
+        <dashpattern pattern="none"/>
+        <dashed dashed="1"/>
+        <alpha alpha="1"/>
+        <strokealpha alpha="1"/>
+        <fillalpha alpha="0.64313728"/>
+        <fontfamily family="sans-serif"/>
+        <fontstyle style="0"/>
+        <path>
+            <move x="8.83" y="1"/>
+            <line x="152.65" y="1"/>
+            <line x="152.65" y="29.93"/>
+            <curve x1="146.74" x2="146.74" x3="152.65" y1="33.11" y2="41.64" y3="44.82"/>
+            <line x="152.65" y="73.75"/>
+            <line x="8.83" y="73.75"/>
+            <line x="8.83" y="44.82"/>
+            <curve x1="14.75" x2="14.75" x3="8.83" y1="41.65" y2="33.1" y3="29.93"/>
+            <close/>
+            <move x="0" y="0"/>
+            <line x="0" y="74.75"/>
+            <line x="161.85" y="74.75"/>
+            <line x="161.85" y="0"/>
+            <close/>
+        </path>
+        <fill/>
+        <restore/>
+        <rect/>
+        <stroke/>
+        <strokecolor color="#000000"/>
+        <rect h="38" w="43" x="100.5" y="18.5"/>
+        <stroke/>
+        <fillcolor color="#000000"/>
+        <fillalpha alpha="0.23137255"/>
+        <path>
+            <move x="16.83" y="63.55"/>
+            <line x="143.83" y="63.55"/>
+            <line x="143.83" y="69.08"/>
+            <line x="16.83" y="69.08"/>
+            <close/>
+            <move x="16.83" y="55.25"/>
+            <line x="89.16" y="55.25"/>
+            <line x="89.16" y="60.78"/>
+            <line x="16.83" y="60.78"/>
+            <close/>
+            <move x="16.83" y="46.96"/>
+            <line x="89.16" y="46.96"/>
+            <line x="89.16" y="52.49"/>
+            <line x="16.83" y="52.49"/>
+            <close/>
+            <move x="16.83" y="39.21"/>
+            <line x="89.16" y="39.21"/>
+            <line x="89.16" y="44.74"/>
+            <line x="16.83" y="44.74"/>
+            <close/>
+            <move x="16.83" y="30.92"/>
+            <line x="89.16" y="30.92"/>
+            <line x="89.16" y="36.45"/>
+            <line x="16.83" y="36.45"/>
+            <close/>
+            <move x="16.83" y="22.62"/>
+            <line x="89.16" y="22.62"/>
+            <line x="89.16" y="28.15"/>
+            <line x="16.83" y="28.15"/>
+            <close/>
+            <move x="16.83" y="14.88"/>
+            <line x="89.16" y="14.88"/>
+            <line x="89.16" y="20.41"/>
+            <line x="16.83" y="20.41"/>
+            <close/>
+            <move x="16.83" y="6.58"/>
+            <line x="143.83" y="6.58"/>
+            <line x="143.83" y="12.11"/>
+            <line x="16.83" y="12.11"/>
+            <close/>
+        </path>
+        <fill/>
+    </foreground>
+</shape>
+<shape aspect="variable" h="15.95" name="APC Smart UPS 750 VA 1U" strokewidth="inherit" w="161.85">
+    <connections/>
+    <foreground>
+        <save/>
+        <path>
+            <move x="0" y="0"/>
+            <line x="0" y="15.95"/>
+            <line x="161.85" y="15.95"/>
+            <line x="161.85" y="0"/>
+            <close/>
+        </path>
+        <fill/>
+        <fillcolor color="#000000"/>
+        <fillalpha alpha="0.23232326"/>
+        <path>
+            <move x="116.82" y="9.24"/>
+            <line x="144.49" y="9.24"/>
+            <line x="144.49" y="12.27"/>
+            <line x="116.82" y="12.27"/>
+            <close/>
+            <move x="116.82" y="3.53"/>
+            <line x="144.49" y="3.53"/>
+            <line x="144.49" y="6.55"/>
+            <line x="116.82" y="6.55"/>
+            <close/>
+            <move x="16.5" y="9.24"/>
+            <line x="88.82" y="9.24"/>
+            <line x="88.82" y="12.27"/>
+            <line x="16.5" y="12.27"/>
+            <close/>
+            <move x="16.5" y="3.53"/>
+            <line x="88.82" y="3.53"/>
+            <line x="88.82" y="6.55"/>
+            <line x="16.5" y="6.55"/>
+            <close/>
+        </path>
+        <fill/>
+        <restore/>
+        <rect/>
+        <stroke/>
+        <strokecolor color="#000000"/>
+        <strokealpha alpha="0.64313728"/>
+        <rect h="8.41" w="23" x="91.82" y="3.86"/>
+        <stroke/>
+        <fillcolor color="#000000"/>
+        <strokewidth width="1"/>
+        <linejoin join="miter"/>
+        <linecap cap="butt"/>
+        <miterlimit limit="4"/>
+        <dashpattern pattern="none"/>
+        <dashed dashed="1"/>
+        <strokealpha alpha="1"/>
+        <fillalpha alpha="0.64141415"/>
+        <fontfamily family="sans-serif"/>
+        <fontstyle style="0"/>
+        <path>
+            <move x="0" y="0"/>
+            <line x="0" y="0.5"/>
+            <line x="0" y="15.95"/>
+            <line x="161.85" y="15.95"/>
+            <line x="161.85" y="0"/>
+            <close/>
+            <move x="9.33" y="1.5"/>
+            <line x="152.15" y="1.5"/>
+            <line x="152.15" y="2.74"/>
+            <curve x1="150.93" x2="149.85" x3="149.12" y1="2.94" y2="3.41" y3="4.23"/>
+            <curve x1="148.21" x2="147.78" x3="147.78" y1="5.25" y2="6.58" y3="7.9"/>
+            <curve x1="147.78" x2="148.21" x3="149.12" y1="9.21" y2="10.54" y3="11.57"/>
+            <curve x1="149.85" x2="150.93" x3="152.15" y1="12.39" y2="12.85" y3="13.05"/>
+            <line x="152.15" y="14.45"/>
+            <line x="9.33" y="14.45"/>
+            <line x="9.33" y="13.05"/>
+            <curve x1="10.55" x2="11.63" x3="12.36" y1="12.85" y2="12.39" y3="11.57"/>
+            <curve x1="13.27" x2="13.71" x3="13.71" y1="10.54" y2="9.21" y3="7.9"/>
+            <curve x1="13.71" x2="13.27" x3="12.36" y1="6.58" y2="5.25" y3="4.23"/>
+            <curve x1="11.63" x2="10.55" x3="9.33" y1="3.41" y2="2.94" y3="2.74"/>
+            <close/>
+        </path>
+        <fill/>
+    </foreground>
+</shape>
 </shapes>

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 16372 - 4127
src/main/webapp/stencils/rack/cisco.xml


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1730 - 421
src/main/webapp/stencils/rack/dell.xml


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 7464 - 1927
src/main/webapp/stencils/rack/f5.xml


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 3476 - 1001
src/main/webapp/stencils/rack/general.xml


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 2056 - 524
src/main/webapp/stencils/rack/hp.xml


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 2656 - 604
src/main/webapp/stencils/rack/ibm.xml


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 5139 - 1311
src/main/webapp/stencils/rack/oracle.xml


+ 3 - 0
src/main/webapp/styles/grapheditor.css

@@ -7,6 +7,9 @@
 .geEditor input[type=text]::-ms-clear {
 	display: none;
 }
+.geEditor input, select, textarea, button {
+       font-size: inherit;
+}
 .geEditor div.mxTooltip {
 	background: whiteSmoke;
 	border-color: lightGray;