Explorar o código

7.2.0 release

Gaudenz Alder %!s(int64=8) %!d(string=hai) anos
pai
achega
7a9a4806b3

+ 7 - 0
ChangeLog

@@ -1,3 +1,10 @@
+23-AUG-2017: 7.2.0
+
+- Adds support for line jumps (beta)
+- Improvements for Lucidchart import
+- Adds usage stats for actions
+- Uses mxGraph 3.7.5 beta 13
+
 22-AUG-2017: 7.1.10
 
 - Fixes transistor icon set

+ 1 - 1
VERSION

@@ -1 +1 @@
-7.1.10
+7.2.0

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 61 - 59
etc/mxgraph/mxClient.js


+ 1 - 1
war/cache.manifest

@@ -1,7 +1,7 @@
 CACHE MANIFEST
 
 # THIS FILE WAS GENERATED. DO NOT MODIFY!
-# 08/22/2017 08:52 AM
+# 08/23/2017 11:22 AM
 
 app.html
 index.html?offline=1

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 26 - 0
war/images/trello-logo-white.svg


+ 14 - 14
war/index.html

@@ -358,7 +358,6 @@
 				status.innerHTML = 'Page could not be loaded. Please try refreshing.';
 			}
 		};
-
 	</script>
 </head>
 <body class="geEditor">
@@ -416,24 +415,25 @@
 </div>
 <script type="text/javascript">
 /**
- * Main
+ * Overridden for usage stats.
  */
-App.main();
-
-// Logs footer1 clicks
-if (document != null)
+Action.prototype.createFunction = function(funct)
 {
-	var footerElem = document.getElementById('geFooterLink1');
-	
-	if (footerElem != null)
+	return mxUtils.bind(this, function()
 	{
-		footerElem.onclick = function()
+		if (typeof window.ga === 'function')
 		{
-			var img = new Image();
-			img.src = 'https://log.draw.io/log?msg=geFooterLink1:%20location=' + encodeURIComponent(window.location) + '&v=' + encodeURIComponent(EditorUi.VERSION);
+			ga('send', 'event', 'Action', 'click', this.label);
 		}
-	}
-}
+
+		funct();
+	});
+};
+
+/**
+ * Main
+ */
+App.main();
 
 /**
  * Analytics

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 625 - 605
war/js/app.min.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 434 - 423
war/js/atlas-viewer.min.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1336 - 1314
war/js/atlas.min.js


+ 90 - 15
war/js/diagramly/App.js

@@ -899,10 +899,11 @@ App.prototype.init = function()
 			{
 				this.trello = new TrelloClient(this);
 				
+				//TODO we have no user info from Trello so we don't set a user
 				this.trello.addListener('userChanged', mxUtils.bind(this, function()
 				{
-//					this.updateUserElement();
-//					this.restoreLibraries();
+					this.updateUserElement();
+					this.restoreLibraries();
 				}));
 				
 				// Notifies listeners of new client
@@ -1111,10 +1112,18 @@ App.prototype.init = function()
 	});
 	
 	// Announce Desktop Apps
-//	var td2 = document.getElementById('geFooterItem1');
-//	
-//	if (td2 != null)
-//	{
+	var td2 = document.getElementById('geFooterItem1');
+	
+	if (td2 != null)
+	{
+		mxEvent.addListener(td2, 'click', mxUtils.bind(this, function()
+		{
+			if (typeof window.ga === 'function' && !this.isOffline())
+			{
+				ga('send', 'event', 'Footer', 'click', 'Confluence');
+			}
+		}));
+	}
 //		var link = 'https://download.draw.io/';
 //		var lastHtml = td2.innerHTML;
 //		var os = 'draw.io';
@@ -1227,12 +1236,16 @@ App.prototype.init = function()
 //			}
 //		};
 		
-//		mxEvent.addListener(td, 'click', mxUtils.bind(this, function()
-//		{
+		mxEvent.addListener(td, 'click', mxUtils.bind(this, function()
+		{
 //			this.adsHtml.splice(lastAd, 1);
 //			lastAd = null;
 //			this.updateAd(0);
-//		}));
+			if (typeof window.ga === 'function' && !this.isOffline())
+			{
+				ga('send', 'event', 'Footer', 'click', 'Samepage');
+			}
+		}));
 //
 //		if (mxSettings.getOpenCounter() > 10 && urlParams['embed'] != '1')
 //		{
@@ -1963,6 +1976,10 @@ App.prototype.appIconClicked = function(evt)
 		{
 			window.open('https://onedrive.live.com/');
 		}
+		else if (mode == App.MODE_TRELLO)
+		{
+			window.open('https://trello.com/');
+		}
 		else if (mode == App.MODE_GITHUB)
 		{
 			if (file != null && file.constructor == GitHubFile)
@@ -2564,7 +2581,7 @@ App.prototype.showSplash = function(force)
 	}
 	else if (this.mode == null || force)
 	{
-		var rowLimit = (serviceCount <= 4) ? 2 : 3;
+		var rowLimit = (serviceCount <= 4) ? 2 : (serviceCount > 6 ? 4 : 3);
 		
 		var dlg = new StorageDialog(this, mxUtils.bind(this, function()
 		{
@@ -2572,7 +2589,7 @@ App.prototype.showSplash = function(force)
 			showSecondDialog();
 		}), rowLimit);
 		
-		this.showDialog(dlg.container, (rowLimit < 3) ? 260 : 300, (serviceCount > rowLimit) ? 420 : 300, true, false);
+		this.showDialog(dlg.container, (rowLimit < 3) ? 260 : ((rowLimit < 4) ? 300 : 390), (serviceCount > rowLimit) ? 420 : 300, true, false);
 		dlg.init();
 	}
 	else if (urlParams['create'] == null)
@@ -2767,12 +2784,13 @@ App.prototype.pickLibrary = function(mode)
 {
 	mode = (mode != null) ? mode : this.mode;
 	
-	if (mode == App.MODE_GOOGLE || mode == App.MODE_DROPBOX || mode == App.MODE_ONEDRIVE || mode == App.MODE_GITHUB)
+	if (mode == App.MODE_GOOGLE || mode == App.MODE_DROPBOX || mode == App.MODE_ONEDRIVE || mode == App.MODE_GITHUB || mode == App.MODE_TRELLO)
 	{
 		var peer = (mode == App.MODE_GOOGLE) ? this.drive :
 			((mode == App.MODE_ONEDRIVE) ? this.oneDrive :
 			((mode == App.MODE_GITHUB) ? this.gitHub :
-			this.dropbox));
+			((mode == App.MODE_TRELLO) ? this.trello :
+			this.dropbox)));
 		
 		if (peer != null)
 		{
@@ -2939,6 +2957,15 @@ App.prototype.saveLibrary = function(name, images, file, mode, noSpin, noReload,
 					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.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)
@@ -3821,6 +3848,10 @@ App.prototype.getLibraryStorageHint = function(file)
 	{
 		tip += ' (' + mxResources.get('github') + ')';
 	}
+	else if (file.constructor == TrelloLibrary)
+	{
+		tip += ' (' + mxResources.get('trello') + ')';
+	}
 	else if (file.constructor == DropboxLibrary)
 	{
 		tip += ' (' + mxResources.get('dropbox') + ')';
@@ -3962,7 +3993,13 @@ App.prototype.restoreLibraries = function()
 										peer = this.gitHub;
 									}
 								}
-
+								else if (service == 'T')
+								{
+									if (this.trello != null && this.trello.isAuthorized())
+									{
+										peer = this.trello;
+									}
+								}
 								else if (service == 'D')
 								{
 									if (this.dropbox != null && this.dropbox.getUser() != null)
@@ -4655,6 +4692,10 @@ App.prototype.updateHeader = function()
 				{
 					this.appIcon.style.backgroundImage = 'url(' + IMAGE_PATH + '/github-logo-white.svg)';
 				}
+				else if (mode == App.MODE_TRELLO)
+				{
+					this.appIcon.style.backgroundImage = 'url(' + IMAGE_PATH + '/trello-logo-white.svg)';
+				}
 			}
 		}));
 		
@@ -4893,7 +4934,8 @@ App.prototype.updateUserElement = function()
 	if ((this.drive == null || this.drive.getUser() == null) &&
 		(this.oneDrive == null || this.oneDrive.getUser() == null) &&
 		(this.dropbox == null || this.dropbox.getUser() == null) &&
-		(this.gitHub == null || this.gitHub.getUser() == null))
+		(this.gitHub == null || this.gitHub.getUser() == null) &&
+		(this.trello == null || !this.trello.isAuthorized())) //TODO Trello no user issue
 	{
 		if (this.userElement != null)
 		{
@@ -5163,6 +5205,38 @@ App.prototype.updateUserElement = function()
 						}));
 					}
 					
+					//TODO We have no user info from Trello, how we can create a user?
+					if (this.trello != null)
+					{
+						addUser(this.trello.getUser(), IMAGE_PATH + '/trello-logo.svg', mxUtils.bind(this, function()
+						{
+							var file = this.getCurrentFile();
+
+							if (file != null && file.constructor == TrelloFile)
+							{
+								var doLogout = mxUtils.bind(this, function()
+								{
+									this.trello.logout();
+									window.location.hash = '';
+								});
+								
+								if (!file.isModified())
+								{
+									doLogout();
+								}
+								else
+								{
+									this.confirm(mxResources.get('allChangesLost'), null, doLogout,
+										mxResources.get('cancel'), mxResources.get('discardChanges'));
+								}
+							}
+							else
+							{
+								this.trello.logout();
+							}
+						}));
+					}
+					
 					if (!connected)
 					{
 						var div = document.createElement('div');
@@ -5206,6 +5280,7 @@ App.prototype.updateUserElement = function()
 		{
 			user = this.gitHub.getUser();
 		}
+		//TODO Trello no user issue
 		
 		if (user != null)
 		{

+ 0 - 6
war/js/diagramly/Devel.js

@@ -110,12 +110,6 @@ mxscript(drawDevUrl + 'js/jszip/jszip.min.js');
 // mxRuler
 mxscript(drawDevUrl + 'js/diagramly/ruler/mxRuler.js');
 
-//Edges bridges
-if (urlParams['bridges'] == '1')
-{
-	mxscript(drawDevUrl + 'js/diagramly/mxEdgeBridge.js');
-}
-
 //EquiSpaced Guides
 if (urlParams['equiGuides'] == '1')
 {

+ 41 - 7
war/js/diagramly/Dialogs.js

@@ -280,11 +280,6 @@ var StorageDialog = function(editorUi, fn, rowLimit)
 	{
 		addLogo(IMAGE_PATH + '/github-logo.svg', mxResources.get('github'), App.MODE_GITHUB, 'gitHub');
 	}
-	
-	if (editorUi.trello != null)
-	{
-		addLogo(IMAGE_PATH + '/trello-logo.svg', mxResources.get('trello'), App.MODE_TRELLO, 'trello');
-	}
 
 	if (typeof window.DropboxClient === 'function')
 	{
@@ -295,6 +290,11 @@ var StorageDialog = function(editorUi, fn, rowLimit)
 	{
 		addLogo(IMAGE_PATH + '/onedrive-logo.svg', mxResources.get('oneDrive'), App.MODE_ONEDRIVE, 'oneDrive');
 	}
+	
+	if (typeof window.TrelloClient === 'function')
+	{
+		addLogo(IMAGE_PATH + '/trello-logo.svg', mxResources.get('trello'), App.MODE_TRELLO, 'trello');
+	}
 
 	if (!mxClient.IS_IOS || urlParams['storage'] == 'device')
 	{
@@ -519,6 +519,16 @@ var SplashDialog = function(editorUi)
 		logo.src = IMAGE_PATH + '/github-logo.svg';
 		service = mxResources.get('github');
 	}
+	else if (editorUi.mode == App.MODE_TRELLO)
+	{
+		logo.src = IMAGE_PATH + '/trello-logo.svg';
+		service = mxResources.get('trello');
+		
+//		if (help != null)
+//		{
+//			help.setAttribute('href', 'https://support.draw.io/display/DO/Using+draw.io+with+Trello');
+//		}
+	}
 	else if (editorUi.mode == App.MODE_BROWSER)
 	{
 		logo.src = IMAGE_PATH + '/osa_database.png';
@@ -614,6 +624,10 @@ var SplashDialog = function(editorUi)
 	{
 		storage = mxResources.get('github');
 	}
+	else if (editorUi.mode == App.MODE_TRELLO)
+	{
+		storage = mxResources.get('trello');
+	}
 	else if (editorUi.mode == App.MODE_DEVICE)
 	{
 		storage = mxResources.get('device');
@@ -710,6 +724,16 @@ var SplashDialog = function(editorUi)
 				window.open('https://www.github.com/logout');
 			});
 		}
+		else if (editorUi.mode == App.MODE_TRELLO && editorUi.trello != null)
+		{
+			if (editorUi.trello.isAuthorized())
+			{
+				addLogout(function()
+				{
+					editorUi.trello.logout();
+				});
+			}
+		}
 		else if (editorUi.mode == App.MODE_DROPBOX && editorUi.dropbox != null)
 		{
 			// NOTE: Dropbox has a logout option in the picker
@@ -2508,6 +2532,10 @@ var NewDialog = function(editorUi, compact, showName, callback)
 	{
 		logo.src = IMAGE_PATH + '/github-logo.svg';
 	}
+	else if (editorUi.mode == App.MODE_TRELLO)
+	{
+		logo.src = IMAGE_PATH + '/trello-logo.svg';
+	}
 	else if (editorUi.mode == App.MODE_BROWSER)
 	{
 		logo.src = IMAGE_PATH + '/osa_database.png';
@@ -2546,6 +2574,10 @@ var NewDialog = function(editorUi, compact, showName, callback)
 	{
 		ext = editorUi.gitHub.extension;
 	}
+	else if (editorUi.mode == App.MODE_TRELLO && editorUi.trello != null)
+	{
+		ext = editorUi.trello.extension;
+	}
 	
 	var nameInput = document.createElement('input');
 	nameInput.setAttribute('value', editorUi.defaultFilename + ext);
@@ -2596,7 +2628,7 @@ var NewDialog = function(editorUi, compact, showName, callback)
 				
 			if (title != null && title.length > 0)
 			{
-				var tempMode = (editorUi.mode == App.MODE_ONEDRIVE || (editorUi.mode == App.MODE_GOOGLE &&
+				var tempMode = (editorUi.mode == App.MODE_ONEDRIVE || editorUi.mode == App.MODE_TRELLO || (editorUi.mode == App.MODE_GOOGLE &&
 					(editorUi.stateArg == null || editorUi.stateArg.folderId == null))) ? editorUi.mode : null;
 				
 				editorUi.pickFolder(tempMode, function(folderId)
@@ -4259,7 +4291,8 @@ var LinkDialog = function(editorUi, initialValue, btnLabel, fn, showPages)
 			});
 		});
 	}
-
+	//TODO should Trello support this?
+	
 	mxEvent.addListener(linkInput, 'keypress', function(e)
 	{
 		if (e.keyCode == 13)
@@ -5862,6 +5895,7 @@ var AuthDialog = function(editorUi, peer, showRememberOption, fn)
 		service = mxResources.get('github');
 		img.src = IMAGE_PATH + '/github-logo-white.svg';
 	}
+	//TODO Trello?
 	
 	var p = document.createElement('p');
 	mxUtils.write(p, mxResources.get('authorizeThisAppIn', [service]));

+ 12 - 12
war/js/diagramly/EditorUi.js

@@ -1312,17 +1312,17 @@
 				
 				if (this.enableLogging && !this.isOffline() && file.getMode() != null)
 				{
-		        	try
-		        	{
-	        			var img = new Image();
-						var logDomain = window.DRAWIO_LOG_URL != null ? window.DRAWIO_LOG_URL : '';
-	        			img.src = logDomain + '/log?msg=storageMode:' + encodeURIComponent(file.getMode()) +
-        				'&v=' + encodeURIComponent(EditorUi.VERSION);
-		        	}
-		        	catch (e)
-		        	{
-		        		// ignore
-		        	}
+			        	try
+			        	{
+		        			var img = new Image();
+							var logDomain = window.DRAWIO_LOG_URL != null ? window.DRAWIO_LOG_URL : '';
+		        			img.src = logDomain + '/log?msg=storageMode:' + encodeURIComponent(file.getMode()) +
+	        				'&v=' + encodeURIComponent(EditorUi.VERSION);
+			        	}
+			        	catch (e)
+			        	{
+			        		// ignore
+			        	}
 				}
 				
 				if (this.mode == file.getMode() && file.getMode() != App.MODE_DEVICE && file.getMode() != null)
@@ -9123,7 +9123,7 @@
 			serviceCount++
 		}
 		
-		if (this.trello != null)
+		if (this.trello != null || typeof window.TrelloClient === 'function')
 		{
 			serviceCount++
 		}

+ 289 - 219
war/js/diagramly/Extensions.js

@@ -10,7 +10,7 @@
 	var dx = 0;
 	var dy = 0;
 	
-	var arcSize = 5;
+	var arcSize = 6;
 	var edgeStyle = 'html=1;';
 	var vertexStyle = 'html=1;whiteSpace=wrap;';
 	var labelStyle = 'text;html=1;resizable=0;align=center;verticalAlign=middle;labelBackgroundColor=#ffffff;';
@@ -19,8 +19,81 @@
 	var s = "shape=mxgraph.";
 	var ss = "strokeColor=none;shape=mxgraph.";
 
+//	stencils with hardcoded stroke color
+	var hardStroke = [
+		'VennPlainColor1', 
+		'VennPlainColor2', 
+		'VennPlainColor3', 
+		'VennPlainColor4', 
+		'VennPlainColor5', 
+		'VennPlainColor6', 
+		'VennPlainColor7', 
+		'VennPlainColor8',
+		'VennGradientColor1', 
+		'VennGradientColor2', 
+		'VennGradientColor3', 
+		'VennGradientColor4', 
+		'VennGradientColor5', 
+		'VennGradientColor6', 
+		'VennGradientColor7', 
+		'VennGradientColor8', 
+		'UMLEndBlock',
+		'DefaultTextBlockNew'
+	];
+	
+	//stencils with hardCoded fill color
+	var hardFill = [
+		'AWSAndroidBlock3', 
+		'AWSiOSBlock3', 
+		'AWSJavaBlock3', 
+		'AWSJavaScript', 
+		'AWSNetBlock3', 
+		'AWSNodeJSBlock3', 
+		'AWSPHPBlock3', 
+		'AWSPythonBlock3', 
+		'AWSRubyBlock3', 
+		'AWSXamarin', 
+		'AWSCLIBlock3', 
+		'AWSEclipseToolkitBlock3', 
+		'AWSVisualStudioToolkitBlock3', 
+		'AWSWindowsPowershellToolkitBlock3', 
+		'DefaultTextBlock', 
+		'RectangleContainerBlock', 
+		'UMLStartBlock', 
+		'UMLEndBlock',
+		'DefaultTextBlockNew',
+		'UMLHForkJoinBlock'
+	];
+
+//	stencils with hardcoded opacity
+	var hardOpacity = [
+		'VennPlainColor1', 
+		'VennPlainColor2', 
+		'VennPlainColor3', 
+		'VennPlainColor4', 
+		'VennPlainColor5', 
+		'VennPlainColor6', 
+		'VennPlainColor7', 
+		'VennPlainColor8', 
+		'VennGradientColor1', 
+		'VennGradientColor2', 
+		'VennGradientColor3', 
+		'VennGradientColor4', 
+		'VennGradientColor5', 
+		'VennGradientColor6', 
+		'VennGradientColor7', 
+		'VennGradientColor8'
+	];
+
+	//stencils to rotate counter clockwise 90 degrees
+	var rccw = [
+		'AEUSBBlock', 
+		'AGSCutandpasteBlock', 
+		'iOSDeviceiPadLandscape', 
+		'iOSDeviceiPadProLandscape'
+	];
+	
 	var edgeStyleMap = {
-			//Standard
 						'None': 'none',
 						'Arrow': 'block;endFill=1',
 						'Hollow Arrow': 'block;endFill=0',
@@ -40,22 +113,20 @@
 						'BlockEnd': 'none;endFill=1;startSize=16'
 	};
 
-	// TODO: Add shape mappings
-	// FIXME: Factor our common strings, eg. shape=mxgraph. to save space
 	var styleMap = {
 //Standard
-			'DefaultTextBlockNew': 'text;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;',
-			'DefaultTextBlock': 'text;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;',
-			'DefaultSquareBlock': 'rounded=1;arcSize=' + arcSize + ';',
+			'DefaultTextBlockNew': 'text;strokeColor=none;fillColor=none;',
+			'DefaultTextBlock': 'text;strokeColor=none;fillColor=none;',
+			'DefaultSquareBlock': 'rounded=1;absoluteArcSize=1;arcSize=' + arcSize + ';',
 			'DefaultNoteBlock': 'shape=note;size=15;',
 			'DefaultNoteBlockV2': 'shape=note;size=15;',
 			'HotspotBlock': 'strokeColor=none;opacity=50;',
 			'ImageSearchBlock2': 'shape=image;',
 //Flowchart
-			'ProcessBlock': 'rounded=1;arcSize=' + arcSize + ';',
+			'ProcessBlock': 'rounded=1;absoluteArcSize=1;arcSize=' + arcSize + ';',
 			'DecisionBlock': 'rhombus;rounded=1;arcSize=' + arcSize + ';',
 			'TerminatorBlock': 'rounded=1;arcSize=50;',
-			'PredefinedProcessBlock': 'shape=process;rounded=1;arcSize=' + arcSize + ';',
+			'PredefinedProcessBlock': 'shape=process;absoluteArcSize=1;rounded=1;arcSize=' + arcSize + ';',
 			'DocumentBlock': 'shape=document;',
 			'MultiDocumentBlock': s + 'flowchart.multi-document;',
 			'ManualInputBlock': 'shape=manualInput;size=15;rounded=1;arcSize=' + arcSize + ';',
@@ -78,11 +149,11 @@
 			'BraceNoteBlock': 'shape=curlyBracket;rounded=1;', //EXT
 			'NoteBlock': s + 'flowchart.annotation_1;',
 //Containers
-			'AdvancedSwimLaneBlock': 'swimlane;rounded=1;arcSize=' + arcSize + ';', //EXT
-			'AdvancedSwimLaneBlockRotated': 'swimlane;horizontal=0;rounded=1;arcSize=' + arcSize + ';', //EXT
-			'RectangleContainerBlock': 'fillColor=none;container=1;rounded=1;arcSize=' + arcSize + ';',
+			'AdvancedSwimLaneBlock': 'swimlane;rounded=1;absoluteArcSize=1;arcSize=' + arcSize + ';', //EXT
+			'AdvancedSwimLaneBlockRotated': 'swimlane;horizontal=0;rounded=1;absoluteArcSize=1;arcSize=' + arcSize + ';', //EXT
+			'RectangleContainerBlock': 'fillColor=none;container=1;absoluteArcSize=1;rounded=1;arcSize=' + arcSize + ';',
 			'DiamondContainerBlock':  'shape=rhombus;fillColor=none;container=1;',
-			'RoundedRectangleContainerBlock': 'rounded=1;fillColor=none;container=1;', 
+			'RoundedRectangleContainerBlock': 'absoluteArcSize=1;arcSize=' + arcSize+ ';rounded=1;fillColor=none;container=1;', 
 			'CircleContainerBlock': 'shape=ellipse;fillColor=none;container=1;',
 			'PillContainerBlock': 'rounded=1;arcSize=50;fillColor=none;container=1;',
 //			'BraceBlock' NA
@@ -105,7 +176,7 @@
 			'ShapePolyStarBlock': s + 'basic.star;',
 			'ShapeDiamondBlock': 'rhombus;rounded=1;arcSize=' + arcSize + ';',
 //Misc
-			'UI2HotspotBlock' : 'shape=rect;opacity=50;strokeColor=none;rounded=1;',
+			'UI2HotspotBlock' : 'opacity=50;strokeColor=none;absoluteArcSize=1;arcSize=' + arcSize + 'rounded=1;',
 //Android Devices
 //			'AndroidDevice' EXT
 //Android Dialogs
@@ -187,8 +258,8 @@
 //			'iOSTableGroupedSectionBreak' EXT
 //			'iOSTablePlainHeaderFooter' EXT
 //Mind Map
-			'MindMapBlock' : 'shape=rect;rounded=1;',
-			'MindMapStadiumBlock' : 'shape=rect;rounded=1;arcSize=50;',
+			'MindMapBlock' : 'absoluteArcSize=1;arcSize=' + arcSize + 'rounded=1;',
+			'MindMapStadiumBlock' : 'rounded=1;arcSize=50;',
 			'MindMapCloud' : 'shape=cloud;',
 			'MindMapCircle' : 'shape=ellipse;',
 			'MindMapIsoscelesTriangleBlock' : 'shape=triangle;direction=north;',
@@ -237,7 +308,7 @@
 //			'SMSlideshow' EXT
 //			'SMUpload' EXT
 //UML Class Diagram
-			'UMLClassBlock': 'rounded=1;',
+			'UMLClassBlock': 'rounded=1;absoluteArcSize=1;arcSize=' + arcSize + ';',
 			'UMLActiveClassBlock': s + 'flowchart.predefined_process;',
 //			'UMLMultiplicityBlock' NA
 			'UMLPackageBlock': 'shape=folder;tabPosition=left;',
@@ -248,19 +319,19 @@
 			'UMLActorBlock': 'shape=umlActor;labelPosition=center;verticalLabelPosition=bottom;verticalAlign=top;whiteSpace=nowrap;',
 			'UMLUseCaseBlock': 'shape=ellipse;',
 			'UMLCircleContainerBlock': 'shape=ellipse;container=1;',
-			'UMLRectangleContainerBlock': 'rounded=1;container=1;',
+			'UMLRectangleContainerBlock': 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;container=1;',
 //UML State/Activity			
 			'UMLOptionLoopBlock' : s + 'sysml.package2;xSize=90;align=left;spacingLeft=10;overflow=fill;',
 			'UMLAlternativeBlock2' : s + 'sysml.package2;xSize=90;align=left;spacingLeft=10;overflow=fill;',
 			'UMLStartBlock' : 'shape=ellipse;fillColor=#000000;',
-			'UMLStateBlock' : 'shape=rect;rounded=1;',
+			'UMLStateBlock' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
 			'UMLDecisionBlock' : 'shape=rhombus;rounded=1;',
-			'UMLHForkJoinBlock' : 'shape=rect;rounded=1;fillColor=#000000;',
-			'UMLVForkJoinBlock' : 'shape=rect;rounded=1;fillColor=#000000;',
+			'UMLHForkJoinBlock' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;fillColor=#000000;',
+			'UMLVForkJoinBlock' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;fillColor=#000000;',
 			'UMLFlowFinalBlock' : s + 'flowchart.or;',
 			'UMLHistoryStateBlock' : 'shape=ellipse;',
-			'UMLEndBlock' : s + 'bpmn.shape;outline=end;symbol=terminate;',
-			'UMLObjectBlock' : 'shape=rect;rounded=1;',
+			'UMLEndBlock' : s + 'bpmn.shape;outline=end;symbol=terminate;strokeColor=#000000;fillColor=#ffffff;',
+			'UMLObjectBlock' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
 			'UMLSendSignalBlock' : s + 'sysml.sendSigAct;',
 			'UMLReceiveSignalBlock' : s + 'sysml.accEvent;flipH=1;',
 			'UMLAcceptTimeEventActionBlock' : s + 'sysml.timeEvent;',
@@ -271,7 +342,7 @@
 //			'UMLMultiLanePoolRotatedBlock' EXT
 //			'UMLMultidimensionalSwimlane' EXT
 //UML Sequence
-			'UMLActivationBlock' : 'shape=rect;rounded=1;',
+			'UMLActivationBlock' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
 			'UMLDeletionBlock' : s + 'sysml.x;strokeWidth=4;',
 //			'UMLAlternativeBlock' NA
 			'UMLSeqEntityBlock' : s + 'electrical.radio.microphone_1;direction=north;',
@@ -287,7 +358,7 @@
 			'UMLRequiredInterfaceBlock' : 'shape=requires;direction=north;',
 //UML Deployment
 //UML Entity Relationship
-			'UMLEntityBlock' : 'shape=rect;rounded=1;',
+			'UMLEntityBlock' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
 			'UMLWeakEntityBlock' : 'shape=ext;double=1;rounded=1;',
 			'UMLAttributeBlock' : 'shape=ellipse;',
 			'UMLMultivaluedAttributeBlock' : 'shape=doubleEllipse;',
@@ -307,16 +378,16 @@
 //			'BPMNBlackPool' EXT
 //Data Flow
 //			'DFDExternalEntityBlock' NA
-			'DFDExternalEntityBlock2' : 'shape=rect;rounded=1;',
+			'DFDExternalEntityBlock2' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
 			'YDMDFDProcessBlock' : 'shape=ellipse;',
 			'YDMDFDDataStoreBlock' : 'shape=partialRectangle;right=0;left=0;',
-			'GSDFDProcessBlock' : 'shape=swimlane;rounded=1;',
-			'GSDFDProcessBlock2' : 'shape=rect;rounded=1;',
+			'GSDFDProcessBlock' : 'shape=swimlane;rounded=1;absoluteArcSize=1;arcSize=' + arcSize + ';',
+			'GSDFDProcessBlock2' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
 //			'GSDFDDataStoreBlock' NA
 			'GSDFDDataStoreBlock2' : 'shape=partialRectangle;right=0;',
 			
 //Org Chart
-			'OrgBlock' : 'shape=rect;rounded=1;',
+			'OrgBlock' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
 //Tables
 //			'DefaultTableBlock' EXT
 //Processes
@@ -338,7 +409,7 @@
 			'VSMExternalShipmentBoatBlock' : s + 'lean_mapping.boat_shipment;',
 //Information
 			'VSMProductionControlBlock' : s + 'lean_mapping.manufacturing_process;',
-			'VSMOtherInformationBlock' : 'shape=rect;rounded=1;',
+			'VSMOtherInformationBlock' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
 //			'VSMHeijyunkaBoxBlock' NA
 			'VSMSequencedPullBallBlock' : s + 'lean_mapping.sequenced_pull_ball;',
 			'VSMMRPERPBlock' : s + 'lean_mapping.mrp_erp;whiteSpace=wrap;',
@@ -1453,7 +1524,7 @@
 //Desks
 //			'fpDeskEndSegment' NA
 			'fpDeskLongSegment' : 'shape=rect;',
-			'fpDeskShortSegment' : 'shape=rect;rounded=1;',
+			'fpDeskShortSegment' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
 //			'fpDeskSmallCornerSegment' NA
 			'fpDeskLargeCornerSegment' : s + 'floorplan.desk_corner;',
 //			'fpDeskMediumCornerSegment' NA
@@ -1471,10 +1542,10 @@
 			'fpCubicleEnclosed11x9' : s + 'floorplan.wallU;wallThickness=3;',
 //Tables & Chairs
 			'fpTableConferenceOval' : 'shape=ellipse;',
-			'fpTableConferenceBoat' : 'shape=rect;rounded=1;',
-			'fpTableConferenceRectangle' : 'shape=rect;rounded=1;',
+			'fpTableConferenceBoat' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
+			'fpTableConferenceRectangle' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
 			'fpTableDiningRound' : 'shape=ellipse;',
-			'fpTableDiningSquare' : 'shape=rect;rounded=1;',
+			'fpTableDiningSquare' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
 			'fpChairOffice' : s + 'floorplan.office_chair;',
 			'fpChairExecutive' : s + 'floorplan.office_chair;',
 			'fpChairLobby' : s + 'floorplan.office_chair;',
@@ -1483,14 +1554,14 @@
 //Cubicles - Prebuilt
 //Tables - Prebuilt
 //Cabinets - we don't have corresponding stencils, just rounded rectangles			
-			'fpCabinetBasic' : 'shape=rect;rounded=1;',
+			'fpCabinetBasic' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
 //			'fpCabinetCornerLarge' NA
-			'fpCabinetDoubleWide' : 'shape=rect;rounded=1;',
-			'fpCabinetDoubleWithShelves' : 'shape=rect;rounded=1;',
-			'fpCabinetShelvesBasic' : 'shape=rect;rounded=1;',
-			'fpCabinetShelvesDouble' : 'shape=rect;rounded=1;',
-			'fpCabinetBasicWithShelves' : 'shape=rect;rounded=1;',
-			'fpCabinetsAboveDeskShelves' : 'shape=rect;rounded=1;',
+			'fpCabinetDoubleWide' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
+			'fpCabinetDoubleWithShelves' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
+			'fpCabinetShelvesBasic' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
+			'fpCabinetShelvesDouble' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
+			'fpCabinetBasicWithShelves' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
+			'fpCabinetsAboveDeskShelves' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
 //Restroom
 			'fpRestroomToiletPrivate' : s + 'floorplan.toilet;',
 			'fpRestroomToiletPublic' : s + 'floorplan.toilet;',
@@ -1502,7 +1573,7 @@
 			'fpRestroomShower' : s + 'floorplan.shower;flipH=1;',
 //			'fpRestroomCornerSink' NA
 			'fpRestroomPedastalSink' : s + 'floorplan.sink_1;',
-			'fpRestroomCountertop' : 'shape=rect;rounded=1;',
+			'fpRestroomCountertop' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
 			'fpRestroomMirror' : 'shape=line;strokeWidth=3;',
 //			'fpDresserOrnateMirror' NA
 //			'fpRestroomToiletPaper' NA
@@ -1533,13 +1604,13 @@
 //Kitchen
 			'fpKitchenSink' : s + 'floorplan.sink_2;',
 			'fpKitchenDoubleSink' : s + 'floorplan.sink_double;',
-			'fpKitchenCountertop' : 'shape=rect;rounded=1;',
+			'fpKitchenCountertop' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
 			'fpKitchenCountertopCorner' : s + 'floorplan.desk_corner;',
 //Couches
 			'fpCouchLoveSeat' : s + 'floorplan.couch;',
 			'fpCouchSofa' : s + 'floorplan.couch;',
 //			'fpCouchSectional' NA
-			'fpCouchOttoman' : 'shape=rect;rounded=1;',
+			'fpCouchOttoman' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
 //			'fpCouchPillow' NA
 //Technology
 			'fpMiscDesktopComputer' : s + 'floorplan.workstation;',
@@ -1552,7 +1623,7 @@
 			'fpMiscIndoorPlant' : s + 'floorplan.plant;',
 //			'fpMiscPodium' NA
 			'fpPiano' : s + 'floorplan.piano;',
-//			'fpPianoBench' : 'shape=rect;rounded=1;',
+//			'fpPianoBench' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
 //Equipment
 			'PEAxialCompressor' : s + 'pid.compressors.centrifugal_compressor_-_turbine_driven;',
 			'PECentrifugalCompressor' : s + 'pid.compressors.centrifugal_compressor;',
@@ -1916,13 +1987,13 @@
 			'UI2CaptchaBlock' : s + 'mockup.text.captcha;mainText=;',
 //			'Image_ui_formatting_toolbar2'
 //UI Input
-			'UI2ButtonBlock' : 'shape=rect;rounded=1;',
+			'UI2ButtonBlock' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
 //			'UI2CheckBoxBlock' EXT
 //			'UI2HorizontalCheckBoxBlock' EXT
 //			'UI2RadioBlock' EXT
 //			'UI2HorizontalRadioBlock' EXT
 			'UI2ColorPickerBlock' : s + 'mockup.forms.colorPicker;chosenColor=#aaddff;',
-			'UI2TextInputBlock' : 'shape=rect;rounded=1;',
+			'UI2TextInputBlock' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
 			'UI2SelectBlock' : s + 'mockup.forms.comboBox;strokeColor=#999999;fillColor=#ddeeff;align=left;fillColor2=#aaddff;mainText=;fontColor=#666666;',
 			'UI2VSliderBlock' : s + 'mockup.forms.horSlider;sliderStyle=basic;sliderPos=20;handleStyle=circle;direction=north;',
 			'UI2HSliderBlock' : s + 'mockup.forms.horSlider;sliderStyle=basic;sliderPos=20;handleStyle=circle;',
@@ -1972,7 +2043,7 @@
 			'Image_ipad_back_button_black' : s + 'ios.iButtonBack;buttonText=;fillColor=#888888;fillColor2=#000000;',
 			'Image_ipad_sort_handle' : s + 'ios7.icons.options;',
 			'Image_ipad_dropdown' : s + 'ios.iComboBox;buttonText=;fillColor=#dddddd;fillColor2=#3D5565;',
-			'Image_ipad_email_name' : 'shape=rect;rounded=1;',
+			'Image_ipad_email_name' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
 			'Image_ipad_prev_next' : s + 'ios.iPrevNext;strokeColor=#444444;fillColor=#dddddd;fillColor2=#3D5565;fillColor3=#ffffff;',
 			'Image_ipad_keyboard_portrait' : s + 'ios.iKeybLett;',
 			'Image_ipad_keyboard_landscape' : s + 'ios.iKeybLett;',
@@ -1994,8 +2065,8 @@
 			'Image_ipad_pin_green' : s + 'ios.iPin;fillColor2=#00dd00;fillColor3=#004400;strokeColor=#006600;',
 			'Image_ipad_pin_red' : s + 'ios.iPin;fillColor2=#dd0000;fillColor3=#440000;strokeColor=#660000;',
 			'Image_ipad_radio_off' : 'shape=ellipse;', //EXT
-			'Image_ipad_checkbox_off' : 'shape=rect;rounded=1;', //EXT
-			'Image_ipad_indicator' : 'shape=rect;rounded=1;fillColor=#e8878E;gradientColor=#BD1421;strokeColor=#ffffff;',
+			'Image_ipad_checkbox_off' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;', //EXT
+			'Image_ipad_indicator' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;fillColor=#e8878E;gradientColor=#BD1421;strokeColor=#ffffff;',
 //iOS 6 iPhone Elements
 			'Image_iphone_iphone_4' : s + 'ios.iPhone;bgStyle=bgGreen;',
 			'Image_iphone_bg_black' : 'shape=rect;',
@@ -2015,31 +2086,31 @@
 //			'Image_iphone_list' EXT
 //			'Image_iphone_safari_top' NA
 //			'Image_iphone_safari_bottom' NA
-			'Image_iphone_gray_grad_list' : 'shape=rect;rounded=1;', //EXT
+			'Image_iphone_gray_grad_list' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;', //EXT
 //			'Image_iphone_alert_bar' NA
 //			'Image_iphone_alert_dialog' EXT
 //			'Image_iphone_dialog' EXT
 //			'Image_iphone_scroll_pane' EXT
 			'Image_iphone_alpha_list' : s + 'ios.iAlphaList;',
 //iOS 6 iPhone Controls
-			'Image_iphone_button_black' : 'shape=rect;rounded=1;',
-			'Image_iphone_button_blue' : 'shape=rect;rounded=1;',
-			'Image_iphone_button_grayblue' : 'shape=rect;rounded=1;',
-			'Image_iphone_button_red' : 'shape=rect;rounded=1;',
-			'Image_iphone_button_lg_light' : 'shape=rect;rounded=1;',
-			'Image_iphone_button_lg_dark' : 'shape=rect;rounded=1;',
-			'Image_iphone_button_lg_green' : 'shape=rect;rounded=1;',
-			'Image_iphone_button_lg_red' : 'shape=rect;rounded=1;',
-			'Image_iphone_button_lg_yellow' : 'shape=rect;rounded=1;',
-			'Image_iphone_button_xl_green' : 'shape=rect;rounded=1;',
+			'Image_iphone_button_black' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
+			'Image_iphone_button_blue' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
+			'Image_iphone_button_grayblue' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
+			'Image_iphone_button_red' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
+			'Image_iphone_button_lg_light' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
+			'Image_iphone_button_lg_dark' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
+			'Image_iphone_button_lg_green' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
+			'Image_iphone_button_lg_red' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
+			'Image_iphone_button_lg_yellow' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
+			'Image_iphone_button_xl_green' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
 			'Image_iphone_back_button' : s + 'ios.iButtonBack;strokeColor=#444444;buttonText=;fillColor=#dddddd;fillColor2=#3D5565;',
 			'Image_iphone_prev_next' : s + 'ios.iPrevNext;strokeColor=#444444;fillColor=#dddddd;fillColor2=#3D5565;fillColor3=#ffffff;',
 			'Image_iphone_sort_handle' : s + 'ios7.icons.options;',
 			'Image_iphone_slider' : s + 'ios.iSlider;barPos=60;',
 			'Image_iphone_dropdown' : s + 'ios.iComboBox;buttonText=;fillColor=#dddddd;fillColor2=#3D5565;',
-			'Image_iphone_email_name' : 'shape=rect;rounded=1;',
+			'Image_iphone_email_name' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
 			'Image_iphone_switch_off' : s + 'android.switch_off;fillColor=#666666;', //EXT
-			'Image_iphone_keyboard_button_blue' : 'shape=rect;rounded=1;',
+			'Image_iphone_keyboard_button_blue' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;',
 			'Image_iphone_keyboard_letters' : s + 'ios.iKeybLett;',
 			'Image_iphone_keyboard_landscape' : s + 'ios.iKeybLett;',
 //			'Image_iphone_large_tabbed_button' EXT
@@ -2060,10 +2131,10 @@
 			'Image_iphone_pin_green' : s + 'ios.iPin;fillColor2=#00dd00;fillColor3=#004400;strokeColor=#006600;',
 			'Image_iphone_pin_red' : s + 'ios.iPin;fillColor2=#dd0000;fillColor3=#440000;strokeColor=#660000;',
 			'Image_iphone_radio_off' : 'shape=ellipse;', //EXT
-			'Image_iphone_checkbox_off' : 'shape=rect;rounded=1;', //EXT
-			'Image_iphone_indicator' : 'shape=rect;rounded=1;fillColor=#e8878E;gradientColor=#BD1421;strokeColor=#ffffff;',
+			'Image_iphone_checkbox_off' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;', //EXT
+			'Image_iphone_indicator' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;fillColor=#e8878E;gradientColor=#BD1421;strokeColor=#ffffff;',
 			// NOTE: NO COMMA ON LAST LINE
-			'Image_iphone_thread_count' : 'shape=rect;rounded=1;'
+			'Image_iphone_thread_count' : 'absoluteArcSize=1;arcSize=' + arcSize + ';rounded=1;'
 	};
 	
 	function convertText(props)
@@ -2078,6 +2149,8 @@
 			if (props.State.t != null)
 			{
 				text2 = props.State.t;
+				text2 = text2.replace(/</g, '&lt;');
+				text2 = text2.replace(/>/g, '&gt;');
 			}
 		}
 
@@ -2086,8 +2159,9 @@
 		{
 			if (text.t != null)
 			{
+				text.t = text.t.replace(/</g, '&lt;');
+				text.t = text.t.replace(/>/g, '&gt;');
 				return text.t;
-				other = false;
 			}
 		}
 		
@@ -2104,6 +2178,32 @@
 		return obj;
 	};
 		
+	function getTextM(p)
+	{
+		if (p.Text != null)
+		{
+			if (p.Text.m != null)
+			{
+				return p.Text.m;
+			}
+		}
+//		else if(p.TextAreas != null)
+//		{
+//			if (p.TextAreas.Text != null)
+//			{
+//				if (p.TextAreas.Text.Value != null)
+//				{
+//					if (p.TextAreas.Text.Value.m != null)
+//					{
+//						return p.TextAreas.Text.Value.m;
+//					}
+//				}
+//			}
+//		}
+
+		return null;
+	}
+	
 	function updateCell(cell, obj)
 	{
 		var a = getAction(obj);
@@ -2122,7 +2222,9 @@
 			}
 			
 			var p = (a.Properties != null) ? a.Properties : a;
-			
+
+			//TODO separate edge label style from here
+
 			if (p != null)
 			{
 				//adds label
@@ -2131,30 +2233,29 @@
 				//adds font size
 				var isV = false;
 				
-				if (p.Text != null)
+				
+				var m = getTextM(p);
+				
+				if (m != null)
 				{
-					if (p.Text.m != null)
+					var i = 0;
+					
+					while ((!isV) && (i < m.length))
 					{
-						var m = p.Text.m;
-						var i = 0;
+						var currM = m[i];
 						
-						while ((!isV) && (i < m.length))
+						if (currM.n == 's')
 						{
-							var currM = m[i];
-							
-							if (currM.n == 's')
+							if (currM.v != null)
 							{
-								if (currM.v != null)
-								{
-									isV = true;
+								isV = true;
 
-									var fontSize = currM.v;
-									fontSize = Math.round(fontSize * scale);
-									cell.style += 'fontSize=' + fontSize + ';';
-								}
+								var fontSize = currM.v;
+								fontSize = Math.round(fontSize * scale);
+								cell.style += 'fontSize=' + fontSize + ';';
 							}
-							i++;
 						}
+						i++;
 					}
 				}
 				
@@ -2166,38 +2267,34 @@
 				//adds font color
 				var isC = false;
 				
-				if (p.Text != null)
+				if (m != null)
 				{
-					if (p.Text.m != null)
+					var i = 0;
+					
+					while ((!isC) && (i < m.length))
 					{
-						var m = p.Text.m;
-						var i = 0;
+						var currM = m[i];
 						
-						while ((!isC) && (i < m.length))
+						if (currM.n == 'c')
 						{
-							var currM = m[i];
-							
-							if (currM.n == 'c')
+							if (currM.v != null)
 							{
-								if (currM.v != null)
+								isC = true;
+								
+								var currV = currM.v;
+								
+								if (currV.charAt(0) != '#')
 								{
-									isC = true;
-									
-									var currV = currM.v;
-									
-									if (currV.charAt(0) != '#')
-									{
-										currV = '#' + currV;
-									}
+									currV = '#' + currV;
+								}
 
-									var currV = currV.substring(0, 7);
+								var currV = currV.substring(0, 7);
 
-									cell.style += mxConstants.STYLE_FONTCOLOR + '=' + currV + ';';
-								}
+								cell.style += mxConstants.STYLE_FONTCOLOR + '=' + currV + ';';
 							}
-							
-							i++;
 						}
+						
+						i++;
 					}
 
 					var fontStyle = 0;
@@ -2205,9 +2302,8 @@
 					//check for bold text
 					var isBT = false;
 					
-					if (p.Text.m != null)
+					if (m != null)
 					{
-						var m = p.Text.m;
 						var i = 0;
 						
 						while ((!isBT) && (i < m.length))
@@ -2230,9 +2326,8 @@
 					//check for italic text
 					var isIT = false;
 					
-					if (p.Text.m != null)
+					if (m != null)
 					{
-						var m = p.Text.m;
 						var i = 0;
 						
 						while ((!isIT) && (i < m.length))
@@ -2255,9 +2350,8 @@
 					//check for underline text
 					var isUT = false;
 					
-					if (p.Text.m != null)
+					if (m != null)
 					{
-						var m = p.Text.m;
 						var i = 0;
 						
 						while ((!isUT) && (i < m.length))
@@ -2285,155 +2379,135 @@
 					//adds text alignment
 					var isA = false;
 					
-					if (p.Text != null)
+					if (m != null)
 					{
-						if (p.Text.m != null)
+						var i = 0;
+						
+						while ((!isA) && (i < m.length))
 						{
-							var m = p.Text.m;
-							var i = 0;
+							var currM = m[i];
 							
-							while ((!isA) && (i < m.length))
+							if (currM.n == 'a')
 							{
-								var currM = m[i];
-								
-								if (currM.n == 'a')
+								if (currM.v != null)
 								{
-									if (currM.v != null)
-									{
-										isA = true;
-										
-										var currV = currM.v;
-										
-										cell.style += 'align=' + currV + ';';
-									}
+									isA = true;
+									
+									var currV = currM.v;
+									
+									cell.style += 'align=' + currV + ';';
 								}
-								
-								i++;
 							}
+							
+							i++;
 						}
 					}
 
 					//adds left spacing
 					var isIL = false;
 					
-					if (p.Text != null)
+					if (m != null)
 					{
-						if (p.Text.m != null)
+						var i = 0;
+						
+						while ((!isIL) && (i < m.length))
 						{
-							var m = p.Text.m;
-							var i = 0;
+							var currM = m[i];
 							
-							while ((!isIL) && (i < m.length))
+							if (currM.n == 'il')
 							{
-								var currM = m[i];
-								
-								if (currM.n == 'il')
+								if (currM.v != null)
 								{
-									if (currM.v != null)
-									{
-										isIL = true;
-										
-										var currV = currM.v;
-										
-										cell.style += 'spacingLeft=' + currV + ';';
-									}
+									isIL = true;
+									
+									var currV = currM.v;
+									
+									cell.style += 'spacingLeft=' + currV + ';';
 								}
-								
-								i++;
 							}
+							
+							i++;
 						}
 					}
 
 					//adds right spacing
 					var isIR = false;
 					
-					if (p.Text != null)
+					if (m != null)
 					{
-						if (p.Text.m != null)
+						var i = 0;
+						
+						while ((!isIR) && (i < m.length))
 						{
-							var m = p.Text.m;
-							var i = 0;
+							var currM = m[i];
 							
-							while ((!isIR) && (i < m.length))
+							if (currM.n == 'ir')
 							{
-								var currM = m[i];
-								
-								if (currM.n == 'ir')
+								if (currM.v != null)
 								{
-									if (currM.v != null)
-									{
-										isIR = true;
-										
-										var currV = currM.v;
-										
-										cell.style += 'spacingRight=' + currV + ';';
-									}
+									isIR = true;
+									
+									var currV = currM.v;
+									
+									cell.style += 'spacingRight=' + currV + ';';
 								}
-								
-								i++;
 							}
+							
+							i++;
 						}
 					}
 
 					//adds top spacing
 					var isMT = false;
 					
-					if (p.Text != null)
+					if (m != null)
 					{
-						if (p.Text.m != null)
+						var i = 0;
+						
+						while ((!isMT) && (i < m.length))
 						{
-							var m = p.Text.m;
-							var i = 0;
+							var currM = m[i];
 							
-							while ((!isMT) && (i < m.length))
+							if (currM.n == 'mt')
 							{
-								var currM = m[i];
-								
-								if (currM.n == 'mt')
+								if (currM.v != null)
 								{
-									if (currM.v != null)
-									{
-										isMT = true;
-										
-										var currV = currM.v;
-										
-										cell.style += 'spacingTop=' + currV + ';';
-									}
+									isMT = true;
+									
+									var currV = currM.v;
+									
+									cell.style += 'spacingTop=' + currV + ';';
 								}
-								
-								i++;
 							}
+							
+							i++;
 						}
 					}
 
 					//adds bottom spacing
 					var isMB = false;
 					
-					if (p.Text != null)
+					if (m != null)
 					{
-						if (p.Text.m != null)
+						var i = 0;
+						
+						while ((!isMB) && (i < m.length))
 						{
-							var m = p.Text.m;
-							var i = 0;
+							var currM = m[i];
 							
-							while ((!isMB) && (i < m.length))
+							if (currM.n == 'mb')
 							{
-								var currM = m[i];
-								
-								if (currM.n == 'mb')
+								if (currM.v != null)
 								{
-									if (currM.v != null)
-									{
-										isMB = true;
-										
-										var currV = currM.v;
-										
-										cell.style += 'spacingBottom=' + currV + ';';
-									}
+									isMB = true;
+									
+									var currV = currM.v;
+									
+									cell.style += 'spacingBottom=' + currV + ';';
 								}
-								
-								i++;
 							}
+							
+							i++;
 						}
 					}
 
@@ -2481,10 +2555,6 @@
 				// Adds styles
 				cell.style += createStyle(mxConstants.STYLE_STROKEWIDTH, parseFloat(p.LineWidth) * scale, '1');
 				
-//				stencils with hardcoded stroke color
-				var hardStroke = ['VennPlainColor1', 'VennPlainColor2', 'VennPlainColor3', 'VennPlainColor4', 'VennPlainColor5', 'VennPlainColor6', 'VennPlainColor7', 'VennPlainColor8',
-					'VennGradientColor1', 'VennGradientColor2', 'VennGradientColor3', 'VennGradientColor4', 'VennGradientColor5', 'VennGradientColor6', 'VennGradientColor7', 'VennGradientColor8'];
-				
 				if (!hardStroke.includes(a.Class))
 				{
 					if (p.LineWidth == 0)
@@ -2508,10 +2578,6 @@
 				cell.style += createStyle(mxConstants.STYLE_ALIGN, p.TextAlign, 'center');
 				cell.style += createStyle(mxConstants.STYLE_VERTICAL_ALIGN, p.TextVAlign, 'middle');
 				
-//				stencils with hardcoded opacity
-				var hardOpacity = ['VennPlainColor1', 'VennPlainColor2', 'VennPlainColor3', 'VennPlainColor4', 'VennPlainColor5', 'VennPlainColor6', 'VennPlainColor7', 'VennPlainColor8', 
-					'VennGradientColor1', 'VennGradientColor2', 'VennGradientColor3', 'VennGradientColor4', 'VennGradientColor5', 'VennGradientColor6', 'VennGradientColor7', 'VennGradientColor8'];
-
 				if (!hardOpacity.includes(a.Class))
 				{
 					cell.style += createStyle(mxConstants.STYLE_OPACITY, p.Opacity, '100');
@@ -2527,9 +2593,6 @@
 					// Fixes the case for horizontal swimlanes where we use horizontal=0
 					// and Lucid uses rotation
 					
-					//stencils to rotate counter clockwise 90 degrees
-					var rccw = ['AEUSBBlock', 'AGSCutandpasteBlock', 'iOSDeviceiPadLandscape', 'iOSDeviceiPadProLandscape'];
-					
 					if (a.Class == 'AdvancedSwimLaneBlockRotated')
 					{
 						deg += 90;
@@ -2574,10 +2637,7 @@
 				// Gradients and fill color
 				if (p.FillColor != null)
 				{
-					//stencils with hardCoded fill color
-					var exc = ['AWSAndroidBlock3', 'AWSiOSBlock3', 'AWSJavaBlock3', 'AWSJavaScript', 'AWSNetBlock3', 'AWSNodeJSBlock3', 'AWSPHPBlock3', 'AWSPythonBlock3', 'AWSRubyBlock3', 'AWSXamarin', 'AWSCLIBlock3', 'AWSEclipseToolkitBlock3', 'AWSVisualStudioToolkitBlock3', 'AWSWindowsPowershellToolkitBlock3', 'DefaultTextBlock', 'RectangleContainerBlock'];
-				
-					if (!exc.includes(a.Class))
+					if (!hardFill.includes(a.Class))
 					{
 						if (typeof p.FillColor === 'object')
 						{
@@ -2696,8 +2756,17 @@
 			
 			while (ta['t' + count] != null)
 			{
-				var ta = ta['t' + count];
-				e = insertLabel(ta, e);
+				var tmp = ta['t' + count];
+				e = insertLabel(tmp, e);
+				count++;
+			}
+			
+			var count = 1;
+			
+			while (ta['m' + count] != null)
+			{
+				var tmp = ta['m' + count];
+				e = insertLabel(tmp, e);
 				count++;
 			}
 			
@@ -2719,6 +2788,7 @@
 
 	function insertLabel(textArea, e)
 	{
+		//TODO move edge label style to here
 		var x = (parseFloat(textArea.Location) - 0.5) * 2;
 		var lab = new mxCell(convertText(textArea), new mxGeometry(x, 0, 0, 0), labelStyle);
 		lab.geometry.relative = true

+ 42 - 12
war/js/diagramly/Menus.js

@@ -1655,14 +1655,14 @@
 			
 			if (editorUi.trello != null)
 			{
-				menu.addItem(mxResources.get('trello', null, 'Trello') + '...', null, function()
+				menu.addItem(mxResources.get('trello') + '...', null, function()
 				{
 					pickFileFromService(editorUi.trello);
 				}, parent);
 			}
 			else if (trelloEnabled)
 			{
-				menu.addItem(mxResources.get('trello', null, 'Trello') + ' (' + mxResources.get('loading') + '...)', null, function()
+				menu.addItem(mxResources.get('trello') + ' (' + mxResources.get('loading') + '...)', null, function()
 				{
 					// do nothing
 				}, parent, null, false);
@@ -1895,12 +1895,12 @@
 
 		editorUi.actions.put('offline', new Action(mxResources.get('offline') + '...', function()
 		{
-		    window.open('http://www.draw.io/app')
+		    window.open('https://www.draw.io/app')
 		}));
 		
-		editorUi.actions.put('chromeApp', new Action(mxResources.get('chromeApp') + '...', function()
+		editorUi.actions.put('download', new Action(mxResources.get('download') + '...', function()
 		{
-			window.open('https://chrome.google.com/webstore/detail/drawio-desktop/pebppomjfocnoigkeepgbmcifnnlndla')
+			window.open('https://download.draw.io')
 		}));
 
 		this.editorUi.actions.addAction('share...', mxUtils.bind(this, function()
@@ -2105,14 +2105,14 @@
 			
 			if (editorUi.trello != null)
 			{
-				menu.addItem(mxResources.get('trello', null, 'Trello') + '...', null, function()
+				menu.addItem(mxResources.get('trello') + '...', null, function()
 				{
 					editorUi.pickFile(App.MODE_TRELLO);
 				}, parent);
 			}
 			else if (trelloEnabled)
 			{
-				menu.addItem(mxResources.get('trello', null, 'Trello') + ' (' + mxResources.get('loading') + '...)', null, function()
+				menu.addItem(mxResources.get('trello') + ' (' + mxResources.get('loading') + '...)', null, function()
 				{
 					// do nothing
 				}, parent, null, false);
@@ -2222,6 +2222,21 @@
 				}, parent, null, false);
 			}
 			
+			if (editorUi.trello != null)
+			{
+				menu.addItem(mxResources.get('trello') + '...', null, function()
+				{
+					editorUi.showLibraryDialog(null, null, null, null, App.MODE_TRELLO);
+				}, parent);
+			}
+			else if (trelloEnabled)
+			{
+				menu.addItem(mxResources.get('trello') + ' (' + mxResources.get('loading') + '...)', null, function()
+				{
+					// do nothing
+				}, parent, null, false);
+			}
+			
 			menu.addSeparator(parent);
 
 			if (isLocalStorage && urlParams['browser'] != '0')
@@ -2299,6 +2314,21 @@
 				}, parent, null, false);
 			}
 			
+			if (editorUi.trello != null)
+			{
+				menu.addItem(mxResources.get('trello') + '...', null, function()
+				{
+					editorUi.pickLibrary(App.MODE_TRELLO);
+				}, parent);
+			}
+			else if (trelloEnabled)
+			{
+				menu.addItem(mxResources.get('trello') + ' (' + mxResources.get('loading') + '...)', null, function()
+				{
+					// do nothing
+				}, parent, null, false);
+			}
+			
 			menu.addSeparator(parent);
 
 			if (isLocalStorage && urlParams['browser'] != '0')
@@ -2456,15 +2486,15 @@
 			}
 
 			menu.addSeparator(parent);
-			
-			if (!editorUi.isOfflineApp() && urlParams['embed'] != '1')
+
+			if (!editorUi.isOffline() && !navigator.standalone && urlParams['embed'] != '1')
 			{
-				this.addMenuItems(menu, ['-', 'offline'], parent);
+				this.addMenuItems(menu, ['download'], parent);
 			}
 			
-			if (!editorUi.isOffline() && !navigator.standalone && urlParams['embed'] != '1')
+			if (!editorUi.isOfflineApp() && urlParams['embed'] != '1')
 			{
-				this.addMenuItems(menu, ['chromeApp'], parent);
+				this.addMenuItems(menu, ['offline'], parent);
 			}
 		})));
 

+ 24 - 0
war/js/diagramly/Pages.js

@@ -1100,6 +1100,30 @@ EditorUi.prototype.createPageMenuTab = function()
 				{
 					this.insertPage();
 				}), parent);
+
+				var page = this.currentPage;
+				
+				if (page != null)
+				{
+					menu.addSeparator(parent);
+	
+					menu.addItem(mxResources.get('delete'), null, mxUtils.bind(this, function()
+					{
+						this.removePage(page);
+					}), parent);
+					
+					menu.addItem(mxResources.get('rename'), null, mxUtils.bind(this, function()
+					{
+						this.renamePage(page, page.getName());
+					}), parent);
+					
+					menu.addSeparator(parent);
+					
+					menu.addItem(mxResources.get('duplicate'), null, mxUtils.bind(this, function()
+					{
+						this.duplicatePage(page, mxResources.get('copyOf', [page.getName()]));
+					}), parent);
+				}
 			}
 		}));
 		

+ 19 - 9
war/js/diagramly/TrelloClient.js

@@ -104,9 +104,9 @@ TrelloClient.prototype.getFile = function(id, success, error, denyConvert, asLib
 /**
  * 
  */
-TrelloClient.prototype.insertLibrary = function(filename, data, success, error, folderId)
+TrelloClient.prototype.insertLibrary = function(filename, data, success, error, cardId)
 {
-	this.insertFile(filename, data, success, error, true, folderId);
+	this.insertFile(filename, data, success, error, true, cardId);
 };
 
 /**
@@ -298,7 +298,7 @@ TrelloClient.prototype.showTrelloDialog = function(showFiles, fn)
 	content.style.height = '224px';
 
 	var hd = document.createElement('h3');
-	mxUtils.write(hd, showFiles? mxResources.get('selectFile') : mxResources.get('selectCard', null, 'Select Card'));
+	mxUtils.write(hd, showFiles? mxResources.get('selectFile') : mxResources.get('selectCard'));
 	hd.style.cssText = 'width:100%;text-align:center;margin-top:0px;margin-bottom:12px';
 	content.appendChild(hd);
 
@@ -439,7 +439,7 @@ TrelloClient.prototype.showTrelloDialog = function(showFiles, fn)
 				{
 					if (filter != null)
 					{
-						div.appendChild(createLink(mxResources.get('ClearFilter', null, 'Clear Filter'), mxUtils.bind(this, function()
+						div.appendChild(createLink(mxResources.get('clearFilter'), mxUtils.bind(this, function()
 						{
 							filter = null;
 							selectCard();
@@ -454,7 +454,7 @@ TrelloClient.prototype.showTrelloDialog = function(showFiles, fn)
 					{
 						if (filter != null)
 						{
-							div.appendChild(createLink(mxResources.get('ClearFilter', null, 'Clear Filter'), mxUtils.bind(this, function()
+							div.appendChild(createLink(mxResources.get('clearFilter'), mxUtils.bind(this, function()
 							{
 								filter = null;
 								selectCard();
@@ -462,16 +462,16 @@ TrelloClient.prototype.showTrelloDialog = function(showFiles, fn)
 						}
 						else
 						{
-							div.appendChild(createLink(mxResources.get('FilterCards', null, 'Filter Cards') + '...', mxUtils.bind(this, function()
+							div.appendChild(createLink(mxResources.get('filterCards') + '...', mxUtils.bind(this, function()
 							{
-								var dlg = new FilenameDialog(this.ui, mxResources.get('CardName', null, 'Card Name'), mxResources.get('ok'), mxUtils.bind(this, function(value)
+								var dlg = new FilenameDialog(this.ui, mxResources.get('cardName'), mxResources.get('ok'), mxUtils.bind(this, function(value)
 								{
 									if (value != null)
 									{
 										filter = value;
 										selectCard();
 									}
-								}), mxResources.get('CardName', null, 'Card Name'));
+								}), mxResources.get('cardName'));
 								this.ui.showDialog(dlg.container, 300, 80, true, false);
 								dlg.init();
 							})));
@@ -523,7 +523,17 @@ TrelloClient.prototype.showTrelloDialog = function(showFiles, fn)
 };
 
 /**
- * Checks if the client is authorized and calls the next step.
+ * Checks if the client is authorized
+ */
+TrelloClient.prototype.isAuthorized = function()
+{
+	//TODO this may break if Trello client.js is changed
+	return localStorage["trello_token"] != null; //Trello.authorized(); doesn't work unless authorize is called first
+};
+
+
+/**
+ * Logout and deauthorize the user. 
  */
 TrelloClient.prototype.logout = function()
 {

+ 0 - 382
war/js/diagramly/mxEdgeBridge.js

@@ -1,382 +0,0 @@
-/**
- * Copyright (c) 2017, CTI LOGIC
- * Copyright (c) 2006-2017, JGraph Ltd
- * Copyright (c) 2006-2017, Gaudenz Alder
- * 
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
- *
- * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-(function ()
-{
-	mxConnector.prototype.defaultJumpSize = 6;
-
-	mxConnector.prototype.checkLineIntersection = function (line1Start, line1End, line2Start, line2End)
-	{
-		// if the lines intersect, the result contains the the
-		// intersection point if both line segment 1 and line segment 2 contain the point
-		// null otherwise
-		var denominator = ((line2End.y - line2Start.y) * (line1End.x - line1Start.x)) -
-			((line2End.x - line2Start.x) * (line1End.y - line1Start.y));
-
-		if (denominator == 0)
-		{
-			return null;
-		}
-		else
-		{
-			var a = line1Start.y - line2Start.y;
-			var b = line1Start.x - line2Start.x;
-			var numerator1 = ((line2End.x - line2Start.x) * a) - ((line2End.y - line2Start.y) * b);
-			var numerator2 = ((line1End.x - line1Start.x) * a) - ((line1End.y - line1Start.y) * b);
-			a = numerator1 / denominator;
-			b = numerator2 / denominator;
-
-			// if we cast these lines infinitely in both directions, they intersect here:
-			var x = line1Start.x + (a * (line1End.x - line1Start.x));
-			var y = line1Start.y + (a * (line1End.y - line1Start.y));
-
-			 // on both lines?
-			if (a > 0 && a < 1 && b > 0 && b < 1)
-			{
-				return new mxPoint(x, y);
-			}
-			else
-			{
-				return null;
-			}
-		}
-	};
-
-	// Code from https://stackoverflow.com/questions/27664298/calculating-intersection-point-of-quadratic-bezier-curve
-	mxConnector.prototype.calcQLintersects = function (p1, p2, p3, a1, a2)
-	{
-		//linear interpolation utility
-		var lerp = function (a, b, x)
-		{
-			return (a + x * (b - a));
-		};
-
-		var intersections = [];
-
-		// inverse line normal
-		var normal = {
-			x: a1.y - a2.y,
-			y: a2.x - a1.x,
-		};
-
-		// Q-coefficients
-		var c2 = {
-			x: p1.x + p2.x * -2 + p3.x,
-			y: p1.y + p2.y * -2 + p3.y
-		};
-
-		var c1 = {
-			x: p1.x * -2 + p2.x * 2,
-			y: p1.y * -2 + p2.y * 2,
-		};
-
-		var c0 = {
-			x: p1.x,
-			y: p1.y
-		};
-
-		// Transform to line 
-		var coefficient = a1.x * a2.y - a2.x * a1.y;
-		var a = normal.x * c2.x + normal.y * c2.y;
-		var b = (normal.x * c1.x + normal.y * c1.y) / a;
-		var c = (normal.x * c0.x + normal.y * c0.y + coefficient) / a;
-
-		// solve the roots
-		var roots = [];
-		d = b * b - 4 * c;
-		
-		if (d > 0)
-		{
-			var e = Math.sqrt(d);
-			roots.push((-b + Math.sqrt(d)) / 2);
-			roots.push((-b - Math.sqrt(d)) / 2);
-		}
-		else if (d == 0)
-		{
-			roots.push(-b / 2);
-		}
-
-		// calc the solution points
-		for (var i = 0; i < roots.length; i++)
-		{
-			var minX = Math.min(a1.x, a2.x);
-			var minY = Math.min(a1.y, a2.y);
-			var maxX = Math.max(a1.x, a2.x);
-			var maxY = Math.max(a1.y, a2.y);
-			var t = roots[i];
-			
-			if (t >= 0 && t <= 1)
-			{
-				// possible point -- pending bounds check
-				var point = {
-					x: lerp(lerp(p1.x, p2.x, t), lerp(p2.x, p3.x, t), t),
-					y: lerp(lerp(p1.y, p2.y, t), lerp(p2.y, p3.y, t), t)
-				}
-				
-				var x = point.x;
-				var y = point.y;
-				
-				// bounds checks
-				if (a1.x == a2.x && y >= minY && y <= maxY)
-				{
-					// vertical line
-					intersections.push(point);
-				}
-				else if (a1.y == a2.y && x >= minX && x <= maxX)
-				{
-					// horizontal line
-					intersections.push(point);
-				}
-				else if (x >= minX && y >= minY && x <= maxX && y <= maxY)
-				{
-					// line passed bounds check
-					intersections.push(point);
-				}
-			}
-		}
-		
-		return intersections;
-	};
-
-	mxConnector.prototype.getOnLinePointAtDist = function (x1, x2, y1, y2)
-	{
-		var dx = x1 - x2;
-		var dy = y1 - y2;
-		var d = Math.sqrt(dy * dy + dx * dx);
-		var t = this.jumpSize / d;
-
-		return new mxPoint((1 - t) * x1 + t * x2, (1 - t) * y1 + t * y2);
-	};
-
-	mxConnector.prototype.addBridgePoints = function (intersectPt, result, l2p1, l2p2, otherId, eState)
-	{
-		// instead of reordering, get the order and the top edge has the bridge
-		var dx = result.x - l2p2.x;
-		var dy = result.y - l2p2.y;
-		var dist = Math.sqrt(dx * dx + dy * dy);
-		dx /= dist;
-		dy /= dist;
-
-		intersectPt.push(this.getOnLinePointAtDist(result.x, l2p1.x, result.y, l2p1.y));
-		intersectPt.push(new mxPoint(result.x + this.jumpSize * dy, result.y - this.jumpSize * dx));
-		intersectPt.push(this.getOnLinePointAtDist(result.x, l2p2.x, result.y, l2p2.y));
-
-		// add others id here since here is the actual bridge!
-		if (eState.oldIntersectIds != null)
-		{
-			eState.oldIntersectIds[otherId] = true;
-		}
-		else
-		{
-			eState.oldIntersectIds = {otherId: true};
-		}
-	};
-
-	mxConnector.prototype.scalePoint = function (point, scale)
-	{
-		return {
-			x: point.x / scale,
-			y: point.y / scale
-		};
-	};
-
-	//TODO Add curves support for curve edges (paintCurvedLine) for curve intersecting another curve
-	var mxConnectorPaintLine = mxConnector.prototype.paintLine;
-
-	mxConnector.prototype.paintLine = function (canvas, pts, rounded)
-	{
-		this.jumpSize = parseInt(mxUtils.getValue(this.style, 'jumpSize', this.defaultJumpSize));
-		var jumpStyle = mxUtils.getValue(this.style, 'jumpStyle', 'none');
-
-		if (this.outline || jumpStyle === 'none')
-		{
-			mxConnectorPaintLine.apply(this, arguments);
-		}
-		else
-		{
-			var arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
-			canvas.begin();
-
-			var ptsCln = pts;
-			var state = this.state;
-			var graph = state.view.graph;
-
-			// during DnD we can save the extra calculations
-			var model = graph.getModel();
-			var noRedraw = state.redrawEdge;
-			ptsCln = [];
-
-			if (state.oldIntersectIds)
-			{
-				for (var id in state.oldIntersectIds)
-				{
-					var c = model.getCell(id);
-
-					if (c != null)
-					{
-						var eState = graph.view.getState(c);
-
-						if (eState != null && eState.style != null)
-						{
-							eState.redrawEdge = true;
-							eState.shape.redraw();
-						}
-					}
-				}
-				
-				delete state.oldIntersectIds;
-			}
-
-			// for each pair find the intersection
-			for (var i = 0; i < pts.length - 1; i++)
-			{
-				var l2p1 = pts[i];
-				var l2p2 = pts[i + 1];
-				ptsCln.push(l2p1);
-				var intersectPt = [];
-
-				for (var id in model.cells)
-				{
-					var edge = model.cells[id];
-
-					if (edge.isEdge() && edge != state.cell)
-					{
-						var eState = graph.view.getState(edge);
-
-						if (eState != null && eState.absolutePoints != null)
-						{
-							var eScale = eState.view.scale;
-
-							if (eState.style == null || eState.style[mxConstants.STYLE_CURVED] != 1) //line edge
-							{
-								for (var j = 0; j < eState.absolutePoints.length - 1; j++)
-								{
-									var l1p1 = eState.absolutePoints[j];
-									var l1p2 = eState.absolutePoints[j + 1];
-									//the absolute points of current edge is scaled before calling this function, so we have to scale others to get correct intersections
-									var result = this.checkLineIntersection(this.scalePoint(l1p1, eScale), this.scalePoint(l1p2, eScale), l2p1, l2p2);
-
-									if (result != null)
-									{
-										var getEdgeOrder = function (edge1, edge2)
-										{
-											var p1 = edge1.getParent();
-											var p2 = edge2.getParent();
-
-											if (p1 == p2)
-											{
-												return p1.getIndex(edge1) - p1.getIndex(edge2); //+ve edge1 on top, -ve edge2 on top
-											}
-											else
-											{
-												return 0; //not the same parent, so we cannot determine
-											}
-										};
-
-										if (getEdgeOrder(state.cell, eState.cell) > 0) //instead of reordering, get the order and the top edge has the bridge
-										{
-											this.addBridgePoints(intersectPt, result, l2p1, l2p2, state.cell.id, eState);
-										}
-										else if (!noRedraw)
-										{
-											eState.redrawEdge = true;
-											eState.shape.redraw();
-										}
-									}
-								}
-							}
-							else // curve edge (guad Bezier)
-							{
-								// We'll not check edge order here as always line will have bridges as it is better than curve bridges
-								var ePts = eState.absolutePoints;
-								var pt = this.scalePoint(ePts[0], eScale);
-								var n = ePts.length;
-
-								var allPts = [];
-
-								for (var k = 1; k < n - 2; k++)
-								{
-									var p0 = this.scalePoint(ePts[k], eScale);
-									var p1 = this.scalePoint(ePts[k + 1], eScale);
-									
-									var ip = {
-										x: (p0.x + p1.x) / 2,
-										y: (p0.y + p1.y) / 2
-									};
-
-									allPts.push.apply(allPts, this.calcQLintersects(pt, p0, ip, l2p1, l2p2));
-
-									pt = ip;
-								}
-
-								var p0 = this.scalePoint(ePts[n - 2], eScale);
-								var p1 = this.scalePoint(ePts[n - 1], eScale);
-
-								allPts.push.apply(allPts, this.calcQLintersects(pt, p0, p1, l2p1, l2p2));
-
-								if (allPts.length > 0)
-								{
-									for (var o = 0; o < allPts.length; o++)
-									{
-										this.addBridgePoints(intersectPt, allPts[o], l2p1, l2p2, state.cell.id, eState);
-									}
-								}
-							}
-						}
-					}
-				}
-
-				if (intersectPt.length > 0)
-				{
-					// sort points and then add them
-					intersectPt.sort(function (p1, p2)
-					{
-						var dx1 = p1.x - l2p1.x;
-						var dy1 = p1.y - l2p1.y;
-						var d1 = dx1 * dx1 + dy1 * dy1;
-
-						var dx2 = p2.x - l2p1.x;
-						var dy2 = p2.y - l2p1.y;
-						var d2 = dx2 * dx2 + dy2 * dy2;
-
-						return d1 - d2;
-					});
-
-					ptsCln.push(intersectPt[0]);
-					this.addPoints(canvas, ptsCln, rounded, arcSize, false);
-					ptsCln = [intersectPt[intersectPt.length - 1]];
-					
-					if (jumpStyle !== 'gap')
-					{
-						this.addPoints(canvas, intersectPt, jumpStyle !== 'square', arcSize, false);
-					}
-				}
-
-				ptsCln.push(l2p2);
-			}
-
-			if (noRedraw)
-			{
-				state.redrawEdge = false;
-			}
-
-			this.addPoints(canvas, ptsCln, rounded, arcSize, false);
-			canvas.stroke();
-		}
-	};
-})();

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 368 - 358
war/js/embed-static.min.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 171 - 169
war/js/extensions.min.js


+ 9 - 1
war/js/mxgraph/Actions.js

@@ -1201,7 +1201,7 @@ function Action(label, funct, enabled, iconCls, shortcut)
 {
 	mxEventSource.call(this);
 	this.label = label;
-	this.funct = funct;
+	this.funct = this.createFunction(funct);
 	this.enabled = (enabled != null) ? enabled : true;
 	this.iconCls = iconCls;
 	this.shortcut = shortcut;
@@ -1211,6 +1211,14 @@ function Action(label, funct, enabled, iconCls, shortcut)
 // Action inherits from mxEventSource
 mxUtils.extend(Action, mxEventSource);
 
+/**
+ * Sets the enabled state of the action and fires a stateChanged event.
+ */
+Action.prototype.createFunction = function(funct)
+{
+	return funct;
+};
+
 /**
  * Sets the enabled state of the action and fires a stateChanged event.
  */

+ 3 - 2
war/js/mxgraph/EditorUi.js

@@ -371,7 +371,7 @@ EditorUi = function(editor, container, lightbox)
 	
 	// Stores the current style and assigns it to new cells
 	var styles = ['rounded', 'shadow', 'glass', 'dashed', 'dashPattern', 'comic', 'labelBackgroundColor'];
-	var connectStyles = ['shape', 'edgeStyle', 'curved', 'rounded', 'elbow', 'comic'];
+	var connectStyles = ['shape', 'edgeStyle', 'curved', 'rounded', 'elbow', 'comic', 'jumpStyle', 'jumpSize'];
 	
 	// Note: Everything that is not in styles is ignored (styles is augmented below)
 	this.setDefaultStyle = function(cell)
@@ -446,7 +446,8 @@ EditorUi = function(editor, container, lightbox)
 	var valueStyles = ['fontFamily', 'fontSize', 'fontColor'];
 	
 	// Keys that always update the current edge style regardless of selection
-	var alwaysEdgeStyles = ['edgeStyle', 'startArrow', 'startFill', 'startSize', 'endArrow', 'endFill', 'endSize', 'jettySize', 'orthogonalLoop'];
+	var alwaysEdgeStyles = ['edgeStyle', 'startArrow', 'startFill', 'startSize', 'endArrow',
+		'endFill', 'endSize', 'jettySize', 'orthogonalLoop'];
 	
 	// Keys that are ignored together (if one appears all are ignored)
 	var keyGroups = [['startArrow', 'startFill', 'startSize', 'endArrow', 'endFill', 'endSize', 'jettySize', 'orthogonalLoop'],

+ 109 - 0
war/js/mxgraph/Format.js

@@ -4192,6 +4192,115 @@ StyleFormatPanel.prototype.addStroke = function(container)
 	this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }});
 	listener();
 
+	return this.addLineJumps(container);
+};
+
+/**
+ * Adds UI for configuring line jumps.
+ */
+StyleFormatPanel.prototype.addLineJumps = function(container)
+{
+	var ss = this.format.getSelectionState();
+	
+	if (Graph.lineJumpsEnabled && ss.edges.length > 0 && ss.vertices.length == 0)
+	{
+		var ui = this.editorUi;
+		var editor = ui.editor;
+		var graph = editor.graph;
+		
+		// Used if only edges selected
+		var stylePanel = document.createElement('div');
+		stylePanel.style.whiteSpace = 'nowrap';
+		stylePanel.style.padding = '8px 0px 10px 16px';
+		stylePanel.style.borderTop = '1px solid #c0c0c0';
+		stylePanel.style.overflow = 'visible';
+		stylePanel.style.position = 'relative';
+		stylePanel.style.left = '-16px';
+		stylePanel.style.top = '4px';
+		stylePanel.style.width = (ui.formatWidth) + 'px';
+		stylePanel.style.height = '12px';
+		stylePanel.className = 'geToolbarContainer';
+		
+		var span = document.createElement('div');
+		span.style.position = 'absolute';
+		span.style.fontWeight = 'bold';
+		span.style.width = '76px';
+		
+		mxUtils.write(span, mxResources.get('lineJumps'));
+		stylePanel.appendChild(span);
+		
+		var styleSelect = document.createElement('select');
+		styleSelect.style.position = 'absolute';
+		styleSelect.style.marginTop = '-2px';
+		styleSelect.style.right = '92px';
+		styleSelect.style.width = '62px';
+
+		var styles = ['none', 'arc', 'gap', 'sharp'];
+
+		for (var i = 0; i < styles.length; i++)
+		{
+			var styleOption = document.createElement('option');
+			styleOption.setAttribute('value', styles[i]);
+			mxUtils.write(styleOption, mxResources.get(styles[i]));
+			styleSelect.appendChild(styleOption);
+		}
+		
+		mxEvent.addListener(styleSelect, 'change', function(evt)
+		{
+			graph.getModel().beginUpdate();
+			try
+			{
+				graph.setCellStyles('jumpStyle', styleSelect.value, graph.getSelectionCells());
+				ui.fireEvent(new mxEventObject('styleChanged', 'keys', ['jumpStyle'],
+					'values', [styleSelect.value], 'cells', graph.getSelectionCells()));
+			}
+			finally
+			{
+				graph.getModel().endUpdate();
+			}
+			
+			mxEvent.consume(evt);
+		});
+		
+		// Stops events from bubbling to color option event handler
+		mxEvent.addListener(styleSelect, 'click', function(evt)
+		{
+			mxEvent.consume(evt);
+		});
+		
+		stylePanel.appendChild(styleSelect);
+		
+		var jumpSizeUpdate;
+		
+		var jumpSize = this.addUnitInput(stylePanel, 'pt', 38, 33, function()
+		{
+			jumpSizeUpdate.apply(this, arguments);
+		});
+		
+		container.appendChild(stylePanel);
+		
+		jumpSizeUpdate = this.installInputHandler(jumpSize, 'jumpSize',
+			Graph.defaultJumpSize, 0, 999, ' pt');
+		
+		var listener = mxUtils.bind(this, function(sender, evt, force)
+		{
+			ss = this.format.getSelectionState();
+			styleSelect.value = mxUtils.getValue(ss.style, 'jumpStyle', 'none');
+
+			if (force || document.activeElement != jumpSize)
+			{
+				var tmp = parseInt(mxUtils.getValue(ss.style, 'jumpSize', Graph.defaultJumpSize));
+				jumpSize.value = (isNaN(tmp)) ? '' : tmp  + ' pt';
+			}
+		});
+
+		this.addKeyHandler(jumpSize, listener);
+
+		graph.getModel().addListener(mxEvent.CHANGE, listener);
+		this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }});
+		listener();
+	}
+	
 	return container;
 };
 

+ 326 - 2
war/js/mxgraph/Graph.js

@@ -874,7 +874,19 @@ Graph.touchStyle = mxClient.IS_TOUCH || (mxClient.IS_FF && mxClient.IS_WIN) || n
 Graph.fileSupport = window.File != null && window.FileReader != null && window.FileList != null &&
 	(window.urlParams == null || urlParams['filesupport'] != '0');
 
-// Graph inherits from mxGraph
+/**
+ * Default size for line jumps.
+ */
+Graph.lineJumpsEnabled = true;
+
+/**
+ * Default size for line jumps.
+ */
+Graph.defaultJumpSize = 6;
+
+/**
+ * Graph inherits from mxGraph.
+ */
 mxUtils.extend(Graph, mxGraph);
 
 /**
@@ -1250,7 +1262,9 @@ Graph.prototype.isIgnoreTerminalEvent = function(evt)
  */
 Graph.prototype.isSplitTarget = function(target, cells, evt)
 {
-	return !mxEvent.isAltDown(evt) && !mxEvent.isShiftDown(evt) && mxGraph.prototype.isSplitTarget.apply(this, arguments);
+	return !this.model.isEdge(cells[0]) &&
+		!mxEvent.isAltDown(evt) && !mxEvent.isShiftDown(evt) &&
+		mxGraph.prototype.isSplitTarget.apply(this, arguments);
 };
 
 /**
@@ -3273,6 +3287,306 @@ HoverIcons.prototype.setCurrentState = function(state)
 
 (function()
 {
+	
+	/**
+	 * Reset the list of processed edges.
+	 */
+	var mxGraphViewResetValidationState = mxGraphView.prototype.resetValidationState;
+	
+	mxGraphView.prototype.resetValidationState = function()
+	{
+		mxGraphViewResetValidationState.apply(this, arguments);
+		
+		this.validEdges = [];
+	};
+	
+	/**
+	 * Updates jumps for valid edges and repaints if needed.
+	 */
+	var mxGraphViewValidateCellState = mxGraphView.prototype.validateCellState;
+	
+	mxGraphView.prototype.validateCellState = function(cell, recurse)
+	{
+		var state = this.getState(cell);
+		
+		// Forces repaint if jumps change on a valid edge
+		if (state != null && this.graph.model.isEdge(state.cell) &&
+			state.style != null && state.style[mxConstants.STYLE_CURVED] != 1 &&
+			!state.invalid && this.updateLineJumps(state))
+		{
+			this.graph.cellRenderer.redraw(state, false, this.isRendering());
+		}
+		
+		state = mxGraphViewValidateCellState.apply(this, arguments);
+		
+		// Adds to the list of edges that may intersect with later edges
+		if (state != null && this.graph.model.isEdge(state.cell) &&
+			state.style[mxConstants.STYLE_CURVED] != 1)
+		{
+			// LATER: Reuse jumps for valid edges
+			this.validEdges.push(state);
+		}
+		
+		return state;
+	};
+
+	/**
+	 * Forces repaint if routed points have changed.
+	 */
+	var mxCellRendererIsShapeInvalid = mxCellRenderer.prototype.isShapeInvalid;
+	
+	mxCellRenderer.prototype.isShapeInvalid = function(state, shape)
+	{
+		return mxCellRendererIsShapeInvalid.apply(this, arguments) ||
+			(state.routedPoints != null && shape.routedPoints != null &&
+			!mxUtils.equalPoints(shape.routedPoints, state.routedPoints))
+	};
+
+	
+	/**
+	 * Updates jumps for invalid edges.
+	 */
+	var mxGraphViewUpdateCellState = mxGraphView.prototype.updateCellState;
+	
+	mxGraphView.prototype.updateCellState = function(state)
+	{
+		mxGraphViewUpdateCellState.apply(this, arguments);
+
+		// Updates jumps on invalid edge before repaint
+		if (this.graph.model.isEdge(state.cell) &&
+			state.style[mxConstants.STYLE_CURVED] != 1)
+		{
+			this.updateLineJumps(state);
+		}
+	};
+	
+	/**
+	 * Updates the jumps between given state and processed edges.
+	 */
+	mxGraphView.prototype.updateLineJumps = function(state)
+	{
+		if (Graph.lineJumpsEnabled)
+		{
+			var changed = state.routedPoints != null;
+			var thresh = 0.5 * this.scale;
+			var actual = null;
+			
+			if (mxUtils.getValue(state.style, 'jumpStyle', 'none') !== 'none')
+			{
+				var pts = state.absolutePoints;
+				changed = false;
+				actual = [];
+				
+				// Type 0 means normal waypoint, 1 means jump
+				function addPoint(type, x, y)
+				{
+					var rpt = new mxPoint(x, y);
+					rpt.type = type;
+					
+					actual.push(rpt);
+					var curr = (state.routedPoints != null) ? state.routedPoints[actual.length - 1] : null;
+					
+					return curr == null || curr.type != type || curr.x != x || curr.y != y;
+				};
+				
+				for (var i = 0; i < pts.length - 1; i++)
+				{
+					var p1 = pts[i + 1];
+					var p0 = pts[i];
+					var list = [];
+					
+					changed = addPoint(0, p0.x, p0.y) || changed;
+					
+					// Processes all previous edges
+					for (var e = 0; e < this.validEdges.length; e++)
+					{
+						var state2 = this.validEdges[e];
+						var pts2 = state2.absolutePoints;
+						var added = false;
+						
+						// Compares each segment of the edge with the current segment
+						for (var j = 0; j < pts2.length - 1; j++)
+						{
+							var p2 = pts2[j];
+							var p3 = pts2[j + 1];
+							var pt = mxUtils.intersection(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y);
+
+							// Handles intersection between two segments
+							if (pt != null && (Math.abs(pt.x - p2.x) > thresh ||
+								Math.abs(pt.y - p2.y) > thresh) &&
+								(Math.abs(pt.x - p3.x) > thresh ||
+								Math.abs(pt.y - p3.y) > thresh))
+							{
+								var dx = pt.x - p0.x;
+								var dy = pt.y - p0.y;
+								var temp = {distSq: dx * dx + dy * dy, x: pt.x, y: pt.y};
+							
+								// Intersections must be ordered by distance from start of segment
+								for (var t = 0; t < list.length; t++)
+								{
+									if (list[t].distSq > temp.distSq)
+									{
+										list.splice(t, 0, temp);
+										temp = null;
+										
+										break;
+									}
+								}
+								
+								// Ignores multiple intersections at segment joint
+								if (temp != null && (list.length == 0 ||
+									list[list.length - 1].x !== temp.x ||
+									list[list.length - 1].y !== temp.y))
+								{
+									list.push(temp);
+								}
+							}
+						}
+					}
+					
+					// Adds ordered intersections to routed points
+					for (var j = 0; j < list.length; j++)
+					{
+						changed = addPoint(1, list[j].x, list[j].y) || changed;
+					}
+				}
+	
+				var pt = pts[pts.length - 1];
+				changed = addPoint(0, pt.x, pt.y) || changed;
+			}
+			
+			state.routedPoints = actual;
+			
+			return changed;
+		}
+		else
+		{
+			return false;
+		}
+	};
+	
+	/**
+	 * Overrides painting the actual shape for taking into account jump style.
+	 */
+	var mxConnectorPaintLine = mxConnector.prototype.paintLine;
+
+	mxConnector.prototype.paintLine = function (c, absPts, rounded)
+	{
+		// Required for checking dirty state
+		this.routedPoints = (this.state != null) ? this.state.routedPoints : null;
+		
+		if (this.outline || this.state == null || this.style == null ||
+			this.state.routedPoints == null || this.state.routedPoints.length == 0)
+		{
+			mxConnectorPaintLine.apply(this, arguments);
+		}
+		else
+		{
+			var arcSize = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE,
+				mxConstants.LINE_ARCSIZE) / 2;
+			var size = (parseInt(mxUtils.getValue(this.style, 'jumpSize',
+				Graph.defaultJumpSize)) - 2) / 2 + this.strokewidth;
+			var style = mxUtils.getValue(this.style, 'jumpStyle', 'none');
+			var f = Editor.jumpSizeRatio;
+			var moveTo = true;
+			var last = null;
+			var len = null;
+			var pts = [];
+			var n = null;
+			c.begin();
+			
+			for (var i = 0; i < this.state.routedPoints.length; i++)
+			{
+				var rpt = this.state.routedPoints[i];
+				var pt = new mxPoint(rpt.x / this.scale, rpt.y / this.scale);
+				
+				// Takes first and last point from passed-in array
+				if (i == 0)
+				{
+					pt = absPts[0];
+				}
+				else if (i == this.state.routedPoints.length - 1)
+				{
+					pt = absPts[absPts.length - 1];
+				}
+				
+				var done = false;
+
+				// Type 1 is an intersection
+				if (last != null && rpt.type == 1)
+				{
+					if (n == null)
+					{
+						n = new mxPoint(pt.x - last.x, pt.y - last.y);
+						len = Math.sqrt(n.x * n.x + n.y * n.y);
+						n.x = n.x * size / len;
+						n.y = n.y * size / len;
+					}
+					
+					// Checks if next/previous points are too close
+					var next = this.state.routedPoints[i + 1];
+					var dx = next.x / this.scale - pt.x;
+					var dy = next.y / this.scale - pt.y;
+					var dist = dx * dx + dy * dy;
+					
+					if (dist > size * size && len > 0)
+					{
+						var dx = last.x - pt.x;
+						var dy = last.y - pt.y;
+						var dist = dx * dx + dy * dy;
+						
+						if (dist > size * size)
+						{
+							var p0 = new mxPoint(pt.x - n.x, pt.y - n.y);
+							var p1 = new mxPoint(pt.x + n.x, pt.y + n.y);
+							pts.push(p0);
+							
+							this.addPoints(c, pts, rounded, arcSize, false, null, moveTo);
+	
+							var f = (Math.round(n.x) <= 0) ? 1 : -1;
+							moveTo = false;
+							
+							if (style == 'sharp')
+							{
+								c.lineTo(p0.x - n.y * f, p0.y + n.x * f);
+								c.lineTo(p1.x - n.y * f, p1.y + n.x * f);
+								c.lineTo(p1.x, p1.y);
+							}
+							else if (style == 'arc')
+							{
+								f *= 1.3;
+								c.curveTo(p0.x - n.y * f, p0.y + n.x * f,
+									p1.x - n.y * f, p1.y + n.x * f,
+									p1.x, p1.y);
+							}
+							else
+							{
+								c.moveTo(p1.x, p1.y);
+								moveTo = true;
+							}
+	
+							pts = [p1];
+							done = true;
+						}
+					}
+				}
+				else
+				{
+					n = null;
+				}
+				
+				if (!done)
+				{
+					pts.push(pt);
+					last = pt;
+				}
+			}
+			
+			this.addPoints(c, pts, rounded, arcSize, false, null, moveTo);
+			c.stroke();
+		}
+	};
+	
 	/**
 	 * Adds support for snapToPoint style.
 	 */
@@ -3800,6 +4114,16 @@ if (typeof mxVertexHandler != 'undefined')
 			{
 				style += 'comic=' + this.currentEdgeStyle['comic'] + ';';
 			}
+
+			if (this.currentEdgeStyle['jumpStyle'] != null)
+			{
+				style += 'jumpStyle=' + this.currentEdgeStyle['jumpStyle'] + ';';
+			}
+
+			if (this.currentEdgeStyle['jumpSize'] != null)
+			{
+				style += 'jumpSize=' + this.currentEdgeStyle['jumpSize'] + ';';
+			}
 			
 			// Special logic for custom property of elbowEdgeStyle
 			if (this.currentEdgeStyle['edgeStyle'] == 'elbowEdgeStyle' && this.currentEdgeStyle['elbow'] != null)

+ 39 - 10
war/js/mxgraph/Shapes.js

@@ -685,9 +685,20 @@
 				
 				if (this.isRounded)
 				{
-					var f = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE,
-						mxConstants.RECTANGLE_ROUNDING_FACTOR * 100) / 100;
-					var r = Math.min(w * f, h * f);
+					var r = 0;
+					
+					if (mxUtils.getValue(this.style, mxConstants.STYLE_ABSOLUTE_ARCSIZE, 0) == '1')
+					{
+						r = Math.min(w / 2, Math.min(h / 2, mxUtils.getValue(this.style,
+							mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2));
+					}
+					else
+					{
+						var f = mxUtils.getValue(this.style, mxConstants.STYLE_ARCSIZE,
+							mxConstants.RECTANGLE_ROUNDING_FACTOR * 100) / 100;
+						r = Math.min(w * f, h * f);
+					}
+					
 					c.moveTo(x + r, y);
 					c.lineTo(x + w - r, y);
 					c.quadTo(x + w, y, x + w, y + r);
@@ -2726,17 +2737,35 @@
 		{
 			return createHandle(state, [mxConstants.STYLE_ARCSIZE], function(bounds)
 			{
-				var arcSize = Math.max(0, parseFloat(mxUtils.getValue(state.style,
-					mxConstants.STYLE_ARCSIZE, mxConstants.RECTANGLE_ROUNDING_FACTOR * 100))) / 100;
 				var tmp = (yOffset != null) ? yOffset : bounds.height / 8;
 				
-				return new mxPoint(bounds.x + bounds.width - Math.min(Math.max(bounds.width / 2, bounds.height / 2),
-					Math.min(bounds.width, bounds.height) * arcSize), bounds.y + tmp);
+				if (mxUtils.getValue(state.style, mxConstants.STYLE_ABSOLUTE_ARCSIZE, 0) == '1')
+				{
+					var arcSize = mxUtils.getValue(state.style, mxConstants.STYLE_ARCSIZE, mxConstants.LINE_ARCSIZE) / 2;
+					
+					return new mxPoint(bounds.x + bounds.width - Math.min(bounds.width / 2, arcSize), bounds.y + tmp);
+				}
+				else
+				{
+					var arcSize = Math.max(0, parseFloat(mxUtils.getValue(state.style,
+						mxConstants.STYLE_ARCSIZE, mxConstants.RECTANGLE_ROUNDING_FACTOR * 100))) / 100;
+					
+					return new mxPoint(bounds.x + bounds.width - Math.min(Math.max(bounds.width / 2, bounds.height / 2),
+						Math.min(bounds.width, bounds.height) * arcSize), bounds.y + tmp);
+				}
 			}, function(bounds, pt, me)
 			{
-				var f = Math.min(50, Math.max(0, (bounds.width - pt.x + bounds.x) * 100 /
-					Math.min(bounds.width, bounds.height)));
-				this.state.style[mxConstants.STYLE_ARCSIZE] = Math.round(f);
+				if (mxUtils.getValue(state.style, mxConstants.STYLE_ABSOLUTE_ARCSIZE, 0) == '1')
+				{
+					this.state.style[mxConstants.STYLE_ARCSIZE] = Math.round(Math.max(0, Math.min(bounds.width,
+						(bounds.x + bounds.width - pt.x) * 2)));
+				}
+				else
+				{
+					var f = Math.min(50, Math.max(0, (bounds.width - pt.x + bounds.x) * 100 /
+						Math.min(bounds.width, bounds.height)));
+					this.state.style[mxConstants.STYLE_ARCSIZE] = Math.round(f);
+				}
 			});
 		}
 

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 368 - 358
war/js/reader.min.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 434 - 423
war/js/viewer.min.js


+ 5 - 0
war/plugins/trees/trees.js

@@ -9,6 +9,11 @@
  */
 Draw.loadPlugin(function(ui)
 {
+	if (ui.editor.chromeless)
+	{
+		return;
+	}
+	
 	var spacing = 10;
 	var level = 40;