Gaudenz Alder пре 5 година
родитељ
комит
a9a00f4944
33 измењених фајлова са 3573 додато и 3254 уклоњено
  1. 9 0
      ChangeLog
  2. 1 1
      VERSION
  3. 1 0
      etc/build/build.xml
  4. 24 23
      etc/mxgraph/mxClient.js
  5. 13 1
      src/main/java/com/mxgraph/online/GoogleAuthServlet.java
  6. 13 1
      src/main/java/com/mxgraph/online/MSGraphAuthServlet.java
  7. 1 0
      src/main/webapp/WEB-INF/google_client_redirect_uri
  8. 1 0
      src/main/webapp/WEB-INF/msgraph_client_redirect_uri
  9. 10 0
      src/main/webapp/WEB-INF/web.xml
  10. 1 1
      src/main/webapp/cache.manifest
  11. 1 1
      src/main/webapp/export3.html
  12. 0 1
      src/main/webapp/index.html
  13. 1679 1672
      src/main/webapp/js/app.min.js
  14. 58 4
      src/main/webapp/js/diagramly/App.js
  15. 22 163
      src/main/webapp/js/diagramly/Dialogs.js
  16. 12 1
      src/main/webapp/js/diagramly/DrawioFile.js
  17. 13 4
      src/main/webapp/js/diagramly/DrawioFileSync.js
  18. 39 18
      src/main/webapp/js/diagramly/DriveClient.js
  19. 33 41
      src/main/webapp/js/diagramly/Editor.js
  20. 229 1
      src/main/webapp/js/diagramly/EditorUi.js
  21. 11 0
      src/main/webapp/js/diagramly/GitHubFile.js
  22. 1 1
      src/main/webapp/js/diagramly/Menus.js
  23. 4 4
      src/main/webapp/js/diagramly/OneDriveClient.js
  24. 21 7
      src/main/webapp/js/diagramly/mxRuler.js
  25. 2 2
      src/main/webapp/js/diagramly/sidebar/Sidebar-Flowchart.js
  26. 3 3
      src/main/webapp/js/mxgraph/EditorUi.js
  27. 27 6
      src/main/webapp/js/mxgraph/Graph.js
  28. 1 1
      src/main/webapp/js/mxgraph/Sidebar.js
  29. 6 6
      src/main/webapp/js/shapes.min.js
  30. 1276 1270
      src/main/webapp/js/viewer.min.js
  31. 2 2
      src/main/webapp/resources/dia_fr.txt
  32. 55 11
      src/main/webapp/shapes/mxBasic.js
  33. 4 8
      src/main/webapp/styles/grapheditor.css

+ 9 - 0
ChangeLog

@@ -1,3 +1,12 @@
+14-OCT-2019: 12.1.1
+
+- Uses uncompressed XML files in GitLab and GitHub
+- Fixes background color for cropped PDF export
+- Improves logic for hiding cell moving guides
+- Fixes token override in Google Drive viewer
+- Adds roundtrip editing for PlantUML images
+- Uses mxGraph 4.0.3 beta 6
+
 09-OCT-2019: 12.1.0
 
 - Escape no longer starts editing in Safari and IE 11

+ 1 - 1
VERSION

@@ -1 +1 @@
-12.1.0
+12.1.1

+ 1 - 0
etc/build/build.xml

@@ -414,6 +414,7 @@
 			<classpath refid="javac.class.path" />
 		</javac>
 		<copy todir="${javac.dir}" file="${src.dir}/log4j.properties" />
+		<copy todir="${javac.dir}/com/mxgraph/io/gliffy/importer" file="${src.dir}/com/mxgraph/io/gliffy/importer/gliffyTranslation.properties" />
 	</target>
 
 	<target name="clean" description="Cleans build directories">

Разлика између датотеке није приказан због своје велике величине
+ 24 - 23
etc/mxgraph/mxClient.js


+ 13 - 1
src/main/java/com/mxgraph/online/GoogleAuthServlet.java

@@ -10,6 +10,7 @@ public class GoogleAuthServlet extends AbsAuthServlet
 {
 	public static String CLIENT_SECRET_FILE_PATH = "/WEB-INF/google_client_secret";
 	public static String CLIENT_ID_FILE_PATH = "/WEB-INF/google_client_id";
+	public static String CLIENT_REDIRECT_URI_FILE_PATH = "/WEB-INF/google_client_redirect_uri";
 	private static Config CONFIG = null;
 	
 	protected Config getConfig()
@@ -44,9 +45,20 @@ public class GoogleAuthServlet extends AbsAuthServlet
 				throw new RuntimeException("Client ID path invalid");
 			}
 			
+			try
+			{
+				CONFIG.REDIRECT_URI = Utils
+						.readInputStream(getServletContext()
+								.getResourceAsStream(CLIENT_REDIRECT_URI_FILE_PATH))
+						.replaceAll("\n", "");
+			}
+			catch (IOException e)
+			{
+				throw new RuntimeException("Client ID path invalid");
+			}
+			
 			CONFIG.AUTH_SERVICE_URL = "https://www.googleapis.com/oauth2/v4/token";
 			CONFIG.DEV_REDIRECT_URI = "https://test.draw.io/google";
-			CONFIG.REDIRECT_URI = "https://www.draw.io/google";
 		}
 		
 		return CONFIG;

+ 13 - 1
src/main/java/com/mxgraph/online/MSGraphAuthServlet.java

@@ -12,6 +12,7 @@ public class MSGraphAuthServlet extends AbsAuthServlet
 	public static String CLIENT_SECRET_FILE_PATH = "/WEB-INF/msgraph_client_secret";
 	public static String DEV_CLIENT_ID_FILE_PATH = "/WEB-INF/msgraph_dev_client_id";
 	public static String CLIENT_ID_FILE_PATH = "/WEB-INF/msgraph_client_id";
+	public static String CLIENT_REDIRECT_URI_FILE_PATH = "/WEB-INF/msgraph_client_redirect_uri";
 	
 	private static Config CONFIG = null;
 	
@@ -69,8 +70,19 @@ public class MSGraphAuthServlet extends AbsAuthServlet
 				throw new RuntimeException("Client ID invalid.");
 			}
 			
+			try
+			{
+				CONFIG.REDIRECT_URI = Utils
+						.readInputStream(getServletContext()
+								.getResourceAsStream(CLIENT_REDIRECT_URI_FILE_PATH))
+						.replaceAll("\n", "");
+			}
+			catch (IOException e)
+			{
+				throw new RuntimeException("Redirect Uri is invalid");
+			}
+			
 			CONFIG.DEV_REDIRECT_URI = "https://test.draw.io/microsoft";
-			CONFIG.REDIRECT_URI = "https://www.draw.io/microsoft";
 			CONFIG.AUTH_SERVICE_URL = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
 		}
 		

+ 1 - 0
src/main/webapp/WEB-INF/google_client_redirect_uri

@@ -0,0 +1 @@
+Replace_with_your_own_google_client_redirect_url

+ 1 - 0
src/main/webapp/WEB-INF/msgraph_client_redirect_uri

@@ -0,0 +1 @@
+Replace_with_your_own_microsoft_graph_client_redirect_uri

+ 10 - 0
src/main/webapp/WEB-INF/web.xml

@@ -129,6 +129,16 @@
     <servlet-name>GoogleAuthServlet</servlet-name>
     <url-pattern>/google</url-pattern>
   </servlet-mapping>
+  <servlet>
+    <description/>
+    <display-name>ConverterServlet</display-name>
+    <servlet-name>ConverterServlet</servlet-name>
+    <servlet-class>com.mxgraph.online.ConverterServlet</servlet-class>
+  </servlet>
+  <servlet-mapping>
+    <servlet-name>ConverterServlet</servlet-name>
+    <url-pattern>/convert</url-pattern>
+  </servlet-mapping>
   <servlet>
     <description/>
     <display-name>ExportProxyServlet</display-name>

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

@@ -1,7 +1,7 @@
 CACHE MANIFEST
 
 # THIS FILE WAS GENERATED. DO NOT MODIFY!
-# 10/09/2019 11:28 AM
+# 10/14/2019 01:46 PM
 
 app.html
 index.html?offline=1

+ 1 - 1
src/main/webapp/export3.html

@@ -325,7 +325,7 @@
 				}
 	
 				// Sets background color on page
-				if (bg != null && data.format != 'pdf')
+				if (bg != null && (data.format != 'pdf' || xmlDoc.documentElement.getAttribute('page') != '1'))
 				{
 					document.body.style.backgroundColor = bg;
 				}

+ 0 - 1
src/main/webapp/index.html

@@ -158,7 +158,6 @@
 
 			if (mxIsElectron5)
 			{
-				//TODO Remove unsafe-eval which requires removing dependency on eval in many parts of the code (stencils, styles, decoder, ...) 
 				addMeta(null, 'default-src \'self\' \'unsafe-inline\'; connect-src \'self\' https://*.draw.io; img-src * data:; media-src *; font-src *', 'Content-Security-Policy');
 			}
 		})();

Разлика између датотеке није приказан због своје велике величине
+ 1679 - 1672
src/main/webapp/js/app.min.js


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

@@ -1132,7 +1132,7 @@ App.prototype.init = function()
 		}));
 	}
 	
-	var createFooter = mxUtils.bind(this, function(label, link, className, closeHandler, helpLink)
+	var createFooter = mxUtils.bind(this, function(label, link, className, closeHandler, helpLink, clickHandler)
 	{
 		var footer = document.createElement('div');
 		footer.style.cssText = 'position:absolute;bottom:0px;max-width:90%;padding:10px;padding-right:26px;' +
@@ -1140,12 +1140,12 @@ App.prototype.init = function()
 		footer.className = className;
 
 		var icn = ((className == 'geStatusAlert') ? '<img src="' + mxClient.imageBasePath + '/warning.gif" border="0" ' +
-				'style="margin-top:-4px;margin-right:8px;margin-left:8px;" valign="middle"/>' : '');
+			'style="margin-top:-4px;margin-right:8px;margin-left:8px;" valign="middle"/>' : '');
 		
 		mxUtils.setPrefixedStyle(footer.style, 'transform', 'translate(-50%,110%)');
 		mxUtils.setPrefixedStyle(footer.style, 'transition', 'all 1s ease');
 		footer.style.whiteSpace = 'nowrap';
-		footer.innerHTML = '<a href="' + link +
+		footer.innerHTML = '<a href="' + ((link != null) ? link : 'javascript:void(0)') +
 			'" target="_blank" style="display:inline;text-decoration:none;font-weight:700;font-size:13px;opacity:1;">' +
 			icn + label + icn + '</a>' + ((helpLink != null) ? '<a href="' + helpLink +
 			'" target="_blank" style="display:inline;text-decoration:none;font-weight:700;font-size:13px;opacity:1;margin-right:8px;">Help</a>' : '');
@@ -1166,6 +1166,12 @@ App.prototype.init = function()
 			mxEvent.addListener(img, 'click', closeHandler);
 		}
 		
+		if (clickHandler != null)
+		{
+			footer.style.paddingRight = '40px';
+			mxEvent.addListener(footer, 'click', clickHandler);
+		}
+		
 		return footer;
 	});
 
@@ -1347,7 +1353,7 @@ App.prototype.init = function()
 			this.mode = App.mode;
 		}
 		
-		if (!mxClient.IS_CHROMEAPP && !EditorUi.isElectronApp && urlParams['embed'] != '1' &&
+		if (!mxClient.IS_CHROMEAPP && !EditorUi.isElectronApp && urlParams['embed'] != '1' && DrawioFile.SYNC == 'auto' &&
 			urlParams['local'] != '1' && urlParams['stealth'] != '1' && urlParams['offline'] != '1' &&
 			(!this.editor.chromeless || this.editor.editable))
 		{
@@ -1423,6 +1429,54 @@ App.prototype.init = function()
 						this.footerShowing = false;
 					}), 15000);
 				}
+				else if ((!isLocalStorage || mxSettings.settings == null ||
+					mxSettings.settings.closeRateFooter == null) &&
+					(!this.editor.chromeless || this.editor.editable) &&
+					!this.footerShowing && urlParams['open'] == null)
+				{
+					var star = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZ' +
+						'XdvcmtzIENTM5jWRgMAAAQRdEVYdFhNTDpjb20uYWRvYmUueG1wADw/eHBhY2tldCBiZWdpbj0iICAgIiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+Cjx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8i' +
+						'IHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDQuMS1jMDM0IDQ2LjI3Mjk3NiwgU2F0IEphbiAyNyAyMDA3IDIyOjExOjQxICAgICAgICAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDI' +
+						'vMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp4YXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iPgogICAgICAgICA8eGFwOkNyZW' +
+						'F0b3JUb29sPkFkb2JlIEZpcmV3b3JrcyBDUzM8L3hhcDpDcmVhdG9yVG9vbD4KICAgICAgICAgPHhhcDpDcmVhdGVEYXRlPjIwMDgtMDItMTdUMDI6MzY6NDVaPC94YXA6Q3JlYXRlRGF0ZT4KICAgICAgICAgPHhhcDpNb2RpZ' +
+						'nlEYXRlPjIwMDktMDMtMTdUMTQ6MTI6MDJaPC94YXA6TW9kaWZ5RGF0ZT4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOmRjPSJo' +
+						'dHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyI+CiAgICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2UvcG5nPC9kYzpmb3JtYXQ+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgo' +
+						'gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIC' +
+						'AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI' +
+						'CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIIImu8AAAAAVdEVYdENyZWF0aW9uIFRpbWUAMi8xNy8wOCCcqlgAAAHuSURBVDiNlZJBi1JRGIbfk+fc0ZuMXorJe4XujWoMdREaA23HICj6AQeLINr0C4I27ab2' +
+						'7VqOI9+q/sH8gMDceG1RkIwgClEXFMbRc5zTZgZURmG+5fu9PN/7Hg6wZohoh4h21nn4uqXW+q0xZgzg+SrPlTXX73uet+26bp6ICpcGaK1fua57M5vN3tZav7gUgIiSqVTqcRAEm0EQbCaTyQoRXb3Iy4hoG8CT6XSaY4xtMMa' +
+						'SQohMPp8v+r7vAEC3243CMGwqpfoApsaYE8uyfgM45ABOjDEvXdfNlMvlzFINAIDneY7neZVzvdlsDgaDQYtzfsjOIjtKqU+e5+0Wi0V3VV8ACMOw3+/3v3HOX0sp/7K53te11h/S6fRuoVAIhBAL76OUOm2320dRFH0VQuxJKf' +
+						'8BAFu+UKvVvpRKpWe2bYt5fTweq0ajQUKIN1LK43N94SMR0Y1YLLYlhBBKqQUw51wkEol7WmuzoC8FuJtIJLaUUoii6Ljb7f4yxpz6vp9zHMe2bfvacDi8BeDHKkBuNps5rVbr52QyaVuW9ZExttHpdN73ej0/Ho+nADxYCdBaV' +
+						'0aj0RGAz5ZlHUgpx2erR/V6/d1wOHwK4CGA/QsBnPN9AN+llH+WkqFare4R0QGAO/M6M8Ysey81/wGqa8MlVvHPNAAAAABJRU5ErkJggg==';
+					var rate = '<a style="cursor:default;" title="Please Rate Us"><b>Please Rate Us:</b></a>' +
+						'<img border="0" align="absmiddle" title="1 star" style="margin-top:-6px;cursor:pointer;margin-left:8px;" src="' + star + '">' +
+						'<img border="0" align="absmiddle" title="2 stars" style="margin-top:-6px;margin-left:3px;cursor:pointer;" src="' + star + '">' +
+						'<img border="0" align="absmiddle" title="3 stars" style="margin-top:-6px;margin-left:3px;cursor:pointer;" src="' + star + '">' +
+						'<img border="0" align="absmiddle" title="4 stars" style="margin-top:-6px;margin-left:3px;cursor:pointer;" src="' + star + '" ' +
+						'onclick="javascript:window.open(\'https://marketplace.atlassian.com/apps/1210933/draw-io-diagrams-for-confluence?hosting=cloud&tab=reviews\');">';
+					
+					var footer = createFooter(rate, null, 'geStatusMessage', null, null,
+						mxUtils.bind(this, function()
+						{
+							footer.parentNode.removeChild(footer);
+							this.hideFooter();
+
+							// Close permanently
+							if (isLocalStorage && mxSettings.settings != null)
+							{
+								mxSettings.settings.closeRateFooter = Date.now();
+								mxSettings.save();
+							}
+						}));
+					
+					document.body.appendChild(footer);
+					this.footerShowing = true;
+					
+					window.setTimeout(mxUtils.bind(this, function()
+					{
+						mxUtils.setPrefixedStyle(footer.style, 'transform', 'translate(-50%,0%)');
+					}), 1500);
+				}
 			}));
 		}
 	}

+ 22 - 163
src/main/webapp/js/diagramly/Dialogs.js

@@ -2054,182 +2054,41 @@ var ParseDialog = function(editorUi, title, defaultType)
 		
 		if (type == 'plantUmlPng' || type == 'plantUmlSvg' || type == 'plantUmlTxt')
 		{
-			var plantUmlServerUrl = (type == 'plantUmlTxt') ? PLANT_URL + '/txt/' :
-				((type == 'plantUmlPng') ? PLANT_URL + '/png/' : PLANT_URL + '/svg/');
-			var graph = editorUi.editor.graph;
-
-			// TODO: Change server to return base64 and accept POST request
 			if (editorUi.spinner.spin(document.body, mxResources.get('inserting')))
 			{
-				function encode64(data)
-				{
-					r = "";
-					
-					for (i = 0; i < data.length; i += 3)
-					{
-						if (i + 2 == data.length)
-						{
-							r += append3bytes(data.charCodeAt(i), data.charCodeAt(i + 1), 0);
-						}
-						else if (i + 1 == data.length)
-						{
-							r += append3bytes(data.charCodeAt(i), 0, 0);
-						}
-						else
-						{
-							r += append3bytes(data.charCodeAt(i), data.charCodeAt(i + 1),
-								data.charCodeAt(i + 2));
-						}
-					}
-					
-					return r;
-				}
-
-				function append3bytes(b1, b2, b3)
-				{
-					c1 = b1 >> 2;
-					c2 = ((b1 & 0x3) << 4) | (b2 >> 4);
-					c3 = ((b2 & 0xF) << 2) | (b3 >> 6);
-					c4 = b3 & 0x3F;
-					r = "";
-					r += encode6bit(c1 & 0x3F);
-					r += encode6bit(c2 & 0x3F);
-					r += encode6bit(c3 & 0x3F);
-					r += encode6bit(c4 & 0x3F);
-					
-					return r;
-				}
-
-				function encode6bit(b)
+				var graph = editorUi.editor.graph;
+				var format = (type == 'plantUmlTxt') ? 'txt' :
+					((type == 'plantUmlPng') ? 'png' : 'svg');
+				editorUi.generatePlantUmlImage(text, format, function(data, w, h)
 				{
-					if (b < 10)
-					{
-						return String.fromCharCode(48 + b);
-					}
-					
-					b -= 10;
-					
-					if (b < 26)
-					{
-						return String.fromCharCode(65 + b);
-					}
-					
-					b -= 26;
-					
-					if (b < 26)
-					{
-						return String.fromCharCode(97 + b);
-					}
-					
-					b -= 26;
+					editorUi.spinner.stop();
+					var cell = null;
 					
-					if (b == 0)
+					graph.getModel().beginUpdate();
+					try
 					{
-						return '-';
+						cell = (format == 'txt') ?
+							editorUi.insertAsPreText(data, insertPoint.x, insertPoint.y) :
+							graph.insertVertex(null, null, null, insertPoint.x, insertPoint.y,
+								w, h, 'shape=image;noLabel=1;verticalAlign=top;aspect=fixed;imageAspect=0;' +
+								'image=' + editorUi.convertDataUri(data) + ';')
+						graph.setAttributeForCell(cell, 'plantUmlData',
+							JSON.stringify({data: text, format: format}));
 					}
-					
-					if (b == 1)
+					finally
 					{
-						return '_';
+						graph.getModel().endUpdate();
 					}
 					
-					return '?';
-				}
-
-				// TODO: Remove unescape, use btoa for compatibility with graph.compress
-				function compress(s)
-				{
-					return encode64(pako.deflateRaw(s, { to : 'string' }));
-				};
-
-				var xhr = new XMLHttpRequest();
-				xhr.open('GET', plantUmlServerUrl + compress(text), true);
-
-				if (type != 'plantUmlTxt')
-				{
-					xhr.responseType = 'blob';
-				}
-
-				xhr.onload = function(e)
-				{
-					if (this.status >= 200 && this.status < 300)
+					if (cell != null)
 					{
-						if (type == 'plantUmlTxt')
-						{
-							editorUi.spinner.stop();
-							graph.setSelectionCell(editorUi.insertAsPreText(
-								this.response, insertPoint.x, insertPoint.y));
-							graph.scrollCellToVisible(graph.getSelectionCell());
-						}
-						else
-						{
-							var reader = new FileReader();
-							reader.readAsDataURL(this.response);
-
-							reader.onloadend = function(e)
-							{
-								var img = new Image();
-
-								img.onload = function()
-								{
-									editorUi.spinner.stop();
-									var w = img.width;
-									var h = img.height;
-
-									// Workaround for 0 image size in IE11
-									if (w == 0 && h == 0)
-									{
-										var data = reader.result;
-										var comma = data.indexOf(',');
-										var svgText = decodeURIComponent(escape(atob(data.substring(comma + 1))));
-										var root = mxUtils.parseXml(svgText);
-										var svgs = root.getElementsByTagName('svg');
-
-										if (svgs.length > 0)
-										{
-											w = parseFloat(svgs[0].getAttribute('width'));
-											h = parseFloat(svgs[0].getAttribute('height'));
-										}
-									}
-
-									graph.getModel().beginUpdate();
-									try
-									{
-										cell = graph.insertVertex(null, null, text, insertPoint.x, insertPoint.y,
-											w, h, 'shape=image;noLabel=1;verticalAlign=top;aspect=fixed;imageAspect=0;' +
-											'image=' + editorUi.convertDataUri(reader.result) + ';');
-									}
-									finally
-									{
-										graph.getModel().endUpdate();
-									}
-
-									graph.setSelectionCell(cell);
-									graph.scrollCellToVisible(graph.getSelectionCell());
-								};
-
-								img.src = reader.result;
-							};
-
-							reader.onerror = function(e)
-							{
-								editorUi.handleError(e);
-							};
-						}
-					}
-					else
-					{
-						editorUi.spinner.stop();
-						editorUi.handleError(e);
+						graph.setSelectionCell(cell);
+						graph.scrollCellToVisible(cell);
 					}
-				};
-
-				xhr.onerror = function(e)
+				}, function(err)
 				{
 					editorUi.handleError(e);
-				};
-
-				xhr.send();
+				});
 			}
 		}
 		else if (type == 'table')

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

@@ -840,6 +840,17 @@ DrawioFile.prototype.updateFileData = function()
 	this.setData(this.ui.getFileData(null, null, null, null, null, null, null, null, this, !this.isCompressed()));
 };
 
+/**
+ * Translates this point by the given vector.
+ * 
+ * @param {number} dx X-coordinate of the translation.
+ * @param {number} dy Y-coordinate of the translation.
+ */
+DrawioFile.prototype.isCompressedStorage = function()
+{
+	return true;
+};
+
 /**
  * Translates this point by the given vector.
  * 
@@ -856,7 +867,7 @@ DrawioFile.prototype.isCompressed = function()
 	}
 	else
 	{
-		return Editor.compressXml;
+		return this.isCompressedStorage() && Editor.compressXml;
 	}
 };
 

+ 13 - 4
src/main/webapp/js/diagramly/DrawioFileSync.js

@@ -135,6 +135,11 @@ DrawioFileSync = function(file)
 			}
 			catch (e)
 			{
+				this.file.redirectToNewApp(mxUtils.bind(this, function()
+				{
+					// Callback adds cancel option
+				}));
+				
 				if (window.console != null && urlParams['test'] == '1')
 				{
 					console.log(e);
@@ -684,14 +689,15 @@ DrawioFileSync.prototype.updateDescriptor = function(desc)
  */
 DrawioFileSync.prototype.catchup = function(desc, success, error, abort)
 {
-	if (abort == null || !abort())
+	if (desc != null && (abort == null || !abort()))
 	{
-		var secret = this.file.getDescriptorSecret(desc);
 		var etag = this.file.getDescriptorRevisionId(desc);
 		var current = this.file.getCurrentRevisionId();
 		
 		if (current == etag)
 		{
+			this.file.patchDescriptor(this.file.getDescriptor(), desc);
+			
 			if (success != null)
 			{
 				success();
@@ -706,6 +712,8 @@ DrawioFileSync.prototype.catchup = function(desc, success, error, abort)
 		}
 		else
 		{
+			var secret = this.file.getDescriptorSecret(desc);
+			
 			// Cache entry may not have been uploaded to cache before new
 			// etag is visible to client so retry once after cache miss
 			var cacheReadyRetryCount = 0;
@@ -913,6 +921,7 @@ DrawioFileSync.prototype.merge = function(patches, checksum, desc, success, erro
 			{
 				EditorUi.debug('Sync.merge', [this],
 					'from', this.file.getCurrentRevisionId(), 'to', etag,
+					'etag', this.file.getDescriptorEtag(desc),
 					'backup', this.file.backupPatch,
 					'attempt', this.catchupRetryCount,
 					'patches', patches,
@@ -1113,8 +1122,8 @@ DrawioFileSync.prototype.fileSaved = function(pages, lastDesc, success, error)
 			if (urlParams['test'] == '1')
 			{
 				EditorUi.debug('Sync.fileSaved', [this],
-					'from', etag, 'to', current, data.length,
-					'bytes', 'diff', diff, 'checksum', checksum);
+					'from', etag, 'to', current, 'etag', this.file.getCurrentEtag(),
+					data.length, 'bytes', 'diff', diff, 'checksum', checksum);
 			}
 			
 			// Logs successull diff

+ 39 - 18
src/main/webapp/js/diagramly/DriveClient.js

@@ -8,23 +8,6 @@ DriveClient = function(editorUi)
 	
 	DrawioClient.call(this, editorUi, 'gDriveAuthInfo');
 
-	var authInfo = JSON.parse(this.token);
-	
-	if (authInfo != null && authInfo.current != null)
-	{
-		authInfo = authInfo.current;
-		
-		this.userId = authInfo.userId;
-		this.token = authInfo.access_token;
-		
-		var remainingTime = (authInfo.expires - Date.now()) / 1000;
-		
-		authInfo.expires_in = remainingTime < 600? 1 : remainingTime; //10 min tolerance window in case of any rounding errors
-		this.resetTokenRefresh(authInfo);
-
-		this.authCalled = false;
-	}
-	
 	/**
 	 * Holds a reference to the UI. Needed for the sharing client.
 	 */
@@ -37,6 +20,10 @@ DriveClient = function(editorUi)
 	// Reading files now possible with no initial click in drive
 	if (this.ui.editor.chromeless && !this.ui.editor.editable && urlParams['rt'] != '1')
 	{
+		// Uses separate name for the viewer auth tokens
+		this.cookieName = 'gDriveViewerAuthInfo';
+		this.token = this.getPersistentToken();
+		
 		this.appId = window.DRAWIO_GOOGLE_VIEWER_APP_ID || '850530949725';
 		this.clientId = window.DRAWIO_GOOGLE_VIEWER_CLIENT_ID || '850530949725.apps.googleusercontent.com';
 		this.scopes = ['https://www.googleapis.com/auth/drive.readonly',
@@ -57,6 +44,23 @@ DriveClient = function(editorUi)
 	{
 		this.scopes.push('https://www.googleapis.com/auth/photos.upload');
 	}
+	
+	var authInfo = JSON.parse(this.token);
+	
+	if (authInfo != null && authInfo.current != null)
+	{
+		authInfo = authInfo.current;
+		
+		this.userId = authInfo.userId;
+		this.token = authInfo.access_token;
+		
+		var remainingTime = (authInfo.expires - Date.now()) / 1000;
+		
+		authInfo.expires_in = remainingTime < 600? 1 : remainingTime; //10 min tolerance window in case of any rounding errors
+		this.resetTokenRefresh(authInfo);
+
+		this.authCalled = false;
+	}
 };
 
 // Extends mxEventSource
@@ -65,7 +69,7 @@ mxUtils.extend(DriveClient, mxEventSource);
 // Extends DrawioClient
 mxUtils.extend(DriveClient, DrawioClient);
 
-DriveClient.prototype.redirectUri = 'https://' + window.location.hostname + '/google';
+DriveClient.prototype.redirectUri = window.location.protocol + '//' + window.location.host + '/google';
 DriveClient.prototype.GDriveBaseUrl = 'https://www.googleapis.com/drive/v2';
 
 /**
@@ -1547,6 +1551,15 @@ DriveClient.prototype.saveFile = function(file, revision, success, errFn, noChec
 															}
 															else
 															{
+
+																if (urlParams['test'] == '1' && resp.headRevisionId == head0)
+																{
+																	EditorUi.debug('DriveClient: Remote Etag Changed',
+																		'local', etag, 'remote', resp.etag,
+																		'rev', file.desc.headRevisionId,
+																		'response', [resp], 'file', [file]);
+																}
+																
 																error(err, resp);
 															}
 														}
@@ -1593,6 +1606,14 @@ DriveClient.prototype.saveFile = function(file, revision, success, errFn, noChec
 											// Checks head revision ID and updates etag or returns conflict
 											if (desc2 != null && desc2.headRevisionId == head0)
 											{
+												if (urlParams['test'] == '1' && etag != desc2.etag)
+												{
+													EditorUi.debug('DriveClient: Preflight Etag Update',
+														'from', etag, 'to', desc2.etag,
+														'rev', file.desc.headRevisionId,
+														'response', [desc2], 'file', [file]);
+												}
+												
 												etag = desc2.etag;
 												doExecuteSave(realOverwrite);
 											}

+ 33 - 41
src/main/webapp/js/diagramly/Editor.js

@@ -363,7 +363,37 @@
 		'Edward Morrison,Brand Manager,emo,Office 2,Evan Miller,me@example.com,#d5e8d4,#82b366,,https://www.draw.io,https://cdn3.iconfinder.com/data/icons/user-avatars-1/512/users-10-3-128.png\n' +
 		'Ron Donovan,System Admin,rdo,Office 3,Evan Miller,me@example.com,#d5e8d4,#82b366,"emo,tva",https://www.draw.io,https://cdn3.iconfinder.com/data/icons/user-avatars-1/512/users-2-128.png\n' +
 		'Tessa Valet,HR Director,tva,Office 4,Evan Miller,me@example.com,#d5e8d4,#82b366,,https://www.draw.io,https://cdn3.iconfinder.com/data/icons/user-avatars-1/512/users-3-128.png\n';
-	
+
+	/**
+	 * Compresses the given string.
+	 */
+	Editor.fastCompress = function(data)
+	{
+		if (data == null || data.length == 0 || typeof(pako) === 'undefined')
+		{
+			return data;
+		}
+		else
+		{
+			return pako.deflateRaw(data, {to: 'string'});
+		}
+	};
+
+	/**
+	 * Decompresses the given string.
+	 */
+	Editor.fastDecompress = function(data)
+	{
+	   	if (data == null || data.length == 0 || typeof(pako) === 'undefined')
+		{
+			return data;
+		}
+		else
+		{
+			return pako.inflateRaw(data, {to: 'string'});
+		}
+	};
+
 	/**
 	 * Helper function to extract the graph model XML node.
 	 */
@@ -553,8 +583,8 @@
 					if (value.substring(0, idx) == 'mxGraphModel')
 					{
 						// Workaround for Java URL Encoder using + for spaces, which isn't compatible with JS
-						var xmlData = pako.inflateRaw(
-							value.substring(idx + 2), { to : 'string' }).replace(/\+/g,' ');
+						var xmlData = pako.inflateRaw(value.substring(idx + 2),
+							{to: 'string'}).replace(/\+/g,' ');
 						
 						if (xmlData != null && xmlData.length > 0)
 						{
@@ -4530,44 +4560,6 @@
 		}
 	};
 
-	/**
-	 * Returns a base64 encoded version of the compressed string.
-	 */
-	Graph.compress = function(data, deflate)
-	{
-		if (data == null || data.length == 0 || typeof(pako) === 'undefined')
-		{
-			return data;
-		}
-		else
-		{
-	   		var tmp = (deflate) ? pako.deflate(encodeURIComponent(data), { to : 'string' }) :
-	   			pako.deflateRaw(encodeURIComponent(data),  { to : 'string' });
-	   		
-	   		return (window.btoa) ? btoa(tmp) : Base64.encode(tmp, true);
-		}
-	};
-
-	/**
-	 * Returns a decompressed version of the base64 encoded string.
-	 */
-	Graph.decompress = function(data, inflate)
-	{
-	   	if (data == null || data.length == 0 || typeof(pako) === 'undefined')
-		{
-			return data;
-		}
-		else
-		{
-			var tmp = (window.atob) ? atob(data) : Base64.decode(data, true);
-			
-   			var inflated = (inflate) ? pako.inflate(tmp,  { to : 'string' }) :
-				pako.inflateRaw(tmp,  { to : 'string' })
-
-			return Graph.zapGremlins(decodeURIComponent(inflated));
-		}
-	};
-
 	/**
 	 * Specifies special libraries that are loaded via dynamic JS. Add cases
 	 * where the filename cannot be worked out from the package name. The

+ 229 - 1
src/main/webapp/js/diagramly/EditorUi.js

@@ -7254,6 +7254,167 @@
 		}
 	};
 
+	/**
+	 * Generates a plant UML image. Possible types are svg, png and txt.
+	 */
+	EditorUi.prototype.generatePlantUmlImage = function(data, type, success, error)
+	{	
+		function encode64(data)
+		{
+			r = "";
+			
+			for (i = 0; i < data.length; i += 3)
+			{
+				if (i + 2 == data.length)
+				{
+					r += append3bytes(data.charCodeAt(i), data.charCodeAt(i + 1), 0);
+				}
+				else if (i + 1 == data.length)
+				{
+					r += append3bytes(data.charCodeAt(i), 0, 0);
+				}
+				else
+				{
+					r += append3bytes(data.charCodeAt(i), data.charCodeAt(i + 1),
+						data.charCodeAt(i + 2));
+				}
+			}
+			
+			return r;
+		}
+
+		function append3bytes(b1, b2, b3)
+		{
+			c1 = b1 >> 2;
+			c2 = ((b1 & 0x3) << 4) | (b2 >> 4);
+			c3 = ((b2 & 0xF) << 2) | (b3 >> 6);
+			c4 = b3 & 0x3F;
+			r = "";
+			r += encode6bit(c1 & 0x3F);
+			r += encode6bit(c2 & 0x3F);
+			r += encode6bit(c3 & 0x3F);
+			r += encode6bit(c4 & 0x3F);
+			
+			return r;
+		}
+
+		function encode6bit(b)
+		{
+			if (b < 10)
+			{
+				return String.fromCharCode(48 + b);
+			}
+			
+			b -= 10;
+			
+			if (b < 26)
+			{
+				return String.fromCharCode(65 + b);
+			}
+			
+			b -= 26;
+			
+			if (b < 26)
+			{
+				return String.fromCharCode(97 + b);
+			}
+			
+			b -= 26;
+			
+			if (b == 0)
+			{
+				return '-';
+			}
+			
+			if (b == 1)
+			{
+				return '_';
+			}
+			
+			return '?';
+		}
+
+		// TODO: Remove unescape, use btoa for compatibility with graph.compress
+		function compress(s)
+		{
+			return encode64(pako.deflateRaw(s, { to : 'string' }));
+		};
+
+		var plantUmlServerUrl = (type == 'txt') ? PLANT_URL + '/txt/' :
+			((type == 'png') ? PLANT_URL + '/png/' : PLANT_URL + '/svg/');
+		
+		var xhr = new XMLHttpRequest();
+		xhr.open('GET', plantUmlServerUrl + compress(data), true);
+
+		if (type != 'txt')
+		{
+			xhr.responseType = 'blob';
+		}
+
+		xhr.onload = function(e)
+		{
+			if (this.status >= 200 && this.status < 300)
+			{
+				if (type == 'txt')
+				{
+					success(this.response);
+				}
+				else
+				{
+					var reader = new FileReader();
+					reader.readAsDataURL(this.response);
+
+					reader.onloadend = function(e)
+					{
+						var img = new Image();
+
+						img.onload = function()
+						{
+							var w = img.width;
+							var h = img.height;
+
+							// Workaround for 0 image size in IE11
+							if (w == 0 && h == 0)
+							{
+								var data = reader.result;
+								var comma = data.indexOf(',');
+								var svgText = decodeURIComponent(escape(atob(data.substring(comma + 1))));
+								var root = mxUtils.parseXml(svgText);
+								var svgs = root.getElementsByTagName('svg');
+
+								if (svgs.length > 0)
+								{
+									w = parseFloat(svgs[0].getAttribute('width'));
+									h = parseFloat(svgs[0].getAttribute('height'));
+								}
+							}
+							
+							success(reader.result, w, h);
+						};
+
+						img.src = reader.result;
+					};
+
+					reader.onerror = function(e)
+					{
+						error(e);
+					};
+				}
+			}
+			else
+			{
+				error(e);
+			}
+		};
+
+		xhr.onerror = function(e)
+		{
+			error(e);
+		};
+
+		xhr.send();
+	};
+
 	/**
 	 * Inserts the given text as a preformatted HTML text.
 	 */
@@ -7266,7 +7427,7 @@
 		try
 		{
 			cell = graph.insertVertex(null, null, '<pre>' + text + '</pre>',
-				x, y, 1, 1, 'text;html=1;align=center;verticalAlign=middle;');
+				x, y, 1, 1, 'text;html=1;align=left;verticalAlign=top;');
 			graph.updateCellSize(cell, true);
 		}
 		finally
@@ -8626,6 +8787,73 @@
 		var ui = this;
 		var graph = this.editor.graph;
 		
+		// Overrides function to add editing for Plant UML.
+		var cellEditorStartEditing = graph.cellEditor.startEditing;
+		
+		graph.cellEditor.startEditing = function(cell, trigger)
+		{
+			var data = this.graph.getAttributeForCell(cell, 'plantUmlData');
+			
+			if (data != null)
+			{
+				var obj = JSON.parse(data);
+				
+		    	var dlg = new TextareaDialog(ui, mxResources.get('plantUml') + ':',
+		    		obj.data, function(text)
+				{
+		    		if (text != null)
+					{
+		    			if (ui.spinner.spin(document.body, mxResources.get('inserting')))
+		    			{
+		    				ui.generatePlantUmlImage(text, obj.format, function(data, w, h)
+		    				{
+		    					ui.spinner.stop();
+
+		    					graph.getModel().beginUpdate();
+		    					try
+		    					{
+		    						if (obj.format == 'txt')
+			    					{
+			    						graph.labelChanged(cell, '<pre>' + data + '</pre>');
+			    						graph.updateCellSize(cell, true);
+			    					}
+		    						else
+		    						{
+		    							graph.setCellStyles('image', ui.convertDataUri(data), [cell]);
+		    							var geo = graph.model.getGeometry(cell);
+		    							
+		    							if (geo != null)
+		    							{
+		    								geo = geo.clone();
+		    								geo.width = w;
+		    								geo.height = h;
+		    								graph.cellsResized([cell], [geo], false);
+		    							}
+		    						}
+		    						
+		    						graph.setAttributeForCell(cell, 'plantUmlData',
+			    						JSON.stringify({data: text, format: obj.format}));
+		    					}
+		    					finally
+		    					{
+		    						graph.getModel().endUpdate();
+		    					}
+		    				}, function(err)
+		    				{
+		    					ui.handleError(e);
+		    				});
+		    			}
+					}
+				}, null, null, 400, 220);
+				ui.showDialog(dlg.container, 420, 300, true, true);
+				dlg.init();
+			}
+			else
+			{
+				cellEditorStartEditing.apply(this, arguments);
+			}
+		};
+		
 		// Redirects custom link title via UI for page links
 		graph.getLinkTitle = function(href)
 		{

+ 11 - 0
src/main/webapp/js/diagramly/GitHubFile.js

@@ -117,6 +117,17 @@ GitHubFile.prototype.getLatestVersion = function(success, error)
 	this.peer.getFile(this.getId(), success, error);
 };
 
+/**
+ * Translates this point by the given vector.
+ * 
+ * @param {number} dx X-coordinate of the translation.
+ * @param {number} dy Y-coordinate of the translation.
+ */
+GitHubFile.prototype.isCompressedStorage = function()
+{
+	return false;
+};
+
 /**
  * Hook for subclassers to update the descriptor from given file
  */

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

@@ -713,7 +713,7 @@
 		editorUi.actions.addAction('feedback...', function()
 		{
 			var dlg = new FeedbackDialog(editorUi);
-			editorUi.showDialog(dlg.container, 610, 360, true, true);
+			editorUi.showDialog(dlg.container, 610, 360, true, false);
 			dlg.init();
 		});
 

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

@@ -27,8 +27,8 @@ mxUtils.extend(OneDriveClient, DrawioClient);
  * LATER: If thumbnails are disabled, make sure to replace the
  * existing thumbnail with the placeholder only once.
  */
-OneDriveClient.prototype.clientId = (window.location.hostname == 'test.draw.io') ?
-	'2e598409-107f-4b59-89ca-d7723c8e00a4' : '45c10911-200f-4e27-a666-9e9fca147395';
+OneDriveClient.prototype.clientId = window.DRAWIO_MSGRAPH_CLIENT_ID || ((window.location.hostname == 'test.draw.io') ?
+	'2e598409-107f-4b59-89ca-d7723c8e00a4' : '45c10911-200f-4e27-a666-9e9fca147395');
 
 /**
  * OAuth 2.0 scopes for installing Drive Apps.
@@ -38,8 +38,8 @@ OneDriveClient.prototype.scopes = 'user.read files.readwrite.all offline_access'
 /**
  * OAuth 2.0 scopes for installing Drive Apps.
  */
-OneDriveClient.prototype.redirectUri = 'https://' + window.location.hostname + '/microsoft';
-OneDriveClient.prototype.pickerRedirectUri = 'https://' + window.location.hostname + '/onedrive3.html';
+OneDriveClient.prototype.redirectUri = window.location.protocol + '//' + window.location.host + '/microsoft';
+OneDriveClient.prototype.pickerRedirectUri = window.location.protocol + '//' + window.location.host + '/onedrive3.html';
 
 /**
  * This is the default endpoint for personal accounts

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

@@ -341,9 +341,16 @@ function mxRuler(editorUi, unit, isVertical, isSecondery)
 		{
 			if (ruler.guidePart != null)
 			{
-				ctx.putImageData(ruler.guidePart.imgData1, ruler.guidePart.x1, ruler.guidePart.y1);	
-				ctx.putImageData(ruler.guidePart.imgData2, ruler.guidePart.x2, ruler.guidePart.y2);	
-				ctx.putImageData(ruler.guidePart.imgData3, ruler.guidePart.x3, ruler.guidePart.y3);	
+				try
+				{
+					ctx.putImageData(ruler.guidePart.imgData1, ruler.guidePart.x1, ruler.guidePart.y1);	
+					ctx.putImageData(ruler.guidePart.imgData2, ruler.guidePart.x2, ruler.guidePart.y2);	
+					ctx.putImageData(ruler.guidePart.imgData3, ruler.guidePart.x3, ruler.guidePart.y3);
+				}
+				catch (e)
+				{
+					// ignore
+				}
 			}
 			
 			ret = ruler.origGuideMove.apply(this, arguments);
@@ -421,10 +428,17 @@ function mxRuler(editorUi, unit, isVertical, isSecondery)
 		
 		if (ruler.guidePart != null)
 		{
-			ctx.putImageData(ruler.guidePart.imgData1, ruler.guidePart.x1, ruler.guidePart.y1);	
-			ctx.putImageData(ruler.guidePart.imgData2, ruler.guidePart.x2, ruler.guidePart.y2);	
-			ctx.putImageData(ruler.guidePart.imgData3, ruler.guidePart.x3, ruler.guidePart.y3);
-			ruler.guidePart = null;
+			try
+			{
+				ctx.putImageData(ruler.guidePart.imgData1, ruler.guidePart.x1, ruler.guidePart.y1);	
+				ctx.putImageData(ruler.guidePart.imgData2, ruler.guidePart.x2, ruler.guidePart.y2);	
+				ctx.putImageData(ruler.guidePart.imgData3, ruler.guidePart.x3, ruler.guidePart.y3);
+				ruler.guidePart = null;
+			}
+			catch (e)
+			{
+				// ignore
+			}
 		}
 		
 		return ret;

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

@@ -12,8 +12,8 @@
 		
 		this.addPaletteFunctions('flowchart', mxResources.get('flowchart'), false,
 		[
-			this.createVertexTemplateEntry(s + 'annotation_1;align=left;pointerEvents=1;connectable=0;', w * 0.5, h, '', 'Annotation', null, null, this.getTagsForStencil(gn, 'annotation_1', dt).join(' ')),
-			this.createVertexTemplateEntry(s + 'annotation_2;align=left;labelPosition=right;pointerEvents=1;connectable=0;', w * 0.5, h, '', 'Annotation', null, null, this.getTagsForStencil(gn, 'annotation_2', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'annotation_1;align=left;pointerEvents=1;', w * 0.5, h, '', 'Annotation', null, null, this.getTagsForStencil(gn, 'annotation_1', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'annotation_2;align=left;labelPosition=right;pointerEvents=1;', w * 0.5, h, '', 'Annotation', null, null, this.getTagsForStencil(gn, 'annotation_2', dt).join(' ')),
 			this.createVertexTemplateEntry(s3 + 'card;whiteSpace=wrap;size=20;arcSize=12;', w, h * 0.6, '', 'Card', null, null, this.getTagsForStencil(gn, 'card', dt).join(' ')),
 			this.createVertexTemplateEntry(s2 + 'collate;', w, h, '', 'Collate', null, null, this.getTagsForStencil(gn, 'collate', dt).join(' ')),
 			this.createVertexTemplateEntry('shape=parallelogram;html=1;strokeWidth=2;perimeter=parallelogramPerimeter;whiteSpace=wrap;rounded=1;arcSize=12;size=0.23;', w, h * 0.6, '', 'Data', null, null, this.getTagsForStencil(gn, 'data', dt).join(' ')),

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

@@ -972,7 +972,7 @@ EditorUi.compactUi = true;
 EditorUi.prototype.splitSize = (mxClient.IS_TOUCH || mxClient.IS_POINTER) ? 12 : 8;
 
 /**
- * Specifies the height of the menubar. Default is 34.
+ * Specifies the height of the menubar. Default is 30.
  */
 EditorUi.prototype.menubarHeight = 30;
 
@@ -1013,12 +1013,12 @@ EditorUi.prototype.hsplitPosition = (screen.width <= 640) ? 118 : ((urlParams['s
 EditorUi.prototype.allowAnimation = true;
 
 /**
- * Specifies if animations are allowed in <executeLayout>. Default is true.
+ * Default is 2.
  */
 EditorUi.prototype.lightboxMaxFitScale = 2;
 
 /**
- * Specifies if animations are allowed in <executeLayout>. Default is true.
+ * Default is 4.
  */
 EditorUi.prototype.lightboxVerticalDivider = 4;
 

+ 27 - 6
src/main/webapp/js/mxgraph/Graph.js

@@ -1102,8 +1102,8 @@ Graph.compress = function(data, deflate)
 	}
 	else
 	{
-   		var tmp = Graph.bytesToString((deflate) ? pako.deflate(encodeURIComponent(data)) :
-   			pako.deflateRaw(encodeURIComponent(data)));
+   		var tmp = (deflate) ? pako.deflate(encodeURIComponent(data), {to: 'string'}) :
+   			pako.deflateRaw(encodeURIComponent(data), {to: 'string'});
    		
    		return (window.btoa) ? btoa(tmp) : Base64.encode(tmp, true);
 	}
@@ -1122,9 +1122,10 @@ Graph.decompress = function(data, inflate)
 	{
 		var tmp = (window.atob) ? atob(data) : Base64.decode(data, true);
 		
-		return Graph.zapGremlins(decodeURIComponent(
-			Graph.bytesToString((inflate) ? pako.inflate(tmp) :
-				pako.inflateRaw(tmp))));
+		var inflated = (inflate) ? pako.inflate(tmp, {to: 'string'}) :
+			pako.inflateRaw(tmp, {to: 'string'})
+
+		return Graph.zapGremlins(decodeURIComponent(inflated));
 	}
 };
 
@@ -8577,7 +8578,8 @@ if (typeof mxVertexHandler != 'undefined')
 				{
 					var state = this.graph.view.getState(cells[0]);
 					
-					if (state != null && state.width < 2 && state.height < 2 && state.text != null && state.text.boundingBox != null)
+					if (state != null && state.width < 2 && state.height < 2 && state.text != null &&
+						state.text.boundingBox != null)
 					{
 						return mxRectangle.fromRectangle(state.text.boundingBox);
 					}
@@ -8586,7 +8588,26 @@ if (typeof mxVertexHandler != 'undefined')
 			
 			return mxGraphHandlerGetBoundingBox.apply(this, arguments);
 		};
+
+		// Ignores child cells with part style as guides
+		var mxGraphHandlerGetGuideStates = mxGraphHandler.prototype.getGuideStates;
 		
+		mxGraphHandler.prototype.getGuideStates = function()
+		{
+			var states = mxGraphHandlerGetGuideStates.apply(this, arguments);
+			var result = [];
+			
+			for (var i = 0; i < states.length; i++)
+			{
+				if (mxUtils.getValue(states[i].style, 'part', '0') != '1')
+				{
+					result.push(states[i]);
+				}
+			}
+			
+			return result;
+		};
+
 		// Uses text bounding box for edge labels
 		var mxVertexHandlerGetSelectionBounds = mxVertexHandler.prototype.getSelectionBounds;
 		mxVertexHandler.prototype.getSelectionBounds = function(state)

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

@@ -1806,7 +1806,7 @@ Sidebar.prototype.addBpmnPalette = function(dir, expand)
 	 	this.createVertexTemplateEntry('shape=mxgraph.bpmn.business_rule_task;html=1;outlineConnect=0;', 14, 14, '', 'Business Rule Task', null, null, this.getTagsForStencil('mxgraph.bpmn', 'business_rule_task').join(' ')),
 	 	this.createVertexTemplateEntry('shape=mxgraph.bpmn.service_task;html=1;outlineConnect=0;', 14, 14, '', 'Service Task', null, null, this.getTagsForStencil('mxgraph.bpmn', 'service_task').join(' ')),
 	 	this.createVertexTemplateEntry('shape=mxgraph.bpmn.script_task;html=1;outlineConnect=0;', 14, 14, '', 'Script Task', null, null, this.getTagsForStencil('mxgraph.bpmn', 'script_task').join(' ')),
-		this.createVertexTemplateEntry('html=1;shape=mxgraph.flowchart.annotation_2;align=left;labelPosition=right;connectable=0;', 50, 100, '', 'Annotation', null, null, this.getTagsForStencil('bpmn', 'annotation_1', 'bpmn business process model ').join(' ')),
+		this.createVertexTemplateEntry('html=1;shape=mxgraph.flowchart.annotation_2;align=left;labelPosition=right;', 50, 100, '', 'Annotation', null, null, this.getTagsForStencil('bpmn', 'annotation_1', 'bpmn business process model ').join(' ')),
 		this.createVertexTemplateEntry('rounded=1;arcSize=10;dashed=1;strokeColor=#000000;fillColor=none;gradientColor=none;dashPattern=8 3 1 3;strokeWidth=2;',
 				 200, 200, '', 'Group', null, null, this.getTagsForStencil('bpmn', 'group', 'bpmn business process model ').join(' ')),
 	 	this.createEdgeTemplateEntry('endArrow=block;endFill=1;endSize=6;html=1;', 100, 0, '', 'Sequence Flow', null, 'bpmn sequence flow'),

Разлика између датотеке није приказан због своје велике величине
+ 6 - 6
src/main/webapp/js/shapes.min.js


Разлика између датотеке није приказан због своје велике величине
+ 1276 - 1270
src/main/webapp/js/viewer.min.js


+ 2 - 2
src/main/webapp/resources/dia_fr.txt

@@ -593,13 +593,13 @@ renamed=Renommé
 renameIt=Renommer {1}
 renaming=Renommage
 replace=Remplacer
-replaceIt={1} existe déjà. Voulez-vous le remplacer ?
+replaceIt={1} existe déjà. Voulez-vous le remplacer?
 replaceExistingDrawing=Remplacer le diagramme existant
 required=obligatoire
 reset=Réinitialiser
 resetView=Réinitialiser la vue
 resize=Redimensionner
-resizeLargeImages=Souhaitez-vous redimensionner les grandes images pour rendre l'application plus rapide ?
+resizeLargeImages=Souhaitez-vous redimensionner les grandes images pour rendre l'application plus rapide?
 retina=Rétine
 responsive=Adapte
 restore=Récupérer

+ 55 - 11
src/main/webapp/shapes/mxBasic.js

@@ -2431,9 +2431,10 @@ mxShapeBasicPie.prototype.cst = {PIE : 'mxgraph.basic.pie'};
 mxShapeBasicPie.prototype.paintVertexShape = function(c, x, y, w, h)
 {
 	c.translate(x, y);
-
-	var startAngle = 2 * Math.PI * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'startAngle', this.startAngle))));
-	var endAngle = 2 * Math.PI * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'endAngle', this.endAngle))));
+	var startAngleSource = Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'startAngle', this.startAngle))));
+	var endAngleSource = Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'endAngle', this.endAngle))));
+	var startAngle = 2 * Math.PI * startAngleSource;
+	var endAngle = 2 * Math.PI * endAngleSource;
 	var rx = w * 0.5;
 	var ry = h * 0.5;
 	
@@ -2451,15 +2452,36 @@ mxShapeBasicPie.prototype.paintVertexShape = function(c, x, y, w, h)
 		
 	var bigArc = 0;
 	
-	if (angDiff > Math.PI)
+	if (angDiff >= Math.PI)
 	{
 		bigArc = 1;
 	}
 		
 	c.begin();
-	c.moveTo(rx, ry);
-	c.lineTo(startX, startY);
-	c.arcTo(rx, ry, 0, bigArc, 1, endX, endY);
+	var startAngleDiff = startAngleSource % 1;
+	var endAngleDiff = endAngleSource % 1;
+	
+	if (startAngleDiff == 0 && endAngleDiff == 0.5)
+	{
+		c.moveTo(rx, ry);
+		c.lineTo(startX, startY);
+		c.arcTo(rx, ry, 0, 0, 1, w, h * 0.5);
+		c.arcTo(rx, ry, 0, 0, 1, w * 0.5, h);
+	}
+	else if (startAngleDiff == 0.5 && endAngleDiff == 0)
+	{
+		c.moveTo(rx, ry);
+		c.lineTo(startX, startY);
+		c.arcTo(rx, ry, 0, 0, 1, 0, h * 0.5);
+		c.arcTo(rx, ry, 0, 0, 1, w * 0.5, 0);
+	}
+	else
+	{
+		c.moveTo(rx, ry);
+		c.lineTo(startX, startY);
+		c.arcTo(rx, ry, 0, bigArc, 1, endX, endY);
+	}
+	
 	c.close();
 	c.fillAndStroke();
 };
@@ -2554,8 +2576,10 @@ mxShapeBasicArc.prototype.paintVertexShape = function(c, x, y, w, h)
 {
 	c.translate(x, y);
 
-	var startAngle = 2 * Math.PI * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'startAngle', this.startAngle))));
-	var endAngle = 2 * Math.PI * Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'endAngle', this.endAngle))));
+	var startAngleSource = Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'startAngle', this.startAngle))));
+	var endAngleSource = Math.max(0, Math.min(1, parseFloat(mxUtils.getValue(this.style, 'endAngle', this.endAngle))));
+	var startAngle = 2 * Math.PI * startAngleSource;
+	var endAngle = 2 * Math.PI * endAngleSource;
 	var rx = w * 0.5;
 	var ry = h * 0.5;
 	
@@ -2579,8 +2603,28 @@ mxShapeBasicArc.prototype.paintVertexShape = function(c, x, y, w, h)
 	}
 		
 	c.begin();
-	c.moveTo(startX, startY);
-	c.arcTo(rx, ry, 0, bigArc, 1, endX, endY);
+	
+	var startAngleDiff = startAngleSource % 1;
+	var endAngleDiff = endAngleSource % 1;
+	
+	if (startAngleDiff == 0 && endAngleDiff == 0.5)
+	{
+		c.moveTo(startX, startY);
+		c.arcTo(rx, ry, 0, 0, 1, w, h * 0.5);
+		c.arcTo(rx, ry, 0, 0, 1, w * 0.5, h);
+	}
+	else if (startAngleDiff == 0.5 && endAngleDiff == 0)
+	{
+		c.moveTo(startX, startY);
+		c.arcTo(rx, ry, 0, 0, 1, 0, h * 0.5);
+		c.arcTo(rx, ry, 0, 0, 1, w * 0.5, 0);
+	}
+	else
+	{
+		c.moveTo(startX, startY);
+		c.arcTo(rx, ry, 0, bigArc, 1, endX, endY);
+	}
+
 	c.stroke();
 };
 

+ 4 - 8
src/main/webapp/styles/grapheditor.css

@@ -93,20 +93,16 @@
 	margin-top:-5px;
 	padding:4px 6px 4px 6px;
 	font-size:12px;
-	background-image: -webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);
-    background-image: -o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);
-    background-image: -webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));
-    background-image: linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);
+	background: -webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);
+    background: -o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);
+    background: -webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));
+    background: linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);
     filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
     background-repeat: repeat-x;
     border:1px solid #b2dba1;
 	border-radius:3px;
 	color:#3c763d !important;
 }
-.geStatusMessage:hover {
-	background:#c8e5bc;
-	border-color:#b2dba1;
-}
 .geAlert {
 	position:absolute;
 	white-space:nowrap;