David Benson 6 éve
szülő
commit
fc245fa9b8
98 módosított fájl, 50532 hozzáadás és 6369 törlés
  1. 17 0
      ChangeLog
  2. 1 1
      VERSION
  3. 4 0
      etc/build/build.xml
  4. 0 30
      etc/emf2png/README.md
  5. 0 7
      etc/emf2png/app/__init__.py
  6. 0 23
      etc/emf2png/app/routes.py
  7. 0 1
      etc/emf2png/emf2png.py
  8. 7 7
      etc/mxgraph/mxClient.js
  9. 30 0
      src/main/java/com/mxgraph/io/gliffy/importer/GliffyDiagramConverter.java
  10. 188 0
      src/main/java/com/mxgraph/online/CacheServlet.java
  11. BIN
      src/main/webapp/WEB-INF/lib/commons-logging-1.2.jar
  12. BIN
      src/main/webapp/WEB-INF/lib/httpclient-4.5.5.jar
  13. BIN
      src/main/webapp/WEB-INF/lib/httpcore-4.4.9.jar
  14. BIN
      src/main/webapp/WEB-INF/lib/pusher-http-java-1.0.0.jar
  15. 1 1
      src/main/webapp/cache.manifest
  16. 254 225
      src/main/webapp/export3.html
  17. BIN
      src/main/webapp/images/sidebar-aws4.png
  18. 2129 1951
      src/main/webapp/js/app.min.js
  19. 317 314
      src/main/webapp/js/atlas-viewer.min.js
  20. 2692 2402
      src/main/webapp/js/atlas.min.js
  21. 24 0
      src/main/webapp/js/diagramly/App.js
  22. 10 1
      src/main/webapp/js/diagramly/Devel.js
  23. 715 0
      src/main/webapp/js/diagramly/DiffSync.js
  24. 3 0
      src/main/webapp/js/diagramly/DrawioFile.js
  25. 7 7
      src/main/webapp/js/diagramly/DriveClient.js
  26. 56 5
      src/main/webapp/js/diagramly/DriveFile.js
  27. 23 0
      src/main/webapp/js/diagramly/Editor.js
  28. 146 151
      src/main/webapp/js/diagramly/EditorUi.js
  29. 1260 0
      src/main/webapp/js/diagramly/FileSync.js
  30. 3 3
      src/main/webapp/js/diagramly/Init.js
  31. 81 55
      src/main/webapp/js/diagramly/Menus.js
  32. 122 106
      src/main/webapp/js/diagramly/graphml/mxGraphMlCodec.js
  33. 472 0
      src/main/webapp/js/diagramly/mxTableLayout.js
  34. 1029 0
      src/main/webapp/js/diagramly/sidebar/Sidebar-AWS4.js
  35. 11 1
      src/main/webapp/js/diagramly/sidebar/Sidebar.js
  36. 65 16
      src/main/webapp/js/diagramly/vsdx/mxVsdxCanvas2D.js
  37. 7 7
      src/main/webapp/js/embed-static.min.js
  38. 710 597
      src/main/webapp/js/extensions.min.js
  39. 7 7
      src/main/webapp/js/reader.min.js
  40. 9 2
      src/main/webapp/js/shapes.min.js
  41. 1 0
      src/main/webapp/js/stencils.min.js
  42. 317 314
      src/main/webapp/js/viewer.min.js
  43. 6 3
      src/main/webapp/resources/dia.txt
  44. 6 3
      src/main/webapp/resources/dia_am.txt
  45. 5 2
      src/main/webapp/resources/dia_ar.txt
  46. 4 1
      src/main/webapp/resources/dia_bg.txt
  47. 6 3
      src/main/webapp/resources/dia_bn.txt
  48. 5 2
      src/main/webapp/resources/dia_bs.txt
  49. 4 1
      src/main/webapp/resources/dia_ca.txt
  50. 5 2
      src/main/webapp/resources/dia_cs.txt
  51. 5 2
      src/main/webapp/resources/dia_da.txt
  52. 5 2
      src/main/webapp/resources/dia_de.txt
  53. 5 2
      src/main/webapp/resources/dia_el.txt
  54. 6 3
      src/main/webapp/resources/dia_eo.txt
  55. 5 2
      src/main/webapp/resources/dia_es.txt
  56. 32 29
      src/main/webapp/resources/dia_et.txt
  57. 4 1
      src/main/webapp/resources/dia_fa.txt
  58. 4 1
      src/main/webapp/resources/dia_fi.txt
  59. 4 1
      src/main/webapp/resources/dia_fil.txt
  60. 5 2
      src/main/webapp/resources/dia_fr.txt
  61. 6 3
      src/main/webapp/resources/dia_gu.txt
  62. 4 1
      src/main/webapp/resources/dia_he.txt
  63. 6 3
      src/main/webapp/resources/dia_hi.txt
  64. 6 3
      src/main/webapp/resources/dia_hr.txt
  65. 4 1
      src/main/webapp/resources/dia_hu.txt
  66. 4 1
      src/main/webapp/resources/dia_i18n.txt
  67. 5 2
      src/main/webapp/resources/dia_id.txt
  68. 4 1
      src/main/webapp/resources/dia_it.txt
  69. 4 1
      src/main/webapp/resources/dia_ja.txt
  70. 6 3
      src/main/webapp/resources/dia_kn.txt
  71. 4 1
      src/main/webapp/resources/dia_ko.txt
  72. 6 3
      src/main/webapp/resources/dia_lt.txt
  73. 6 3
      src/main/webapp/resources/dia_lv.txt
  74. 6 3
      src/main/webapp/resources/dia_ml.txt
  75. 6 3
      src/main/webapp/resources/dia_mr.txt
  76. 5 2
      src/main/webapp/resources/dia_ms.txt
  77. 6 3
      src/main/webapp/resources/dia_nl.txt
  78. 5 2
      src/main/webapp/resources/dia_no.txt
  79. 4 1
      src/main/webapp/resources/dia_pl.txt
  80. 5 2
      src/main/webapp/resources/dia_pt-br.txt
  81. 5 2
      src/main/webapp/resources/dia_pt.txt
  82. 4 1
      src/main/webapp/resources/dia_ro.txt
  83. 4 1
      src/main/webapp/resources/dia_ru.txt
  84. 6 3
      src/main/webapp/resources/dia_sk.txt
  85. 6 3
      src/main/webapp/resources/dia_sl.txt
  86. 4 1
      src/main/webapp/resources/dia_sr.txt
  87. 5 2
      src/main/webapp/resources/dia_sv.txt
  88. 6 3
      src/main/webapp/resources/dia_sw.txt
  89. 6 3
      src/main/webapp/resources/dia_ta.txt
  90. 6 3
      src/main/webapp/resources/dia_te.txt
  91. 4 1
      src/main/webapp/resources/dia_th.txt
  92. 4 1
      src/main/webapp/resources/dia_tr.txt
  93. 5 2
      src/main/webapp/resources/dia_uk.txt
  94. 5 2
      src/main/webapp/resources/dia_vi.txt
  95. 5 2
      src/main/webapp/resources/dia_zh-tw.txt
  96. 4 1
      src/main/webapp/resources/dia_zh.txt
  97. 261 0
      src/main/webapp/shapes/mxAWS4.js
  98. 39256 0
      src/main/webapp/stencils/aws4.xml

+ 17 - 0
ChangeLog

@@ -1,3 +1,20 @@
+21-NOV-2018: 9.4.6
+
+- Fixes corrupted chars in XML from JSON backup import
+
+20-NOV-2018: 9.4.5
+
+- Adds 2018 AWS icons
+- Uses mxGraph 3.9.11 beta 5
+
+16-NOV-2018: 9.4.4
+
+- Adds GraphML import
+
+15-NOV-2018: 9.4.3
+
+- Internal release
+
 12-NOV-2018: 9.4.2
 
 - Fixes undoable edit when expanding Advanced sidebar

+ 1 - 1
VERSION

@@ -1 +1 @@
-9.4.2
+9.4.6

+ 4 - 0
etc/build/build.xml

@@ -111,6 +111,7 @@
 				<file name="Sidebar-AWS.js" />
 				<file name="Sidebar-AWS3.js" />
 				<file name="Sidebar-AWS3D.js" />
+				<file name="Sidebar-AWS4.js" />
 				<file name="Sidebar-Azure.js" />
 				<file name="Sidebar-Basic.js" />
 				<file name="Sidebar-Bootstrap.js" />
@@ -290,6 +291,9 @@
 				<file name="bmpDecoder.js" />
 				<file name="importer.js" />
 			</sources>
+			<sources dir="${war.dir}/js/diagramly/graphml">
+				<file name="mxGraphMlCodec.js" />
+			</sources>
 		</jscomp>
 		<concat destfile="${war.dir}/js/extensions.min.js" fixlastline="yes" append="yes">
 	    		<fileset dir="${war.dir}/js/jszip" includes="**/*.min.js"/>

+ 0 - 30
etc/emf2png/README.md

@@ -1,30 +0,0 @@
-# emf2png service
-
-It uses Python 2.7 and virualenv (pip install virualenv)
-
-Create a virtual environment to include needed packages
-* virtualenv venv
-
-On linux
-* source venv/bin/activate
-On Windows
-* venv\scripts\activate
-
-Install the following packages
-* pip install flask
-* pip install Pillow
-* pip install flask-cors
-
-To run the server (development)
-
-On Linux
-* export FLASK_APP=emf2png.py
-On Windows
-* set FLASK_APP=emf2png.py
-
-* flask run
-
-To deploy the app
-
-http://flask.pocoo.org/docs/1.0/deploying/
-https://cloud.google.com/appengine/docs/standard/python/getting-started/python-standard-env

+ 0 - 7
etc/emf2png/app/__init__.py

@@ -1,7 +0,0 @@
-from flask import Flask, jsonify
-from flask_cors import CORS
-
-app = Flask(__name__)
-CORS(app)
-
-from app import routes

+ 0 - 23
etc/emf2png/app/routes.py

@@ -1,23 +0,0 @@
-from flask import jsonify, request, send_file, abort
-from PIL import Image
-from io import BytesIO
-from app import app
-from urlparse import urlparse
-
-@app.route('/convertEMF', methods=['POST'])
-def get_tasks():
-	hostname = urlparse(request.referrer).hostname
-	if hostname.endswith(".draw.io") == False and hostname.endswith(".jgraph.com") == False:
-		abort(403)
-	
-	img = request.files['img']
-	pngImg = BytesIO()
-	Image.open(img).save(pngImg, "png")
-	pngImg.seek(0)
-	return send_file(pngImg,
-                     attachment_filename=img.filename+'.png',
-					 as_attachment=True,
-                     mimetype='image/png')
-
-if __name__ == '__main__':
-    app.run(debug=True)

+ 0 - 1
etc/emf2png/emf2png.py

@@ -1 +0,0 @@
-from app import app

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 7 - 7
etc/mxgraph/mxClient.js


+ 30 - 0
src/main/java/com/mxgraph/io/gliffy/importer/GliffyDiagramConverter.java

@@ -942,6 +942,14 @@ public class GliffyDiagramConverter
 				}
 				else
 				{
+					if (gliffyObject.isGroup())
+					{
+						for (GliffyObject childObject : gliffyObject.children)
+						{
+							rotateGroupedObject(gliffyObject, childObject);
+						}
+
+					}
 					style.append("rotation=" + gliffyObject.rotation + ";");
 				}
 			}
@@ -998,6 +1006,28 @@ public class GliffyDiagramConverter
 		return cell;
 	}
 
+	/**
+	 * Rotate objects inside Group
+	 * 
+	 * @param group
+	 * @param childObject
+	 */
+	private void rotateGroupedObject(GliffyObject group, GliffyObject childObject)
+	{
+		mxPoint pivot = new mxPoint(group.width / 2 - childObject.width / 2, group.height / 2 - childObject.height / 2);
+		mxPoint temp = new mxPoint(childObject.x, childObject.y);
+		if (group.rotation != 0)
+		{
+			double rads = Math.toRadians(group.rotation);
+			double cos = Math.cos(rads);
+			double sin = Math.sin(rads);
+			temp = mxUtils.getRotatedPoint(temp, cos, sin, pivot);
+			childObject.x = (float) temp.getX();
+			childObject.y = (float) temp.getY();
+			childObject.rotation += group.rotation;
+		}
+	}
+	
 	/**
 	 * Update borders of Text bracket in Frame objects.
 	 * 

+ 188 - 0
src/main/java/com/mxgraph/online/CacheServlet.java

@@ -0,0 +1,188 @@
+/**
+ * $Id: ProxyServlet.java,v 1.4 2013/12/13 13:18:11 david Exp $
+ * Copyright (c) 2011-2012, JGraph Ltd
+ */
+package com.mxgraph.online;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.cache.Cache;
+import javax.cache.CacheException;
+import javax.cache.CacheFactory;
+import javax.cache.CacheManager;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.google.appengine.api.memcache.stdimpl.GCacheFactory;
+import com.pusher.rest.Pusher;
+
+/**
+ * Servlet implementation ProxyServlet
+ */
+@SuppressWarnings("serial")
+public class CacheServlet extends HttpServlet
+{
+	protected static int expirationDelta = 300;
+
+	protected static Cache cache;
+
+	protected static Pusher pusher = new Pusher("528601",
+			"fd30ee6d04a388192212", "b6f57ca802122304055f");
+
+	protected static DateFormat dateFormat = new SimpleDateFormat(
+			"yyyy-MM-dd HH:mm:ss.SSS");
+
+	static
+	{
+		try
+		{
+			CacheFactory cacheFactory = CacheManager.getInstance()
+					.getCacheFactory();
+			Map<Object, Object> properties = new HashMap<>();
+			properties.put(GCacheFactory.EXPIRATION_DELTA, expirationDelta);
+			cache = cacheFactory.createCache(properties);
+		}
+		catch (CacheException e)
+		{
+			e.printStackTrace();
+		}
+
+		pusher.setCluster("eu");
+		pusher.setEncrypted(true);
+	}
+
+	/**
+	 * @see HttpServlet#HttpServlet()
+	 */
+	public CacheServlet()
+	{
+		super();
+	}
+
+	/**
+	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
+	 */
+	protected void doGet(HttpServletRequest request,
+			HttpServletResponse response) throws ServletException, IOException
+	{
+		String qs = request.getQueryString();
+		String ref = request.getHeader("referer");
+		boolean stats = qs != null && qs.equals("stats");
+
+		if (stats || (ref != null && ref.toLowerCase()
+				.matches("https?://([a-z0-9,-]+[.])*draw[.]io/.*")))
+		{
+			PrintWriter writer = response.getWriter();
+			response.setCharacterEncoding("UTF-8");
+
+			if (stats)
+			{
+				response.setContentType("text/plain");
+				writer.println("timestamp: " + new Date().toString());
+				writer.println("cache size: " + cache.size());
+				response.setStatus(HttpServletResponse.SC_OK);
+			}
+			else
+			{
+				// Disables wire-compression
+				response.setContentType("application/octet-stream");
+				String temp = request.getParameter("keys");
+				String id = request.getParameter("id");
+
+				if (id != null && temp != null)
+				{
+					String[] keys = temp.split(";");
+					List<String> values = new ArrayList<String>(keys.length);
+
+					for (String key : keys)
+					{
+						String fullKey = id + ":" + key;
+
+						if (cache.containsKey(fullKey))
+						{
+							values.add(cache.get(fullKey).toString());
+						}
+						else
+						{
+							values.clear();
+							break;
+						}
+					}
+
+					writer.print("[" + String.join(",", values) + "]");
+					System.out.println("keys: " + temp + " bytes: "
+							+ (String.join("", values).length()
+									- values.size() * 2));
+					response.setStatus(HttpServletResponse.SC_OK);
+				}
+				else
+				{
+					response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+				}
+			}
+
+			writer.flush();
+			writer.close();
+		}
+		else
+		{
+			response.setStatus(HttpServletResponse.SC_FORBIDDEN);
+		}
+	}
+
+	/**
+	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
+	 */
+	protected void doPost(HttpServletRequest request,
+			HttpServletResponse response) throws ServletException, IOException
+	{
+		String ref = request.getHeader("referer");
+
+		if (ref != null && ref.toLowerCase()
+				.matches("https?://([a-z0-9,-]+[.])*draw[.]io/.*"))
+		{
+			String key = request.getParameter("key");
+			String value = request.getParameter("value");
+
+			if (key != null)
+			{
+				int index = key.indexOf(":");
+
+				// Puts diff in cache
+				if (value != null && value.length() < 1000000 &&
+					!cache.containsKey(key))
+				{
+					cache.put(key, value);
+				}
+
+				// Send notification to clients
+				String msg = request.getParameter("msg");
+				String id = (index > 0) ? key.substring(0, index) : key;
+
+				pusher.trigger(id, "changed", (msg != null) ? msg : "");
+				System.out.println("key: " + key + " bytes: "
+						+ ((value != null) ? value.length() : 0) + " msg: "
+						+ msg);
+				System.out.println(dateFormat.format(new Date()) + ":DEBUG:"
+						+ ((value != null) ? value : "null"));
+			}
+
+			response.setStatus(HttpServletResponse.SC_OK);
+		}
+		else
+		{
+			response.setStatus(HttpServletResponse.SC_FORBIDDEN);
+		}
+	}
+
+}

BIN
src/main/webapp/WEB-INF/lib/commons-logging-1.2.jar


BIN
src/main/webapp/WEB-INF/lib/httpclient-4.5.5.jar


BIN
src/main/webapp/WEB-INF/lib/httpcore-4.4.9.jar


BIN
src/main/webapp/WEB-INF/lib/pusher-http-java-1.0.0.jar


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

@@ -1,7 +1,7 @@
 CACHE MANIFEST
 
 # THIS FILE WAS GENERATED. DO NOT MODIFY!
-# 11/13/2018 08:35 AM
+# 11/21/2018 04:30 PM
 
 app.html
 index.html?offline=1

+ 254 - 225
src/main/webapp/export3.html

@@ -40,17 +40,6 @@
 			if (xmlDoc.documentElement.nodeName == 'mxfile')
 			{
 				diagrams = xmlDoc.documentElement.getElementsByTagName('diagram');
-				
-				if (diagrams.length > 0)
-				{
-					from = Math.max(0, Math.min(parseInt(data.from) || from, diagrams.length - 1));
-					var diagramNode = diagrams[from];
-					
-					if (diagramNode != null)
-					{
-				        xmlDoc = mxUtils.parseXml(graph.decompress(mxUtils.getTextContent(diagramNode)));
-					}
-				}
 			}
 	        
 	        /**
@@ -72,163 +61,13 @@
 				
 				return graphGetGlobalVariable.apply(this, arguments);
 			};
-
-			// Enables math typesetting
-			var math = xmlDoc.documentElement.getAttribute('math') == '1';
-			
-			if (math)
-			{
-				mxClient.NO_FO = true;
-			}
-
-			// Configure graph
-			graph.foldingEnabled = false;
-			graph.setEnabled(false);
-			
-			// Sets background image
-			var bgImg = xmlDoc.documentElement.getAttribute('backgroundImage');
-
-			if (bgImg != null)
-			{
-				bgImg = JSON.parse(bgImg);
-				graph.setBackgroundImage(new mxImage(bgImg.src, bgImg.width, bgImg.height));
-			}
-			
-			// Parses XML into graph
-			var codec = new mxCodec(xmlDoc);
-			codec.decode(xmlDoc.documentElement, graph.getModel());
-
-			// Loads background color
-			var bg = (data.bg != null && data.bg.length > 0) ? data.bg : xmlDoc.documentElement.getAttribute('background');
-
-			// Normalizes values for transparent backgrounds
-			if (bg == 'none' || bg == '')
-			{
-				bg = null;
-			}
-			
-			// Checks if export format supports transparent backgrounds
-			if (bg == null && data.format != 'gif' && data.format != 'png')
-			{
-				bg = '#ffffff';
-			}
-
-			// Sets background color on page
-			if (bg != null)
-			{
-				document.body.style.backgroundColor = bg;
-			}
-
-			// Sets initial value for PDF page background
-			graph.pdfPageVisible = false;
-			
-			// Handles PDF output where the output should match the page format if the page is visible
-			if (data.format == 'pdf' && xmlDoc.documentElement.getAttribute('page') == '1' && data.w == 0 && data.h == 0)
-			{
-				var pw = xmlDoc.documentElement.getAttribute('pageWidth');
-				var ph = xmlDoc.documentElement.getAttribute('pageHeight');
-				graph.pdfPageVisible = true;
-				
-				if (pw != null && ph != null)
-				{
-					graph.pageFormat = new mxRectangle(0, 0, parseFloat(pw), parseFloat(ph));
-				}
-				
-				var ps = xmlDoc.documentElement.getAttribute('pageScale');
-				
-				if (ps != null)
-				{
-					graph.pageScale = ps;
-				}
-				
-				graph.getPageSize = function()
-				{
-					return new mxRectangle(0, 0, this.pageFormat.width * this.pageScale,
-							this.pageFormat.height * this.pageScale);
-				};
-				
-				graph.getPageLayout = function()
-				{
-					var size = this.getPageSize();
-					var bounds = this.getGraphBounds();
-					
-					if (bounds.width == 0 || bounds.height == 0)
-					{
-						return new mxRectangle(0, 0, 1, 1);
-					}
-					else
-					{
-						// Computes untransformed graph bounds
-						var x = Math.ceil(bounds.x / this.view.scale - this.view.translate.x);
-						var y = Math.ceil(bounds.y / this.view.scale - this.view.translate.y);
-						var w = Math.floor(bounds.width / this.view.scale);
-						var h = Math.floor(bounds.height / this.view.scale);
-						
-						var x0 = Math.floor(x / size.width);
-						var y0 = Math.floor(y / size.height);
-						var w0 = Math.ceil((x + w) / size.width) - x0;
-						var h0 = Math.ceil((y + h) / size.height) - y0;
-						
-						return new mxRectangle(x0, y0, w0, h0);
-					}
-				};
-
-				// Fits the number of background pages to the graph
-				graph.view.getBackgroundPageBounds = function()
-				{
-					var layout = this.graph.getPageLayout();
-					var page = this.graph.getPageSize();
-					
-					return new mxRectangle(this.scale * (this.translate.x + layout.x * page.width),
-							this.scale * (this.translate.y + layout.y * page.height),
-							this.scale * layout.width * page.width,
-							this.scale * layout.height * page.height);
-				};
-			}
-
-			if (!graph.pdfPageVisible)
-			{
-				var b = graph.getGraphBounds();
-				
-				// Floor is needed to keep rendering crisp
-				if (data.w > 0 && data.h > 0)
-				{
-					var s = Math.min(data.w / b.width, data.h / b.height);
-					graph.view.scaleAndTranslate(s,
-						Math.floor(data.border / s - b.x),
-						Math.floor(data.border / s - b.y));
-				}
-				else
-				{
-					graph.view.scaleAndTranslate(data.scale, Math.floor(data.border - b.x),
-						Math.floor(data.border - b.y));
-				}
-			}
-			else
-			{
-				// Disables border for PDF page export
-				data.border = 0;
-				
-				// Moves to first page in page layout
-				var layout = graph.getPageLayout();
-				var page = graph.getPageSize();
-				var dx = layout.x * page.width;
-				var dy = layout.y * page.height;
-				
-				if (dx != 0 || dy != 0)
-				{
-					graph.view.setTranslate(Math.floor(-dx), Math.floor(-dy));
-				}
-			}
-			
-			// Gets the diagram bounds and sets the document size
-			var bounds = (graph.pdfPageVisible) ? graph.view.getBackgroundPageBounds() : graph.getGraphBounds();
-			bounds.width = Math.ceil(bounds.width + data.border);
-			bounds.height = Math.ceil(bounds.height + data.border);
 			
+			var preview = null;
+			var waitCounter = 1;
+			var bounds;
 			// Waits for all images to finish loading
 			var cache = new Object();
-			var waitCounter = 1;
+			var math = false;
 			
 			// Decrements waitCounter and invokes callback when finished
 			function decrementWaitCounter()
@@ -267,10 +106,6 @@
 				}
 			};
 			
-			// Includes images in SVG and HTML labels
-			waitForImages('image', 'xlink:href');
-			waitForImages('img', 'src');
-			
 			// Waits for MathJax.Hub to become available to register
 			// wait counter callback asynchronously after math render
 			var editorDoMathJaxRender = Editor.doMathJaxRender;
@@ -298,77 +133,271 @@
 				}
 			};
 
-			// Converts the graph to a vertical sequence of pages for PDF export
-			if (graph.pdfPageVisible)
+			function renderPage()
 			{
-				var pf = graph.pageFormat || mxConstants.PAGE_FORMAT_A4_PORTRAIT;
-				var scale = 1 / graph.pageScale;
-				var autoOrigin = false;
-				var border = 0;
-
-				// Negative coordinates are cropped or shifted if page visible
-				var gb = graph.getGraphBounds();
-				var x0 = 0;
-				var y0 = 0;
-		
-				// Applies print scale
-				pf = mxRectangle.fromRectangle(pf);
-				pf.width = Math.ceil(pf.width);
-				pf.height = Math.ceil(pf.height);
 				
-				// Starts at first visible page
-				var layout = graph.getPageLayout();
-				x0 -= layout.x * pf.width;
-				y0 -= layout.y * pf.height;
+				// Enables math typesetting
+				math |= xmlDoc.documentElement.getAttribute('math') == '1';
 				
-				var preview = new mxPrintPreview(graph, scale, pf, border, x0, y0);
-				preview.printBackgroundImage = true;
-				preview.autoOrigin = autoOrigin;
-				preview.backgroundColor = bg;
-
-				// Renders print output into this document and removes the graph container
-				preview.open(null, window);
-				graph.container.parentNode.removeChild(graph.container);
-
-				// Adds shadow
-				// NOTE: Shadow rasterizes output
-				/*if (mxClient.IS_SVG && xmlDoc.documentElement.getAttribute('shadow') == '1')
+				if (math)
+				{
+					mxClient.NO_FO = true;
+				}
+	
+				// Configure graph
+				graph.foldingEnabled = false;
+				graph.setEnabled(false);
+				
+				// Sets background image
+				var bgImg = xmlDoc.documentElement.getAttribute('backgroundImage');
+	
+				if (bgImg != null)
+				{
+					bgImg = JSON.parse(bgImg);
+					graph.setBackgroundImage(new mxImage(bgImg.src, bgImg.width, bgImg.height));
+				}
+				
+				// Parses XML into graph
+				var codec = new mxCodec(xmlDoc);
+				codec.decode(xmlDoc.documentElement, graph.getModel());
+	
+				// Loads background color
+				var bg = (data.bg != null && data.bg.length > 0) ? data.bg : xmlDoc.documentElement.getAttribute('background');
+	
+				// Normalizes values for transparent backgrounds
+				if (bg == 'none' || bg == '')
 				{
-					var svgs = document.getElementsByTagName('svg');
+					bg = null;
+				}
+				
+				// Checks if export format supports transparent backgrounds
+				if (bg == null && data.format != 'gif' && data.format != 'png')
+				{
+					bg = '#ffffff';
+				}
+	
+				// Sets background color on page
+				if (bg != null)
+				{
+					document.body.style.backgroundColor = bg;
+				}
+	
+				// Sets initial value for PDF page background
+				graph.pdfPageVisible = false;
+				
+				// Handles PDF output where the output should match the page format if the page is visible
+				if (data.format == 'pdf' && xmlDoc.documentElement.getAttribute('page') == '1' && data.w == 0 && data.h == 0)
+				{
+					var pw = xmlDoc.documentElement.getAttribute('pageWidth');
+					var ph = xmlDoc.documentElement.getAttribute('pageHeight');
+					graph.pdfPageVisible = true;
 					
-					for (var i = 0; i < svgs.length; i++)
+					if (pw != null && ph != null)
 					{
-						var svg = svgs[i];
-
-						var filter = graph.addSvgShadow(svg, null, true);
-						filter.setAttribute('id', 'shadow-' + i);
-						svg.appendChild(filter);
-						svg.setAttribute('filter', 'url(#' + 'shadow-' + i + ')');
+						graph.pageFormat = new mxRectangle(0, 0, parseFloat(pw), parseFloat(ph));
+					}
+					
+					var ps = xmlDoc.documentElement.getAttribute('pageScale');
+					
+					if (ps != null)
+					{
+						graph.pageScale = ps;
 					}
 					
-					border = 7;
-				}*/
+					graph.getPageSize = function()
+					{
+						return new mxRectangle(0, 0, this.pageFormat.width * this.pageScale,
+								this.pageFormat.height * this.pageScale);
+					};
+					
+					graph.getPageLayout = function()
+					{
+						var size = this.getPageSize();
+						var bounds = this.getGraphBounds();
+						
+						if (bounds.width == 0 || bounds.height == 0)
+						{
+							return new mxRectangle(0, 0, 1, 1);
+						}
+						else
+						{
+							// Computes untransformed graph bounds
+							var x = Math.ceil(bounds.x / this.view.scale - this.view.translate.x);
+							var y = Math.ceil(bounds.y / this.view.scale - this.view.translate.y);
+							var w = Math.floor(bounds.width / this.view.scale);
+							var h = Math.floor(bounds.height / this.view.scale);
+							
+							var x0 = Math.floor(x / size.width);
+							var y0 = Math.floor(y / size.height);
+							var w0 = Math.ceil((x + w) / size.width) - x0;
+							var h0 = Math.ceil((y + h) / size.height) - y0;
+							
+							return new mxRectangle(x0, y0, w0, h0);
+						}
+					};
+	
+					// Fits the number of background pages to the graph
+					graph.view.getBackgroundPageBounds = function()
+					{
+						var layout = this.graph.getPageLayout();
+						var page = this.graph.getPageSize();
+						
+						return new mxRectangle(this.scale * (this.translate.x + layout.x * page.width),
+								this.scale * (this.translate.y + layout.y * page.height),
+								this.scale * layout.width * page.width,
+								this.scale * layout.height * page.height);
+					};
+				}
+	
+				if (!graph.pdfPageVisible)
+				{
+					var b = graph.getGraphBounds();
+					
+					// Floor is needed to keep rendering crisp
+					if (data.w > 0 && data.h > 0)
+					{
+						var s = Math.min(data.w / b.width, data.h / b.height);
+						graph.view.scaleAndTranslate(s,
+							Math.floor(data.border / s - b.x),
+							Math.floor(data.border / s - b.y));
+					}
+					else
+					{
+						graph.view.scaleAndTranslate(data.scale, Math.floor(data.border - b.x),
+							Math.floor(data.border - b.y));
+					}
+				}
+				else
+				{
+					// Disables border for PDF page export
+					data.border = 0;
+					
+					// Moves to first page in page layout
+					var layout = graph.getPageLayout();
+					var page = graph.getPageSize();
+					var dx = layout.x * page.width;
+					var dy = layout.y * page.height;
+					
+					if (dx != 0 || dy != 0)
+					{
+						graph.view.setTranslate(Math.floor(-dx), Math.floor(-dy));
+					}
+				}
 				
-				bounds = new mxRectangle(0, 0, pf.width, pf.height);
-				renderMath(document.body);
+				// Gets the diagram bounds and sets the document size
+				bounds = (graph.pdfPageVisible) ? graph.view.getBackgroundPageBounds() : graph.getGraphBounds();
+				bounds.width = Math.ceil(bounds.width + data.border);
+				bounds.height = Math.ceil(bounds.height + data.border);
+				
+				// Converts the graph to a vertical sequence of pages for PDF export
+				if (graph.pdfPageVisible)
+				{
+					var pf = graph.pageFormat || mxConstants.PAGE_FORMAT_A4_PORTRAIT;
+					var scale = 1 / graph.pageScale;
+					var autoOrigin = false;
+					var border = 0;
+	
+					// Negative coordinates are cropped or shifted if page visible
+					var gb = graph.getGraphBounds();
+					var x0 = 0;
+					var y0 = 0;
+			
+					// Applies print scale
+					pf = mxRectangle.fromRectangle(pf);
+					pf.width = Math.ceil(pf.width);
+					pf.height = Math.ceil(pf.height);
+					
+					// Starts at first visible page
+					var layout = graph.getPageLayout();
+					x0 -= layout.x * pf.width;
+					y0 -= layout.y * pf.height;
+					
+					if (preview == null) {
+						preview = new mxPrintPreview(graph, scale, pf, border, x0, y0);
+						preview.printBackgroundImage = true;
+						preview.autoOrigin = autoOrigin;
+						preview.backgroundColor = bg;
+						// Renders print output into this document and removes the graph container
+						preview.open(null, window);
+						graph.container.parentNode.removeChild(graph.container);
+					}
+					else
+					{
+						preview.backgroundColor = bg;
+						preview.autoOrigin = autoOrigin; 
+						preview.appendGraph(graph, scale, x0, y0);
+					}
+					// Adds shadow
+					// NOTE: Shadow rasterizes output
+					/*if (mxClient.IS_SVG && xmlDoc.documentElement.getAttribute('shadow') == '1')
+					{
+						var svgs = document.getElementsByTagName('svg');
+						
+						for (var i = 0; i < svgs.length; i++)
+						{
+							var svg = svgs[i];
+	
+							var filter = graph.addSvgShadow(svg, null, true);
+							filter.setAttribute('id', 'shadow-' + i);
+							svg.appendChild(filter);
+							svg.setAttribute('filter', 'url(#' + 'shadow-' + i + ')');
+						}
+						
+						border = 7;
+					}*/
+					
+					bounds = new mxRectangle(0, 0, pf.width, pf.height);
+				}
+				else
+				{
+					// Adds shadow
+					// NOTE: PDF shadow rasterizes output so it's disabled
+					if (data.format != 'pdf' && mxClient.IS_SVG && xmlDoc.documentElement.getAttribute('shadow') == '1')
+					{
+						graph.addSvgShadow(graph.view.canvas.ownerSVGElement, null, true);
+						graph.setShadowVisible(true);
+						bounds.width += 7;
+						bounds.height += 7;
+					}
+					
+					document.body.style.width = Math.ceil(bounds.x + bounds.width) + 'px';
+					document.body.style.height = Math.ceil(bounds.y + bounds.height) + 'px';
+				}
 			}
-			else
+			
+			if (diagrams != null && diagrams.length > 0)
 			{
-				// Adds shadow
-				// NOTE: PDF shadow rasterizes output so it's disabled
-				if (data.format != 'pdf' && mxClient.IS_SVG && xmlDoc.documentElement.getAttribute('shadow') == '1')
+				var to = diagrams.length - 1;
+				
+				//Parameters to and all pages should not be sent with formats other than PDF with page view enabled
+				if (!data.allPages)
 				{
-					graph.addSvgShadow(graph.view.canvas.ownerSVGElement, null, true);
-					graph.setShadowVisible(true);
-					bounds.width += 7;
-					bounds.height += 7;
+					from = Math.max(0, Math.min(parseInt(data.from) || from, diagrams.length - 1));
+					to = parseInt(data.to);
+					//If to is not defined, use from (so one page), otherwise, to is restricted to the range from "from" to diagrams.length - 1
+					to = isNaN(to)? from : Math.max(from, Math.min(to, diagrams.length - 1));
 				}
-				
-				renderMath(graph.container);
-				document.body.style.width = Math.ceil(bounds.x + bounds.width) + 'px';
-				document.body.style.height = Math.ceil(bounds.y + bounds.height) + 'px';
+					
+				for (var i = from; i <= to; i++) 
+				{
+					if (diagrams[i] != null)
+					{
+						xmlDoc = mxUtils.parseXml(graph.decompress(mxUtils.getTextContent(diagrams[i])));
+						graph.getModel().clear();
+						from = i;
+						renderPage();
+					}
+				}
+			}
+			else
+			{
+				renderPage();
 			}
 			
+			// Includes images in SVG and HTML labels
+			waitForImages('image', 'xlink:href');
+			waitForImages('img', 'src');
+			renderMath(document.body);
 			// Immediate return if not waiting for any content
 			decrementWaitCounter();
 		};

BIN
src/main/webapp/images/sidebar-aws4.png


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 2129 - 1951
src/main/webapp/js/app.min.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 317 - 314
src/main/webapp/js/atlas-viewer.min.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 2692 - 2402
src/main/webapp/js/atlas.min.js


+ 24 - 0
src/main/webapp/js/diagramly/App.js

@@ -186,6 +186,11 @@ App.TRELLO_JQUERY_URL = 'https://code.jquery.com/jquery-1.7.1.min.js';
  */
 App.FOOTER_PLUGIN_URL = 'https://www.jgraph.com/drawio-footer.js';
 
+/**
+ * Specifies the ID for the pusher project.
+ */
+App.PUSHER_ID = 'fd30ee6d04a388192212';
+
 /**
  * Switch to disable Google realtime starting on 11/12/2018 at 9:00am (UTC).
  */
@@ -1153,6 +1158,25 @@ App.prototype.isLegacyDriveDomain = function()
 	return urlParams['drive'] == 0 || window.location.hostname == 'legacy.draw.io';
 };
 
+/**
+ * Returns the pusher instance for notifications. Creates the instance of none exists.
+ */
+App.prototype.getPusher = function()
+{
+	if (this.pusher == null && typeof window.Pusher === 'function')
+	{
+		//Pusher.logToConsole = true;
+		
+		this.pusher = new Pusher(App.PUSHER_ID,
+		{
+			encrypted: true,
+			cluster: 'eu'
+		});
+	}
+	
+	return this.pusher;
+};
+
 /**
  * 
  */

+ 10 - 1
src/main/webapp/js/diagramly/Devel.js

@@ -37,6 +37,7 @@ mxscript(drawDevUrl + 'js/diagramly/sidebar/Sidebar-Atlassian.js');
 mxscript(drawDevUrl + 'js/diagramly/sidebar/Sidebar-AWS.js');
 mxscript(drawDevUrl + 'js/diagramly/sidebar/Sidebar-AWS3.js');
 mxscript(drawDevUrl + 'js/diagramly/sidebar/Sidebar-AWS3D.js');
+mxscript(drawDevUrl + 'js/diagramly/sidebar/Sidebar-AWS4.js');
 mxscript(drawDevUrl + 'js/diagramly/sidebar/Sidebar-Azure.js');
 mxscript(drawDevUrl + 'js/diagramly/sidebar/Sidebar-Basic.js');
 mxscript(drawDevUrl + 'js/diagramly/sidebar/Sidebar-Bootstrap.js');
@@ -80,6 +81,8 @@ mxscript(drawDevUrl + 'js/diagramly/Dialogs.js');
 mxscript(drawDevUrl + 'js/diagramly/Editor.js');
 mxscript(drawDevUrl + 'js/diagramly/EditorUi.js');
 mxscript(drawDevUrl + 'js/diagramly/Settings.js');
+mxscript(drawDevUrl + 'js/diagramly/FileSync.js');
+mxscript(drawDevUrl + 'js/diagramly/DiffSync.js');
 
 // Excluded in base.min.js
 mxscript(drawDevUrl + 'js/diagramly/DrawioClient.js');
@@ -123,4 +126,10 @@ mxscript(drawDevUrl + 'js/jszip/jszip.min.js');
 mxscript(drawDevUrl + 'js/diagramly/ruler/mxRuler.js');
 
 //GraphMl Import
-mxscript(drawDevUrl + 'js/diagramly/graphml/mxGraphMlCodec.js');
+mxscript(drawDevUrl + 'js/diagramly/graphml/mxGraphMlCodec.js');
+
+//Table Layout
+if (urlParams['tableLayout'] == '1')
+{
+  mxscript(drawDevUrl + 'js/diagramly/mxTableLayout.js');
+}

+ 715 - 0
src/main/webapp/js/diagramly/DiffSync.js

@@ -0,0 +1,715 @@
+/**
+ * Copyright (c) 2006-2017, JGraph Ltd
+ * Copyright (c) 2006-2017, Gaudenz Alder
+ */
+/**
+ * Removes all labels, user objects and styles from the given node in-place.
+ */
+EditorUi.prototype.patchPages = function(pages, diff)
+{
+	var newPages = [];
+	var inserted = {};
+	var removed = {};
+	var lookup = {};
+	var moved = {};
+	
+	for (var i = 0; i < pages.length; i++)
+	{
+		lookup[pages[i].getId()] = pages[i];
+	}
+	
+	if (diff.removed != null)
+	{
+		for (var i = 0; i < diff.removed.length; i++)
+		{
+			removed[diff.removed[i]] = true;
+		}
+	}
+
+	var newFirstPage = null;
+	
+	if (diff.inserted != null)
+	{
+		for (var i = 0; i < diff.inserted.length; i++)
+		{
+			inserted[diff.inserted[i].previous] = diff.inserted[i];
+		}
+	}
+	
+	if (diff.changed != null)
+	{
+		for (var id in diff.changed)
+		{
+			var pageDiff = diff.changed[id];
+			
+			if (pageDiff.previous != null)
+			{
+				moved[pageDiff.previous] = id;
+			}
+		}
+	}
+	
+	var addPage = mxUtils.bind(this, function(page, pageDiff)
+	{
+		var id = (page != null) ? page.getId() : '';
+		
+		if (page != null)
+		{
+			newPages.push(page);
+			
+			if (pageDiff != null)
+			{
+				this.patchPage(page, pageDiff.cells);
+			}
+		}
+		
+		var mov = moved[id];
+		
+		if (mov != null)
+		{
+			addPage(lookup[mov]);
+		}
+		
+		var ins = inserted[id];
+		
+		if (ins != null)
+		{
+			var diagram = mxUtils.parseXml(ins.xml).documentElement;
+			var doc = mxUtils.parseXml(this.editor.graph.decompress(mxUtils.getTextContent(diagram)));
+			var codec = new mxCodec(doc);
+			var model = codec.decode(doc.documentElement);
+
+			var newPage = new DiagramPage(diagram);
+			newPage.root = model.root;
+			
+			addPage(newPage);
+		}
+	});
+	
+	addPage();
+	
+	for (var i = 0; i < pages.length; i++)
+	{
+		if (!removed[pages[i].getId()])
+		{
+			var pageDiff = (diff.changed != null) ? diff.changed[pages[i].getId()] : null;
+			
+			if (pageDiff != null && pageDiff.name != null)
+			{
+				pages[i].setName(pageDiff.name);
+			}
+			
+			if (pageDiff == null || pageDiff.previous == null)
+			{
+				addPage(pages[i], pageDiff);
+			}
+		}
+	}
+	
+	return newPages;
+};
+
+/**
+ * Removes all labels, user objects and styles from the given node in-place.
+ */
+EditorUi.prototype.patchPage = function(page, diff)
+{
+	if (diff != null)
+	{
+		var model = (page == this.currentPage) ? this.editor.graph.model : new mxGraphModel(page.root);
+		
+		model.beginUpdate();
+		try
+		{
+			if (diff.inserted != null)
+			{
+				var previous = {};
+				var lookup = {};
+				var cells = [];
+				
+				var doLookup = mxUtils.bind(this, function(id)
+				{
+					if (id == null)
+					{
+						return null;
+					}
+					else
+					{
+						var entry = lookup[id];
+						
+						if (entry != null)
+						{
+							return entry.cell;
+						}
+						else
+						{
+							return model.getCell(id);
+						}
+					}
+				});
+				
+				var addCell = mxUtils.bind(this, function(cell, json)
+				{
+					var parent = doLookup(json.parent);
+					
+					if (json.previous == null)
+					{
+						model.add(parent, cell, 0);
+					}
+					else
+					{
+						var prev = doLookup(json.previous);
+						var index = parent.getIndex(prev);
+						
+						if (index >= 0)
+						{
+							model.add(parent, cell, index + 1);
+						}
+						else
+						{
+							console.error('previous cell', json.previous, 'was not found');
+						}
+					}
+					
+					var next = previous[cell.getId()];
+					
+					if (next != null)
+					{
+						var nextCell = lookup[next];
+						
+						if (nextCell != null)
+						{
+							addCell(nextCell.cell, nextCell.json);
+						}
+					}
+				});
+				
+				for (var i = 0; i < diff.inserted.length; i++)
+				{
+					var cell = this.getCellForJson(diff.inserted[i]);
+					lookup[cell.getId()] = {cell: cell, json: diff.inserted[i]};
+					previous[diff.inserted[i].previous] = cell.getId();
+					cells.push({cell: cell, json: diff.inserted[i]});
+				}
+				
+				for (var i = 0; i < cells.length; i++)
+				{
+					addCell(cells[i].cell, cells[i].json);
+				}
+				
+				for (var i = 0; i < cells.length; i++)
+				{
+					model.setTerminal(cells[i].cell, doLookup(cells[i].json.source), true);
+					model.setTerminal(cells[i].cell, doLookup(cells[i].json.target), false);
+				}
+			}
+	
+			if (diff.changed != null)
+			{
+				for (var id in diff.changed)
+				{
+					this.patchCell(model, diff.changed, id);
+				}
+			}
+
+			if (diff.removed != null)
+			{
+				for (var i = 0; i < diff.removed.length; i++)
+				{
+					var cell = model.getCell(diff.removed[i]);
+					
+					if (cell != null)
+					{
+						model.remove(cell);
+					}
+					else
+					{
+						console.error('removed cell', diff.removed[i], 'was not found');
+					}
+				}
+			}
+		}
+		finally
+		{
+			model.endUpdate();
+		}
+	}
+};
+
+/**
+ * Removes all labels, user objects and styles from the given node in-place.
+ */
+EditorUi.prototype.patchCell = function(model, diff, id)
+{
+	var cell = model.getCell(id);
+	var json = diff[id];
+	
+	if (cell != null && json != null)
+	{
+		var codec = new mxCodec();
+		
+		if (json.value != null)
+		{
+			model.setValue(cell, json.value);
+		}
+		else if (json.xmlValue != null)
+		{
+			model.setValue(cell, mxUtils.parseXml(json.xmlValue).documentElement);
+		}
+		
+		if (json.style != null)
+		{
+			model.setStyle(cell, json.style);
+		}
+		
+		if (json.geometry != null)
+		{
+			model.setGeometry(cell, codec.decode(mxUtils.parseXml(json.geometry).documentElement));
+		}
+		
+		if (json.source != null)
+		{
+			model.setTerminal(cell, model.getCell(json.source), true);
+		}
+		
+		if (json.target != null)
+		{
+			model.setTerminal(cell, model.getCell(json.target), false);
+		}
+		
+		if (json.parent != null)
+		{
+			var parent = model.getCell(json.parent);
+
+			if (json.previous == '')
+			{
+				model.add(parent, cell, 0);
+			}
+			else
+			{
+				var prev = model.getCell(json.previous);
+				var index = parent.getIndex(prev);
+				
+				if (index >= 0)
+				{
+					model.add(parent, cell, index + 1);
+				}
+				else
+				{
+					console.error('previous cell', json.previous, 'was not found');
+				}
+			}
+		}
+		else if (json.previous != null)
+		{
+			var parent = cell.parent;
+
+			if (json.previous == '')
+			{
+				model.add(parent, cell, 0);
+			}
+			else
+			{
+				var prev = model.getCell(json.previous);
+				var index = parent.getIndex(prev);
+				
+				if (index >= 0)
+				{
+					model.add(parent, cell, index + 1);
+				}
+				else
+				{
+					console.error('previous cell', json.previous, 'was not found');
+				}
+			}
+		}
+	}
+};
+
+/**
+ * Gets a file node that is comparable with a remote file node
+ * so that using isEqualNode returns true if the files can be
+ * considered equal.
+ */
+EditorUi.prototype.getPagesForNode = function(node)
+{
+	var diagrams = node.getElementsByTagName('diagram');
+	var pages = [];
+	
+	for (var i = 0; i < diagrams.length; i++)
+	{
+		var doc = mxUtils.parseXml(this.editor.graph.decompress(mxUtils.getTextContent(diagrams[i])));
+		var codec = new mxCodec(doc);
+		var model = codec.decode(doc.documentElement);
+
+		var page = new DiagramPage(diagrams[i]);
+		page.root = model.root;
+		pages.push(page);
+	}
+	
+	return pages;
+};
+
+/**
+ * Removes all labels, user objects and styles from the given node in-place.
+ */
+EditorUi.prototype.diffPages = function(oldPages, newPages)
+{
+	var lookup = {};
+	var diff = {};
+	var prev = null;
+	
+	for (var i = 0; i < newPages.length; i++)
+	{
+		lookup[newPages[i].getId()] = {'page': newPages[i], 'prev': prev};
+		prev = newPages[i];
+	}
+
+	var removed = [];
+	var inserted = [];
+	var diff = {};
+	prev = null;
+	
+	for (var i = 0; i < oldPages.length; i++)
+	{
+		var id = oldPages[i].getId();
+		var newPage = lookup[id];
+		
+		if (newPage == null)
+		{
+			removed.push(id);
+		}
+		else
+		{
+			var pageDiff = {};
+			var temp = this.diffPage(oldPages[i], newPage.page);
+			
+			if (Object.keys(temp).length > 0)
+			{
+				pageDiff['cells'] = temp;
+			}
+			
+			if (((newPage.prev != null) ? prev == null : prev != null) ||
+				(prev != null && newPage.prev != null &&
+				prev.id != newPage.prev.id))
+			{
+				pageDiff['previous'] = (newPage.prev != null) ? newPage.prev.getId() : '';
+			}
+			
+			if (oldPages[i].getName() != newPage.page.getName())
+			{
+				pageDiff['name'] = newPage.page.getName();
+			}
+			
+			if (Object.keys(pageDiff).length > 0)
+			{
+				diff[id] = pageDiff;
+			}
+		}
+
+		delete lookup[oldPages[i].getId()];
+		prev = oldPages[i];
+	}
+	
+	for (var id in lookup)
+	{
+		var newPage = lookup[id];
+		inserted.push({'xml': mxUtils.getXml(newPage.page.node),
+			'previous': (newPage.prev != null) ?
+			newPage.prev.getId() : ''});
+	}
+	
+	var result = {};
+	
+	if (removed.length > 0)
+	{
+		result['removed'] = removed;
+	}
+	
+	if (inserted.length > 0)
+	{
+		result['inserted'] = inserted;
+	}
+	
+	if (Object.keys(diff).length > 0)
+	{
+		result['changed'] = diff;
+	}
+	
+	return result;
+};
+
+/**
+ * Removes all labels, user objects and styles from the given node in-place.
+ */
+EditorUi.prototype.createCellLookup = function(cell, prev, lookup)
+{
+	lookup = (lookup != null) ? lookup : {};
+	lookup[cell.getId()] = {'cell': cell, 'prev': prev};
+	
+	var childCount = cell.getChildCount();
+	prev = null;
+	
+	for (var i = 0; i < childCount; i++)
+	{
+		var child = cell.getChildAt(i);
+		this.createCellLookup(child, prev, lookup);
+		prev = child;
+	}
+	
+	return lookup;
+};
+
+/**
+ * Removes all labels, user objects and styles from the given node in-place.
+ */
+EditorUi.prototype.diffCellRecursive = function(cell, prev, lookup, diff, removed)
+{
+	diff = (diff != null) ? diff : {};
+	var newCell = lookup[cell.getId()];
+	delete lookup[cell.getId()];
+	
+	if (newCell == null)
+	{
+		removed.push(cell.getId());
+	}
+	else
+	{
+		var temp = this.diffCell(cell, newCell.cell);
+		
+		if (temp.parent != null ||
+			(((newCell.prev != null) ? prev == null : prev != null) ||
+			(prev != null && newCell.prev != null &&
+			prev.id != newCell.prev.id)))
+		{
+			temp['previous'] = (newCell.prev != null) ? newCell.prev.getId() : '';
+		}
+		
+		if (Object.keys(temp).length > 0)
+		{
+			diff[cell.getId()] = temp;
+		}
+	}
+
+	var childCount = cell.getChildCount();
+	prev = null;
+	
+	for (var i = 0; i < childCount; i++)
+	{
+		var child = cell.getChildAt(i);
+		this.diffCellRecursive(child, prev, lookup, diff, removed);
+		prev = child;
+	}
+	
+	return diff;
+};
+
+/**
+ * Removes all labels, user objects and styles from the given node in-place.
+ */
+EditorUi.prototype.diffPage = function(oldPage, newPage)
+{
+	this.updatePageRoot(newPage);
+
+	var removed = [];
+	var inserted = [];
+	var lookup = this.createCellLookup(newPage.root);
+	var diff = this.diffCellRecursive(oldPage.root, null, lookup, diff, removed);
+	var codec = new mxCodec();
+
+	for (var id in lookup)
+	{
+		var newCell = lookup[id];
+		inserted.push(this.getJsonForCell(newCell.cell, newCell.prev));
+	}
+	
+	var result = {};
+	
+	if (removed.length > 0)
+	{
+		result['removed'] = removed;
+	}
+	
+	if (inserted.length > 0)
+	{
+		result['inserted'] = inserted;
+	}
+	
+	if (Object.keys(diff).length > 0)
+	{
+		result['changed'] = diff;
+	}
+	
+	return result;
+};
+
+/**
+ * Removes all labels, user objects and styles from the given node in-place.
+ */
+EditorUi.prototype.getCellForJson = function(json)
+{
+	var codec = new mxCodec();
+	var geometry = (json.geometry != null) ? codec.decode(mxUtils.parseXml(json.geometry).documentElement) : null;
+	var value = json.value;
+	
+	if (json.xmlValue != null)
+	{
+		value = mxUtils.parseXml(json.xmlValue).documentElement;
+	}
+	
+	var cell = new mxCell(value, geometry, json.style);
+	cell.vertex = json.vertex;
+	cell.edge = json.edge;
+	cell.id = json.id;
+	
+	return cell;
+};
+
+/**
+ * Removes all labels, user objects and styles from the given node in-place.
+ */
+EditorUi.prototype.getJsonForCell = function(cell, previous)
+{
+	var result = {id: cell.getId(), vertex: (cell.vertex) ? 1 : 0,
+		edge: (cell.edge) ? 1 : 0};
+	var codec = new mxCodec();
+
+	if (previous != null)
+	{
+		result['previous'] = previous.getId();
+	}
+
+	if (cell.parent != null)
+	{
+		result['parent'] = cell.parent.getId();
+	}
+
+	if (cell.source != null)
+	{
+		result['source'] = cell.source.getId();
+	}
+
+	if (cell.target != null)
+	{
+		result['target'] = cell.target.getId();
+	}
+
+	if (cell.style != null)
+	{
+		result['style'] = cell.style;
+	}
+
+	if (cell.geometry != null)
+	{
+		result['geometry'] = mxUtils.getXml(codec.encode(cell.geometry));
+	}
+	
+	if (cell.value != null)
+	{
+		if (typeof cell.value === 'object' && typeof cell.value.nodeType === 'number' &&
+			typeof cell.value.nodeName === 'string' && typeof cell.value.getAttribute === 'function')
+		{
+			result['xmlValue'] = mxUtils.getXml(cell.value);
+		}
+		else
+		{
+			result['value'] = cell.value;
+		}
+	}
+	
+	return result;
+};
+
+/**
+ * Removes all labels, user objects and styles from the given node in-place.
+ */
+EditorUi.prototype.diffCell = function(oldCell, newCell)
+{
+	var diff = {};
+
+	if (oldCell.parent != null && newCell.parent != null &&
+		oldCell.parent.id != newCell.parent.id)
+	{
+		diff['parent'] = newCell.parent.id;
+	}
+	
+	if (((oldCell.source != null) ? newCell.source == null : newCell.source != null) ||
+		(oldCell.source != null && newCell.source != null &&
+		oldCell.source.id != newCell.source.id))
+	{
+		diff['source'] = (newCell.source != null) ? newCell.source.id : '';
+	}
+	
+	if (((oldCell.target != null) ? newCell.target == null : newCell.target != null) ||
+		(oldCell.target != null && newCell.target != null &&
+		oldCell.target.id != newCell.target.id))
+	{
+		diff['target'] = (newCell.target != null) ? newCell.target.id : '';
+	}
+	
+	function isNode(value)
+	{
+		return value != null && typeof value === 'object' && typeof value.nodeType === 'number' &&
+			typeof value.nodeName === 'string' && typeof value.getAttribute === 'function';
+	};
+	
+	if (isNode(oldCell.value) && isNode(newCell.value))
+	{
+		if (!oldCell.value.isEqualNode(newCell.value))
+		{
+			diff['xmlValue'] = mxUtils.getXml(newCell.value);
+		}
+	}
+	else if (oldCell.value != newCell.value)
+	{
+		if (isNode(newCell.value))
+		{
+			diff['xmlValue'] = mxUtils.getXml(newCell.value);
+		}
+		else
+		{
+			diff['value'] = (newCell.value != null) ? newCell.value : '';
+		}
+	}
+	
+	if (oldCell.style != newCell.style)
+	{
+		diff['style'] = newCell.style;
+	}
+
+	var codec = new mxCodec();
+	
+	// FIXME: Proto only needed because source.geometry has no constructor (wrong type?)
+	if (!this.isObjectEqual(oldCell.geometry, newCell.geometry, new mxGeometry()))
+	{
+		diff['geometry'] = mxUtils.getXml(codec.encode(newCell.geometry));
+	}
+	
+	return diff;
+};
+
+/**
+ *
+ */
+EditorUi.prototype.isObjectEqual = function(source, target, proto)
+{
+	if (source == null && target == null)
+	{
+		return true;
+	}
+	else if ((source != null) ? target == null : target != null)
+	{
+		return false;
+	}
+	else
+	{
+		var replacer = function(key, value)
+		{
+			return (proto == null || proto[key] != value) ? ((value === true) ? 1 : value) : undefined;
+		};
+
+		//console.log('eq', JSON.stringify(source, replacer), JSON.stringify(target, replacer));
+		
+		return JSON.stringify(source, replacer) == JSON.stringify(target, replacer);
+	}
+};

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

@@ -19,6 +19,9 @@ DrawioFile = function(ui, data)
 	 * @default 0
 	 */
 	this.data = data || '';
+
+	// Keeps a copy of the initial data for the shadow document
+	this.initialData = data;
 };
 
 //Extends mxEventSource

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

@@ -1167,7 +1167,7 @@ DriveClient.prototype.saveFile = function(file, revision, success, error, noChec
 /**
  * Sends a message to all collaborators and stores the head revision ID.
  */
-DriveClient.prototype.notifyRealtimeConverted = function(desc)
+DriveClient.prototype.notifyRealtimeConverted = function(desc, age)
 {
 	try
 	{
@@ -1181,7 +1181,7 @@ DriveClient.prototype.notifyRealtimeConverted = function(desc)
 						doc.getModel().getRoot() != null)
 					{
 						doc.getModel().getRoot().set('realtimeConverted',
-							desc.headRevisionId);
+							'rev=' + desc.headRevisionId + ' age=' + age);
 					}
 				}
 				catch (e)
@@ -1354,10 +1354,10 @@ DriveClient.prototype.createUploadRequest = function(id, metadata, data, revisio
 	
 	var headers = {'Content-Type' : 'multipart/mixed; boundary="' + bd + '"'};
 	
-	if (etag != null)
-	{
-		headers['If-Match'] = etag;
-	}
+//	if (etag != null)
+//	{
+//		headers['If-Match'] = etag;
+//	}
 
 	var reqObj = 
 	{
@@ -1767,7 +1767,7 @@ DriveClient.prototype.convertRealtimeFile = function(desc, success, error)
 		try
 		{
 			var age = this.getRealtimeAge(desc, json);
-			this.notifyRealtimeConverted(desc);
+			this.notifyRealtimeConverted(desc, age);
 			
 			// Uses realtime if newer or less than 5 minutes old
 			if (age < 300000)

+ 56 - 5
src/main/webapp/js/diagramly/DriveFile.js

@@ -2,7 +2,7 @@
  * Copyright (c) 2006-2017, JGraph Ltd
  * Copyright (c) 2006-2017, Gaudenz Alder
  */
-DriveFile = function(ui, data, desc, doc)
+DriveFile = function(ui, data, desc, doc, noSync)
 {
 	DrawioFile.call(this, ui, data);
 	
@@ -12,8 +12,21 @@ DriveFile = function(ui, data, desc, doc)
 	{
 		this.realtime = new DriveRealtime(this, doc);
 	}
+	else if (!noSync && DriveFile.SYNC_TYPE != 'none')
+	{
+		this.sync = null; // new FileSync(this);
+	}
 };
 
+/**
+ * Global switch for realtime collaboration type to use:
+ * 
+ * - 'none' means to let the user overwrite/discard changes or create a copy of the file.
+ * - 'sync' means to synchronize changes using a status message and merge remote changes.
+ * - 'realtime' means merging changes in realtime.
+ */
+DriveFile.SYNC_TYPE = 'none';
+
 //Extends mxEventSource
 mxUtils.extend(DriveFile, DrawioFile);
 
@@ -95,9 +108,22 @@ DriveFile.prototype.isAutosaveOptional = function()
  */
 DriveFile.prototype.isAutosave = function()
 {
-	return this.ui.editor.autosave || (this.realtime != null && this.isAutosaveRevision());
+	return (this.sync == null || !this.sync.inConflictState) &&
+		(this.ui.editor.autosave || (this.realtime != null &&
+		this.isAutosaveRevision()));
 };
 
+/**
+ * Overridden to bypass unsaved status message.
+ */
+DriveFile.prototype.addUnsavedStatus = function(err)
+{
+	if (this.sync == null || !this.sync.inConflictState)
+	{
+		DrawioFile.prototype.addUnsavedStatus.apply(this, arguments);
+	}
+}
+
 /**
  * Returns true if an autosave is required at the time of execution.
  * This implementation returns true.
@@ -180,6 +206,9 @@ DriveFile.prototype.saveFile = function(title, revision, success, error, unloadi
 	}
 	else if (!this.savingFile)
 	{
+		// Creates ID and secret for file sync cache entry
+		var cacheId = Editor.guid();
+		var secret = Editor.s4() + Editor.s4() + Editor.s4() + Editor.s4() + Editor.s4();
 		var prevModified = this.isModified;
 		var modified = this.isModified();
 		
@@ -195,6 +224,7 @@ DriveFile.prototype.saveFile = function(title, revision, success, error, unloadi
 		var doSave = mxUtils.bind(this, function(realOverwrite, realRevision)
 		{
 			this.savingFile = true;
+			var snapshot = this.data;
 			
 			this.ui.drive.saveFile(this, realRevision, mxUtils.bind(this, function(resp)
 			{
@@ -213,6 +243,11 @@ DriveFile.prototype.saveFile = function(title, revision, success, error, unloadi
 					this.desc = resp;
 					this.contentChanged();
 					
+					if (this.sync != null)
+					{
+						this.sync.fileSaved(cacheId, secret, snapshot);
+					}
+					
 					if (success != null)
 					{
 						success(resp);
@@ -235,13 +270,17 @@ DriveFile.prototype.saveFile = function(title, revision, success, error, unloadi
 					this.isModified = prevModified;
 					this.savingFile = false;
 					
-					if (error != null)
+					if (this.sync != null && this.isConflict(err))
+					{
+						this.sync.fileConflict(success, error);
+					}
+					else if (error != null)
 					{
 						error(err);
 					}
 				});
 				
-				if (this.isConflict(err))
+				if (DriveFile.SYNC_TYPE == 'none' && this.isConflict(err))
 				{
 					this.showConflictDialog(function()
 					{
@@ -257,7 +296,8 @@ DriveFile.prototype.saveFile = function(title, revision, success, error, unloadi
 				{
 					doError();
 				}
-			}), unloading, unloading, realOverwrite);
+			}), unloading, unloading, realOverwrite, (this.sync != null) ?
+				this.sync.createProperties(cacheId, secret) : null);
 		});
 		
 		doSave(overwrite, revision);
@@ -417,6 +457,11 @@ DriveFile.prototype.open = function()
 	else
 	{
 		DrawioFile.prototype.open.apply(this, arguments);
+		
+		if (this.sync != null)
+		{
+			this.sync.start();
+		}
 	}
 };
 
@@ -433,6 +478,12 @@ DriveFile.prototype.close = function(unloading)
 		this.realtime.destroy(unloading);
 		this.realtime = null;
 	}
+
+	if (this.sync != null)
+	{
+		this.sync.destroy(unloading);
+		this.sync = null;
+	}
 };
 
 /**

+ 23 - 0
src/main/webapp/js/diagramly/Editor.js

@@ -2650,6 +2650,28 @@
 				
 				return rackLayout;
 			}
+			else if (typeof(mxTableLayout) != 'undefined' && style['childLayout'] == 'tableLayout')
+	        {
+	            var tableLayout = new mxTableLayout(this.graph);
+	            tableLayout.rows = style['tableRows'] || 2;
+	            tableLayout.columns = style['tableColumns'] || 2;
+	            tableLayout.colPercentages = style['colPercentages'];
+	            tableLayout.rowPercentages = style['rowPercentages'];
+	            tableLayout.equalColumns = mxUtils.getValue(style, 'equalColumns', tableLayout.colPercentages? '0' : '1') == '1';
+	            tableLayout.equalRows = mxUtils.getValue(style, 'equalRows', tableLayout.rowPercentages? '0' : '1') == '1';
+	            tableLayout.resizeParent = mxUtils.getValue(style, 'resizeParent', '1') == '1';
+	            tableLayout.border = style['tableBorder'] || tableLayout.border;
+	            tableLayout.marginLeft = style['marginLeft'] || 0;
+	            tableLayout.marginRight = style['marginRight'] || 0;
+	            tableLayout.marginTop = style['marginTop'] || 0;
+	            tableLayout.marginBottom = style['marginBottom'] || 0;
+	            tableLayout.autoAddCol = mxUtils.getValue(style, 'autoAddCol', '0') == '1';
+	            tableLayout.autoAddRow = mxUtils.getValue(style, 'autoAddRow', tableLayout.autoAddCol? '0' : '1') == '1';
+	            tableLayout.colWidths = style['colWidths'] || "100";
+	            tableLayout.rowHeights = style['rowHeights'] || "50";
+	            
+	            return tableLayout;
+	        }
 			
 			return layoutManagerGetLayout.apply(this, arguments);
 		}
@@ -3229,6 +3251,7 @@
 	mxStencilRegistry.libraries['eip'] = [SHAPES_PATH + '/mxEip.js', STENCIL_PATH + '/eip.xml'];
 	mxStencilRegistry.libraries['networks'] = [SHAPES_PATH + '/mxNetworks.js', STENCIL_PATH + '/networks.xml'];
 	mxStencilRegistry.libraries['aws3d'] = [SHAPES_PATH + '/mxAWS3D.js', STENCIL_PATH + '/aws3d.xml'];
+	mxStencilRegistry.libraries['aws4'] = [SHAPES_PATH + '/mxAWS4.js', STENCIL_PATH + '/aws4.xml'];
 	mxStencilRegistry.libraries['veeam'] = [STENCIL_PATH + '/veeam/2d.xml', STENCIL_PATH + '/veeam/3d.xml', STENCIL_PATH + '/veeam/veeam.xml'];
 	mxStencilRegistry.libraries['pid2inst'] = [SHAPES_PATH + '/pid2/mxPidInstruments.js'];
 	mxStencilRegistry.libraries['pid2misc'] = [SHAPES_PATH + '/pid2/mxPidMisc.js', STENCIL_PATH + '/pid/misc.xml'];

+ 146 - 151
src/main/webapp/js/diagramly/EditorUi.js

@@ -547,6 +547,8 @@
 				var replaceStrLen = replaceString.length;
 				data = data.slice(0, index) + replaceString + data.slice(index + replaceStrLen - 1, data.length);
 			}
+			
+			data = this.editor.graph.zapGremlins(data);
 		}
 		
 		return data;
@@ -981,60 +983,78 @@
 
 		var node = (data != null && data.length > 0) ? mxUtils.parseXml(data).documentElement : null;
 
-		// Some nodes must be extracted here to find the mxfile node
-		// LATER: Remove duplicate call to extractGraphModel in overridden setGraphXml
-		var tmp = (node != null) ? this.editor.extractGraphModel(node, true) : null;
+		// Checks for parser errors
+		var errors = node.getElementsByTagName('parsererror');
 		
-		if (tmp != null)
+		if (errors.length > 0)
 		{
-			node = tmp;
+			var cause = mxResources.get('invalidOrMissingFile');
+			var divs = errors[0].getElementsByTagName('div');
+			
+			if (divs.length > 0)
+			{
+				cause = mxUtils.getTextContent(divs[0]);
+			}
+			
+			throw new Error(cause);
 		}
-
-		if (node != null && node.nodeName == 'mxfile')
+		else
 		{
-			var nodes = node.getElementsByTagName('diagram');
-
-			if (urlParams['pages'] != '0' || nodes.length > 1 ||
-				(nodes.length == 1 && nodes[0].hasAttribute('name')))
+			// Some nodes must be extracted here to find the mxfile node
+			// LATER: Remove duplicate call to extractGraphModel in overridden setGraphXml
+			var tmp = (node != null) ? this.editor.extractGraphModel(node, true) : null;
+			
+			if (tmp != null)
 			{
-				this.fileNode = node;
-				this.pages = [];
-				
-				// Wraps page nodes
-				for (var i = 0; i < nodes.length; i++)
+				node = tmp;
+			}
+	
+			if (node != null && node.nodeName == 'mxfile')
+			{
+				var nodes = node.getElementsByTagName('diagram');
+	
+				if (urlParams['pages'] != '0' || nodes.length > 1 ||
+					(nodes.length == 1 && nodes[0].hasAttribute('name')))
 				{
-					var page = new DiagramPage(nodes[i]);
+					this.fileNode = node;
+					this.pages = [];
 					
-					// Checks for invalid page names
-					if (page.getName() == null)
+					// Wraps page nodes
+					for (var i = 0; i < nodes.length; i++)
 					{
-						page.setName(mxResources.get('pageWithNumber', [i + 1]));
+						var page = new DiagramPage(nodes[i]);
+						
+						// Checks for invalid page names
+						if (page.getName() == null)
+						{
+							page.setName(mxResources.get('pageWithNumber', [i + 1]));
+						}
+						
+						this.pages.push(page);
 					}
 					
-					this.pages.push(page);
+					this.currentPage = this.pages[Math.max(0, Math.min(this.pages.length - 1, urlParams['page'] || 0))];
+					node = this.currentPage.node;
 				}
-				
-				this.currentPage = this.pages[Math.max(0, Math.min(this.pages.length - 1, urlParams['page'] || 0))];
-				node = this.currentPage.node;
 			}
-		}
-		
-		// Creates tabbed file structure if enforced by URL
-		if (urlParams['pages'] != '0' && this.fileNode == null && node != null)
-		{
-			this.fileNode = node.ownerDocument.createElement('mxfile');
-			this.currentPage = new DiagramPage(node.ownerDocument.createElement('diagram'));
-			this.currentPage.setName(mxResources.get('pageWithNumber', [1]));
-	 	 	this.pages = [this.currentPage];
-		}
-		
-		// Avoids scroll offset when switching page
-		this.editor.setGraphXml(node);
-		
-		// Avoids duplicate parsing of the XML stored in the node
-		if (this.currentPage != null)
-		{
-			this.currentPage.root = this.editor.graph.model.root;
+			
+			// Creates tabbed file structure if enforced by URL
+			if (urlParams['pages'] != '0' && this.fileNode == null && node != null)
+			{
+				this.fileNode = node.ownerDocument.createElement('mxfile');
+				this.currentPage = new DiagramPage(node.ownerDocument.createElement('diagram'));
+				this.currentPage.setName(mxResources.get('pageWithNumber', [1]));
+		 	 	this.pages = [this.currentPage];
+			}
+			
+			// Avoids scroll offset when switching page
+			this.editor.setGraphXml(node);
+			
+			// Avoids duplicate parsing of the XML stored in the node
+			if (this.currentPage != null)
+			{
+				this.currentPage.root = this.editor.graph.model.root;
+			}
 		}
 	};
 
@@ -1172,7 +1192,7 @@
 							this.editor.graph.pageVisible = pageVisible;
 						}
 						
-						var req = this.createDownloadRequest(newTitle, format, ignoreSelection, base64, transparent);
+						var req = this.createDownloadRequest(newTitle, format, ignoreSelection, base64, transparent, currentPage);
 						this.editor.graph.pageVisible = prev;
 						
 						return req;
@@ -1196,15 +1216,16 @@
 	 * @param {number} dx X-coordinate of the translation.
 	 * @param {number} dy Y-coordinate of the translation.
 	 */
-	EditorUi.prototype.createDownloadRequest = function(filename, format, ignoreSelection, base64, transparent)
+	EditorUi.prototype.createDownloadRequest = function(filename, format, ignoreSelection, base64, transparent, currentPage)
 	{
 		var bounds = this.editor.graph.getGraphBounds();
 		
-		// Exports only current page for PDF since it does not contain file data, but for
-		// the other formats with XML included we need to send the complete data and use
+		// Exports only current page for images that does not contain file data, but for
+		// the other formats with XML included or pdf with all pages, we need to send the complete data and use
 		// the from/to URL parameters to specify the page to be exported.
-		var data = this.getFileData(true, null, null, null, ignoreSelection, format != 'xmlpng');
+		var data = this.getFileData(true, null, null, null, ignoreSelection, currentPage == false? false : format != 'xmlpng');
 		var range = '';
+		var allPages = '';
 		
 		if (bounds.width * bounds.height > MAX_AREA || data.length > MAX_REQUEST_SIZE)
 		{
@@ -1213,6 +1234,11 @@
 		
 		var embed = '0';
        	
+		if (format == 'pdf' && currentPage == false)
+		{
+			allPages = '&allPages=1';
+		}
+		
        	if (format == 'xmlpng')
        	{
        		embed = '1';
@@ -1239,7 +1265,7 @@
 			bg = mxConstants.NONE;
 		}
        	
-		return new mxXmlRequest(EXPORT_URL, 'format=' + format + range +
+		return new mxXmlRequest(EXPORT_URL, 'format=' + format + range + allPages +
 			'&bg=' + ((bg != null) ? bg : mxConstants.NONE) +
 			'&base64=' + base64 + '&embedXml=' + embed + '&xml=' +
 			encodeURIComponent(data) + ((filename != null) ?
@@ -1742,6 +1768,7 @@
 				// DescriptorChanged updates the enabled state of the graph
 				this.setGraphEnabled(true);
 				this.setMode(file.getMode());
+				// this.editor.graph.model.prefix = Editor.guid() + '-';
 				this.editor.undoManager.clear();
 				this.descriptorChanged();
 				this.updateUi();
@@ -2002,8 +2029,6 @@
 				
 				if (value != null && key == 'rtCell')
 				{
-					console.log('here', replacer, obj, key,
-						obj.constructor !== mxCell, key !== 'rtCell');
 					value = null;
 				}
 				
@@ -2030,82 +2055,6 @@
 	    return hash;
 	};
 
-	/**
-	 * Gets a file node that is comparable with a remote file node
-	 * so that using isEqualNode returns true if the files can be
-	 * considered equal.
-	 */
-	EditorUi.prototype.getComparableFile = function(node)
-	{
-		// Removes all attributes from the mxfile
-		while (node.attributes.length > 0)
-		{
-			node.removeAttribute(node.attributes[0].name);
-		}
-
-		// Removes all diagram IDs since those can be missing in
-		// realtime but will be added on the fly
-		var diagrams = node.getElementsByTagName('diagram');
-		
-		for (var i = 0; i < diagrams.length; i++)
-		{
-			diagrams[i].removeAttribute('name');
-			diagrams[i].removeAttribute('id');
-
-			// Uncompress diagram data for structural comparison
-			var tmp = this.ui.editor.graph.decompress(mxUtils.getTextContent(diagrams[i]));
-			
-			if (tmp != null && tmp.length > 0)
-			{
-				while (diagrams[i].firstChild != null)
-				{
-					diagrams[i].removeChild(diagrams[i].firstChild);
-				}
-
-				diagrams[i].appendChild(mxUtils.parseXml(tmp).documentElement);
-			}
-		}
-		
-		// Some attributes have been initialized using different defaults
-		// in the UI compared to realtime so they must be ignored
-		var models = node.getElementsByTagName('mxGraphModel');
-		
-		for (var i = 0; i < models.length; i++)
-		{
-			while (models[i].attributes.length > 0)
-			{
-				models[i].removeAttribute(models[i].attributes[0].name);
-			}
-		}
-		
-		return node;
-	};
-
-	/**
-	 * Removes all labels, user objects and styles from the given node in-place.
-	 */
-	EditorUi.prototype.anonymizeNode = function(node)
-	{
-		if (node != null)
-		{
-			var nodes = node.getElementsByTagName('mxCell');
-		
-			for (var i = 0; i < nodes.length; i++)
-			{
-				nodes[i].removeAttribute('style');
-				nodes[i].removeAttribute('value');
-				
-				if (nodes[i].parentNode != null && nodes[i].parentNode.nodeName == 'UserObject' &&
-					nodes[i].parentNode.parentNode != null)
-				{
-					nodes[i].parentNode.parentNode.replaceChild(nodes[i], nodes[i].parentNode);
-				}
-			}
-		}
-		
-		return node;
-	};
-
 	/**
 	 * Adds empty implementation
 	 */
@@ -4023,17 +3972,29 @@
 		}
 	};
 	
+	EditorUi.prototype.addRadiobox = function(div, radioGroupName, label, checked, disabled, disableNewline, visible)
+	{
+		return this.addCheckbox(div, label, checked, disabled, disableNewline, visible, true, radioGroupName);
+	}
+	
 	/**
 	 * 
 	 */
-	EditorUi.prototype.addCheckbox = function(div, label, checked, disabled, disableNewline, visible)
+	EditorUi.prototype.addCheckbox = function(div, label, checked, disabled, disableNewline, visible, asRadio, radioGroupName)
 	{
 		visible = (visible != null) ? visible : true;
 		
 		var cb = document.createElement('input');
 		cb.style.marginRight = '8px';
 		cb.style.marginTop = '16px';
-		cb.setAttribute('type', 'checkbox');
+		cb.setAttribute('type', asRadio? 'radio' : 'checkbox');
+		var id = "cb" + Math.random();
+		cb.id = id;
+		
+		if (radioGroupName != null)
+		{
+			cb.setAttribute('name', radioGroupName);
+		}
 		
 		if (checked)
 		{
@@ -4050,23 +4011,15 @@
 		{
 			div.appendChild(cb);
 			
-			var span = document.createElement('span');
-			mxUtils.write(span, label);
-			div.appendChild(span);
+			var lbl = document.createElement('label');
+			mxUtils.write(lbl, label);
+			lbl.setAttribute('for', id);
+			div.appendChild(lbl);
 
 			if (!disableNewline)
 			{
 				mxUtils.br(div);
 			}
-			
-			mxEvent.addListener(span, 'click', mxUtils.bind(this, function(evt)
-			{
-				if (cb.getAttribute('disabled') != 'disabled')
-				{
-					cb.checked = !cb.checked;
-					mxEvent.consume(evt);
-				}
-			}));
 		}
 		
 		return cb;
@@ -6239,6 +6192,46 @@
 		}
 	};
 
+	
+	/**
+	 * Imports the given GraphML (yEd) file
+	 */
+	EditorUi.prototype.importGraphML = function(xmlData, done, onerror)
+	{
+		onerror = (onerror != null) ? onerror : mxUtils.bind(this, function(e)
+		{
+			this.handleError(e);
+		});
+		
+		var delayed = mxUtils.bind(this, function()
+		{
+			this.loadingExtensions = false;
+			
+			if (this.doImportGraphML)
+			{
+				
+				try
+				{
+					this.doImportGraphML(xmlData, done, onerror);
+				}
+				catch (e)
+				{
+					onerror(e);
+				}
+			}
+		});
+		
+		if (!this.doImportGraphML && !this.loadingExtensions && !this.isOffline())
+		{
+			this.loadingExtensions = true;
+			mxscript('js/extensions.min.js', delayed);
+		}
+		else
+		{
+			delayed();
+		}
+	};	
+	
 	/**
 	 * Export the diagram to VSDX
 	 */
@@ -6579,7 +6572,7 @@
 	};
 	
 	/**
-	 * Returns true for Gliffy or GraphML data or .vsdx filenames.
+	 * Returns true for Gliffy
 	 */
 	EditorUi.prototype.isLucidChartData = function(data)
 	{
@@ -6736,17 +6729,11 @@
 					'verticalAlign=top;aspect=fixed;imageAspect=0;image=' + data + ';')];
 			}
 		}
-		else if (/(\.*<graphml )/.test(data) && typeof window.mxGraphMlCodec !== 'undefined') 
+		else if (/(\.*<graphml )/.test(data)) 
         {
-            new mxGraphMlCodec().decode(data, mxUtils.bind(this, function(xml)
-            {
-                var importedCells = this.importXml(xml, dx, dy, crop);
-                
-                if (done != null)
-                {
-                    done(importedCells);
-                }
-            }));
+			async = true;
+
+			this.importGraphML(data, handleResult);
         }
 		else if (file != null && filename != null && ((/(\.v(dx|sdx?))($|\?)/i.test(filename)) || /(\.vs(x|sx?))($|\?)/i.test(filename)))
 		{
@@ -9033,6 +9020,14 @@
 									handleResult(xml);
 								}));
 							}
+							else if (/(\.*<graphml )/.test(data)) 
+							{
+								this.importGraphML(data, mxUtils.bind(this, function(xml)
+								{
+									this.spinner.stop();
+									handleResult(xml);
+								}));
+							}
 							else if (Graph.fileSupport && !this.isOffline() && new XMLHttpRequest().upload &&
 								this.isRemoteFileFormat(data, name))
 							{

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1260 - 0
src/main/webapp/js/diagramly/FileSync.js


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

@@ -14,7 +14,7 @@ window.isSvgBrowser = window.isSvgBrowser || (navigator.userAgent.indexOf('MSIE'
 window.EXPORT_URL = window.EXPORT_URL || 'https://exp.draw.io/ImageExport4/export';
 window.PLANT_URL = window.PLANT_URL || 'https://exp-plant.draw.io/plantuml3';
 window.VSD_CONVERT_URL = window.VSD_CONVERT_URL || "https://convert.draw.io/VsdConverter/api/converter";
-//window.EMF_CONVERT_URL = window.EMF_CONVERT_URL || "http://localhost:5000/convertEMF";
+window.EMF_CONVERT_URL = window.EMF_CONVERT_URL || "https://convert.draw.io/emf2png/convertEMF";
 window.SAVE_URL = window.SAVE_URL || 'save';
 window.OPEN_URL = window.OPEN_URL || 'open';
 window.PROXY_URL = window.PROXY_URL || 'proxy';
@@ -110,8 +110,8 @@ window.mxLanguageMap = window.mxLanguageMap ||
 	'th' : 'ไทย',
 	'ko' : '한국어',
 	'ja' : '日本語',
-	'zh' : '中文(简体)',
-	'zh-tw' : '中文(繁體)'
+	'zh' : '简体中文',
+	'zh-tw' : '繁體中文'
 };
 
 if (typeof window.mxBasePath === 'undefined')

+ 81 - 55
src/main/webapp/js/diagramly/Menus.js

@@ -194,6 +194,7 @@
 			}
 			else
 			{
+				var noPages = editorUi.pages == null || editorUi.pages.length <= 1;
 				var div = document.createElement('div');
 				div.style.whiteSpace = 'nowrap';
 				
@@ -202,34 +203,55 @@
 				hd.style.cssText = 'width:100%;text-align:center;margin-top:0px;margin-bottom:4px';
 				div.appendChild(hd);
 				
-				var selection = editorUi.addCheckbox(div, mxResources.get('selectionOnly'),
-					false, graph.isSelectionEmpty());
-				var crop = editorUi.addCheckbox(div, mxResources.get('crop'),
-					!graph.pageVisible || !editorUi.pdfPageExport,
-					!editorUi.pdfPageExport);
-				crop.style.marginBottom = '16px';
+				var cropEnableFn = function()
+				{
+					if (allPages != this && this.checked)
+					{
+						crop.removeAttribute('disabled');
+					}
+					else
+					{
+						crop.setAttribute('disabled', 'disabled');
+						crop.checked = false;
+					}
+				};
+				
+				var dlgH = 146;
 				
-				// Crop is only enabled if selection only is selected
-				if (!editorUi.pdfPageExport)
+				if (editorUi.pdfPageExport && !noPages)
 				{
-					mxEvent.addListener(selection, 'change', function()
+					var allPages = editorUi.addRadiobox(div, 'pages', mxResources.get('allPages'), true);
+					var currentPage = editorUi.addRadiobox(div, 'pages', mxResources.get('currentPage', null, 'Current Page'), false);
+					var selection = editorUi.addRadiobox(div, 'pages', mxResources.get('selectionOnly'), false, graph.isSelectionEmpty());
+					var crop = editorUi.addCheckbox(div, mxResources.get('crop'), false, true);
+					
+					mxEvent.addListener(allPages, 'change', cropEnableFn);
+					mxEvent.addListener(currentPage, 'change', cropEnableFn);
+					mxEvent.addListener(selection, 'change', cropEnableFn);
+					dlgH = 205;
+				}
+				else
+				{
+					var selection = editorUi.addCheckbox(div, mxResources.get('selectionOnly'),
+							false, graph.isSelectionEmpty());
+					var crop = editorUi.addCheckbox(div, mxResources.get('crop'),
+							!graph.pageVisible || !editorUi.pdfPageExport,
+							!editorUi.pdfPageExport);
+					
+					// Crop is only enabled if selection only is selected
+					if (!editorUi.pdfPageExport)
 					{
-						if (selection.checked)
-						{
-							crop.removeAttribute('disabled');
-						}
-						else
-						{
-							crop.setAttribute('disabled', 'disabled');
-						}
-					});	
+						mxEvent.addListener(selection, 'change', cropEnableFn);	
+					}
 				}
 				
+				crop.style.marginBottom = '16px';
+				
 				var dlg = new CustomDialog(editorUi, div, mxUtils.bind(this, function()
 				{
-					editorUi.downloadFile('pdf', null, null, !selection.checked, null, !crop.checked);
+					editorUi.downloadFile('pdf', null, null, !selection.checked, noPages? true : !allPages.checked, !crop.checked);
 				}), null, mxResources.get('export'));
-				editorUi.showDialog(dlg.container, 300, 146, true, true);
+				editorUi.showDialog(dlg.container, 300, dlgH, true, true);
 			}
 		}));
 		
@@ -1068,37 +1090,47 @@
 				
 				this.editorUi.actions.addAction('testDownloadRtModel...', mxUtils.bind(this, function()
 				{
-					var file = this.editorUi.getCurrentFile();
-					
-					if (file != null && file.constructor == DriveFile &&
-						editorUi.spinner.spin(document.body, mxResources.get('export')))
+					if (editorUi.drive == null)
 					{
-						// LATER: Download full model dump with history
-						var req = new mxXmlRequest('https://www.googleapis.com/drive/v2/files/' +
-								file.getId() + '/realtime?supportsTeamDrives=true', null, 'GET');
-
-						// Adds auth token
-						req.setRequestHeaders = function(request)
-						{
-							mxXmlRequest.prototype.setRequestHeaders.apply(this, arguments);
-							var token = gapi.auth.getToken().access_token;
-							request.setRequestHeader('authorization', 'Bearer ' + token);	
-						};
-						
-						req.send(function(req)
+						editorUi.handleError({message: mxResources.get('serviceUnavailableOrBlocked')});
+					}
+					else
+					{
+						editorUi.drive.execute(mxUtils.bind(this, function()
 						{
-							editorUi.spinner.stop();
+							var fileId =prompt('File ID', '');
 							
-							if (req.getStatus() >= 200 && req.getStatus() <= 299)
+							if (fileId != null && fileId.length > 0 &&
+								editorUi.spinner.spin(document.body, mxResources.get('export')))
 							{
-								editorUi.saveLocalFile(req.getText(), 'json-' + file.getId()+'.txt', 'text/plain');
-							}
-							else
-							{
-								editorUi.handleError({message: mxResources.get('fileNotFound')},
-									mxResources.get('errorLoadingFile'));
+								// LATER: Download full model dump with history
+								var req = new mxXmlRequest('https://www.googleapis.com/drive/v2/files/' +
+										fileId + '/realtime?supportsTeamDrives=true', null, 'GET');
+		
+								// Adds auth token
+								req.setRequestHeaders = function(request)
+								{
+									mxXmlRequest.prototype.setRequestHeaders.apply(this, arguments);
+									var token = gapi.auth.getToken().access_token;
+									request.setRequestHeader('authorization', 'Bearer ' + token);	
+								};
+								
+								req.send(function(req)
+								{
+									editorUi.spinner.stop();
+									
+									if (req.getStatus() >= 200 && req.getStatus() <= 299)
+									{
+										editorUi.saveLocalFile(req.getText(), 'json-' + fileId +'.txt', 'text/plain');
+									}
+									else
+									{
+										editorUi.handleError({message: mxResources.get('fileNotFound')},
+											mxResources.get('errorLoadingFile'));
+									}
+								});
 							}
-						});
+						}));
 					}
 				}));
 
@@ -1106,15 +1138,9 @@
 				{
 					this.addMenuItems(menu, ['-', 'testShowRtModel', 'testDebugRtModel', 'testDownloadRtModel'], parent);
 				}
-				else if (this.editorUi.getCurrentFile() != null && this.editorUi.getCurrentFile().constructor == DriveFile)
-				{
-					this.addMenuItems(menu, ['-', 'testDownloadRtModel'], parent);
-				}
-				else
-				{
-					menu.addSeparator(parent);
-				}
 
+				this.addMenuItems(menu, ['-', 'testDownloadRtModel'], parent);
+				
 				menu.addItem(mxResources.get('testImportRtModel') + '...', null, function()
 				{
 					var input = document.createElement('input');
@@ -1145,7 +1171,7 @@
 			
 					input.click();
 				});
-				
+
 				mxResources.parse('testShowConsole=Show Console');
 				this.editorUi.actions.addAction('testShowConsole', function()
 				{

+ 122 - 106
src/main/webapp/js/diagramly/graphml/mxGraphMlCodec.js

@@ -7,116 +7,128 @@ function mxGraphMlCodec()
 mxGraphMlCodec.prototype.refRegexp = /^\{y\:GraphMLReference\s+(\d+)\}$/;
 mxGraphMlCodec.prototype.staticRegexp = /^\{x\:Static\s+(.+)\.(.+)\}$/;
 
-mxGraphMlCodec.prototype.decode = function (xml, callback)
+mxGraphMlCodec.prototype.decode = function (xml, callback, onError)
 {
-	var doc = mxUtils.parseXml(xml);
-	
-	var graphs = this.getDirectChildNamedElements(doc.documentElement, mxGraphMlConstants.GRAPH);
-	
-	this.initializeKeys(doc.documentElement);
-	
-	var mxFile = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><mxfile>";
-	for (var i = 0; i < graphs.length; i++)
+	try
 	{
-		var pageElement = graphs[i];
-
-		var graph = this.createMxGraph();
-		var model = graph.getModel();
+		var doc = mxUtils.parseXml(xml);
 		
-        model.beginUpdate();
-        try 
-        {
-	        this.nodesMap = {};
-	    	this.edges = [];
-	        this.importGraph(pageElement, graph, graph.getDefaultParent());
+		var graphs = this.getDirectChildNamedElements(doc.documentElement, mxGraphMlConstants.GRAPH);
+		
+		this.initializeKeys(doc.documentElement);
+		
+		var mxFile = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><mxfile>";
+		for (var i = 0; i < graphs.length; i++)
+		{
+			var pageElement = graphs[i];
+	
+			var graph = this.createMxGraph();
+			var model = graph.getModel();
+			
+	        model.beginUpdate();
+	        try 
+	        {
+		        this.nodesMap = {};
+		    	this.edges = [];
+		        this.importGraph(pageElement, graph, graph.getDefaultParent());
+		    	
+		    	for (var i = 0; i < this.edges.length; i++)
+				{
+		    		var edgesObj = this.edges[i];
+		    		var edges = edgesObj.edges;
+		    		var parent = edgesObj.parent;
+		    		var dx = edgesObj.dx, dy = edgesObj.dy;
+		
+			    	for (var j = 0; j < edges.length; j++)
+			    	{
+			    		this.importEdge(edges[j], graph, parent, dx, dy);
+			    	}
+				}
+	        }
+	        catch(e)
+	        {
+	        	console.log(e);
+	        	throw e;
+	        }
+	        finally
+	        {
+	        	model.endUpdate();
+	        }
 	    	
-	    	for (var i = 0; i < this.edges.length; i++)
-			{
-	    		var edgesObj = this.edges[i];
-	    		var edges = edgesObj.edges;
-	    		var parent = edgesObj.parent;
-	    		var dx = edgesObj.dx, dy = edgesObj.dy;
-	
-		    	for (var j = 0; j < edges.length; j++)
-		    	{
-		    		this.importEdge(edges[j], graph, parent, dx, dy);
-		    	}
-			}
-        }
-        catch(e)
-        {
-        	console.log(e);
-        }
-        finally
-        {
-        	model.endUpdate();
-        }
-    	
-    	//update edges' labels to convert their labels relative coordinate to ours
-        model.beginUpdate();
-        try 
-        {
-        	var cells = graph.getModel().cells;
-        	var tr = graph.view.translate;
-        	
-        	for (var id in cells)
-    		{
-        		var edge = cells[id];
-        		
-        		if (edge.edge && edge.getChildCount() > 0)
-    			{
-        			for (var i = 0; i < edge.getChildCount(); i++)
-    				{
-        				var cell = edge.children[i];
-                		var geo = cell.geometry;
-                		
-                		if (!geo.adjustIt) continue;
-                		
-	        			var state = graph.view.getState(edge);
-	        			var abdPs = state.absolutePoints;
-	        			var p0 = abdPs[0];
-	        			var pe = abdPs[abdPs.length - 1];
-	        			
-	        			var ratio = geo.x;
-	        			var dist = geo.y;
-	        			var dx = pe.x - p0.x
-	        			var dy = pe.y - p0.y
-	 
-	        			var x = p0.x + ratio * dx;
-	        			var y = p0.y + ratio * dy;
-	        			
-	        			var d = Math.sqrt(dx*dx + dy*dy);
-	        			dx /= d;
-	        			dy /= d;
-	        			
-	        			x -= dist * dy;
-	        			y += dist * dx;
-	        			
-	        			var np = graph.view.getRelativePoint(state, x, y);
-	        			geo.x = np.x;
-	        			geo.y = np.y;
-	    			}
+	    	//update edges' labels to convert their labels relative coordinate to ours
+	        model.beginUpdate();
+	        try 
+	        {
+	        	var cells = graph.getModel().cells;
+	        	var tr = graph.view.translate;
+	        	
+	        	for (var id in cells)
+	    		{
+	        		var edge = cells[id];
+	        		
+	        		if (edge.edge && edge.getChildCount() > 0)
+	    			{
+	        			for (var i = 0; i < edge.getChildCount(); i++)
+	    				{
+	        				var cell = edge.children[i];
+	                		var geo = cell.geometry;
+	                		
+	                		if (!geo.adjustIt) continue;
+	                		
+		        			var state = graph.view.getState(edge);
+		        			var abdPs = state.absolutePoints;
+		        			var p0 = abdPs[0];
+		        			var pe = abdPs[abdPs.length - 1];
+		        			
+		        			var ratio = geo.x;
+		        			var dist = geo.y;
+		        			var dx = pe.x - p0.x
+		        			var dy = pe.y - p0.y
+		 
+		        			var x = p0.x + ratio * dx;
+		        			var y = p0.y + ratio * dy;
+		        			
+		        			var d = Math.sqrt(dx*dx + dy*dy);
+		        			dx /= d;
+		        			dy /= d;
+		        			
+		        			x -= dist * dy;
+		        			y += dist * dx;
+		        			
+		        			var np = graph.view.getRelativePoint(state, x, y);
+		        			geo.x = np.x;
+		        			geo.y = np.y;
+		    			}
+		    		}
 	    		}
-    		}
-        }
-        catch(e)
-        {
-        	console.log(e);
-        }
-        finally
-        {
-        	model.endUpdate();
-        }
-    	
-        mxFile += this.processPage(graph, i+1);
-	}
-
-	mxFile += "</mxfile>";
+	        }
+	        catch(e)
+	        {
+	        	console.log(e);
+	        	throw e;
+	        }
+	        finally
+	        {
+	        	model.endUpdate();
+	        }
+	    	
+	        mxFile += this.processPage(graph, i+1);
+		}
 	
-	if (callback)
-	{
-		callback(mxFile);
+		mxFile += "</mxfile>";
+		
+		if (callback)
+		{
+			callback(mxFile);
+		}
 	}
+    catch(e)
+    {
+    	if (onError) 
+    	{
+    		onError(e);
+    	}
+    }
 };
 
 mxGraphMlCodec.prototype.initializeKeys = function (graphmlElement)
@@ -965,7 +977,6 @@ mxGraphMlCodec.prototype.addNodeStyle = function (node, dataObj, style)
 		"yjs:ShapeNodeStyle": styleCommonMap,
 		"demostyle:FlowchartNodeStyle": styleCommonMap,
 		"demostyle:AssetNodeStyle": assetNodesStyle,
-		"demostyle:DemoGroupStyle": styleCommonMap,
 		"bpmn:ActivityNodeStyle": bpmnActivityStyle,
 		"bpmn:GatewayNodeStyle": bpmnGatewayStyle,
 		"bpmn:ConversationNodeStyle": bpmnConversationStyle,
@@ -3108,11 +3119,16 @@ var mxGraphMlConstants =
 	
 	Y_LABEL: "y:Label",
 	
-	TEXT: "Text",
-	
 	LAYOUTPARAMETER: "LayoutParameter",
 	
 	YJS_DEFAULTLABELSTYLE: "yjs:DefaultLabelStyle",
 	
 	MEMBER: "Member"
 };
+
+
+EditorUi.prototype.doImportGraphML = function(xmlData, done, onerror)
+{
+	new mxGraphMlCodec().decode(xmlData, done, onerror);
+};
+

+ 472 - 0
src/main/webapp/js/diagramly/mxTableLayout.js

@@ -0,0 +1,472 @@
+/**
+ * Copyright (c) 2006-2018, JGraph Ltd
+ */
+/**
+ * Class: mxTableLayout
+ * 
+ * Extends <mxGraphLayout> to create a table of the
+ * child vertices. The children do not need to be connected for this layout
+ * to work.
+ * 
+ * Example:
+ * 
+ * (code)
+ * var layout = new mxTableLayout(graph, 2, 2); //2x2 table layout
+ * layout.execute(graph.getDefaultParent());
+ * (end)
+ * 
+ * Constructor: mxTableLayout
+ * 
+ * Constructs a new table layout for the specified graph
+ */
+function mxTableLayout(graph, rows, columns, border)
+{
+	mxGraphLayout.call(this, graph);
+	this.rows = (rows != null && rows > 0) ? rows : 2;
+	this.columns = (columns != null && columns > 0) ? columns : 2;
+	this.border = (border != null) ? border : 0;
+};
+
+/**
+ * Extends mxStackLayout.
+ */
+mxTableLayout.prototype = new mxStackLayout();
+mxTableLayout.prototype.constructor = mxTableLayout;
+
+/**
+ * Variable: rows
+ *
+ * Specifies the number of rows of the layout. Default is 2.
+ */
+mxTableLayout.prototype.rows = 2;
+
+/**
+ * Variable: columns
+ *
+ * Specifies the number of columns of the layout. Default is 2.
+ */
+mxTableLayout.prototype.columns = 2;
+
+/**
+ * Variable: border
+ *
+ * Border between cells and around the table. Default is 0.
+ */
+mxTableLayout.prototype.border = 0;
+
+/**
+ * Variable: marginTop
+ * 
+ * Top margin for the child area. Default is 0.
+ */
+mxTableLayout.prototype.marginTop = 0;
+
+/**
+ * Variable: marginLeft
+ * 
+ * Top margin for the child area. Default is 0.
+ */
+mxTableLayout.prototype.marginLeft = 0;
+
+/**
+ * Variable: marginRight
+ * 
+ * Top margin for the child area. Default is 0.
+ */
+mxTableLayout.prototype.marginRight = 0;
+
+/**
+ * Variable: marginBottom
+ * 
+ * Top margin for the child area. Default is 0.
+ */
+mxTableLayout.prototype.marginBottom = 0;
+
+/**
+ * Variable: equalColumns
+ * 
+ * Boolean indicating if columns are distributed equally. Default is true
+ */
+mxTableLayout.prototype.equalColumns = true;
+
+/**
+ * Variable: colWidths
+ * 
+ * Required only if resizeParent is true and autoAddCol is true. It should be one value if equalColumns is true. Default is 100
+ */
+mxTableLayout.prototype.colWidths = "100";
+
+/**
+ * Variable: equalRows
+ * 
+ * Boolean indicating if rows are distributed equally. Default is true
+ */
+mxTableLayout.prototype.equalRows = true;
+
+/**
+ * Variable: rowHeights
+ * 
+ * Required only if resizeParent is true and autoAddRow is true. It should be one value if equalRows is true. Default is 50
+ */
+mxTableLayout.prototype.rowHeights = "50";
+
+/**
+ * Variable: colPercentages
+ * 
+ * The percentages of each column from the parent width. This value is ignored if equalColumns is true. Default is null.
+ */
+mxTableLayout.prototype.colPercentages = null;
+	
+/**
+ * Variable: rowPercentages
+ * 
+ * The percentages of each row from the parent width. This value is ignored if equalRows is true. Default is null.
+ */
+mxTableLayout.prototype.rowPercentages = null;
+
+/**
+ * Variable: resizeParent
+ * 
+ * If the parent should be resized when adding new rows/columns. Default is false.
+ */
+mxTableLayout.prototype.resizeParent = false;
+
+/**
+ * Variable: autoAddRow
+ * 
+ * Weather a new row should be created. Default is true.
+ */
+mxTableLayout.prototype.autoAddRow = true;
+
+/**
+ * Variable: autoAddCol
+ * 
+ * Weather a new column should be created. This value is ignored if autoAddRow is true. Default is false.
+ */
+mxTableLayout.prototype.autoAddCol = false;
+
+/**
+ * Variable: fill
+ * 
+ * Boolean indicating if dimension should be changed to fill out the parent
+ * cell. Default is true.
+ */
+mxTableLayout.prototype.fill = true;
+
+/**
+ * Function: moveCell
+ * 
+ * Implements <mxGraphLayout.moveCell>.
+ */
+mxTableLayout.prototype.moveCell = function(cell, x, y)
+{
+	var model = this.graph.getModel();
+	var parent = model.getParent(cell);
+	var pstate = this.graph.getView().getState(parent);
+
+	if (pstate != null)
+	{
+		x -= pstate.x;
+		y -= pstate.y;
+	}
+	
+	if (cell != null && parent != null)
+	{
+		var i = 0;
+		var childCount = model.getChildCount(parent);
+
+		for (i = 0; i < childCount; i++)
+		{
+			var child = model.getChildAt(parent, i);
+			
+			if (child != cell)
+			{
+				var bounds = model.getGeometry(child);
+				
+				if (bounds != null)
+				{
+					if (x >= bounds.x && x <= bounds.x + bounds.width
+							&& y >= bounds.y && y <= bounds.y + bounds.height)
+					{
+						break;
+					}
+				}
+			}
+		}
+
+		model.add(parent, cell, i);
+	}
+};
+
+/**
+ * Function: execute
+ * 
+ * Implements <mxGraphLayout.execute>.
+ * 
+ * Only children where <isVertexIgnored> returns false are taken into
+ * account.
+ */
+mxTableLayout.prototype.execute = function(parent)
+{
+	if (parent != null)
+	{
+		var pgeo = this.getParentSize(parent);
+		var model = this.graph.getModel();	
+		var fillWidth = null, fillHeight = null;
+		var x = this.marginLeft + this.border;
+		var y = this.marginTop + this.border;
+
+		if (pgeo == null)
+		{
+			return; //We cannot do anything without knowing the parent geometry
+		}
+
+		fillHeight = pgeo.height - this.marginTop - this.marginBottom - 2 * this.border;
+		fillWidth = pgeo.width - this.marginLeft - this.marginRight - 2 * this.border;
+
+		// Handles swimlane start size
+		if (this.graph.isSwimlane(parent))
+		{
+			// Uses computed style to get latest 
+			var style = this.graph.getCellStyle(parent);
+			var start = mxUtils.getNumber(style, mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_STARTSIZE);
+			var horz = mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, true) == 1;
+
+			if (pgeo != null)
+			{
+				if (horz)
+				{
+					start = Math.min(start, pgeo.height);
+				}
+				else
+				{
+					start = Math.min(start, pgeo.width);
+				}
+			}
+			
+			if (horz)
+			{
+				fillHeight -= start;
+				y += start;
+			}
+			else
+			{
+				fillWidth -= start;
+				x += start;
+			}
+		}
+
+		var childCount = model.getChildCount(parent);
+		var rows = this.rows;
+		var cols = this.columns;
+		var cellCount = rows * cols;
+		
+		//if auto-add without parent-resize, then each cell size in the table depends on how many columns/rows
+		if (!this.resizeParent && (this.autoAddCol || this.autoAddRow) && childCount > cellCount)
+		{
+			var actualChildCount = 0;
+			//get actual child count (movable and not ignored)
+			for (var i = 0; i < childCount; i++)
+			{
+				var child = model.getChildAt(parent, i);
+				
+				if (!this.isVertexIgnored(child) && this.isVertexMovable(child))
+				{
+					actualChildCount++;
+				}
+			}
+			
+			if (actualChildCount > cellCount)
+			{
+				if (this.autoAddRow)
+				{
+					rows = Math.ceil(actualChildCount / cols);
+				}
+				else
+				{
+					cols = Math.ceil(actualChildCount / rows);
+				}
+			}
+		}
+		
+		var cellWidth = [], cellHeight = [];
+		fillWidth -= this.border * (cols - 1);
+		fillHeight -= this.border * (rows - 1);
+
+		//Calc each cell width/height in the table
+		if (this.resizeParent && this.autoAddCol && !this.autoAddRow)
+		{
+			cellWidth = this.colWidths && this.colWidths.split? this.colWidths.split(',') : [(this.colWidths || 100)];
+			
+			if (this.equalColumns)
+			{
+				var w = parseFloat(cellWidth[0]);
+				
+				for (var i = 0; i < cols; i++)
+				{
+					cellWidth[i] = w;
+				}
+			}
+			else
+			{
+				for(var i = 0; i < cellWidth.length; i++) 
+				{
+					cellWidth[i] = parseFloat(cellWidth[i]);
+				}
+			}
+		}
+		else
+		{
+			if (this.equalColumns || this.colPercentages == null)
+			{
+				var w = fillWidth / cols;
+				
+				for (var i = 0; i < cols; i++)
+				{
+					cellWidth.push(w);
+				}
+			}
+			else
+			{
+				//TODO handle incorrect configurations
+				var ratios = this.colPercentages.split(',');
+	
+				for (var i = 0; i < cols; i++)
+				{
+					cellWidth.push(fillWidth * parseInt(ratios[i]) / 100);
+				}
+			}
+		}
+
+		if (this.resizeParent && (this.autoAddRow || !this.autoAddCol))
+		{
+			cellHeight = this.rowHeights && this.rowHeights.split? this.rowHeights.split(',') : [(this.rowHeights || 50)];
+			
+			if (this.equalRows)
+			{
+				var h = parseFloat(cellHeight[0]);
+				
+				for (var i = 0; i < rows; i++)
+				{
+					cellHeight[i] = h;
+				}
+			}
+			else
+			{
+				for(var i = 0; i < cellHeight.length; i++) 
+				{
+					cellHeight[i] = parseFloat(cellHeight[i]);
+				}
+			}
+		}
+		else
+		{
+			if (this.equalRows || this.rowPercentages == null)
+			{
+				var h = fillHeight / rows;
+				
+				for (var i = 0; i < rows; i++)
+				{
+					cellHeight.push(h);
+				}
+			}
+			else
+			{
+				//TODO handle incorrect configurations
+				var ratios = this.rowPercentages.split(',');
+	
+				for (var i = 0; i < rows; i++)
+				{
+					cellHeight.push(fillHeight * parseInt(ratios[i]) / 100);
+				}
+			}
+		}
+		
+		model.beginUpdate();
+		try
+		{
+			var rowIndex = 0, colIndex = 0;
+			var tableWidth = 0, tableHeight = 0; 
+			//save the initial value of x
+			var x0 = x, y0 = y;
+
+			//children are filled row by row
+			for (var i = 0; i < childCount; i++)
+			{
+				var child = model.getChildAt(parent, i);
+				
+				if (!this.isVertexIgnored(child) && this.isVertexMovable(child))
+				{
+					var geo = model.getGeometry(child);
+					
+					if (geo != null)
+					{
+						geo = geo.clone();
+						
+						geo.x = x;
+						geo.y = y;
+						
+						if (this.fill)
+						{
+							geo.height = cellHeight[rowIndex];
+							geo.width = cellWidth[colIndex];									
+						}
+						
+						this.setChildGeometry(child, geo);
+						
+						if (this.autoAddRow || !this.autoAddCol)
+						{
+							if (colIndex + 1 == cols)
+							{
+								tableWidth = x + cellWidth[colIndex];
+								x = x0;
+								y += cellHeight[rowIndex] + this.border;
+								colIndex = 0;
+								rowIndex = (rowIndex + 1) % rows;
+							}
+							else
+							{
+								x += cellWidth[colIndex] + this.border;
+								colIndex++;
+							}
+						}
+						else
+						{
+							if (rowIndex + 1 == rows)
+							{
+								tableHeight = y + cellHeight[rowIndex];
+								y = y0;
+								x += cellWidth[colIndex] + this.border;
+								rowIndex = 0;
+								colIndex = (colIndex + 1) % cols;
+							}
+							else
+							{
+								y += cellHeight[rowIndex] + this.border;
+								rowIndex++;
+							}
+						}
+					}
+				}
+			}
+
+			if (this.resizeParent && !this.graph.isCellCollapsed(parent))
+			{
+				var pgeo2 = pgeo.clone();
+
+				pgeo2.width = (tableWidth? tableWidth + this.border : (rowIndex > 0? x + cellWidth[colIndex] + this.border : x)) + this.marginRight;
+				pgeo2.height = (tableHeight? tableHeight + this.border: (colIndex > 0? y + cellHeight[rowIndex] + this.border : y)) + this.marginBottom;
+
+				if (pgeo.x != pgeo2.x || pgeo.y != pgeo2.y ||
+					pgeo.width != pgeo2.width || pgeo.height != pgeo2.height)
+				{
+					model.setGeometry(parent, pgeo2);
+				}
+			}
+		}
+		finally
+		{
+			model.endUpdate();
+		}
+	}
+};

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1029 - 0
src/main/webapp/js/diagramly/sidebar/Sidebar-AWS4.js


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

@@ -107,6 +107,13 @@
 	                          'Game Development', 'General', 'Groups', 'Internet of Things',  
 	                          'Management Tools', 'Messaging', 'Migration', 'Mobile Services', 'Networking and Content Delivery', 'On Demand Workforce', 'SDKs', 'Security Identity and Compliance', 'Storage'];
 	
+	/**
+	 *
+	 */
+	Sidebar.prototype.aws4 = ['Arrows', 'General Resources', 'Illustrations', 'Groups Light', 'Groups Dark', 'Analytics', 'Application Integration', 'AR VR', 'Cost Management', 'Business Productivity', 'Compute', 'Customer Engagement',
+							  'Database', 'Desktop App Streaming', 'Developer Tools', 'Game Development', 'Internet of Things', 'IoT Things', 'IoT Resources', 'Machine Learning', 'Management Tools',
+							  'Media Services', 'Migration', 'Mobile Services', 'Network Content Delivery', 'Security Identity Compliance', 'Storage'];
+	
 	/**
 	 * 
 	 */
@@ -166,6 +173,7 @@
            	                           {id: 'electrical', prefix: 'electrical', libs: Sidebar.prototype.electrical},
            	                           {id: 'aws2', prefix: 'aws2', libs: Sidebar.prototype.aws2},
            	                           {id: 'aws3', prefix: 'aws3', libs: Sidebar.prototype.aws3},
+           	                           {id: 'aws4', prefix: 'aws4', libs: Sidebar.prototype.aws4},
            	                           {id: 'pid', prefix: 'pid', libs: Sidebar.prototype.pids},
            	                           {id: 'cisco', prefix: 'cisco', libs: Sidebar.prototype.cisco},
            	                           {id: 'cisco_safe', prefix: 'cisco_safe', libs: Sidebar.prototype.cisco_safe},
@@ -432,8 +440,9 @@
             			          {title: 'Sitemap', id: 'sitemap', image: IMAGE_PATH + '/sidebar-sitemap.png'},
             			          {title: mxResources.get('uml'), id: 'uml', image: IMAGE_PATH + '/sidebar-uml.png'}]},
             			{title: mxResources.get('networking'),
-            			entries: [{title: mxResources.get('aws'), id: 'aws3', image: IMAGE_PATH + '/sidebar-aws3.png'},
+            			entries: [{title: 'AWS17', id: 'aws3', image: IMAGE_PATH + '/sidebar-aws3.png'},
             			// TODO: Add isometric containers  		                          
+            				      {title: 'AWS18', id: 'aws4', image: IMAGE_PATH + '/sidebar-aws4.png'},
             					  {title: 'Allied Telesis', id: 'allied_telesis', image: IMAGE_PATH + '/sidebar-allied_telesis.png'},
             			          {title: mxResources.get('aws3d'), id: 'aws3d', image: IMAGE_PATH + '/sidebar-aws3d.png'},
             			          {title: mxResources.get('azure'), id: 'azure', image: IMAGE_PATH + '/sidebar-azure.png'},
@@ -851,6 +860,7 @@
 		this.addMSCAEPalette();
 		this.addBpmnPalette(dir, false);
 		this.addAWS3Palette();
+		this.addAWS4Palette();
 		this.addAWS3DPalette();
 		this.addLeanMappingPalette();
 		this.addIos7Palette();

+ 65 - 16
src/main/webapp/js/diagramly/vsdx/mxVsdxCanvas2D.js

@@ -951,38 +951,87 @@ mxVsdxCanvas2D.prototype.text = function(x, y, w, h, str, align, valign, wrap, f
 			};
 			createTextRow(styleMap, charSect, pSect, text, str);
 		}
-		
-		var wShift = 0;
-		var hShift = 0;
 
+		var wShift = 0, hShift = 0;
+
+		h = Math.max(h, calcH); 
+		w = Math.max(w, calcW);
+		var hw = w/2, hh = h/2;
+		var pRotDegrees = parseInt(mxUtils.getValue(this.cellState.style, 'rotation', '0'));
+		var pRot = pRotDegrees * Math.PI / 180;
+
+		//TODO Fix align and valign for rotated cases. Currently, all rotated shapes labels are centered
 		switch(align) 
 		{
-			case "right": wShift = calcW/2; break;
-			case "center": wShift = 0; break;
-			case "left": wShift = -calcW/2; break;
+			case "right": 
+				if (pRotDegrees != 0) 
+				{
+					x -= hw * Math.cos(pRot);
+					y -= hw * Math.sin(pRot);
+				}
+				else 
+				{
+					wShift = calcW/2;
+				}
+			break;
+			case "center":
+				//nothing
+			break;
+			case "left":
+				if (pRotDegrees != 0) 
+				{
+					x += hw * Math.cos(pRot);
+					y += hw * Math.sin(pRot);
+				}
+				else
+				{
+					wShift = -calcW/2;
+				}
+			break;
 		}
-		
+
 		switch(valign) 
 		{
-			case "top": hShift = calcH/2; break;
-			case "middle": hShift = 0; break;
-			case "bottom": hShift = -calcH/2; break;
+			case "top": 
+				if (pRotDegrees != 0) 
+				{
+					x += hh * Math.sin(pRot);
+					y += hh * Math.cos(pRot);
+				}
+				else
+				{
+					hShift = calcH/2;
+				}
+			break;
+			case "middle":
+				//nothing
+			break;
+			case "bottom": 
+				if (pRotDegrees != 0) 
+				{
+					x -= hh * Math.sin(pRot);
+					y -= hh * Math.cos(pRot);
+				}
+				else
+				{
+					hShift = -calcH/2;
+				}
+			break;
 		}
 
-		h = Math.max(h, calcH); 
-		w = Math.max(w, calcW);
-			
 		x = (x - geo.x + s.dx) * s.scale;
 		y = (geo.height - y + geo.y - s.dy) * s.scale;
 
-		var hw = w/2, hh = h/2;
 		this.shape.appendChild(this.createCellElemScaled("TxtPinX", x));
 		this.shape.appendChild(this.createCellElemScaled("TxtPinY", y));
 		this.shape.appendChild(this.createCellElemScaled("TxtWidth", w));
 		this.shape.appendChild(this.createCellElemScaled("TxtHeight", h));
-		this.shape.appendChild(this.createCellElemScaled("TxtLocPinX", hw + wShift));
-		this.shape.appendChild(this.createCellElemScaled("TxtLocPinY", hh + hShift));
+        this.shape.appendChild(this.createCellElemScaled("TxtLocPinX", hw + wShift));
+        this.shape.appendChild(this.createCellElemScaled("TxtLocPinY", hh + hShift));
 
+		
+		rotation -= pRotDegrees;
+		
 		if (rotation != 0)
 			this.shape.appendChild(this.createCellElem("TxtAngle", (360 - rotation) * Math.PI / 180));
 

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 7 - 7
src/main/webapp/js/embed-static.min.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 710 - 597
src/main/webapp/js/extensions.min.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 7 - 7
src/main/webapp/js/reader.min.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 9 - 2
src/main/webapp/js/shapes.min.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 0
src/main/webapp/js/stencils.min.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 317 - 314
src/main/webapp/js/viewer.min.js


+ 6 - 3
src/main/webapp/resources/dia.txt

@@ -99,6 +99,7 @@ draftFound=A draft for '{1}' has been found. Load it into the editor or discard
 dragAndDropNotSupported=Drag and drop not supported for images. Would you like to import instead?
 dropboxCharsNotAllowed=The following characters are not allowed: \ / : ? * " |
 check=Check
+checksum=Checksum
 circle=Circle
 cisco=Cisco
 classic=Classic
@@ -222,9 +223,9 @@ enterPropertyName=Enter Property Name
 enterValue=Enter Value
 entityRelation=Entity Relation
 error=Error
-errorDeletingFile=Error Deleting File
+errorDeletingFile=Error deleting file
 errorLoadingFile=Error loading file
-errorRenamingFile=Error renaming file.
+errorRenamingFile=Error renaming file
 errorRenamingFileNotFound=Error renaming file. File was not found.
 errorRenamingFileForbidden=Error renaming file. Insufficient access rights.
 errorSavingDraft=Error saving draft
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Feedback successfully sent.
 floorplans=Floorplans
 file=File
-fileChangedOverwrite=The file has been modified. Do you want to save the file and overwrite those changes?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Overwrite
+synchronize=Synchronize
 filename=Filename
 fileExists=File already exists
 fileNearlyFullSeeFaq=File nearly full, please see FAQ

+ 6 - 3
src/main/webapp/resources/dia_am.txt

@@ -99,6 +99,7 @@ draftFound=A draft for '{1}' has been found. Load it into the editor or discard
 dragAndDropNotSupported=Drag and drop not supported for images. Would you like to import instead?
 dropboxCharsNotAllowed=The following characters are not allowed: \ / : ? * " |
 check=Check
+checksum=Checksum
 circle=Circle
 cisco=Cisco
 classic=Classic
@@ -222,9 +223,9 @@ enterPropertyName=Enter Property Name
 enterValue=Enter Value
 entityRelation=Entity Relation
 error=Error
-errorDeletingFile=Error Deleting File
+errorDeletingFile=Error deleting file
 errorLoadingFile=Error loading file
-errorRenamingFile=Error renaming file.
+errorRenamingFile=Error renaming file
 errorRenamingFileNotFound=Error renaming file. File was not found.
 errorRenamingFileForbidden=Error renaming file. Insufficient access rights.
 errorSavingDraft=Error saving draft
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Feedback successfully sent.
 floorplans=Floorplans
 file=File
-fileChangedOverwrite=The file has been modified. Do you want to save the file and overwrite those changes?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Overwrite
+synchronize=Synchronize
 filename=Filename
 fileExists=File already exists
 fileNearlyFullSeeFaq=File nearly full, please see FAQ

+ 5 - 2
src/main/webapp/resources/dia_ar.txt

@@ -99,6 +99,7 @@ draftFound=A draft for '{1}' has been found. Load it into the editor or discard
 dragAndDropNotSupported=Drag and drop not supported for images. Would you like to import instead?
 dropboxCharsNotAllowed=The following characters are not allowed: \ / : ? * " |
 check=Check
+checksum=Checksum
 circle=‫دائرة‬
 cisco=Cisco
 classic=‫تقليدي‬
@@ -222,7 +223,7 @@ enterPropertyName=‫ادخل اسم الخاصية‬
 enterValue=‫ادخل قيمة‬
 entityRelation=‫علاقة الكيانات‬
 error=‫خطأ‬
-errorDeletingFile=Error Deleting File
+errorDeletingFile=Error deleting file
 errorLoadingFile=‫خطأ في تحميل الملف‬
 errorRenamingFile=‫خطأ في إعادة تسمية الملف.‬
 errorRenamingFileNotFound=‫خطأ في إعادة تسمية الملف. الملف غير موجود.‬
@@ -254,8 +255,10 @@ feedback=‫تعليق‬
 feedbackSent=‫تم إرسال التعليق بنجاح.‬
 floorplans=Floorplans
 file=‫ملف‬
-fileChangedOverwrite=The file has been modified. Do you want to save the file and overwrite those changes?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Overwrite
+synchronize=Synchronize
 filename=‫اسم الملف‬
 fileExists=‫الملف موجود مسبقا‬
 fileNearlyFullSeeFaq=File nearly full, please see FAQ

+ 4 - 1
src/main/webapp/resources/dia_bg.txt

@@ -99,6 +99,7 @@ draftFound=Открита е чернова за {1}. За да продължи
 dragAndDropNotSupported=Опцията плъзгане и пускане не се поддържа за изображения. Желаете ли да импортирате вместо това?
 dropboxCharsNotAllowed=Следните знаци не са позволени: \ / : ? * " |
 check=Проверка
+checksum=Checksum
 circle=Кръг
 cisco=Cisco
 classic=Класически
@@ -254,8 +255,10 @@ feedback=Обратна връзка
 feedbackSent=Обратната връзка е изпратена успешно.
 floorplans=План на помещенията
 file=Файл
-fileChangedOverwrite=Файлът беше променен. Презаписване на промените?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Презаписване
+synchronize=Synchronize
 filename=Име на файл
 fileExists=Файлът вече съществува
 fileNearlyFullSeeFaq=Файлът е почти пълен, моля вижте раздела Често задавани въпроси

+ 6 - 3
src/main/webapp/resources/dia_bn.txt

@@ -99,6 +99,7 @@ draftFound=A draft for '{1}' has been found. Load it into the editor or discard
 dragAndDropNotSupported=Drag and drop not supported for images. Would you like to import instead?
 dropboxCharsNotAllowed=The following characters are not allowed: \ / : ? * " |
 check=Check
+checksum=Checksum
 circle=Circle
 cisco=Cisco
 classic=Classic
@@ -222,9 +223,9 @@ enterPropertyName=Enter Property Name
 enterValue=Enter Value
 entityRelation=Entity Relation
 error=Error
-errorDeletingFile=Error Deleting File
+errorDeletingFile=Error deleting file
 errorLoadingFile=Error loading file
-errorRenamingFile=Error renaming file.
+errorRenamingFile=Error renaming file
 errorRenamingFileNotFound=Error renaming file. File was not found.
 errorRenamingFileForbidden=Error renaming file. Insufficient access rights.
 errorSavingDraft=Error saving draft
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Feedback successfully sent.
 floorplans=Floorplans
 file=File
-fileChangedOverwrite=The file has been modified. Do you want to save the file and overwrite those changes?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Overwrite
+synchronize=Synchronize
 filename=Filename
 fileExists=File already exists
 fileNearlyFullSeeFaq=File nearly full, please see FAQ

+ 5 - 2
src/main/webapp/resources/dia_bs.txt

@@ -99,6 +99,7 @@ draftFound={1} nacrt pronađen. Učitajte ga u uređivač ili ga odbacite kako b
 dragAndDropNotSupported=Prevlačenje nije podržano kada je riječ o slikama. Želite li uvesti umjesto toga?
 dropboxCharsNotAllowed=Sljedeći znakovi nisu dozvoljeni: \ / : ? * " |
 check=Provjeri
+checksum=Checksum
 circle=Krug
 cisco=Cisco
 classic=Klasičan
@@ -224,7 +225,7 @@ entityRelation=Veza entiteta
 error=Greška
 errorDeletingFile=Greška pri brisanju fajla
 errorLoadingFile=Greška pri učitavanju fajla
-errorRenamingFile=Greška pri preimenovanju fajla.
+errorRenamingFile=Greška pri preimenovanju fajla
 errorRenamingFileNotFound=Greška pri preimenovanju fajla. Fajl nije pronađen.
 errorRenamingFileForbidden=Greška pri preimenovanju fajla. Nedovoljne ovlasti pristupa.
 errorSavingDraft=Greška pri spašavanju nacrta.
@@ -254,8 +255,10 @@ feedback=Povratna informacija
 feedbackSent=Povratna informacija uspješno poslata.
 floorplans=Tlocrt
 file=Fajl
-fileChangedOverwrite=Fajl izmjenjen. Piši preko izmjena. 
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Piši preko
+synchronize=Synchronize
 filename=Naziv fajla
 fileExists=Fajl već postoji
 fileNearlyFullSeeFaq=Fajl skoro pun, pogledajte Često postavljana pitanja

+ 4 - 1
src/main/webapp/resources/dia_ca.txt

@@ -99,6 +99,7 @@ draftFound=S'ha trobat un esborrany per a '{1}'. Carrega'l a l'editor o descarta
 dragAndDropNotSupported=Les imatges no es poden arrosegar i amollar. Vols importar-les?
 dropboxCharsNotAllowed=No es permeten aquests caràcters: \ / : ? * " |
 check=Comprova
+checksum=Checksum
 circle=Cercle
 cisco=Cisco
 classic=Clàssic
@@ -254,8 +255,10 @@ feedback=Opinió
 feedbackSent=S'ha enviat la seva opinió correctament.
 floorplans=Plànols
 file=Fitxer
-fileChangedOverwrite=El fitxer s'ha modificat. Sobreescriure els canvis?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Sobreescriure
+synchronize=Synchronize
 filename=Nom del fitxer
 fileExists=Aquest fitxer ja existeix
 fileNearlyFullSeeFaq=El fitxer està quasi ple, si us plau llegeix les PMF

+ 5 - 2
src/main/webapp/resources/dia_cs.txt

@@ -99,6 +99,7 @@ draftFound=Byl nalezen koncept pro '{1}'. Abyste mohli pokračovat, nahrajte ho
 dragAndDropNotSupported=Pro obrázky není funkce Drag & Drop k dispozici. Chcete ho místo toho naimportovat?
 dropboxCharsNotAllowed=Následující znaky nejsou povoleny: \ / : ? * " |
 check=Zkontrolovat
+checksum=Checksum
 circle=Kruh
 cisco=Cisco
 classic=Klasické
@@ -224,7 +225,7 @@ entityRelation=ER
 error=Chyba
 errorDeletingFile=Chyba při mazání souboru
 errorLoadingFile=Chyba při nahrávání souboru
-errorRenamingFile=Chyba při přejmenování souboru.
+errorRenamingFile=Chyba při přejmenování souboru
 errorRenamingFileNotFound=Chyba při přejmenování souboru. Soubor nenalezen.
 errorRenamingFileForbidden=Chyba při přejmenování souboru. Nedostatečná přístupová oprávnění.
 errorSavingDraft=Chyba při ukládání konceptu
@@ -254,8 +255,10 @@ feedback=Zpětná vazba
 feedbackSent=Zpětná vazba úspěšně odeslána
 floorplans=Půdorysy
 file=Soubor
-fileChangedOverwrite=Soubor by změněn. Přepsat změny?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Přepsat
+synchronize=Synchronize
 filename=Název souboru
 fileExists=Soubor již existuje
 fileNearlyFullSeeFaq=Soubor je skolo plný, podívejte se do často kladených otázek (FAQ)

+ 5 - 2
src/main/webapp/resources/dia_da.txt

@@ -99,6 +99,7 @@ draftFound=Et udkast for '{1}' blev fundet. Load det i editoren eller kasser det
 dragAndDropNotSupported=Drag & drop er ikke understøttet for billeder Vil du importere i stedet?
 dropboxCharsNotAllowed=Følgende tegn er ikke tilladt: \ / : ? * " |
 check=Tjek
+checksum=Checksum
 circle=Cirkel
 cisco=Cisco
 classic=Klassisk
@@ -224,7 +225,7 @@ entityRelation=Enhedsrelation
 error=Fejl
 errorDeletingFile=Fejl ved sletning af fil
 errorLoadingFile=Fejl ved indlæsning af fil
-errorRenamingFile=Fejl ved omdøbning af fil.
+errorRenamingFile=Fejl ved omdøbning af fil
 errorRenamingFileNotFound=Fejl ved omdøbning af fil. Filen blev ikke fundet.
 errorRenamingFileForbidden=Fejl ved omdøbning af fil. Utilstrækkelige adgangsrettigheder.
 errorSavingDraft=Fejl ved gemning af udkast
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Feedback blev sendt.
 floorplans=Grundplan
 file=Fil
-fileChangedOverwrite=Filen blev ændret. Overskriv ændringer?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Overskriv
+synchronize=Synchronize
 filename=Filnavn
 fileExists=Filen findes allerede
 fileNearlyFullSeeFaq=Filen er næsten fuld, se venligst FAQ

+ 5 - 2
src/main/webapp/resources/dia_de.txt

@@ -99,6 +99,7 @@ draftFound=Ein Entwurf für '{1}' wurde gefunden. Setzen Sie die Bearbeitung for
 dragAndDropNotSupported=Drag and drop not supported for images. Would you like to import instead?
 dropboxCharsNotAllowed=Unzulässige Zeichen: \ / : ? * " |
 check=Prüfen
+checksum=Prüfsumme
 circle=Kreis
 cisco=Cisco
 classic=Klassisch
@@ -224,7 +225,7 @@ entityRelation=Entity Relation
 error=Fehler
 errorDeletingFile=Fehler beim Löschen der Datei
 errorLoadingFile=Fehler beim Laden der Datei
-errorRenamingFile=Fehler beim Umbenennen der Datei.
+errorRenamingFile=Fehler beim Umbenennen der Datei
 errorRenamingFileNotFound=Fehler beim Umbenennen der Datei. Datei wurde nicht gefunden.
 errorRenamingFileForbidden=Fehler beim Umbenennen der Datei. Ungenügende Zugriffsrechte.
 errorSavingDraft=Fehler beim Speichern des Entwurfs
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Feedback erfolgreich versendet.
 floorplans=Grundriss
 file=Datei
-fileChangedOverwrite=Die Datei wurde geändert. Möchten Sie die Datei speichern und die Änderungen überschreiben?
+fileChangedSyncDialog=Die Datei wurde geändert. Möchten Sie die Änderungen synchronisieren?
+fileChangedSync=Die Datei wurde geändert. Hier klicken um zu synchronisieren.
 overwrite=Überschreiben
+synchronize=Synchronisieren
 filename=Dateiname
 fileExists=Datei existiert bereits
 fileNearlyFullSeeFaq=Maximale Dateigröße fast erreicht, bitte lesen Sie die FAQ

+ 5 - 2
src/main/webapp/resources/dia_el.txt

@@ -99,6 +99,7 @@ draftFound=Έχει βρεθει ένα σχέδιο για το '{1}' . Φορ
 dragAndDropNotSupported=Το Drag & Drop δεν υποστηρίζεται για τις εικόνες. Θα θέλατε να τις εισάγετε παρόλα αυτά;
 dropboxCharsNotAllowed=Οι παρακάτω χαρακτήρες δεν υποστηρίζονται: \ / : ? * " |
 check=Έλεγχος
+checksum=Checksum
 circle=Κύκλος
 cisco=Cisco
 classic=Κλασικό
@@ -224,7 +225,7 @@ entityRelation=Σχέση Οντότητας
 error=Σφάλμα
 errorDeletingFile=Σφάλμα κατά την διαγραφή αρχείου
 errorLoadingFile=Σφάλμα κατά τη φόρτωση του αρχείου
-errorRenamingFile=Σφάλμα κατά τη μετονομασία του αρχείου.
+errorRenamingFile=Σφάλμα κατά τη μετονομασία του αρχείου
 errorRenamingFileNotFound=Σφάλμα κατά τη μετονομασία του αρχείου. Το αρχείο δεν βρέθηκε.
 errorRenamingFileForbidden=Σφάλμα κατά τη μετονομασία του αρχείου. Ανεπαρκή δικαιώματα πρόσβασης.
 errorSavingDraft=Σφάλμα κατά την αποθήκευση του σχεδίου
@@ -254,8 +255,10 @@ feedback=Κριτική
 feedbackSent= Η κριτική απεστάλη επιτυχώς.
 floorplans=Κατόψεις
 file=Αρχείο
-fileChangedOverwrite=Το αρχείο τροποποιήθηκε. Θέλετε να αντικατασταθούν οι αλλαγές;
+fileChangedSyncDialog=Το αρχείο τροποποιήθηκε. Θέλετε να αντικατασταθούν οι αλλαγές;
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Αντικατάσταση
+synchronize=Synchronize
 filename=Όνομα αρχείου
 fileExists=Το αρχείο υπάρχει ήδη
 fileNearlyFullSeeFaq=Το αρχείο είναι σχεδόν πλήρες, παρακαλώ δείτε τις Συχνές Ερωτήσεις

+ 6 - 3
src/main/webapp/resources/dia_eo.txt

@@ -99,6 +99,7 @@ draftFound=A draft for '{1}' has been found. Load it into the editor or discard
 dragAndDropNotSupported=Drag and drop not supported for images. Would you like to import instead?
 dropboxCharsNotAllowed=The following characters are not allowed: \ / : ? * " |
 check=Check
+checksum=Checksum
 circle=Circle
 cisco=Cisco
 classic=Classic
@@ -222,9 +223,9 @@ enterPropertyName=Enter Property Name
 enterValue=Enter Value
 entityRelation=Entity Relation
 error=Eraro
-errorDeletingFile=Error Deleting File
+errorDeletingFile=Error deleting file
 errorLoadingFile=Error loading file
-errorRenamingFile=Error renaming file.
+errorRenamingFile=Error renaming file
 errorRenamingFileNotFound=Error renaming file. File was not found.
 errorRenamingFileForbidden=Error renaming file. Insufficient access rights.
 errorSavingDraft=Error saving draft
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Feedback successfully sent.
 floorplans=Floorplans
 file=Dosiero
-fileChangedOverwrite=The file has been modified. Do you want to save the file and overwrite those changes?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Overwrite
+synchronize=Synchronize
 filename=Dosiernomo
 fileExists=File already exists
 fileNearlyFullSeeFaq=File nearly full, please see FAQ

+ 5 - 2
src/main/webapp/resources/dia_es.txt

@@ -99,6 +99,7 @@ draftFound=Se encontró un borrador para '{1}'. Cárguelo en el editor o descár
 dragAndDropNotSupported=La opción de arrastrar y soltar no está soportada para las imágenes. ¿En lugar de eso, le gustaría importar?
 dropboxCharsNotAllowed=Los siguientes caracteres no están permitidos: \ / : ? * " |
 check=Verificar
+checksum=Checksum
 circle=Círculo
 cisco=Cisco
 classic=Clásico
@@ -224,7 +225,7 @@ entityRelation=Relación de la entidad
 error=Error
 errorDeletingFile=Error al borrar el archivo
 errorLoadingFile=Error al cargar el archivo
-errorRenamingFile=Error al renombrar el archivo.
+errorRenamingFile=Error al renombrar el archivo
 errorRenamingFileNotFound=Error al renombrar el archivo. No se encontró el archivo.
 errorRenamingFileForbidden=Error al renombrar el archivo. Derechos de acceso insuficientes.
 errorSavingDraft=Error al guardar el borrador
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Su opinión ha sido enviada exitosamente.
 floorplans=Planos
 file=Archivo
-fileChangedOverwrite=El archivo fue cambiado. ¿Sobrescribir los cambios?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Sobrescribir
+synchronize=Synchronize
 filename=Nombre de archivo
 fileExists=El archivo ya existe
 fileNearlyFullSeeFaq=Archivo casi lleno, por favor vea las Preguntas Frecuentes

+ 32 - 29
src/main/webapp/resources/dia_et.txt

@@ -2,7 +2,7 @@
 # https://docs.google.com/spreadsheet/ccc?key=0AmQEO36liL4FdDJLWVNMaVV2UmRKSnpXU09MYkdGbEE
 aboutDrawio=Info draw.io kohta
 accessDenied=Ligipääs keelatud
-action=Action
+action=Tegevus
 actualSize=Tegelik suurus
 add=Lisa
 addedFile=Lisatud {1}
@@ -25,7 +25,7 @@ allTags=Kõik sildid
 anchor=Ankur
 android=Android
 angle=Nurk
-arc=Arc
+arc=Kaar
 areYouSure=Oled kindel?
 ensureDataSaved=Kontrolli enne sulgemist andmete salvestumist.
 allChangesSaved=Kõik muudatused salvestatud
@@ -63,7 +63,7 @@ blockquote=Tsitaat
 blog=Blogi
 bold=Rasvane
 bootstrap=Bootstrap
-border=Border
+border=Piirjoon
 borderColor=Piirjoone värv
 borderWidth=Piirjoone laius
 bottom=Alaäär
@@ -75,7 +75,7 @@ browser=Brauser
 bulletedList=Punktloetelu
 business=Äri
 busy=Toiming käimas
-cabinets=Kabinetid
+cabinets=Elektrikilbid
 cancel=Tühista
 center=Aseta keskele 
 cannotLoad=Laadimine ebaõnnestus. Proovi hiljem uuesti.
@@ -90,15 +90,16 @@ chatLeft={1} lahkus
 chatWindowTitle=Chat
 chooseAnOption=Tee valik
 chromeApp=Chrome App
-collaborativeEditingNotice=Important Notice for Collaborative Editing
+collaborativeEditingNotice=Oluline teadaanne grupitöö muutmise jaoks
 compressed=Pakitud
 commitMessage=Kinnita sõnum
 csv=CSV
-dark=Dark
+dark=Tume
 draftFound=Mustand {1} jaoks on leitud. Lae see töötluskeskkonda või tühista jätkamiseks.
 dragAndDropNotSupported=Piltidele puudub pukseerimise tugi. Kas sooviksid selle asemel importida?
 dropboxCharsNotAllowed=Järgnevad tähemärgid pole lubatud:  \ / : ? * " |
 check=Kontrolli
+checksum=Kontrollsumma
 circle=Ring
 cisco=Cisco
 classic=Klassikaline
@@ -112,10 +113,10 @@ collapse=Vähenda
 collapseExpand=Vähenda/Suurenda 
 collapse-expand=Vajuta vähendamiseks/suurendamiseks\nShift+klikk naabrite liigutamiseks \nAlt-klikk grupi suuruse säilitamiseks
 collapsible=Vähendatav
-comic=Koomiks
+comic=Vabakäejoonis
 comment=Kommentaar
 commentsNotes=Märkused
-compress=Compress
+compress=Paki kokku
 connect=Ühenda
 connecting=Ühendamas
 connectWithDrive=Ühenda Google Drive'iga
@@ -129,7 +130,7 @@ copy=Kopeeri
 copyConnect=Kopeeri ühendamisel
 copyOf=Koopia {1}
 copyOfDrawing=Joonise koopia
-copySize=Copy Size
+copySize=Kopeeri suurus
 copyStyle=Kopeeri stiil
 create=Lisa
 createNewDiagram=Lisa uus diagramm
@@ -175,7 +176,7 @@ doubleClickOrientation=Topeltklõps suuna muutmiseks
 doubleClickTooltip=Topeltklõps teksti sisestamiseks
 doubleClickChangeProperty=Topeltklõps nime muutmiseks
 download=Lae alla
-downloadDesktop=Download draw.io Desktop
+downloadDesktop=Lae draw.io töölaua programmina
 downloadAs=Lae alla nimega
 clickHereToSave=Kliki siia salvestamiseks
 draftDiscarded=Mustand tühistatud
@@ -214,7 +215,7 @@ embed=Lisa
 embedImages=Lisa kujutisi
 mainEmbedNotice=Kleebi sellele lehele
 electrical=Elektriline
-ellipse=Ellipse
+ellipse=Ellips
 embedNotice=Kleebi see üks kord lehe lõppu
 enterGroup=Sisesta rühm
 enterName=Sisesta nimi
@@ -224,7 +225,7 @@ entityRelation=Olemite seos
 error=Viga
 errorDeletingFile=Viga faili kustutamisel
 errorLoadingFile=Viga faili laadimisel
-errorRenamingFile=Viga faili nime muutmisel.
+errorRenamingFile=Viga faili nime muutmisel
 errorRenamingFileNotFound=Viga faili nime muutmisel. Faili ei leitud.
 errorRenamingFileForbidden=Viga faili nime muutmisel. Ebapiisavad ligipääsuõigused.
 errorSavingDraft=Viga mustandi salvestamisel
@@ -233,7 +234,7 @@ errorSavingFileUnknown=Viga Google'i serveritega autoriseerimisel. Palun värske
 errorSavingFileForbidden=Viga faili salvestamisel. Ebapiisavad ligipääsuõigused.
 errorSavingFileNameConflict=Diagramm ei salvestunud. Käesolev leht juba sisaldab faili nimega '{1}'.
 errorSavingFileNotFound=Viga faili salvestamisel. Faili ei leitud.
-errorSavingFileReadOnlyMode=Could not save diagram while read-only mode is active.
+errorSavingFileReadOnlyMode=Diagramm ei salvestunud kuna 'vaid loetav'  režiim on aktiivne. 
 errorSavingFileSessionTimeout=Sessioon on lõppenud. Palun <a target='_blank' href='{1}'>{2}</a> ja naase sellele vahelehele, et proovida uuesti salvestamist.
 errorSendingFeedback=Viga tagasiside saatmisel.
 errorUpdatingPreview=Viga eelvaate uuendamisel.
@@ -245,7 +246,7 @@ exporting=Eksport
 exportAs=Ekspordi nimega
 exportOptionsDisabled=Ekspordi valikud keelatud
 exportOptionsDisabledDetails=Faili omanik on keelanud võimaluse kommenteerijatel ja vaatajatel sisu alla laadida, printida või kopeerida.
-externalChanges=External Changes
+externalChanges=Välised muudatused
 extras=Lisad
 facebook=Facebook
 failedToSaveTryReconnect=Salvestamine ebaõnnestunud, proov ühendust luua
@@ -254,8 +255,10 @@ feedback=Tagasiside
 feedbackSent=Tagasiside edukalt saadetud.
 floorplans=Plaanid
 file=Fail
-fileChangedOverwrite=Faili muudeti. Kirjutab muudatused üle?
+fileChangedSyncDialog=Faili on muudetud. Kas soovid need muudatused ühildada?
+fileChangedSync=Faili on muudetud. Kliki siin et muudatused ühildada.
 overwrite=Kirjuta üle
+synchronize=Synchronize
 filename=Faili nimi
 fileExists=Fail juba eksisteerib
 fileNearlyFullSeeFaq=Fail peaaegu täis, palun vaata KKK-d
@@ -268,7 +271,7 @@ fileOpenLocation=Kuidas sooviksid faili(e) avada?
 fileWillBeSavedInAppFolder={1} salvestatakse aplikatsiooni kausta.
 fill=Täida
 fillColor=Täitevärv
-filterCards=Filter Cards
+filterCards=Filtreeri kaardid
 find=Otsi
 fit=Sobita
 fitContainer=Muuda mahuti suurust
@@ -302,7 +305,7 @@ formatPdf=PDF
 formatSql=SQL
 formatSvg=SVG
 formatHtmlEmbedded=HTML
-formatSvgEmbedded=SVG (XML-ifa)
+formatSvgEmbedded=SVG (XML-iga)
 formatVsdx=VSDX
 formatVssx=VSSX
 formatXmlPlain=XML (tavaline)
@@ -370,7 +373,7 @@ insertHorizontalRule=Sisesta horisontaalliin
 insertLink=Sisesta link
 insertPage=Sisesta leht
 insertRectangle=Sisesta ristkülik
-insertRhombus=Insert Rhombus
+insertRhombus=Sisesta romb
 insertRowBefore=Sisesta rida ülespoole
 insertRowAfter=Sisesta rida allapoole
 insertText=Sisesta tekst
@@ -426,12 +429,12 @@ loggedOut=Välja logitud
 logIn=logi sisse
 loveIt=Ma armastan {1}
 lucidchart=Lucidchart
-maps=Maps
+maps=Kaardid
 mathematicalTypesetting=Matemaatiline vormistus
 makeCopy=Tee koopia
 manual=Manuaalne
 middle=Keskel
-minimal=Minimal
+minimal=Minimaalne
 misc=Erinevad
 mockups=Mallid
 modificationDate=Muutmise kuupäev
@@ -445,7 +448,7 @@ moving=Liigutamine
 moveSelectionTo=Liiguta valik {1}-te
 name=Nimi
 navigation=Navigatsioon
-network=Network
+network=rk
 networking=Võrgustumine
 new=Uus
 newLibrary=Uus raamatukogu
@@ -476,7 +479,7 @@ notConnected=Pole ühendust
 note=Märge
 notUsingService=Ei kasuta {1}?
 numberedList=Nummerdatud nimekiri
-offline=Offline
+offline=Võrguühenduseta
 ok=OK
 oneDrive=OneDrive
 online=Online
@@ -574,7 +577,7 @@ required=vajalik
 reset=Tühjenda
 resetView=Tühista erivaade
 resize=Muuda suurust
-resizeLargeImages=Do you want to resize large images to make the application run faster?
+resizeLargeImages=Kas soovite suurte piltide mõõte muuta rakenduse töökiiruse parandamiseks?
 retina=Retina
 responsive=Responsiivne
 restore=Taasta
@@ -608,7 +611,7 @@ search=Otsi
 searchShapes=Otsi kujundeid
 selectAll=Vali kõik
 selectionOnly=Ainult valik
-selectCard=Select Card
+selectCard=Vali kaart
 selectEdges=Vali ääred
 selectFile=Vali fail
 selectFolder=Vali kaust
@@ -655,8 +658,8 @@ support=Tugi
 sysml=SysML
 tags=Sildid
 table=Tabel
-tables=Tables
-takeOver=Take Over
+tables=Tabelid
+takeOver=Võta üle
 targetSpacing=Eesmärgi vahekaugus
 template=Mall
 templates=Mallid
@@ -682,7 +685,7 @@ tryOpeningViaThisPage=Proovi selle lehe kaudu avamist
 turn=Pööra 90º
 type=Tüüp
 twitter=Twitter
-uml=UMI
+uml=UML
 underline=Alljoonda
 undo=Võta tagasi
 ungroup=Eemalda rühmitus
@@ -692,14 +695,14 @@ untitled=Pealkirjata
 untitledDiagram=Pealkirjata diagramm
 untitledLayer=Pealkirjata kiht
 untitledLibrary=Pealkirjata raamatukogu
-unknownError=Pealkirjata viga
+unknownError=Ootamatu viga
 updateFile=Uuenda {1}
 updatingDocument=Uuendan dokumenti. Palun oota...
 updatingPreview=Uuenda eelvaadet. Palun oota...
 updatingSelection=Uuendan valikut. Palun oota...
 upload=Lae üles
 url=URL
-useOffline=Use Offline
+useOffline=Kasuta võrguta režiimis
 useRootFolder=Use root folder?
 userManual=Kasutusjuhend
 vertical=Vertikaalne

+ 4 - 1
src/main/webapp/resources/dia_fa.txt

@@ -99,6 +99,7 @@ draftFound=‫پیش نویس '{1}' یافت شد. آن را به داخل وی
 dragAndDropNotSupported=‫حرکت و کشیدن و انداختن برای تصاویر امکانپذیر نیست. آیا می خواهید بجای آن تصاویر را وارد کنید؟‬
 dropboxCharsNotAllowed=‫کاراکترهای زیر مجاز نمی باشند: \ / : ? * " |‬
 check=‫بررسی کردن‬
+checksum=Checksum
 circle=‫حلقه‬
 cisco=Cisco
 classic=‫کلاسیک‬
@@ -254,8 +255,10 @@ feedback=‫نظر‬
 feedbackSent=‫نظرات با موفقیت ارسال شد.‬
 floorplans=‫طرح کف‬
 file=‫فایل‬
-fileChangedOverwrite=‫فایل تغییر داده شده است. این تغییرات بر روی نسخه فعلی ذخیره شود؟ ‬
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=‫ذخیره بر روی نسخه فعلی‬
+synchronize=Synchronize
 filename=‫نام فایل‬
 fileExists=‫فایل از قبل وجود دارد‬
 fileNearlyFullSeeFaq=‫فایل تقریبا پر است، لطفا به قسمت FAQ مراجعه کنید‬

+ 4 - 1
src/main/webapp/resources/dia_fi.txt

@@ -99,6 +99,7 @@ draftFound=Vedos tiedostolle '{1}' on löytynyt. Lataa se muokattavaksi tai hylk
 dragAndDropNotSupported=Vedä ja pudota'-toiminto ei tue kuvia. Haluatko tuoda kuvat?
 dropboxCharsNotAllowed=Seuraavat merkit eivät ole sallittuja: \ / : ? * " |
 check=Tarkista
+checksum=Checksum
 circle=Ympyrä
 cisco=Cisco
 classic=Klassinen
@@ -254,8 +255,10 @@ feedback=Palaute
 feedbackSent=Palaute lähetetty onnistuneesti.
 floorplans=Pohjapiirrokset
 file=Tiedosto
-fileChangedOverwrite=Tiedostoa on muutettu. Tallennetaanko muutokset?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Tallenna muutokset.
+synchronize=Synchronize
 filename=Tiedostonimi
 fileExists=Tiedosto on jo olemassa
 fileNearlyFullSeeFaq=Tiedosto lähes täynnä, ole hyvä ja katso FAQ.

+ 4 - 1
src/main/webapp/resources/dia_fil.txt

@@ -99,6 +99,7 @@ draftFound=Isang draft para sa '{1}' ang nahanap. Ikarga ito sa loob ng editor o
 dragAndDropNotSupported=Ang paghila at paglagay ay hindi suportado para sa mga imahe. Gusto mo bang mag angkat na lang?
 dropboxCharsNotAllowed=Ang mga sumusunod na simbolo ay hindi pinahihintulutan: \ / : ? * " |
 check=Alamin
+checksum=Checksum
 circle=Bilog
 cisco=Cisco
 classic=Klasiko
@@ -254,8 +255,10 @@ feedback=Kumento
 feedbackSent=Ang Kumento ay matagumpay na naipadala
 floorplans=Mga Floorplan
 file=File
-fileChangedOverwrite=Ang File ay nabago. Sapawan ang mga pagbabago?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Sapawan
+synchronize=Synchronize
 filename=Pangalan ng File
 fileExists=Ang File  na ito ay mayroon na
 fileNearlyFullSeeFaq=Malapit nang mapuno ang file, mangyaring tingnan ang FAQ

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

@@ -99,6 +99,7 @@ draftFound=Un brouillon pour '{1}' a été trouvé. Pour poursuivre, souhaitez-v
 dragAndDropNotSupported=Le glisser-déposer n'est pas supporté pour les images. Voulez-vous importer à la place?
 dropboxCharsNotAllowed=Les caractères suivants ne sont pas autorisés : \ / : ? * " |
 check=Vérifier
+checksum=Checksum
 circle=Cercle
 cisco=Cisco
 classic=Classique
@@ -224,7 +225,7 @@ entityRelation=Relation entre les éléments
 error=Erreur
 errorDeletingFile=Erreur lors de la suppression du fichier
 errorLoadingFile=Erreur lors du chargement du fichier
-errorRenamingFile=Erreur lors du renommage du fichier.
+errorRenamingFile=Erreur lors du renommage du fichier
 errorRenamingFileNotFound=Erreur lors du renommage du fichier. Le fichier est introuvable.
 errorRenamingFileForbidden=Erreur lors du renommage du fichier. Droits d'accès insuffisants.
 errorSavingDraft=Erreur lors de la sauvegarde du brouillon
@@ -254,8 +255,10 @@ feedback=Commentaire
 feedbackSent=Commentaire envoyé.
 floorplans=Plans de sol
 file=Fichier
-fileChangedOverwrite=Le fichier a été modifié. Ecraser les changements ?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Ecraser
+synchronize=Synchronize
 filename=Nom de fichier
 fileExists=Le fichier existe déjà
 fileNearlyFullSeeFaq=Fichier presque plein, veuillez consulter la FAQ

+ 6 - 3
src/main/webapp/resources/dia_gu.txt

@@ -99,6 +99,7 @@ draftFound=A draft for '{1}' has been found. Load it into the editor or discard
 dragAndDropNotSupported=Drag and drop not supported for images. Would you like to import instead?
 dropboxCharsNotAllowed=The following characters are not allowed: \ / : ? * " |
 check=Check
+checksum=Checksum
 circle=Circle
 cisco=Cisco
 classic=Classic
@@ -222,9 +223,9 @@ enterPropertyName=Enter Property Name
 enterValue=Enter Value
 entityRelation=Entity Relation
 error=Error
-errorDeletingFile=Error Deleting File
+errorDeletingFile=Error deleting file
 errorLoadingFile=Error loading file
-errorRenamingFile=Error renaming file.
+errorRenamingFile=Error renaming file
 errorRenamingFileNotFound=Error renaming file. File was not found.
 errorRenamingFileForbidden=Error renaming file. Insufficient access rights.
 errorSavingDraft=Error saving draft
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Feedback successfully sent.
 floorplans=Floorplans
 file=File
-fileChangedOverwrite=The file has been modified. Do you want to save the file and overwrite those changes?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Overwrite
+synchronize=Synchronize
 filename=Filename
 fileExists=File already exists
 fileNearlyFullSeeFaq=File nearly full, please see FAQ

+ 4 - 1
src/main/webapp/resources/dia_he.txt

@@ -99,6 +99,7 @@ draftFound=‫נמצאה טיוטה עבור '{1}'. טען אותה אל העו
 dragAndDropNotSupported=‫גרירה אינה נתמכת עבור תמונות. תרצה לייבא תמונה במקום?‬
 dropboxCharsNotAllowed=‫התווים הבאים אינם מותרים לשימוש: / \ : ? * " |‬
 check=‫בדוק‬
+checksum=Checksum
 circle=‫עיגול‬
 cisco=Cisco
 classic=‫קלאסי‬
@@ -254,8 +255,10 @@ feedback=‫משוב‬
 feedbackSent=‫המשוב נשלח בהצלחה.‬
 floorplans=‫תכניות קומה‬
 file=‫קובץ‬
-fileChangedOverwrite=‫נערכו שינויים בקובץ. להחליף את השינויים?‬
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=‫להחליף‬
+synchronize=Synchronize
 filename=‫שם קובץ‬
 fileExists=‫הקובץ כבר קיים‬
 fileNearlyFullSeeFaq=‫הקובץ כמעט מלא, ראה FAQ‬

+ 6 - 3
src/main/webapp/resources/dia_hi.txt

@@ -99,6 +99,7 @@ draftFound=A draft for '{1}' has been found. Load it into the editor or discard
 dragAndDropNotSupported=Drag and drop not supported for images. Would you like to import instead?
 dropboxCharsNotAllowed=The following characters are not allowed: \ / : ? * " |
 check=Check
+checksum=Checksum
 circle=Circle
 cisco=Cisco
 classic=Classic
@@ -222,9 +223,9 @@ enterPropertyName=Enter Property Name
 enterValue=Enter Value
 entityRelation=Entity Relation
 error=Error
-errorDeletingFile=Error Deleting File
+errorDeletingFile=Error deleting file
 errorLoadingFile=Error loading file
-errorRenamingFile=Error renaming file.
+errorRenamingFile=Error renaming file
 errorRenamingFileNotFound=Error renaming file. File was not found.
 errorRenamingFileForbidden=Error renaming file. Insufficient access rights.
 errorSavingDraft=Error saving draft
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Feedback successfully sent.
 floorplans=Floorplans
 file=File
-fileChangedOverwrite=The file has been modified. Do you want to save the file and overwrite those changes?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Overwrite
+synchronize=Synchronize
 filename=Filename
 fileExists=File already exists
 fileNearlyFullSeeFaq=File nearly full, please see FAQ

+ 6 - 3
src/main/webapp/resources/dia_hr.txt

@@ -99,6 +99,7 @@ draftFound=A draft for '{1}' has been found. Load it into the editor or discard
 dragAndDropNotSupported=Drag and drop not supported for images. Would you like to import instead?
 dropboxCharsNotAllowed=The following characters are not allowed: \ / : ? * " |
 check=Check
+checksum=Checksum
 circle=Circle
 cisco=Cisco
 classic=Classic
@@ -222,9 +223,9 @@ enterPropertyName=Enter Property Name
 enterValue=Enter Value
 entityRelation=Entity Relation
 error=Error
-errorDeletingFile=Error Deleting File
+errorDeletingFile=Error deleting file
 errorLoadingFile=Error loading file
-errorRenamingFile=Error renaming file.
+errorRenamingFile=Error renaming file
 errorRenamingFileNotFound=Error renaming file. File was not found.
 errorRenamingFileForbidden=Error renaming file. Insufficient access rights.
 errorSavingDraft=Error saving draft
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Feedback successfully sent.
 floorplans=Floorplans
 file=File
-fileChangedOverwrite=The file has been modified. Do you want to save the file and overwrite those changes?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Overwrite
+synchronize=Synchronize
 filename=Filename
 fileExists=File already exists
 fileNearlyFullSeeFaq=File nearly full, please see FAQ

+ 4 - 1
src/main/webapp/resources/dia_hu.txt

@@ -99,6 +99,7 @@ draftFound=Vázlat találva a '{1}'-hoz. Töltse a szerkesztőbe, vagy dobja el
 dragAndDropNotSupported=Fogd és vidd nincs támogatva képekhez. Szeretné-e importálni?
 dropboxCharsNotAllowed=A következő betűk nem engedélyezettek: \ / : ? * " |
 check=Ellenőriz
+checksum=Checksum
 circle=Kör
 cisco=Cisco
 classic=Klasszikus
@@ -254,8 +255,10 @@ feedback=Visszajelzés
 feedbackSent=Visszajelzés sikeresen elküldve.
 floorplans=Alaprajzok
 file=Fájl
-fileChangedOverwrite=A fájl megváltozott. Átírja a változásokat?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Átír
+synchronize=Synchronize
 filename=Fájlnév
 fileExists=Létező fájl
 fileNearlyFullSeeFaq=A fájl majdnem tele, tekintse meg a GYIK-et

+ 4 - 1
src/main/webapp/resources/dia_i18n.txt

@@ -99,6 +99,7 @@ draftFound=draftFound
 dragAndDropNotSupported=dragAndDropNotSupported
 dropboxCharsNotAllowed=dropboxCharsNotAllowed
 check=check
+checksum=checksum
 circle=circle
 cisco=cisco
 classic=classic
@@ -254,8 +255,10 @@ feedback=feedback
 feedbackSent=feedbackSent
 floorplans=floorplans
 file=file
-fileChangedOverwrite=fileChangedOverwrite
+fileChangedSyncDialog=fileChangedSyncDialog
+fileChangedSync=fileChangedSync
 overwrite=overwrite
+synchronize=synchronize
 filename=filename
 fileExists=fileExists
 fileNearlyFullSeeFaq=fileNearlyFullSeeFaq

+ 5 - 2
src/main/webapp/resources/dia_id.txt

@@ -99,6 +99,7 @@ draftFound=Draf untuk '{1}' ditemukan. Muat ke editor atau buang untuk melanjutk
 dragAndDropNotSupported=Tidak mendukung seret dan jatuhkan untuk gambar. Anda ingin mengimpor?
 dropboxCharsNotAllowed=Karakter berikut tidak diizinkan: \ / : ? * " |
 check=Cek
+checksum=Checksum
 circle=Lingkaran
 cisco=Cisco
 classic=Klasik
@@ -224,7 +225,7 @@ entityRelation=Relasi Entitas
 error=Galat
 errorDeletingFile=Galat Menghapus Berkas
 errorLoadingFile=Galat memuat berkas
-errorRenamingFile=Galat menamai ulang berkas.
+errorRenamingFile=Galat menamai ulang berkas
 errorRenamingFileNotFound=Galat menamai ulang berkas. Berkas tidak dapat ditemukan.
 errorRenamingFileForbidden=Galat menamai ulang berkas. Hak akses tidak cukup.
 errorSavingDraft=Galat menyimpan draf
@@ -254,8 +255,10 @@ feedback=Umpan Balik
 feedbackSent=Umpan balik berhasil dikirim.
 floorplans=Denah lantai
 file=Berkas
-fileChangedOverwrite=Berkas diubah. Timpa perubahan?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Timpa
+synchronize=Synchronize
 filename=Nama berkas
 fileExists=Berkas telah ada
 fileNearlyFullSeeFaq=Berkas hampir penuh, harap lihat FAQ

+ 4 - 1
src/main/webapp/resources/dia_it.txt

@@ -99,6 +99,7 @@ draftFound=È stata trovata una bozza per '{1}'. Caricala nell'editor o scartala
 dragAndDropNotSupported=Drag and drop delle immagini non supportato. Vuoi importare?
 dropboxCharsNotAllowed=I seguenti caratteri non sono permessi: \ / : ? * " |
 check=Controlla
+checksum=Checksum
 circle=Cerchio
 cisco=Cisco
 classic=Classico
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Feedback inviato con successo
 floorplans=Piantine
 file=File
-fileChangedOverwrite=Il file è stato cambiato. Vuoi sovrascrivere le modifiche?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Sovrascrivi
+synchronize=Synchronize
 filename=Nome del file
 fileExists=Il file esiste già
 fileNearlyFullSeeFaq=File quasi pieno. Perfavore fai riferimento al nostro FAQ

+ 4 - 1
src/main/webapp/resources/dia_ja.txt

@@ -99,6 +99,7 @@ draftFound=ドラフト{1}が見つかりました。読み込む、または廃
 dragAndDropNotSupported=画像のドラッグアンドドロップには対応していません。その代わりに画像読み込みを選択しますか?
 dropboxCharsNotAllowed=次の文字は使用できません: \ / : ? * " |
 check=チェック
+checksum=Checksum
 circle=円形
 cisco=Cisco
 classic=クラシック
@@ -254,8 +255,10 @@ feedback=フィードバック
 feedbackSent=フィードバックは正しく送信されました。
 floorplans=フロアプラン
 file=ファイル
-fileChangedOverwrite=ファイルが変更されました。変更を上書きしますか。
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=上書き
+synchronize=Synchronize
 filename=ファイル名
 fileExists=ファイルはすでに存在します。
 fileNearlyFullSeeFaq=容量がいっぱいです。FAQを参考にしてください。

+ 6 - 3
src/main/webapp/resources/dia_kn.txt

@@ -99,6 +99,7 @@ draftFound=A draft for '{1}' has been found. Load it into the editor or discard
 dragAndDropNotSupported=Drag and drop not supported for images. Would you like to import instead?
 dropboxCharsNotAllowed=The following characters are not allowed: \ / : ? * " |
 check=Check
+checksum=Checksum
 circle=Circle
 cisco=Cisco
 classic=Classic
@@ -222,9 +223,9 @@ enterPropertyName=Enter Property Name
 enterValue=Enter Value
 entityRelation=Entity Relation
 error=Error
-errorDeletingFile=Error Deleting File
+errorDeletingFile=Error deleting file
 errorLoadingFile=Error loading file
-errorRenamingFile=Error renaming file.
+errorRenamingFile=Error renaming file
 errorRenamingFileNotFound=Error renaming file. File was not found.
 errorRenamingFileForbidden=Error renaming file. Insufficient access rights.
 errorSavingDraft=Error saving draft
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Feedback successfully sent.
 floorplans=Floorplans
 file=File
-fileChangedOverwrite=The file has been modified. Do you want to save the file and overwrite those changes?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Overwrite
+synchronize=Synchronize
 filename=Filename
 fileExists=File already exists
 fileNearlyFullSeeFaq=File nearly full, please see FAQ

+ 4 - 1
src/main/webapp/resources/dia_ko.txt

@@ -99,6 +99,7 @@ draftFound={1}'의 임시저장이 확인되었습니다. 편집하시려면 불
 dragAndDropNotSupported=이미지 드래그하여 붙여넣기는 지원되지 않습니다. 이미지를 불러오시겠습니까?
 dropboxCharsNotAllowed=다음 문자는 사용할 수 없습니다. \ / : ? * " |
 check=확인
+checksum=Checksum
 circle=원형
 cisco=시스코
 classic=기본적인
@@ -254,8 +255,10 @@ feedback=의견
 feedbackSent=의견 보내기 성공.
 floorplans=평면도
 file=파일
-fileChangedOverwrite=파일이 변경되었습니다. 변경을 덮어쓰기 하시겠습니까?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=덮어쓰기
+synchronize=Synchronize
 filename=파일 이름
 fileExists=파일이 이미 존재합니다
 fileNearlyFullSeeFaq=파일에 빈 공간이 거의 남아있지 않습니다. FAQ를 확인해 주시기 바랍니다.

+ 6 - 3
src/main/webapp/resources/dia_lt.txt

@@ -99,6 +99,7 @@ draftFound=A draft for '{1}' has been found. Load it into the editor or discard
 dragAndDropNotSupported=Drag and drop not supported for images. Would you like to import instead?
 dropboxCharsNotAllowed=The following characters are not allowed: \ / : ? * " |
 check=Check
+checksum=Checksum
 circle=Circle
 cisco=Cisco
 classic=Classic
@@ -222,9 +223,9 @@ enterPropertyName=Enter Property Name
 enterValue=Enter Value
 entityRelation=Entity Relation
 error=Error
-errorDeletingFile=Error Deleting File
+errorDeletingFile=Error deleting file
 errorLoadingFile=Error loading file
-errorRenamingFile=Error renaming file.
+errorRenamingFile=Error renaming file
 errorRenamingFileNotFound=Error renaming file. File was not found.
 errorRenamingFileForbidden=Error renaming file. Insufficient access rights.
 errorSavingDraft=Error saving draft
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Feedback successfully sent.
 floorplans=Floorplans
 file=File
-fileChangedOverwrite=The file has been modified. Do you want to save the file and overwrite those changes?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Overwrite
+synchronize=Synchronize
 filename=Filename
 fileExists=File already exists
 fileNearlyFullSeeFaq=File nearly full, please see FAQ

+ 6 - 3
src/main/webapp/resources/dia_lv.txt

@@ -99,6 +99,7 @@ draftFound=A draft for '{1}' has been found. Load it into the editor or discard
 dragAndDropNotSupported=Drag and drop not supported for images. Would you like to import instead?
 dropboxCharsNotAllowed=The following characters are not allowed: \ / : ? * " |
 check=Check
+checksum=Checksum
 circle=Circle
 cisco=Cisco
 classic=Classic
@@ -222,9 +223,9 @@ enterPropertyName=Enter Property Name
 enterValue=Enter Value
 entityRelation=Entity Relation
 error=Error
-errorDeletingFile=Error Deleting File
+errorDeletingFile=Error deleting file
 errorLoadingFile=Error loading file
-errorRenamingFile=Error renaming file.
+errorRenamingFile=Error renaming file
 errorRenamingFileNotFound=Error renaming file. File was not found.
 errorRenamingFileForbidden=Error renaming file. Insufficient access rights.
 errorSavingDraft=Error saving draft
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Feedback successfully sent.
 floorplans=Floorplans
 file=File
-fileChangedOverwrite=The file has been modified. Do you want to save the file and overwrite those changes?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Overwrite
+synchronize=Synchronize
 filename=Filename
 fileExists=File already exists
 fileNearlyFullSeeFaq=File nearly full, please see FAQ

+ 6 - 3
src/main/webapp/resources/dia_ml.txt

@@ -99,6 +99,7 @@ draftFound=A draft for '{1}' has been found. Load it into the editor or discard
 dragAndDropNotSupported=Drag and drop not supported for images. Would you like to import instead?
 dropboxCharsNotAllowed=The following characters are not allowed: \ / : ? * " |
 check=Check
+checksum=Checksum
 circle=Circle
 cisco=Cisco
 classic=Classic
@@ -222,9 +223,9 @@ enterPropertyName=Enter Property Name
 enterValue=Enter Value
 entityRelation=Entity Relation
 error=Error
-errorDeletingFile=Error Deleting File
+errorDeletingFile=Error deleting file
 errorLoadingFile=Error loading file
-errorRenamingFile=Error renaming file.
+errorRenamingFile=Error renaming file
 errorRenamingFileNotFound=Error renaming file. File was not found.
 errorRenamingFileForbidden=Error renaming file. Insufficient access rights.
 errorSavingDraft=Error saving draft
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Feedback successfully sent.
 floorplans=Floorplans
 file=File
-fileChangedOverwrite=The file has been modified. Do you want to save the file and overwrite those changes?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Overwrite
+synchronize=Synchronize
 filename=Filename
 fileExists=File already exists
 fileNearlyFullSeeFaq=File nearly full, please see FAQ

+ 6 - 3
src/main/webapp/resources/dia_mr.txt

@@ -99,6 +99,7 @@ draftFound=A draft for '{1}' has been found. Load it into the editor or discard
 dragAndDropNotSupported=Drag and drop not supported for images. Would you like to import instead?
 dropboxCharsNotAllowed=The following characters are not allowed: \ / : ? * " |
 check=Check
+checksum=Checksum
 circle=Circle
 cisco=Cisco
 classic=Classic
@@ -222,9 +223,9 @@ enterPropertyName=Enter Property Name
 enterValue=Enter Value
 entityRelation=Entity Relation
 error=Error
-errorDeletingFile=Error Deleting File
+errorDeletingFile=Error deleting file
 errorLoadingFile=Error loading file
-errorRenamingFile=Error renaming file.
+errorRenamingFile=Error renaming file
 errorRenamingFileNotFound=Error renaming file. File was not found.
 errorRenamingFileForbidden=Error renaming file. Insufficient access rights.
 errorSavingDraft=Error saving draft
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Feedback successfully sent.
 floorplans=Floorplans
 file=File
-fileChangedOverwrite=The file has been modified. Do you want to save the file and overwrite those changes?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Overwrite
+synchronize=Synchronize
 filename=Filename
 fileExists=File already exists
 fileNearlyFullSeeFaq=File nearly full, please see FAQ

+ 5 - 2
src/main/webapp/resources/dia_ms.txt

@@ -99,6 +99,7 @@ draftFound=Draf bagi '{1}' telah dijumpai. Muat ia ke dalam editor atau buang un
 dragAndDropNotSupported=Seret dan lepas tidak disokong untuk imej. Adakah anda mahu mengimport?
 dropboxCharsNotAllowed=Aksara-aksara berikut tidak dibenarkan: \ / : ? * " |
 check=Semak
+checksum=Checksum
 circle=Bulatan
 cisco=Cisco
 classic=Klasik
@@ -224,7 +225,7 @@ entityRelation=Hubungan Entiti
 error=Ralat
 errorDeletingFile=Ralat Memadam Fail
 errorLoadingFile=Ralat memuatkan fail
-errorRenamingFile=Ralat menamakan semula fail.
+errorRenamingFile=Ralat menamakan semula fail
 errorRenamingFileNotFound=Ralat menamakan semula fail. Fail tidak ditemui.
 errorRenamingFileForbidden=Ralat menamakan semula fail. Hak akses tidak mencukupi.
 errorSavingDraft=Ralat menyimpan draf
@@ -254,8 +255,10 @@ feedback=Maklum balas
 feedbackSent=Maklum balas berjaya dihantar.
 floorplans=Pelan lantai
 file=Fail
-fileChangedOverwrite=Fail telah diubah. Tulis ganti perubahan?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Tulis ganti
+synchronize=Synchronize
 filename=Nama fail
 fileExists=Fail telah wujud
 fileNearlyFullSeeFaq=Fail hampir penuh, sila lihat Soalan Lazim

+ 6 - 3
src/main/webapp/resources/dia_nl.txt

@@ -99,6 +99,7 @@ draftFound=Een concept van '{1}' is gevonden. Laad het in de editor of negeer he
 dragAndDropNotSupported=Slepen en plaatsen is niet beschikbaar voor afbeeldingen. Wilt u in plaats daarvan importeren?
 dropboxCharsNotAllowed=De volgende tekens zijn niet toegestaan: \ / : ? * " |
 check=Controleren
+checksum=Checksum
 circle=Cirkel
 cisco=Cisco
 classic=Klassiek
@@ -224,7 +225,7 @@ entityRelation=Entiteitsrelatie
 error=Fout
 errorDeletingFile=Fout bij verwijderen bestand
 errorLoadingFile=Fout bij laden bestand
-errorRenamingFile=Fout bij hernoemen bestand.
+errorRenamingFile=Fout bij hernoemen bestand
 errorRenamingFileNotFound=Fout bij hernoemen bestand. Bestand was niet gevonden.
 errorRenamingFileForbidden=Fout bij hernoemen bestand. Onvoldoende toegangsrechten.
 errorSavingDraft=Fout bij opslaan concept
@@ -233,7 +234,7 @@ errorSavingFileUnknown=Fout bij het autoriseren met Google servers. Pagina herla
 errorSavingFileForbidden=Fout bij opslaan bestand. Onvoldoende toegangsrechten.
 errorSavingFileNameConflict=Kon diagram niet opslaan. Huidige pagina bevat al een bestand genaamd '{1}'.
 errorSavingFileNotFound=Fout bij opslaan bestand. Bestand niet gevonden.
-errorSavingFileReadOnlyMode=Kon diagram niet opslaan wanneer de modus alleen-lezen geactiveerd is.
+errorSavingFileReadOnlyMode=Het diagram kan niet worden opgeslagen als alleen-lezen geactiveerd is.
 errorSavingFileSessionTimeout=Uw sessie is verlopen. Graag <a target='_blank' href='{1}'>{2}</a> en ga weer naar dit tabblad om opnieuw te proberen op te slaan.
 errorSendingFeedback=Fout bij versturen opmerking.
 errorUpdatingPreview=Fout bij bijwerken voorbeeld.
@@ -254,8 +255,10 @@ feedback=Opmerkingen
 feedbackSent=Opmerkingen verstuurd.
 floorplans=Plattegronden
 file=Bestand
-fileChangedOverwrite=Bestand is gewijzigd. Wijzigingen overschrijven?
+fileChangedSyncDialog=Het bestand is gewijzigd. Wilt u deze aanpassingen synchroniseren?
+fileChangedSync=Het bestand is gewijzigd. Wilt u deze aanpassingen synchroniseren?
 overwrite=Overschrijven
+synchronize=Synchroniseren
 filename=Bestandsnaam
 fileExists=Bestand bestaat al
 fileNearlyFullSeeFaq=Bestand bijna vol, bekijk Veelgestelde vragen

+ 5 - 2
src/main/webapp/resources/dia_no.txt

@@ -99,6 +99,7 @@ draftFound=Et utkast av '{1}' er funnet. Last det ned i editoren eller forkast d
 dragAndDropNotSupported=Dra og slipp funksjon er ikke tilgjengelig for bilder. Vil du importere i stedet for?
 dropboxCharsNotAllowed=Følgende tegn er ikke tillatt: \ / : ? * " |
 check=Sjekk
+checksum=Checksum
 circle=Sirkel
 cisco=Cisco
 classic=Klassisk
@@ -224,7 +225,7 @@ entityRelation=Enhetsrelasjon
 error=Feil
 errorDeletingFile=Feil ved sletting av fil
 errorLoadingFile=Feil ved innlasting av fil
-errorRenamingFile=Feil ved endring av filnavn.
+errorRenamingFile=Feil ved endring av filnavn
 errorRenamingFileNotFound=Feil ved endring av filnavn. Filen ble ikke funnet.
 errorRenamingFileForbidden=Feil ved endring av filnavn. Utilstrekkelige adgangsrettigheter.
 errorSavingDraft=Feil ved lagring av utkast
@@ -254,8 +255,10 @@ feedback=Tilbakemelding
 feedbackSent=Tilbakemelding sendt.
 floorplans=Plantegninger
 file=Fil
-fileChangedOverwrite=Filen ble endret. Vil du overskrive endringene?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Overskriv
+synchronize=Synchronize
 filename=Filnavn
 fileExists=Filen finnes fra før
 fileNearlyFullSeeFaq=Filen er nesten full, vennligst se FAQ

+ 4 - 1
src/main/webapp/resources/dia_pl.txt

@@ -99,6 +99,7 @@ draftFound=Znaleziono wersję roboczą {1}. Załaduj ją do edytora lub odrzuć,
 dragAndDropNotSupported=Przeciągnij i upuść dla obrazów nie jest wspierane. Czy chcesz zamiast tego użyć importowania?
 dropboxCharsNotAllowed=Następujące znaki są niedozwolone: \ / : ? * " |
 check=Sprawdź
+checksum=Checksum
 circle=Okrąg
 cisco=Cisco
 classic=Klasyczny
@@ -254,8 +255,10 @@ feedback=Opinia
 feedbackSent=Przesyłanie opinii powiodło się.
 floorplans=Rzuty pomieszczeń
 file=Plik
-fileChangedOverwrite=Plik został zmieniony. Nadpisać zmiany?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Nadpisz
+synchronize=Synchronize
 filename=Nazwa pliku
 fileExists=Plik już istnieje
 fileNearlyFullSeeFaq=Plik prawie pełen, sprawdź FAQ

+ 5 - 2
src/main/webapp/resources/dia_pt-br.txt

@@ -99,6 +99,7 @@ draftFound=Foi encontrado um rascunho para '{1}'. Carregue no editor ou descarte
 dragAndDropNotSupported=Arraste e solte não suportados para imagens. Gostaria de importar?
 dropboxCharsNotAllowed=Os seguintes caracteres não são permitidos: \/:?*"|
 check=Validar
+checksum=Checksum
 circle=Círculo
 cisco=Cisco
 classic=Clássica
@@ -224,7 +225,7 @@ entityRelation=Relação de entidade
 error=Erro 
 errorDeletingFile=Erro ao excluir o aquivo
 errorLoadingFile=Erro ao carregar o arquivo
-errorRenamingFile=Erro ao renomear o arquivo.
+errorRenamingFile=Erro ao renomear o arquivo
 errorRenamingFileNotFound=Erro ao renomear o arquivo. Arquivo não encontrado.
 errorRenamingFileForbidden=Erro ao renomear o arquivo. Direitos de acesso insuficientes.
 errorSavingDraft=Erro ao salvar o rascunho
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Feedback enviado com sucesso.
 floorplans=Planta baixa
 file=Arquivo 
-fileChangedOverwrite=Arquivo foi alterado. Substituir as alterações?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Substituir
+synchronize=Synchronize
 filename=Nome do arquivo
 fileExists=Arquivo já existente
 fileNearlyFullSeeFaq=Arquivo quase cheio, por favor veja FAQ

+ 5 - 2
src/main/webapp/resources/dia_pt.txt

@@ -99,6 +99,7 @@ draftFound=Encontrado um projeto. Carregar no editor ou rejeitar para continuar.
 dragAndDropNotSupported=Arrastar e largar não suportado para imagens. Deseja importar?
 dropboxCharsNotAllowed=Os seguintes caracteres não são permitidos: \/:?*"|
 check=Verificar
+checksum=Checksum
 circle=Círculo
 cisco=Cisco
 classic=Clássico
@@ -224,7 +225,7 @@ entityRelation=Relação de entidade
 error=Erro 
 errorDeletingFile=Erro ao apagar o ficheiro
 errorLoadingFile=Erro ao carregar o ficheiro
-errorRenamingFile=Erro ao renomear o ficheiro.
+errorRenamingFile=Erro ao renomear o ficheiro
 errorRenamingFileNotFound=Erro ao renomear o ficheiro. Ficheiro não encontrado.
 errorRenamingFileForbidden=Erro ao renomear o ficheiro. Direitos de acesso insuficientes.
 errorSavingDraft=Erro ao salvar o projeto
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Feedback enviado com sucesso.
 floorplans=Plantas
 file=Ficheiro
-fileChangedOverwrite=Ficheiro foi modificado. Sobrepor modificações?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Sobrepor
+synchronize=Synchronize
 filename=Nome do ficheiro
 fileExists=Ficheiro já existente
 fileNearlyFullSeeFaq=Ficheiro quase cheio, por favor veja FAQ

+ 4 - 1
src/main/webapp/resources/dia_ro.txt

@@ -99,6 +99,7 @@ draftFound=O schiță pentru '{1}' a fost găsită. Încarc-o în editor sau în
 dragAndDropNotSupported= „Drag and Drop” nu este suportat pentru imagini. Doriți să importați in schimb?
 dropboxCharsNotAllowed=Următoarele caractere nu sunt permise: \ / : ? * " |
 check=Verifică
+checksum=Checksum
 circle=Cerc
 cisco=Cisco
 classic=Clasic
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Feedback trimis cu succes.
 floorplans=Planuri
 file=Fișier
-fileChangedOverwrite=Fișierul a fost modificat. Suprascrieți modificările?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Suprascrieți.
+synchronize=Synchronize
 filename=Nume fișier
 fileExists=Fișierul există deja
 fileNearlyFullSeeFaq=Fișierul este aproape plin, vedeți FAQ

+ 4 - 1
src/main/webapp/resources/dia_ru.txt

@@ -99,6 +99,7 @@ draftFound=Был обнаружен черновик '{1}'. Загрузите
 dragAndDropNotSupported=Перетаскивание изображений не поддерживается. Импортировать изображение?
 dropboxCharsNotAllowed=Следующие символы не допускаются: \ / : ? * " |
 check=Проверить
+checksum=Checksum
 circle=Круг
 cisco=Cisco
 classic=Классический
@@ -254,8 +255,10 @@ feedback=Обратная связь
 feedbackSent=Сообщение обратной связи успешно отправлено.
 floorplans=Планы помещений
 file=Файл
-fileChangedOverwrite=Файл был изменен. Заменить измененный файл?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Заменить
+synchronize=Synchronize
 filename=Имя файла
 fileExists=Файл уже существует
 fileNearlyFullSeeFaq=Файл почти заполнен, пожалуйста, ознакомьтесь с FAQ

+ 6 - 3
src/main/webapp/resources/dia_sk.txt

@@ -99,6 +99,7 @@ draftFound=A draft for '{1}' has been found. Load it into the editor or discard
 dragAndDropNotSupported=Drag and drop not supported for images. Would you like to import instead?
 dropboxCharsNotAllowed=The following characters are not allowed: \ / : ? * " |
 check=Check
+checksum=Checksum
 circle=Circle
 cisco=Cisco
 classic=Classic
@@ -222,9 +223,9 @@ enterPropertyName=Enter Property Name
 enterValue=Enter Value
 entityRelation=Entity Relation
 error=Error
-errorDeletingFile=Error Deleting File
+errorDeletingFile=Error deleting file
 errorLoadingFile=Error loading file
-errorRenamingFile=Error renaming file.
+errorRenamingFile=Error renaming file
 errorRenamingFileNotFound=Error renaming file. File was not found.
 errorRenamingFileForbidden=Error renaming file. Insufficient access rights.
 errorSavingDraft=Error saving draft
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Feedback successfully sent.
 floorplans=Floorplans
 file=File
-fileChangedOverwrite=The file has been modified. Do you want to save the file and overwrite those changes?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Overwrite
+synchronize=Synchronize
 filename=Filename
 fileExists=File already exists
 fileNearlyFullSeeFaq=File nearly full, please see FAQ

+ 6 - 3
src/main/webapp/resources/dia_sl.txt

@@ -99,6 +99,7 @@ draftFound=A draft for '{1}' has been found. Load it into the editor or discard
 dragAndDropNotSupported=Drag and drop not supported for images. Would you like to import instead?
 dropboxCharsNotAllowed=The following characters are not allowed: \ / : ? * " |
 check=Check
+checksum=Checksum
 circle=Circle
 cisco=Cisco
 classic=Classic
@@ -222,9 +223,9 @@ enterPropertyName=Enter Property Name
 enterValue=Enter Value
 entityRelation=Entity Relation
 error=Error
-errorDeletingFile=Error Deleting File
+errorDeletingFile=Error deleting file
 errorLoadingFile=Error loading file
-errorRenamingFile=Error renaming file.
+errorRenamingFile=Error renaming file
 errorRenamingFileNotFound=Error renaming file. File was not found.
 errorRenamingFileForbidden=Error renaming file. Insufficient access rights.
 errorSavingDraft=Error saving draft
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Feedback successfully sent.
 floorplans=Floorplans
 file=File
-fileChangedOverwrite=The file has been modified. Do you want to save the file and overwrite those changes?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Overwrite
+synchronize=Synchronize
 filename=Filename
 fileExists=File already exists
 fileNearlyFullSeeFaq=File nearly full, please see FAQ

+ 4 - 1
src/main/webapp/resources/dia_sr.txt

@@ -99,6 +99,7 @@ draftFound=Pronađen nacrt
 dragAndDropNotSupported=Prevlačenje nije podržano
 dropboxCharsNotAllowed=Sledeći znaci nisu dozvoljeni: \ / : ? * " |
 check=Provera
+checksum=Checksum
 circle=Krug
 cisco=Cisko
 classic=Klasičan
@@ -254,8 +255,10 @@ feedback=Komentar
 feedbackSent=Povratna informacija je uspešno poslata.
 floorplans=Tlocrt
 file=Datoteka
-fileChangedOverwrite=Datoteka je promenjena. Pregazi izmene?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Prebriši
+synchronize=Synchronize
 filename=Ime datoteke
 fileExists=Već postojeći fajl
 fileNearlyFullSeeFaq=Fajl je skoro pun. Pogledajte Česta pitanja.

+ 5 - 2
src/main/webapp/resources/dia_sv.txt

@@ -99,6 +99,7 @@ draftFound=Ett utkast för '{1}' har lokaliserats. Ladda utkastet till behandlar
 dragAndDropNotSupported=Dra-och-släpp tillåts ej för bilder. Vill du istället importera?
 dropboxCharsNotAllowed=Följande tecken får inte användas: \ / : ? * " |
 check=Kontroll
+checksum=Checksum
 circle=Cirkel
 cisco=Cisco
 classic=Klassisk
@@ -224,7 +225,7 @@ entityRelation=Enhetsrelation
 error=Fel
 errorDeletingFile=Ett fel uppstod vid borttaning av filen
 errorLoadingFile=Ett fel uppstod vid laddning filen
-errorRenamingFile=Ett fel uppstod vid namnändring av filen.
+errorRenamingFile=Ett fel uppstod vid namnändring av filen
 errorRenamingFileNotFound=Ett fel uppstod vid namnändring av filen. Filen kunde inte hittas.
 errorRenamingFileForbidden=Ett fel uppstod vid namnändring av filen. Otillräckliga behörighetsrättigheter.
 errorSavingDraft=Ett fel uppstod vid sparande av utkast
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Feedback har skickats korrekt.
 floorplans=Planritningar
 file=Fil
-fileChangedOverwrite=Filen har ändrats. Vill du överskriva?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Overwrite
+synchronize=Synchronize
 filename=Filnamn
 fileExists=Filen existerar redan
 fileNearlyFullSeeFaq=Filen är nästan full, vänligen se FAQ

+ 6 - 3
src/main/webapp/resources/dia_sw.txt

@@ -99,6 +99,7 @@ draftFound=A draft for '{1}' has been found. Load it into the editor or discard
 dragAndDropNotSupported=Drag and drop not supported for images. Would you like to import instead?
 dropboxCharsNotAllowed=The following characters are not allowed: \ / : ? * " |
 check=Check
+checksum=Checksum
 circle=Circle
 cisco=Cisco
 classic=Classic
@@ -222,9 +223,9 @@ enterPropertyName=Enter Property Name
 enterValue=Enter Value
 entityRelation=Entity Relation
 error=Error
-errorDeletingFile=Error Deleting File
+errorDeletingFile=Error deleting file
 errorLoadingFile=Error loading file
-errorRenamingFile=Error renaming file.
+errorRenamingFile=Error renaming file
 errorRenamingFileNotFound=Error renaming file. File was not found.
 errorRenamingFileForbidden=Error renaming file. Insufficient access rights.
 errorSavingDraft=Error saving draft
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Feedback successfully sent.
 floorplans=Floorplans
 file=File
-fileChangedOverwrite=The file has been modified. Do you want to save the file and overwrite those changes?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Overwrite
+synchronize=Synchronize
 filename=Filename
 fileExists=File already exists
 fileNearlyFullSeeFaq=File nearly full, please see FAQ

+ 6 - 3
src/main/webapp/resources/dia_ta.txt

@@ -99,6 +99,7 @@ draftFound=A draft for '{1}' has been found. Load it into the editor or discard
 dragAndDropNotSupported=Drag and drop not supported for images. Would you like to import instead?
 dropboxCharsNotAllowed=The following characters are not allowed: \ / : ? * " |
 check=Check
+checksum=Checksum
 circle=Circle
 cisco=Cisco
 classic=Classic
@@ -222,9 +223,9 @@ enterPropertyName=Enter Property Name
 enterValue=Enter Value
 entityRelation=Entity Relation
 error=Error
-errorDeletingFile=Error Deleting File
+errorDeletingFile=Error deleting file
 errorLoadingFile=Error loading file
-errorRenamingFile=Error renaming file.
+errorRenamingFile=Error renaming file
 errorRenamingFileNotFound=Error renaming file. File was not found.
 errorRenamingFileForbidden=Error renaming file. Insufficient access rights.
 errorSavingDraft=Error saving draft
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Feedback successfully sent.
 floorplans=Floorplans
 file=File
-fileChangedOverwrite=The file has been modified. Do you want to save the file and overwrite those changes?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Overwrite
+synchronize=Synchronize
 filename=Filename
 fileExists=File already exists
 fileNearlyFullSeeFaq=File nearly full, please see FAQ

+ 6 - 3
src/main/webapp/resources/dia_te.txt

@@ -99,6 +99,7 @@ draftFound=A draft for '{1}' has been found. Load it into the editor or discard
 dragAndDropNotSupported=Drag and drop not supported for images. Would you like to import instead?
 dropboxCharsNotAllowed=The following characters are not allowed: \ / : ? * " |
 check=Check
+checksum=Checksum
 circle=Circle
 cisco=Cisco
 classic=Classic
@@ -222,9 +223,9 @@ enterPropertyName=Enter Property Name
 enterValue=Enter Value
 entityRelation=Entity Relation
 error=Error
-errorDeletingFile=Error Deleting File
+errorDeletingFile=Error deleting file
 errorLoadingFile=Error loading file
-errorRenamingFile=Error renaming file.
+errorRenamingFile=Error renaming file
 errorRenamingFileNotFound=Error renaming file. File was not found.
 errorRenamingFileForbidden=Error renaming file. Insufficient access rights.
 errorSavingDraft=Error saving draft
@@ -254,8 +255,10 @@ feedback=Feedback
 feedbackSent=Feedback successfully sent.
 floorplans=Floorplans
 file=File
-fileChangedOverwrite=The file has been modified. Do you want to save the file and overwrite those changes?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Overwrite
+synchronize=Synchronize
 filename=Filename
 fileExists=File already exists
 fileNearlyFullSeeFaq=File nearly full, please see FAQ

+ 4 - 1
src/main/webapp/resources/dia_th.txt

@@ -99,6 +99,7 @@ draftFound=พบฉบับร่างของ '{1}' แล้ว โหล
 dragAndDropNotSupported=รูปภาพไม่รองรับการลากและวาง คุณต้องการนำเข้าแทนหรือไม่
 dropboxCharsNotAllowed=ไม่อนุญาตให้ใช้อักขระต่อไปนี้: \ / : ? * " |
 check=ตรวจสอบ
+checksum=Checksum
 circle=วงกลม
 cisco=ซิสโก้ 
 classic=คลาสสิค
@@ -254,8 +255,10 @@ feedback=ผลตอบรับ
 feedbackSent=การส่งผลตอบรับเสร็จสมบูรณ์
 floorplans=แปลนอาคาร
 file=ไฟล์
-fileChangedOverwrite=มีการเปลี่ยนแปลงไฟล์แล้ว ต้องการเปลี่ยนแปลงทับหรือไม่
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=เขียนทับ
+synchronize=Synchronize
 filename=ชื่อไฟล์
 fileExists=ไฟล์นี้มีอยู่แล้ว
 fileNearlyFullSeeFaq=ไฟล์ใกล้เต็มแล้ว กรุณาดูที่ FAQ

+ 4 - 1
src/main/webapp/resources/dia_tr.txt

@@ -99,6 +99,7 @@ draftFound=Taslak (1) için bulundu. Editöre yükleyiniz veya devam etmek için
 dragAndDropNotSupported=Desteklenmeyen resimleri sürükle ve at. Veya bu resimleri geri çağırmak ister misiniz ?
 dropboxCharsNotAllowed=Bu karakterler desteklenmemektedir : \ / : ? * " |
 check=Kontrol ediniz
+checksum=Checksum
 circle=Çember
 cisco=Cisco
 classic=Klasik
@@ -254,8 +255,10 @@ feedback=Geri-bildirim
 feedbackSent=Geri-bildirim başarıyla gönderildi.
 floorplans=Kat planları
 file=Dosya
-fileChangedOverwrite=Dosya değiştirildi. Değişiklikleri yinelemek ister misiniz?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Yinele
+synchronize=Synchronize
 filename=Dosya adı
 fileExists=Dosya zaten mevcut
 fileNearlyFullSeeFaq=Dosya neredeyse dolu, lütfen sıkça sorulan sorulara bakınız

+ 5 - 2
src/main/webapp/resources/dia_uk.txt

@@ -99,6 +99,7 @@ draftFound=Була знайдена чернетка '{1}'. Завантажт
 dragAndDropNotSupported=Переміщення зображень не підтримується. Импортувати зображення?
 dropboxCharsNotAllowed=Наступні символи не підтримуються: \ / : ? * " |
 check=Перевірити
+checksum=Checksum
 circle=Коло
 cisco=Cisco
 classic=Класичний
@@ -224,7 +225,7 @@ entityRelation=Зв'язок між об'єктами
 error=Помилка
 errorDeletingFile=Помилка при видаленні файла
 errorLoadingFile=Помилка при завантаженні файла
-errorRenamingFile=Помилка при перейменуванні файла.
+errorRenamingFile=Помилка при перейменуванні файла
 errorRenamingFileNotFound=Помилка при перейменуванні файла. Файл не знайдено.
 errorRenamingFileForbidden=Помилка при перейменуванні файла. Недостатні права доступу.
 errorSavingDraft=Помилка при збереженні чернетки
@@ -254,8 +255,10 @@ feedback=Зворотній зв'язок
 feedbackSent=Форма зворотнього зв'язку успішно надіслана.
 floorplans=Плани приміщень
 file=Файл
-fileChangedOverwrite=Файл було змінено. Перезаписати зміни?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Перезаписати
+synchronize=Synchronize
 filename=Назва файлу
 fileExists=Файл вже існує
 fileNearlyFullSeeFaq=Файл майже повний, будь ласка, прочитайте FAQ

+ 5 - 2
src/main/webapp/resources/dia_vi.txt

@@ -99,6 +99,7 @@ draftFound=Tìm thấy một bản nháp cho '{1}'. Tải lại bản nháp này
 dragAndDropNotSupported=Kéo và thả không hỗ trợ cho hình ảnh. Thay vào đó, bạn có muốn nhập hình ảnh vào không?
 dropboxCharsNotAllowed=Những kí tự sau không được chấp nhận: \ / : ? * " |
 check=Kiểm tra
+checksum=Checksum
 circle=Vòng tròn
 cisco=Cisco
 classic=Cổ điển
@@ -224,7 +225,7 @@ entityRelation=Mối quan hệ của đối tượng
 error=Lỗi
 errorDeletingFile=Lỗi khi xóa tập tin
 errorLoadingFile=Lỗi khi tải tập tin
-errorRenamingFile=Lỗi khi đổi tên tập tin.
+errorRenamingFile=Lỗi khi đổi tên tập tin
 errorRenamingFileNotFound=Lỗi khi đổi tên tập tin. Không tìm thấy tập tin.
 errorRenamingFileForbidden=Lỗi khi đổi tên tập tin. Không đủ quyền truy xuất.
 errorSavingDraft=Lỗi khi lưu bản nháp
@@ -254,8 +255,10 @@ feedback=Phản hồi
 feedbackSent=Gửi phản hồi thành công.
 floorplans=Nội thất
 file=Tập tin
-fileChangedOverwrite=Tập tin đã được thay đổi. Ghi đè các thay đổi?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=Ghi đè
+synchronize=Synchronize
 filename=Tên tập tin
 fileExists=Tập tin đã tồn tại
 fileNearlyFullSeeFaq=Tập tin đã gần đầy, vui lòng xem FAQ

+ 5 - 2
src/main/webapp/resources/dia_zh-tw.txt

@@ -99,6 +99,7 @@ draftFound=發現現有的「{1}」的草圖。要載入它進行編輯或是丟
 dragAndDropNotSupported=不支援圖片拖放。是否使用匯入選項?
 dropboxCharsNotAllowed=不得使用以下字元:\ / : ? * " |
 check=檢查
+checksum=Checksum
 circle=圓形
 cisco=思科
 classic=經典
@@ -224,7 +225,7 @@ entityRelation=實體關係
 error=出錯
 errorDeletingFile=刪除檔案出錯
 errorLoadingFile=載入檔案出錯
-errorRenamingFile=檔案更名出錯
+errorRenamingFile=檔案更名出錯
 errorRenamingFileNotFound=檔案更名出錯。找不到檔案。
 errorRenamingFileForbidden=檔案更名錯誤。沒有足夠的存取權。
 errorSavingDraft=儲存草槁出錯
@@ -254,8 +255,10 @@ feedback=回饋
 feedbackSent=回饋傳送成功。
 floorplans=平面圖
 file=檔案
-fileChangedOverwrite=檔案已更改。是否覆蓋更改?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=覆蓋
+synchronize=Synchronize
 filename=檔案名稱
 fileExists=檔案已存在
 fileNearlyFullSeeFaq=檔案容量即將達到上限,請參閱常見問題集

+ 4 - 1
src/main/webapp/resources/dia_zh.txt

@@ -99,6 +99,7 @@ draftFound={1}的草图已找到。载入其进行编辑或丢弃以继续。
 dragAndDropNotSupported=暂不支持图片拖放功能。要选择导入选项吗?
 dropboxCharsNotAllowed=系统不允许使用下列字符:\ / : ? * " |
 check=核查
+checksum=Checksum
 circle=圆形
 cisco=思科
 classic=经典
@@ -254,8 +255,10 @@ feedback=反馈
 feedbackSent=反馈发送成功
 floorplans=平面图
 file=文件
-fileChangedOverwrite=文件已更改。是否覆盖更改?
+fileChangedSyncDialog=The file has been modified. Do you want to synchronize those changes?
+fileChangedSync=The file has been modified. Click here to synchronize.
 overwrite=覆盖
+synchronize=Synchronize
 filename=文件名
 fileExists=文件已存在
 fileNearlyFullSeeFaq=文件即将达到上限,请参阅常见问题一栏

+ 261 - 0
src/main/webapp/shapes/mxAWS4.js

@@ -0,0 +1,261 @@
+/**
+ * $Id: mxAws4.js,v 1.0 2018/16/11 07:05:39 mate Exp $
+ * Copyright (c) 2006-2018, JGraph Ltd
+ */
+
+//**********************************************************************************************************************************************************
+//Product Icon
+//**********************************************************************************************************************************************************
+/**
+* Extends mxShape.
+*/
+function mxShapeAws4ProductIcon(bounds, fill, stroke, strokewidth)
+{
+	mxShape.call(this);
+	this.bounds = bounds;
+	this.fill = fill;
+	this.stroke = stroke;
+	this.strokewidth = (strokewidth != null) ? strokewidth : 1;
+};
+
+/**
+* Extends mxShape.
+*/
+mxUtils.extend(mxShapeAws4ProductIcon, mxShape);
+
+mxShapeAws4ProductIcon.prototype.cst = {
+		PRODUCT_ICON : 'mxgraph.aws4.productIcon'
+};
+
+/**
+* Function: paintVertexShape
+* 
+* Paints the vertex shape.
+*/
+mxShapeAws4ProductIcon.prototype.paintVertexShape = function(c, x, y, w, h)
+{
+	c.translate(x, y);
+
+	var ind = 1;
+	var strokeColor = mxUtils.getValue(this.state.style, 'strokeColor', '#000000');
+	c.setFillColor(strokeColor);
+
+	c.begin();
+	c.moveTo(0, 0);
+	c.lineTo(w, 0);
+	c.lineTo(w, h);
+	c.lineTo(0, h);
+	c.close();
+	c.fill();
+
+	c.setShadow(false);
+	var fillColor = mxUtils.getValue(this.state.style, 'fillColor', '#ffffff');
+	c.setFillColor(fillColor);
+
+	c.begin();
+	c.moveTo(ind, ind);
+	c.lineTo(w - ind, ind);
+	c.lineTo(w - ind, w - ind);
+	c.lineTo(ind, w - ind);
+	c.close();
+	c.fill();
+	
+
+	var prIcon = mxUtils.getValue(this.state.style, 'prIcon', '');
+	var stencil = mxStencilRegistry.getStencil(prIcon);
+
+	if (stencil != null)
+	{
+		c.setFillColor(strokeColor);
+		c.setStrokeColor('none');
+		stencil.drawShape(c, this, ind, ind, w - 2 * ind, w - 2 * ind);
+	}
+
+};
+
+mxCellRenderer.registerShape(mxShapeAws4ProductIcon.prototype.cst.PRODUCT_ICON, mxShapeAws4ProductIcon);
+
+//**********************************************************************************************************************************************************
+//Resource Icon
+//**********************************************************************************************************************************************************
+/**
+* Extends mxShape.
+*/
+function mxShapeAws4ResourceIcon(bounds, fill, stroke, strokewidth)
+{
+	mxShape.call(this);
+	this.bounds = bounds;
+	this.fill = fill;
+	this.stroke = stroke;
+	this.strokewidth = (strokewidth != null) ? strokewidth : 1;
+};
+
+/**
+* Extends mxShape.
+*/
+mxUtils.extend(mxShapeAws4ResourceIcon, mxShape);
+
+mxShapeAws4ResourceIcon.prototype.cst = {
+		RESOURCE_ICON : 'mxgraph.aws4.resourceIcon'
+};
+
+/**
+* Function: paintVertexShape
+* 
+* Paints the vertex shape.
+*/
+mxShapeAws4ResourceIcon.prototype.paintVertexShape = function(c, x, y, w, h)
+{
+	c.translate(x, y);
+
+	c.begin();
+	c.moveTo(0, 0);
+	c.lineTo(w, 0);
+	c.lineTo(w, h);
+	c.lineTo(0, h);
+	c.close();
+	c.fillAndStroke();
+
+	var prIcon = mxUtils.getValue(this.state.style, 'resIcon', '');
+	var stencil = mxStencilRegistry.getStencil(prIcon);
+
+	if (stencil != null)
+	{
+		var strokeColor = mxUtils.getValue(this.state.style, 'strokeColor', '#000000');
+		c.setFillColor(strokeColor);
+		c.setStrokeColor('none');
+		stencil.drawShape(c, this, 0, 0, w, h);
+	}
+
+};
+
+mxCellRenderer.registerShape(mxShapeAws4ResourceIcon.prototype.cst.RESOURCE_ICON, mxShapeAws4ResourceIcon);
+
+//**********************************************************************************************************************************************************
+//Group
+//**********************************************************************************************************************************************************
+/**
+* Extends mxShape.
+*/
+function mxShapeAws4Group(bounds, fill, stroke, strokewidth)
+{
+	mxShape.call(this);
+	this.bounds = bounds;
+	this.fill = fill;
+	this.stroke = stroke;
+	this.strokewidth = (strokewidth != null) ? strokewidth : 1;
+};
+
+/**
+* Extends mxShape.
+*/
+mxUtils.extend(mxShapeAws4Group, mxShape);
+
+mxShapeAws4Group.prototype.cst = {
+		GROUP : 'mxgraph.aws4.group'
+};
+
+/**
+* Function: paintVertexShape
+* 
+* Paints the vertex shape.
+*/
+mxShapeAws4Group.prototype.paintVertexShape = function(c, x, y, w, h)
+{
+	c.translate(x, y);
+
+	var size = 25;
+
+	c.begin();
+	c.moveTo(0, 0);
+	c.lineTo(w, 0);
+	c.lineTo(w, h);
+	c.lineTo(0, h);
+	c.close();
+	c.fillAndStroke();
+
+	c.setShadow(false);
+
+	var grIcon = mxUtils.getValue(this.state.style, 'grIcon', '');
+	var stencil = mxStencilRegistry.getStencil(grIcon);
+
+	if (stencil != null)
+	{
+		var strokeColor = mxUtils.getValue(this.state.style, 'strokeColor', '#000000');
+		c.setFillColor(strokeColor);
+		c.setStrokeColor('none');
+		stencil.drawShape(c, this, 0, 0, size, size);
+	}
+
+};
+
+mxCellRenderer.registerShape(mxShapeAws4Group.prototype.cst.GROUP, mxShapeAws4Group);
+
+//**********************************************************************************************************************************************************
+//Group Center
+//**********************************************************************************************************************************************************
+/**
+* Extends mxShape.
+*/
+function mxShapeAws4GroupCenter(bounds, fill, stroke, strokewidth)
+{
+	mxShape.call(this);
+	this.bounds = bounds;
+	this.fill = fill;
+	this.stroke = stroke;
+	this.strokewidth = (strokewidth != null) ? strokewidth : 1;
+};
+
+/**
+* Extends mxShape.
+*/
+mxUtils.extend(mxShapeAws4GroupCenter, mxShape);
+
+mxShapeAws4GroupCenter.prototype.cst = {
+		GROUP_CENTER : 'mxgraph.aws4.groupCenter'
+};
+
+/**
+* Function: paintVertexShape
+* 
+* Paints the vertex shape.
+*/
+mxShapeAws4GroupCenter.prototype.paintVertexShape = function(c, x, y, w, h)
+{
+	c.translate(x, y);
+	var grStroke = mxUtils.getValue(this.state.style, 'grStroke', '1');
+
+	var size = 25;
+
+	c.begin();
+	c.moveTo(0, 0);
+	c.lineTo(w, 0);
+	c.lineTo(w, h);
+	c.lineTo(0, h);
+	c.close();
+	
+	if (grStroke == '1')
+	{
+		c.fillAndStroke();
+	}
+	else
+	{
+		c.fill();
+	}
+	
+	c.setShadow(false);
+	var grIcon = mxUtils.getValue(this.state.style, 'grIcon', '');
+	var stencil = mxStencilRegistry.getStencil(grIcon);
+
+	if (stencil != null)
+	{
+		var strokeColor = mxUtils.getValue(this.state.style, 'strokeColor', '#000000');
+		c.setFillColor(strokeColor);
+		c.setStrokeColor('none');
+		stencil.drawShape(c, this, (w - size) * 0.5, 0, size, size);
+	}
+
+};
+
+mxCellRenderer.registerShape(mxShapeAws4GroupCenter.prototype.cst.GROUP_CENTER, mxShapeAws4GroupCenter);
+

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 39256 - 0
src/main/webapp/stencils/aws4.xml