瀏覽代碼

8.6.7 release

Gaudenz Alder 7 年之前
父節點
當前提交
b31e393da4
共有 100 個文件被更改,包括 3757 次插入3466 次删除
  1. 6 0
      ChangeLog
  2. 1 1
      VERSION
  3. 1 1
      src/main/webapp/cache.manifest
  4. 710 702
      src/main/webapp/js/app.min.js
  5. 653 647
      src/main/webapp/js/atlas-viewer.min.js
  6. 962 954
      src/main/webapp/js/atlas.min.js
  7. 29 4
      src/main/webapp/js/diagramly/App.js
  8. 1 1
      src/main/webapp/js/diagramly/Dialogs.js
  9. 3 3
      src/main/webapp/js/diagramly/DriveClient.js
  10. 1 1
      src/main/webapp/js/diagramly/DropboxClient.js
  11. 447 72
      src/main/webapp/js/diagramly/EditorUi.js
  12. 1 1
      src/main/webapp/js/diagramly/GitHubClient.js
  13. 18 15
      src/main/webapp/js/diagramly/Menus.js
  14. 74 65
      src/main/webapp/js/diagramly/Minimal.js
  15. 1 1
      src/main/webapp/js/diagramly/OneDriveClient.js
  16. 1 1
      src/main/webapp/js/diagramly/TrelloClient.js
  17. 132 123
      src/main/webapp/js/diagramly/vsdx/importer.js
  18. 1 1
      src/main/webapp/js/embed-static.min.js
  19. 2 2
      src/main/webapp/js/extensions.min.js
  20. 1 1
      src/main/webapp/js/reader.min.js
  21. 653 647
      src/main/webapp/js/viewer.min.js
  22. 10 208
      src/main/webapp/plugins/update.js
  23. 二進制
      src/main/webapp/templates/business/accd.png
  24. 二進制
      src/main/webapp/templates/business/archimate.png
  25. 二進制
      src/main/webapp/templates/business/bpmn.png
  26. 二進制
      src/main/webapp/templates/business/business_model_1.png
  27. 二進制
      src/main/webapp/templates/business/business_model_2.png
  28. 二進制
      src/main/webapp/templates/business/business_model_canvas_1.png
  29. 1 0
      src/main/webapp/templates/business/business_model_canvas_1.xml
  30. 二進制
      src/main/webapp/templates/business/ishikawa_1.png
  31. 二進制
      src/main/webapp/templates/business/ishikawa_2.png
  32. 二進制
      src/main/webapp/templates/business/pert_1.png
  33. 二進制
      src/main/webapp/templates/business/pert_2.png
  34. 1 0
      src/main/webapp/templates/business/swimlane.xml
  35. 二進制
      src/main/webapp/templates/business/timeline_1.png
  36. 二進制
      src/main/webapp/templates/business/timeline_2.png
  37. 1 2
      src/main/webapp/templates/business/timeline_2.xml
  38. 二進制
      src/main/webapp/templates/business/timeline_3.png
  39. 1 0
      src/main/webapp/templates/business/timeline_3.xml
  40. 二進制
      src/main/webapp/templates/business/timeline_4.png
  41. 1 0
      src/main/webapp/templates/business/timeline_4.xml
  42. 二進制
      src/main/webapp/templates/charts/bar_chart_1.png
  43. 1 0
      src/main/webapp/templates/charts/bar_chart_1.xml
  44. 二進制
      src/main/webapp/templates/charts/coc.png
  45. 二進制
      src/main/webapp/templates/charts/org_chart_1.png
  46. 1 2
      src/main/webapp/templates/charts/org_chart_1.xml
  47. 二進制
      src/main/webapp/templates/charts/org_chart_2.png
  48. 二進制
      src/main/webapp/templates/charts/work_breakdown_structure.png
  49. 1 0
      src/main/webapp/templates/charts/work_breakdown_structure.xml
  50. 二進制
      src/main/webapp/templates/engineering/cabinet.png
  51. 1 2
      src/main/webapp/templates/engineering/cabinet.xml
  52. 二進制
      src/main/webapp/templates/engineering/electrical_1.png
  53. 二進制
      src/main/webapp/templates/engineering/electrical_2.png
  54. 二進制
      src/main/webapp/templates/flowcharts/cross_functional_flowchart.png
  55. 二進制
      src/main/webapp/templates/flowcharts/cross_functional_flowchart_1.png
  56. 0 0
      src/main/webapp/templates/flowcharts/cross_functional_flowchart_1.xml
  57. 二進制
      src/main/webapp/templates/flowcharts/cross_functional_flowchart_2.png
  58. 2 0
      src/main/webapp/templates/flowcharts/cross_functional_flowchart_2.xml
  59. 二進制
      src/main/webapp/templates/flowcharts/data_flow_1.png
  60. 二進制
      src/main/webapp/templates/flowcharts/data_flow_2.png
  61. 二進制
      src/main/webapp/templates/flowcharts/data_flow_3.png
  62. 二進制
      src/main/webapp/templates/flowcharts/epc.png
  63. 二進制
      src/main/webapp/templates/flowcharts/flowchart_1.png
  64. 1 0
      src/main/webapp/templates/flowcharts/flowchart_1.xml
  65. 二進制
      src/main/webapp/templates/flowcharts/flowchart_2.png
  66. 1 0
      src/main/webapp/templates/flowcharts/flowchart_2.xml
  67. 二進制
      src/main/webapp/templates/flowcharts/workflow_1.png
  68. 2 0
      src/main/webapp/templates/flowcharts/workflow_1.xml
  69. 25 5
      src/main/webapp/templates/index.xml
  70. 二進制
      src/main/webapp/templates/layout/blog_wireframe.png
  71. 二進制
      src/main/webapp/templates/layout/bootstrap.png
  72. 二進制
      src/main/webapp/templates/layout/wireframe.png
  73. 二進制
      src/main/webapp/templates/layout/wireframe_1.png
  74. 0 0
      src/main/webapp/templates/layout/wireframe_1.xml
  75. 二進制
      src/main/webapp/templates/layout/wireframe_2.png
  76. 2 0
      src/main/webapp/templates/layout/wireframe_2.xml
  77. 二進制
      src/main/webapp/templates/maps/concept_map.png
  78. 二進制
      src/main/webapp/templates/maps/concept_map_1.png
  79. 0 0
      src/main/webapp/templates/maps/concept_map_1.xml
  80. 二進制
      src/main/webapp/templates/maps/concept_map_2.png
  81. 2 0
      src/main/webapp/templates/maps/concept_map_2.xml
  82. 二進制
      src/main/webapp/templates/maps/living_beings_mind_map.png
  83. 1 0
      src/main/webapp/templates/maps/living_beings_mind_map.xml
  84. 二進制
      src/main/webapp/templates/maps/mind_map.png
  85. 1 0
      src/main/webapp/templates/maps/mind_map.xml
  86. 二進制
      src/main/webapp/templates/maps/site_map.png
  87. 1 2
      src/main/webapp/templates/maps/site_map.xml
  88. 二進制
      src/main/webapp/templates/network/active_directory.png
  89. 二進制
      src/main/webapp/templates/network/aws.png
  90. 二進制
      src/main/webapp/templates/network/aws_3d.png
  91. 二進制
      src/main/webapp/templates/network/azure.png
  92. 二進制
      src/main/webapp/templates/network/azure_1.png
  93. 0 0
      src/main/webapp/templates/network/azure_1.xml
  94. 二進制
      src/main/webapp/templates/network/azure_2.png
  95. 1 0
      src/main/webapp/templates/network/azure_2.xml
  96. 二進制
      src/main/webapp/templates/network/cisco.png
  97. 0 2
      src/main/webapp/templates/network/cisco.xml
  98. 二進制
      src/main/webapp/templates/network/cisco_1.png
  99. 1 0
      src/main/webapp/templates/network/cisco_1.xml
  100. 0 0
      src/main/webapp/templates/network/cisco_2.png

+ 6 - 0
ChangeLog

@@ -1,3 +1,9 @@
+23-MAY-2018: 8.6.7
+
+- Adds #S parameter for loading from CSV source
+- Adds support for VSD files in cloud storage
+- Adds Lucidchart support for #U parameter
+
 22-MAY-2018: 8.6.6
 
 - Fixes enabled state for some menu items

+ 1 - 1
VERSION

@@ -1 +1 @@
-8.6.6
+8.6.7

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

@@ -1,7 +1,7 @@
 CACHE MANIFEST
 
 # THIS FILE WAS GENERATED. DO NOT MODIFY!
-# 05/22/2018 06:17 PM
+# 05/23/2018 04:43 PM
 
 app.html
 index.html?offline=1

文件差異過大導致無法顯示
+ 710 - 702
src/main/webapp/js/app.min.js


文件差異過大導致無法顯示
+ 653 - 647
src/main/webapp/js/atlas-viewer.min.js


文件差異過大導致無法顯示
+ 962 - 954
src/main/webapp/js/atlas.min.js


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

@@ -2985,12 +2985,12 @@ EditorUi.prototype.loadTemplate = function(url, onload, onerror)
 	
 	this.loadUrl(realUrl, mxUtils.bind(this, function(data)
 	{
-		if  (/(\.vsdx)($|\?)/i.test(url))
+		if (/(\.vsdx)($|\?)/i.test(url))
 		{
 			this.importVisio(this.base64ToBlob(data.substring(data.indexOf(',') + 1)), function(xml)
 			{
 				onload(xml);
-			});
+			}, onerror, url);
 		}
 		else if (!this.isOffline() && new XMLHttpRequest().upload && this.isRemoteFileFormat(data, url))
 		{
@@ -3004,6 +3004,13 @@ EditorUi.prototype.loadTemplate = function(url, onload, onerror)
 				}
 			}), url);
 		}
+		else if (data.substring(0, 26) == '{"state":"{\\"Properties\\":')
+		{
+			this.importLucidChart(data, 0, 0, false, mxUtils.bind(this, function()
+			{
+				onload(this.getFileData(true));
+			}));
+		}
 		else
 		{
 			if (/(\.png)($|\?)/i.test(url))
@@ -3386,6 +3393,24 @@ App.prototype.loadFile = function(id, sameWindow, file, success)
 					success();
 				}
 			}
+			else if (id.charAt(0) == 'S')
+			{
+				this.spinner.stop();
+				
+				try
+				{
+					this.loadDescriptor(JSON.parse(
+						this.editor.graph.decompress(id.substring(1))),
+						success, mxUtils.bind(this, function(e)
+					{
+						this.handleError(e, mxResources.get('errorLoadingFile'));
+					}));
+				}
+				catch (e)
+				{
+					this.handleError(e, mxResources.get('errorLoadingFile'));
+				}
+			}
 			else if (id.charAt(0) == 'R')
 			{
 				// Raw file encoded into URL
@@ -4322,8 +4347,8 @@ App.prototype.convertFile = function(url, filename, mimeType, extension, success
 		gitHubUrl = true;
 	}
 	
-	// Workaround for wrong binary response with VSDX/VSD files
-	if ((/\.vsdx$/i.test(filename) || /\.vsd$/i.test(filename)) && Graph.fileSupport && new XMLHttpRequest().upload &&
+	// Workaround for wrong binary response with VSD(X) files
+	if (/\.vsdx?$/i.test(filename) && Graph.fileSupport && new XMLHttpRequest().upload &&
 		typeof new XMLHttpRequest().responseType === 'string')
 	{
 		var req = new XMLHttpRequest();

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

@@ -2551,7 +2551,7 @@ var ParseDialog = function(editorUi, title, defaultType)
 	
 	var tableOption = document.createElement('option');
 	tableOption.setAttribute('value', 'table');
-	mxUtils.write(tableOption, mxResources.get('table'));
+	mxUtils.write(tableOption, mxResources.get('formatSql'));
 	typeSelect.appendChild(tableOption);
 	
 	if (defaultType == 'formatSql')

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

@@ -640,7 +640,7 @@ DriveClient.prototype.getFile = function(id, success, error, readXml, readLibrar
 				var binary = /\.png$/i.test(resp.title);
 				
 				// Handles .vsdx, Gliffy and PNG+XML files by creating a temporary file
-				if (/\.vsdx$/i.test(resp.title) || /\.gliffy$/i.test(resp.title) ||
+				if (/\.vsdx?$/i.test(resp.title) || /\.gliffy$/i.test(resp.title) ||
 					(!this.ui.useCanvasForExport && binary))
 				{
 					var url = resp.downloadUrl + '&access_token=' + gapi.auth.getToken().access_token;
@@ -655,7 +655,7 @@ DriveClient.prototype.getFile = function(id, success, error, readXml, readLibrar
 					else
 					{
 						this.loadRealtime(resp, mxUtils.bind(this, function(doc)
-					    	{
+					    {
 							try
 							{
 								// Converts XML files to realtime including old realtime model
@@ -675,7 +675,7 @@ DriveClient.prototype.getFile = function(id, success, error, readXml, readLibrar
 							{
 								error(e);
 							}
-					    	}), error);
+					    }), error);
 					}
 				}
 			}

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

@@ -296,7 +296,7 @@ DropboxClient.prototype.getFile = function(path, success, error, asLibrary)
 	asLibrary = (asLibrary != null) ? asLibrary : false;
 	var binary = /\.png$/i.test(path);
 
-	if (/^https:\/\//i.test(path) || /\.vsdx$/i.test(path) || /\.gliffy$/i.test(path) ||
+	if (/^https:\/\//i.test(path) || /\.vsdx?$/i.test(path) || /\.gliffy$/i.test(path) ||
 		(!this.ui.useCanvasForExport && binary))
 	{
 		var fn = mxUtils.bind(this, function()

+ 447 - 72
src/main/webapp/js/diagramly/EditorUi.js

@@ -1246,6 +1246,378 @@
 		this.mode = mode;
 	};
 
+	/**
+	 * Loads the given file descriptor. The descriptor may define the following properties:
+	 * 
+	 * - url: The url to load the data from (proxy is used if CORS is not enabled)
+	 * - data: The data to be inserted. If both, data and url are defined, then the data
+	 * is preprendended to the data returned from the given URL.
+	 * - format: Currently, only 'csv' is supported as an optional value. Default is XML.
+	 * - update: Optional URL to fetch updates from (POST request with the page XML).
+	 * - interval: Optional interval for fetching updates. Default is 60000 (60 seconds).
+	 */
+	EditorUi.prototype.loadDescriptor = function(desc, success, error)
+	{
+		var hash = window.location.hash;
+		
+		var loadData = mxUtils.bind(this, function(data)
+		{
+			var realData = (desc.data != null) ? desc.data : '';
+			
+			if (data != null && data.length > 0)
+			{
+				if (realData.length > 0)
+				{
+					realData += '\n';
+				}
+				
+				realData += data;
+			}
+
+			var xml = (desc.format != 'csv' && realData.length > 0) ? realData : this.emptyDiagramXml;
+			var tempFile = new LocalFile(this, xml, (urlParams['title'] != null) ?
+					decodeURIComponent(urlParams['title']) : this.defaultFilename, true);
+			tempFile.getHash = function()
+			{
+				return hash;
+			};
+			this.fileLoaded(tempFile);
+			
+			if (desc.format == 'csv')
+			{
+				this.importCsv(realData, mxUtils.bind(this, function(cells)
+				{
+					this.editor.undoManager.clear();
+					this.editor.setModified(false);
+					this.editor.setStatus('');
+				}));
+			}
+        	
+			// Installs updates
+			if (desc.update != null)
+			{
+				var interval = (desc.interval != null) ? parseInt(desc.interval) : 60000;
+				var currentThread = null;
+				
+				var doUpdate = mxUtils.bind(this, function()
+				{
+					var page = this.currentPage;
+					
+					mxUtils.post(desc.update, 'xml=' + encodeURIComponent(
+						mxUtils.getXml(this.editor.getGraphXml())),
+						mxUtils.bind(this, function(req)
+					{
+						if (page === this.currentPage)
+						{
+							if (req.getStatus() >= 200 && req.getStatus() <= 300)
+							{
+								var doc = this.updateDiagram(req.getText());
+								schedule();
+							}
+							else
+							{
+								this.handleError({message: mxResources.get('error') + ' ' + req.getStatus()});
+							}
+						}
+					}), mxUtils.bind(this, function(err)
+					{
+						this.handleError(err);
+					}));
+				});
+				
+				var schedule = mxUtils.bind(this, function()
+				{
+					window.clearTimeout(currentThread);
+					currentThread = window.setTimeout(doUpdate, interval);
+				});
+				
+				this.editor.addListener('pageSelected', mxUtils.bind(this, function()
+				{
+					schedule();
+					doUpdate();
+				}));
+				
+				schedule();
+				doUpdate();
+			}
+			
+    		if (success != null)
+    		{
+    			success();
+    		}
+		});
+		
+		if (desc.url != null)
+		{
+            var realUrl = desc.url;
+            
+            if ((/^https?:\/\//.test(realUrl)) && !this.isCorsEnabledForUrl(realUrl))
+            {
+                realUrl = PROXY_URL + '?url=' + encodeURIComponent(desc.url);
+            }
+
+            // LATER: Remove cache-control header
+            this.loadUrl(realUrl, mxUtils.bind(this, function(data)
+            {
+            	loadData(data);
+            }), mxUtils.bind(this, function(err)
+            {
+            	if (error != null)
+            	{
+            		error(err)
+            	}
+            }));
+		}
+		else
+		{
+			loadData(desc.data);
+		}
+	};
+	
+	/**
+	 * Translates this point by the given vector.
+	 * 
+	 * @param {number} dx X-coordinate of the translation.
+	 * @param {number} dy Y-coordinate of the translation.
+	 */
+	EditorUi.prototype.updateDiagram = function(xml)
+	{
+		var doc = null;
+		
+		function createOverlay(desc)
+		{
+			var overlay = new mxCellOverlay(desc.image || graph.warningImage,
+				desc.tooltip, desc.align, desc.valign, desc.offset);
+
+			// Installs a handler for clicks on the overlay
+			overlay.addListener(mxEvent.CLICK, function(sender, evt)
+			{
+				editorUi.alert(desc.tooltip);
+			});
+			
+			return overlay;
+		};
+		
+		if (xml != null && xml.length > 0)
+		{
+			doc = mxUtils.parseXml(xml);
+			var node = (doc != null) ? doc.documentElement : null;
+			
+			if (node != null && node.nodeName == 'updates')
+			{
+				var graph = this.editor.graph;
+				var model = graph.getModel();
+				model.beginUpdate();
+				var fit = null;
+
+				try
+				{
+					node = node.firstChild;
+					
+					while (node != null)
+					{
+						if (node.nodeName == 'update')
+						{
+							// Resolves the cell ID
+							var cell = model.getCell(node.getAttribute('id'));
+							
+							if (cell != null)
+							{
+								// Changes the value
+								try
+								{
+									var value = node.getAttribute('value');
+									
+									if (value != null)
+									{
+										var valueNode = mxUtils.parseXml(value).documentElement;
+
+										if (valueNode != null)
+										{
+											if (valueNode.getAttribute('replace-value') == '1')
+											{
+												model.setValue(cell, valueNode);
+											}
+											else
+											{
+												var attrs = valueNode.attributes;
+												
+												for (var j = 0; j < attrs.length; j++)
+												{
+													graph.setAttributeForCell(cell, attrs[j].nodeName,
+														(attrs[j].nodeValue.length > 0) ? attrs[j].nodeValue : null);
+												}
+											}
+										}
+									}
+								}
+								catch (e)
+								{
+									if (window.console != null)
+									{
+										console.log('Error in value for ' + cell.id + ': ' + e);
+									}
+								}
+								
+								// Changes the style
+								try
+								{
+									var style = node.getAttribute('style');
+									
+									if (style != null)
+									{
+										graph.model.setStyle(cell, style);
+									}
+								}
+								catch (e)
+								{
+									if (window.console != null)
+									{
+										console.log('Error in style for ' + cell.id + ': ' + e);
+									}
+								}
+								
+								// Adds or removes an overlay icon
+								try
+								{
+									var icon = node.getAttribute('icon');
+									
+									if (icon != null)
+									{
+										var desc = (icon.length > 0) ? JSON.parse(icon) : null;
+										
+										if (desc == null || !desc.append)
+										{
+											graph.removeCellOverlays(cell);
+										}
+										
+										if (desc != null)
+										{
+											graph.addCellOverlay(cell, createOverlay(desc));
+										}
+									}
+								}
+								catch (e)
+								{
+									if (window.console != null)
+									{
+										console.log('Error in icon for ' + cell.id + ': ' + e);
+									}
+								}
+								
+								// Replaces the geometry
+								try
+								{
+									var geo = node.getAttribute('geometry');
+									
+									if (geo != null)
+									{
+										geo = JSON.parse(geo);
+										var curr = graph.getCellGeometry(cell);
+										
+										if (curr != null)
+										{
+											curr = curr.clone();
+											
+											// Partially overwrites geometry
+											for (key in geo)
+											{
+												var val = parseFloat(geo[key]);
+												
+												if (key == 'dx')
+												{
+													curr.x += val; 
+												}
+												else if (key == 'dy')
+												{
+													curr.y += val;
+												}
+												else if (key == 'dw')
+												{
+													curr.width += val;
+												}
+												else if (key == 'dh')
+												{
+													curr.height += val;
+												}
+												else
+												{
+													curr[key] = parseFloat(geo[key]);
+												}
+											}
+											
+											graph.model.setGeometry(cell, curr);
+										}
+									}
+								}
+								catch (e)
+								{
+									if (window.console != null)
+									{
+										console.log('Error in icon for ' + cell.id + ': ' + e);
+									}
+								}
+							} // if cell != null
+						} // if node.nodeName == 'update
+						else if (node.nodeName == 'model')
+						{
+							// Finds first child element
+							var dataNode = node.firstChild;
+							
+							while (dataNode != null && dataNode.nodeType != mxConstants.NODETYPE_ELEMENT)
+							{
+								dataNode = dataNode.nextSibling;
+							}
+							
+							if (dataNode != null)
+							{
+								var dec = new mxCodec(node.firstChild);
+								dec.decode(dataNode, model);
+							}
+						}
+						else if (node.nodeName == 'view')
+						{
+							if (node.hasAttribute('scale'))
+							{
+								graph.view.scale = parseFloat(node.getAttribute('scale'));
+							}
+							
+							if (node.hasAttribute('dx') || node.hasAttribute('dy'))
+							{
+								graph.view.translate = new mxPoint(parseFloat(node.getAttribute('dx') || 0),
+									parseFloat(node.getAttribute('dy') || 0));
+							}
+						}
+						else if (node.nodeName == 'fit')
+						{
+							if (node.hasAttribute('max-scale'))
+							{
+								fit = parseFloat(node.getAttribute('max-scale'));
+							}
+							else
+							{
+								fit = 1;
+							}
+						}
+						
+						node = node.nextSibling;
+					} // end of while
+				}
+				finally
+				{
+					model.endUpdate();
+				}
+				
+				if (fit != null && this.chromelessResize)
+				{
+					this.chromelessResize(true, fit);
+				}
+			}
+		}
+		
+		return doc;
+	};
+	
 	/**
 	 * Translates this point by the given vector.
 	 * 
@@ -2096,8 +2468,8 @@
 					
 				    if (evt.dataTransfer.files.length > 0)
 				    {	
-					    	this.importFiles(evt.dataTransfer.files, 0, 0, this.maxImageSize, mxUtils.bind(this, function(data, mimeType, x, y, w, h, img, doneFn, file)
-					    	{
+				    	this.importFiles(evt.dataTransfer.files, 0, 0, this.maxImageSize, mxUtils.bind(this, function(data, mimeType, x, y, w, h, img, doneFn, file)
+				    	{
 							if (data != null && mimeType.substring(0, 6) == 'image/')
 							{
 								var style = 'shape=image;verticalLabelPosition=bottom;verticalAlign=top;aspect=fixed;image=' +
@@ -2178,7 +2550,7 @@
 									}
 								});
 								
-								if  (file != null && img != null && ((/(\.vsdx)($|\?)/i.test(img)) || /(\.vssx)($|\?)/i.test(img) || (/(\.vsd)($|\?)/i.test(img))))
+								if (file != null && img != null && ((/(\.vsdx?)($|\?)/i.test(img)) || /(\.vssx)($|\?)/i.test(img)))
 								{
 									this.importVisio(file, function(xml)
 									{
@@ -5232,11 +5604,11 @@
 				{
 					if (req.getStatus() >= 200 && req.getStatus() <= 299)
 					{
-					    	if (success != null)
-					    	{
-						    	var data = req.getText();
-						    	
-					    		// Returns PNG as base64 encoded data URI
+				    	if (success != null)
+				    	{
+					    	var data = req.getText();
+					    	
+				    		// Returns PNG as base64 encoded data URI
 							if (binary)
 							{
 								// NOTE: This requires BinaryToArray VB script in the page
@@ -5259,23 +5631,23 @@
 								dataUriPrefix = (dataUriPrefix != null) ? dataUriPrefix : 'data:image/png;base64,';
 								data = dataUriPrefix + this.base64Encode(data);
 							}
-					    		
-					    		success(data);
-					    	}
+				    		
+				    		success(data);
+				    	}
 					}
 					else if (error != null)
-				    	{
-				    		error({code: App.ERROR_UNKNOWN}, req);
-				    	}
+			    	{
+			    		error({code: App.ERROR_UNKNOWN}, req);
+			    	}
 				}), function()
 				{
-				    	if (error != null)
-				    	{
-				    		error({code: App.ERROR_UNKNOWN});
-				    	}
+			    	if (error != null)
+			    	{
+			    		error({code: App.ERROR_UNKNOWN});
+			    	}
 				}, binary, this.timeout, function()
 			    {
-				    	if (retry && error != null)
+				    if (retry && error != null)
 					{
 						error({code: App.ERROR_TIMEOUT, retry: fn});
 					}
@@ -5466,18 +5838,18 @@
 			{
 				if (/(\.vsd)($|\?)/i.test(filename) && VSD_CONVERT_URL != null) 
 				{
-					 var formData = new FormData();
-			         formData.append("file1", file);
+					var formData = new FormData();
+					formData.append('file1', file, filename);
+
+					var xhr = new XMLHttpRequest();
+					xhr.open('POST', VSD_CONVERT_URL);
+					xhr.responseType = 'blob';
 					
-			         var xhr = new XMLHttpRequest();
-			 		 xhr.open('POST', VSD_CONVERT_URL);
-			 		 xhr.responseType = "blob";
-			 		
-			 		 xhr.onreadystatechange = mxUtils.bind(this, function()
-			 		 {
-			 			if (xhr.readyState == 4)
-			 			{	
-			 				if (xhr.status >= 200 && xhr.status <= 299)
+					xhr.onreadystatechange = mxUtils.bind(this, function()
+					{
+						if (xhr.readyState == 4)
+						{	
+							if (xhr.status >= 200 && xhr.status <= 299)
 							{
 								try
 								{
@@ -5488,14 +5860,14 @@
 									onerror(e);
 								}
 							}
-			 				else
-		 					{
-			 					onerror({});
-		 					}
-			 			}
-			 		 });
-			 		
-			 		 xhr.send(formData);
+							else
+							{
+								onerror({});
+							}
+						}
+					});
+					
+					xhr.send(formData);
 				}
 				else
 				{
@@ -5972,11 +6344,7 @@
                 }
             }));
         }
-//		else if  (file != null && filename != null && ((/(\.vsdx)($|\?)/i.test(filename)) || /(\.vssx)($|\?)/i.test(filename) || /(\.vsd)($|\?)/i.test(filename)))
-//		{
-//			
-//        }
-		else if  (file != null && filename != null && ((/(\.vsdx)($|\?)/i.test(filename)) || /(\.vssx)($|\?)/i.test(filename) || /(\.vsd)($|\?)/i.test(filename)))
+		else if  (file != null && filename != null && ((/(\.vsdx?)($|\?)/i.test(filename)) || /(\.vssx)($|\?)/i.test(filename)))
 		{
 			//  LATER: done and async are a hack before making this asynchronous
 			async = true;
@@ -6384,7 +6752,7 @@
 						});
 						
 						// Handles special cases
-						if (/(\.vsdx)($|\?)/i.test(file.name) || /(\.vssx)($|\?)/i.test(file.name) || /(\.vsd)($|\?)/i.test(file.name))
+						if (/(\.vsdx?)($|\?)/i.test(file.name) || /(\.vssx)($|\?)/i.test(file.name))
 						{
 							fn(null, file.type, x + index * gs, y + index * gs, 240, 160, file.name, function(cells)
 							{
@@ -8193,7 +8561,7 @@
 								}
 							});
 							
-							if  (/(\.vsdx)($|\?)/i.test(name) || /(\.vssx)($|\?)/i.test(name) || /(\.vsd)($|\?)/i.test(name))
+							if  (/(\.vsdx?)($|\?)/i.test(name) || /(\.vssx)($|\?)/i.test(name))
 							{
 								this.importVisio(file, mxUtils.bind(this, function(xml)
 								{
@@ -9245,10 +9613,10 @@
 		if (this.importCsvDialog == null)
 		{
 			this.importCsvDialog = new TextareaDialog(this, mxResources.get('csv') + ':',
-	    			Editor.defaultCsvValue, mxUtils.bind(this, function(newValue)
-				{
-	    				this.importCsv(newValue);
-				}), null, null, 620, 430, null, true, true, mxResources.get('import'));
+    			Editor.defaultCsvValue, mxUtils.bind(this, function(newValue)
+			{
+    			this.importCsv(newValue);
+			}), null, null, 620, 430, null, true, true, mxResources.get('import'));
 		}
 		
 		this.showDialog(this.importCsvDialog.container, 640, 520, true, true);
@@ -9258,7 +9626,7 @@
 	/**
 	 * TODO: Move to Editor
 	 */
-	EditorUi.prototype.importCsv = function(text)
+	EditorUi.prototype.importCsv = function(text, done)
 	{
 		try
 		{
@@ -9289,8 +9657,15 @@
 				// Delayed after optional layout
     			var afterInsert = function()
     			{
-    				graph.setSelectionCells(select);
-		    		graph.scrollCellToVisible(graph.getSelectionCell());
+    				if (done != null)
+    				{
+    					done(select);
+    				}
+    				else
+    				{
+    					graph.setSelectionCells(select);
+    					graph.scrollCellToVisible(graph.getSelectionCell());
+    				}
     			};
     				
     			// Computes unscaled, untranslated graph bounds
@@ -9581,9 +9956,9 @@
 							var cell = cells[i];
 							
 							for (var j = 0; j < ignore.length; j++)
-					    		{
+					    	{
 								graph.setAttributeForCell(cell, mxUtils.trim(ignore[j]), null);
-					    		}
+					    	}
 						}
 					}
 					
@@ -9616,27 +9991,27 @@
 					if (layout == 'circle')
 					{
 						var circleLayout = new mxCircleLayout(graph);
-		    				circleLayout.resetEdges = false;
-		    				
-		    				var circleLayoutIsVertexIgnored = circleLayout.isVertexIgnored;
-		    				
-	    	    				// Ignore other cells
-		    				circleLayout.isVertexIgnored = function(vertex)
-		    				{
-		    					return circleLayoutIsVertexIgnored.apply(this, arguments) ||
-		    						mxUtils.indexOf(cells, vertex) < 0;
-		    				};
-						
-				    		this.executeLayout(function()
-				    		{
-				    			circleLayout.execute(graph.getDefaultParent());
-				    			postProcess();
-				    		}, true, afterInsert);
+	    				circleLayout.resetEdges = false;
+	    				
+	    				var circleLayoutIsVertexIgnored = circleLayout.isVertexIgnored;
 	    				
-				    		afterInsert = null;
+    	    				// Ignore other cells
+	    				circleLayout.isVertexIgnored = function(vertex)
+	    				{
+	    					return circleLayoutIsVertexIgnored.apply(this, arguments) ||
+	    						mxUtils.indexOf(cells, vertex) < 0;
+	    				};
+					
+			    		this.executeLayout(function()
+			    		{
+			    			circleLayout.execute(graph.getDefaultParent());
+			    			postProcess();
+			    		}, true, afterInsert);
+    				
+			    		afterInsert = null;
 					}
 					else if (layout == 'horizontaltree' || layout == 'verticaltree' ||
-					(layout == 'auto' && select.length == 2 * cells.length - 1 && roots.length == 1))
+							(layout == 'auto' && select.length == 2 * cells.length - 1 && roots.length == 1))
 	    			{
 		    			// Required for layouts to work with new cells
 		    			graph.view.validate();

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

@@ -346,7 +346,7 @@ GitHubClient.prototype.getFile = function(path, success, error, asLibrary, check
 	var binary = /\.png$/i.test(path);
 	
 	// Handles .vsdx, Gliffy and PNG+XML files by creating a temporary file
-	if (!checkExists && (/\.vsdx$/i.test(path) || /\.gliffy$/i.test(path) ||
+	if (!checkExists && (/\.vsdx?$/i.test(path) || /\.gliffy$/i.test(path) ||
 		(!this.ui.useCanvasForExport && binary)))
 	{
 		// Should never be null

+ 18 - 15
src/main/webapp/js/diagramly/Menus.js

@@ -2023,23 +2023,26 @@
 
 		var addInsertItem = function(menu, parent, title, method)
 		{
-			menu.addItem(title, null, mxUtils.bind(this, function()
+			if (method != 'plantUml' || EditorUi.enablePlantUml)
 			{
-				if (method == 'fromText' || method == 'formatSql' || method == 'plantUml')
+				menu.addItem(title, null, mxUtils.bind(this, function()
 				{
-					var dlg = new ParseDialog(editorUi, title, method);
-					editorUi.showDialog(dlg.container, 620, 420, true, false);
-					editorUi.dialog.container.style.overflow = 'auto';
-					dlg.init();
-				}
-				else
-				{
-					var dlg = new CreateGraphDialog(editorUi, title, method);
-					editorUi.showDialog(dlg.container, 620, 420, true, false);
-					// Executed after dialog is added to dom
-					dlg.init();
-				}
-			}), parent);
+					if (method == 'fromText' || method == 'formatSql' || method == 'plantUml')
+					{
+						var dlg = new ParseDialog(editorUi, title, method);
+						editorUi.showDialog(dlg.container, 620, 420, true, false);
+						editorUi.dialog.container.style.overflow = 'auto';
+						dlg.init();
+					}
+					else
+					{
+						var dlg = new CreateGraphDialog(editorUi, title, method);
+						editorUi.showDialog(dlg.container, 620, 420, true, false);
+						// Executed after dialog is added to dom
+						dlg.init();
+					}
+				}), parent);
+			}
 		};
 		
 		var insertVertex = function(value, w, h, style)

+ 74 - 65
src/main/webapp/js/diagramly/Minimal.js

@@ -330,6 +330,22 @@ EditorUi.initMinimalTheme = function()
 	EditorUi.prototype.showCsvImport = false;
     EditorUi.prototype.footerHeight = 0;
 	Graph.prototype.editAfterInsert = true;
+
+    /**
+     * Sets the XML node for the current diagram.
+     */
+    Editor.prototype.isChromelessView = function()
+    {
+    	return false;
+    };
+
+    /**
+     * Sets the XML node for the current diagram.
+     */
+    Graph.prototype.isLightboxView = function()
+    {
+    	return false;
+    };
     
     // Overridden to ignore tabContainer height for diagramContainer
     var editorUiRefresh = EditorUi.prototype.refresh;
@@ -347,7 +363,6 @@ EditorUi.initMinimalTheme = function()
     };
     
     // Overridden to update save menu state
-	
 	/**
 	 * Updates action states depending on the selection.
 	 */
@@ -357,30 +372,9 @@ EditorUi.initMinimalTheme = function()
 	{
 		editorUiUpdateActionStates.apply(this, arguments);
 
-		var saveMenu = this.menus.get('save');
-		
-		if (saveMenu != null)
-		{
-			saveMenu.setEnabled(this.getCurrentFile() != null || urlParams['embed'] == '1');
-		}
+		this.menus.get('save').setEnabled(this.getCurrentFile() != null || urlParams['embed'] == '1');
 	};
 
-    /**
-     * Sets the XML node for the current diagram.
-     */
-    Editor.prototype.isChromelessView = function()
-    {
-    	return false;
-    };
-
-    /**
-     * Sets the XML node for the current diagram.
-     */
-    Graph.prototype.isLightboxView = function()
-    {
-    	return false;
-    };
-    
     // Hides keyboard shortcuts in menus
     var menusAddShortcut = Menus.prototype.addShortcut; 
     
@@ -652,22 +646,15 @@ EditorUi.initMinimalTheme = function()
 	
     // Disables centering of graph after iframe resize
 	EditorUi.prototype.chromelessWindowResize = function() {};
-    
-	// Initializes the user interface
-	var editorUiInit = EditorUi.prototype.init;
 	
-	EditorUi.prototype.init = function()
+	// Adds actions and menus
+	var menusInit = Menus.prototype.init;
+	Menus.prototype.init = function()
 	{
-		editorUiInit.apply(this, arguments);
+		menusInit.apply(this, arguments);
 		
-        var ui = this;
-        var graph = this.editor.graph;
-        var isGraphEnabled = mxUtils.bind(graph, graph.isEnabled);
-        
-        var div = document.createElement('div');
-        div.style.cssText = 'position:absolute;left:0px;right:0px;top:0px;overflow-y:auto;overflow-x:hidden;';
-        div.style.bottom = (urlParams['embed'] != '1' || urlParams['libraries'] == '1') ? '63px' : '32px';
-        this.sidebar = this.createSidebar(div);
+        var ui = this.editorUi;
+        var graph = ui.editor.graph;
         
         ui.actions.get('insertText').label = mxResources.get('text');
         ui.actions.get('insertText').label = mxResources.get('text');
@@ -715,12 +702,7 @@ EditorUi.initMinimalTheme = function()
             ui.showDialog(dlg.container, 620, 420, true, false);
             dlg.init();
         }));
-        ui.actions.put('plantUml', new Action(mxResources.get('plantUml') + '...', function()
-        {
-            var dlg = new ParseDialog(ui, 'Insert from Text', 'plantUml');
-            ui.showDialog(dlg.container, 620, 420, true, false);
-            dlg.init();
-        }));
+
         ui.actions.put('toggleShapes', new Action(mxResources.get('shapes') + '...', function()
         {
         	toggleShapes(ui);
@@ -729,18 +711,18 @@ EditorUi.initMinimalTheme = function()
         {
         	toggleFormat(ui);
         }));
-        var addInsertItem = function(menu, parent, title, method)
+        
+        if (EditorUi.enablePlantUml)
         {
-            menu.addItem(title, null, mxUtils.bind(this, function()
-            {
-                var dlg = new CreateGraphDialog(ui, title, method);
-                ui.showDialog(dlg.container, 620, 420, true, false);
-                // Executed after dialog is added to dom
-                dlg.init();
-            }), parent);
-        };
+	        ui.actions.put('plantUml', new Action(mxResources.get('plantUml') + '...', function()
+	        {
+	            var dlg = new ParseDialog(ui, 'Insert from Text', 'plantUml');
+	            ui.showDialog(dlg.container, 620, 420, true, false);
+	            dlg.init();
+	        }));
+        }
 
-        ui.menus.put('diagram', new Menu(mxUtils.bind(this, function(menu, parent)
+        this.put('diagram', new Menu(mxUtils.bind(this, function(menu, parent)
         {
         	ui.menus.addSubmenu('preferences', menu, parent);
 			menu.addSeparator(parent);
@@ -806,7 +788,7 @@ EditorUi.initMinimalTheme = function()
 
 		if (isLocalStorage)
 		{
-			var openFromMenu = ui.menus.get('openFrom');
+			var openFromMenu = this.get('openFrom');
 			var oldFunct = openFromMenu.funct;
 			
 			openFromMenu.funct = function(menu, parent)
@@ -818,7 +800,7 @@ EditorUi.initMinimalTheme = function()
 			};
 		}
 
-        ui.menus.put('save', new Menu(mxUtils.bind(this, function(menu, parent)
+		this.put('save', new Menu(mxUtils.bind(this, function(menu, parent)
         {
 			var file = ui.getCurrentFile();
 			
@@ -840,9 +822,9 @@ EditorUi.initMinimalTheme = function()
         })));
         
         // Augments the existing export menu
-        var exportAsMenu = ui.menus.get('exportAs');
+        var exportAsMenu = this.get('exportAs');
         
-        ui.menus.put('exportAs', new Menu(mxUtils.bind(this, function(menu, parent)
+        this.put('exportAs', new Menu(mxUtils.bind(this, function(menu, parent)
         {
         	exportAsMenu.funct(menu, parent);
             menu.addSeparator(parent);
@@ -852,9 +834,9 @@ EditorUi.initMinimalTheme = function()
             ui.menus.addMenuItems(menu, ['publishLink'], parent);
         })));
 
-        var langMenu = ui.menus.get('language');
+        var langMenu = this.get('language');
 
-        ui.menus.put('preferences', new Menu(mxUtils.bind(this, function(menu, parent)
+        this.put('preferences', new Menu(mxUtils.bind(this, function(menu, parent)
         {
 			if (urlParams['embed'] != '1')
 			{
@@ -881,7 +863,7 @@ EditorUi.initMinimalTheme = function()
 			}
         })));
 
-        ui.menus.put('insertAdvanced', new Menu(mxUtils.bind(this, function(menu, parent)
+        this.put('insertAdvanced', new Menu(mxUtils.bind(this, function(menu, parent)
         {
             ui.menus.addMenuItems(menu, ['importText', 'createShape', 'plantUml', '-', 'importCsv', 'editDiagram', 'formatSql', '-', 'insertPage'], parent);
         })));
@@ -889,7 +871,7 @@ EditorUi.initMinimalTheme = function()
         mxResources.parse('insertLayout=' + mxResources.get('layout'));
         mxResources.parse('insertAdvanced=' + mxResources.get('advanced'));
         
-        ui.menus.put('insert', new Menu(mxUtils.bind(this, function(menu, parent)
+        this.put('insert', new Menu(mxUtils.bind(this, function(menu, parent)
         {
             ui.menus.addMenuItems(menu, ['insertRectangle', 'insertEllipse', 'insertRhombus', '-', 'insertText',
                                          'insertLink', '-', 'insertImage'], parent);
@@ -901,8 +883,19 @@ EditorUi.initMinimalTheme = function()
 
         var methods = ['horizontalFlow', 'verticalFlow', '-', 'horizontalTree', 'verticalTree',
                        'radialTree', '-', 'organic', 'circle'];
-        
-        ui.menus.put('insertLayout', new Menu(mxUtils.bind(this, function(menu, parent)
+
+        var addInsertItem = function(menu, parent, title, method)
+        {
+            menu.addItem(title, null, mxUtils.bind(this, function()
+            {
+                var dlg = new CreateGraphDialog(ui, title, method);
+                ui.showDialog(dlg.container, 620, 420, true, false);
+                // Executed after dialog is added to dom
+                dlg.init();
+            }), parent);
+        };
+
+        this.put('insertLayout', new Menu(mxUtils.bind(this, function(menu, parent)
         {
             for (var i = 0; i < methods.length; i++)
             {
@@ -917,14 +910,28 @@ EditorUi.initMinimalTheme = function()
             }
         })));
         
-        ui.menus.put('options', new Menu(mxUtils.bind(this, function(menu, parent)
+        this.put('options', new Menu(mxUtils.bind(this, function(menu, parent)
         {
             ui.menus.addMenuItems(menu, ['grid', 'guides', '-', 'connectionArrows', 'connectionPoints', '-',
             	'copyConnect', 'collapseExpand', '-', 'mathematicalTypesetting'], parent);
         })));
+	};
+	
+	// Initializes the user interface
+	var editorUiInit = EditorUi.prototype.init;
+	
+	EditorUi.prototype.init = function()
+	{
+		editorUiInit.apply(this, arguments);
+
+        var div = document.createElement('div');
+        div.style.cssText = 'position:absolute;left:0px;right:0px;top:0px;overflow-y:auto;overflow-x:hidden;';
+        div.style.bottom = (urlParams['embed'] != '1' || urlParams['libraries'] == '1') ? '63px' : '32px';
+        this.sidebar = this.createSidebar(div);
 
         // Needed for creating elements in Format panel
-        ui.toolbar = ui.createToolbar(ui.createDiv('geToolbar'));
+        var ui = this;
+        ui.toolbar = this.createToolbar(ui.createDiv('geToolbar'));
         ui.defaultLibraryName = mxResources.get('untitledLibrary');
         
         var menubar = document.createElement('div');
@@ -1196,7 +1203,9 @@ EditorUi.initMinimalTheme = function()
 		
 		// Container for the user element
 		ui.menubarContainer = ui.buttonContainer;
-		
+
+        var langMenu = this.menus.get('language');
+
 		if (langMenu != null && !mxClient.IS_CHROMEAPP && !EditorUi.isElectronApp && iw >= 480)
 		{
 			var elt = menuObj.addMenu('', langMenu.funct);

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

@@ -320,7 +320,7 @@ OneDriveClient.prototype.getFile = function(id, success, error, denyConvert, asL
 			var binary = /\.png$/i.test(meta.name);
 			
 			// Handles .vsdx, Gliffy and PNG+XML files by creating a temporary file
-			if (/\.vsdx$/i.test(meta.name) || /\.gliffy$/i.test(meta.name) ||
+			if (/\.vsdx?$/i.test(meta.name) || /\.gliffy$/i.test(meta.name) ||
 				(!this.ui.useCanvasForExport && binary))
 			{
 				var mimeType = (meta.file != null) ? meta.file.mimeType : null;

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

@@ -123,7 +123,7 @@ TrelloClient.prototype.getFile = function(id, success, error, denyConvert, asLib
 				// TODO Trello doesn't allow CORS requests to load attachments. Confirm that
 				// and make sure that only a proxy technique can work!
 				// Handles .vsdx, Gliffy and PNG+XML files by creating a temporary file
-				if (/\.vsdx$/i.test(meta.name) || /\.gliffy$/i.test(meta.name) ||
+				if (/\.vsdx?$/i.test(meta.name) || /\.gliffy$/i.test(meta.name) ||
 					(!this.ui.useCanvasForExport && binary))
 				{
 					this.ui.convertFile(PROXY_URL + '?url=' + encodeURIComponent(meta.url), meta.name, meta.mimeType,

+ 132 - 123
src/main/webapp/js/diagramly/vsdx/importer.js

@@ -169,142 +169,151 @@ var com;
 	                    	if (processedFiles == filesCount) 
 	                    	{
 	                    		var dateAfter = new Date();
-	                         //console.log(processedFiles + " File extracted in " + (dateAfter - dateBefore) + "ms");
-	                         allDone();
+		                         //console.log(processedFiles + " File extracted in " + (dateAfter - dateBefore) + "ms");
+		                         allDone();
 	                    	}
                     };
                     
                     JSZip.loadAsync(file)                                   
                     .then(function(zip) 
                     {
-                        var dateAfter = new Date();
-                       	//console.log(" (loaded in " + (dateAfter - dateBefore) + "ms)");
-                       	
-                        zip.forEach(function (relativePath, zipEntry) 
-                        {  
-        					var filename = zipEntry.name;
-                        	var name = filename.toLowerCase();
-        					var nameLen = name.length;
-                            if (name.indexOf('.xml') == nameLen - 4 || name.indexOf('.xml.rels') == nameLen - 9) //xml files
-                            {
-                            	filesCount++;
-        	                    zipEntry.async("string").then(function (str) 
-        	                  	{
-        	                    		if (!(str.length === 0)) {
-        	    						//UTF-8 BOM causes exception while parsing, so remove it
-        	    						//TODO is the text encoding will be correct or string must be re-read as UTF-8?
-                                        if ((function (str, searchString, position) {
-                                            if (position === void 0) { position = 0; }
-                                            return str.substr(position, searchString.length) === searchString;
-                                        })(str, "\u00ef\u00bb\u00bf"))
-                                            str = str.substring(3);
-                                        var doc = mxUtils.parseXml(str);
-                                        if (doc == null) { //FIXME TODO find a way to change encoding in javascript
-//                                            var outBytes = out.toByteArray();
-//                                            if (outBytes[1] === 0 && outBytes[3] === 0 && outBytes[5] === 0) {
-//                                                str = out.toString("UTF-16LE");
-//                                                doc = mxUtils.parseXml(str);
-//                                            }
-                                        	//TODO add any other non-standard encoding that may be needed 
-                                        }
-                                        doc.vsdxFileName = filename;
-                                        /* put */ (docData[filename] = doc);
-                                    }
-	        	                    	processedFiles++;
-	
-	        	                    	doneCheck();
-        	                   	});
-                            }
-                            else if (name.indexOf(mxVsdxCodec.vsdxPlaceholder + "/media") === 0)//binary files
-                           	{
-                            	filesCount++;
-                            	if ((function (str, searchString) { var pos = str.length - searchString.length; var lastIndex = str.indexOf(searchString, pos); return lastIndex !== -1 && lastIndex === pos; })(name, ".emf")) {
-                            		if (JSZip.support.uint8array) 
-                            		{
-		                            	zipEntry.async("uint8array").then(function (emfData) 
-		           	                  	{
-	                                        var imageFound = false;
-	                                        var base64Str = "";
-	                                        for (var i = 0; i < emfData.length - 8; i++) {
-	                                            if (_this.isPng(emfData, i) || _this.isJpg(emfData, i)) {
-	                                            	base64Str = com.mxgraph.online.mxBase64.encodeToString(emfData, i);
-	                                                imageFound = true;
-	                                                break;
-	                                            }
-	                                        }
-	                                        ;
-	                                        if (imageFound) {
-	    	                                    /* put */ (mediaData[filename] = base64Str);
+                    	if (Object.keys(zip.files).length == 0)
+                    	{
+                    		if (onerror != null)
+                    		{
+                    			onerror();
+                    		}
+                    	}
+                    	else
+                    	{
+	                        var dateAfter = new Date();
+	                       	//console.log(" (loaded in " + (dateAfter - dateBefore) + "ms)");
+	                       	
+	                        zip.forEach(function (relativePath, zipEntry) 
+	                        {  
+	        					var filename = zipEntry.name;
+	                        	var name = filename.toLowerCase();
+	        					var nameLen = name.length;
+	                            if (name.indexOf('.xml') == nameLen - 4 || name.indexOf('.xml.rels') == nameLen - 9) //xml files
+	                            {
+	                            	filesCount++;
+	        	                    zipEntry.async("string").then(function (str) 
+	        	                  	{
+	        	                    		if (!(str.length === 0)) {
+	        	    						//UTF-8 BOM causes exception while parsing, so remove it
+	        	    						//TODO is the text encoding will be correct or string must be re-read as UTF-8?
+	                                        if ((function (str, searchString, position) {
+	                                            if (position === void 0) { position = 0; }
+	                                            return str.substr(position, searchString.length) === searchString;
+	                                        })(str, "\u00ef\u00bb\u00bf"))
+	                                            str = str.substring(3);
+	                                        var doc = mxUtils.parseXml(str);
+	                                        if (doc == null) { //FIXME TODO find a way to change encoding in javascript
+	//                                            var outBytes = out.toByteArray();
+	//                                            if (outBytes[1] === 0 && outBytes[3] === 0 && outBytes[5] === 0) {
+	//                                                str = out.toString("UTF-16LE");
+	//                                                doc = mxUtils.parseXml(str);
+	//                                            }
+	                                        	//TODO add any other non-standard encoding that may be needed 
 	                                        }
-		
+	                                        doc.vsdxFileName = filename;
+	                                        /* put */ (docData[filename] = doc);
+	                                    }
 		        	                    	processedFiles++;
-	
+		
 		        	                    	doneCheck();
-		           	                   	});
-                            		}
-                            	}
-                            	else if ((function (str, searchString) { var pos = str.length - searchString.length; var lastIndex = str.indexOf(searchString, pos); return lastIndex !== -1 && lastIndex === pos; })(name, ".bmp")) {
-                            		if (JSZip.support.uint8array) 
-                            		{
-		                            	zipEntry.async("uint8array").then(function (bmpData) 
+	        	                   	});
+	                            }
+	                            else if (name.indexOf(mxVsdxCodec.vsdxPlaceholder + "/media") === 0)//binary files
+	                           	{
+	                            	filesCount++;
+	                            	if ((function (str, searchString) { var pos = str.length - searchString.length; var lastIndex = str.indexOf(searchString, pos); return lastIndex !== -1 && lastIndex === pos; })(name, ".emf")) {
+	                            		if (JSZip.support.uint8array) 
+	                            		{
+			                            	zipEntry.async("uint8array").then(function (emfData) 
+			           	                  	{
+		                                        var imageFound = false;
+		                                        var base64Str = "";
+		                                        for (var i = 0; i < emfData.length - 8; i++) {
+		                                            if (_this.isPng(emfData, i) || _this.isJpg(emfData, i)) {
+		                                            	base64Str = com.mxgraph.online.mxBase64.encodeToString(emfData, i);
+		                                                imageFound = true;
+		                                                break;
+		                                            }
+		                                        }
+		                                        ;
+		                                        if (imageFound) {
+		    	                                    /* put */ (mediaData[filename] = base64Str);
+		                                        }
+			
+			        	                    	processedFiles++;
+		
+			        	                    	doneCheck();
+			           	                   	});
+	                            		}
+	                            	}
+	                            	else if ((function (str, searchString) { var pos = str.length - searchString.length; var lastIndex = str.indexOf(searchString, pos); return lastIndex !== -1 && lastIndex === pos; })(name, ".bmp")) {
+	                            		if (JSZip.support.uint8array) 
+	                            		{
+			                            	zipEntry.async("uint8array").then(function (bmpData) 
+			           	                  	{
+			                            		var bitmap = new BmpDecoder(bmpData);
+			                            		
+			                            		var c = document.createElement("canvas");
+			                            		c.width = bitmap.width;
+			                              	  	c.height = bitmap.height;
+			                            		var ctx = c.getContext("2d");
+			                            		ctx.putImageData(bitmap.imageData, 0, 0);
+			                            		var jpgData = c.toDataURL("image/jpeg");
+	                                            /* put */ (mediaData[filename] = jpgData.substr(23)); //23 is the length of "data:image/jpeg;base64,"
+	
+			        	                    	processedFiles++;
+			        	                    	doneCheck();
+			           	                   	});
+	                            		}
+	                            	}
+	                            	else
+	                            	{
+		                            	zipEntry.async("base64").then(function (base64Str) 
 		           	                  	{
-		                            		var bitmap = new BmpDecoder(bmpData);
-		                            		
-		                            		var c = document.createElement("canvas");
-		                            		c.width = bitmap.width;
-		                              	  	c.height = bitmap.height;
-		                            		var ctx = c.getContext("2d");
-		                            		ctx.putImageData(bitmap.imageData, 0, 0);
-		                            		var jpgData = c.toDataURL("image/jpeg");
-                                            /* put */ (mediaData[filename] = jpgData.substr(23)); //23 is the length of "data:image/jpeg;base64,"
-
-		        	                    	processedFiles++;
-		        	                    	doneCheck();
+	//	                                    if ((function (str, searchString) { var pos = str.length - searchString.length; var lastIndex = str.indexOf(searchString, pos); return lastIndex !== -1 && lastIndex === pos; })(name, ".bmp")) {
+	//	                                        try 
+	//	                                        {
+	//	    	                            		//convert BMP files to PNG
+	//		                                    	var bmpImg = new Image();
+	//		                                        
+	//		                                        bmpImg.onload = function() {
+	//		                                            var c = document.createElement("canvas");
+	//		                                            c.width = bmpImg.width;
+	//		                                            c.height = bmpImg.height;
+	//		                                            var ctx = c.getContext("2d");
+	//		                                            ctx.drawImage(bmpImg, 0, 0);
+	//		                                            var jpgData = c.toDataURL("image/jpeg");
+	//		                                            
+	//		                                            /* put */ (mediaData[filename] = jpgData.substr(23)); //23 is the length of "data:image/jpeg;base64,"
+	//		                                            
+	//		                                            processedFiles++;
+	//		                                            doneCheck();
+	//		                                        };
+	//	
+	//		                                        bmpImg.src = "data:image/bmp;base64," + base64Str;
+	//	                                        }
+	//	                                        catch (e) {} //conversion failed. Nothing can be done!
+	//	                                    }
+	//	                                    else 
+	//	                                    {
+			                                    /* put */ (mediaData[filename] = base64Str);
+			                                	
+			        	                    	processedFiles++;
+			        	                    	doneCheck();
+	//	                                    }
 		           	                   	});
-                            		}
-                            	}
-                            	else
-                            	{
-	                            	zipEntry.async("base64").then(function (base64Str) 
-	           	                  	{
-//	                                    if ((function (str, searchString) { var pos = str.length - searchString.length; var lastIndex = str.indexOf(searchString, pos); return lastIndex !== -1 && lastIndex === pos; })(name, ".bmp")) {
-//	                                        try 
-//	                                        {
-//	    	                            		//convert BMP files to PNG
-//		                                    	var bmpImg = new Image();
-//		                                        
-//		                                        bmpImg.onload = function() {
-//		                                            var c = document.createElement("canvas");
-//		                                            c.width = bmpImg.width;
-//		                                            c.height = bmpImg.height;
-//		                                            var ctx = c.getContext("2d");
-//		                                            ctx.drawImage(bmpImg, 0, 0);
-//		                                            var jpgData = c.toDataURL("image/jpeg");
-//		                                            
-//		                                            /* put */ (mediaData[filename] = jpgData.substr(23)); //23 is the length of "data:image/jpeg;base64,"
-//		                                            
-//		                                            processedFiles++;
-//		                                            doneCheck();
-//		                                        };
-//	
-//		                                        bmpImg.src = "data:image/bmp;base64," + base64Str;
-//	                                        }
-//	                                        catch (e) {} //conversion failed. Nothing can be done!
-//	                                    }
-//	                                    else 
-//	                                    {
-		                                    /* put */ (mediaData[filename] = base64Str);
-		                                	
-		        	                    	processedFiles++;
-		        	                    	doneCheck();
-//	                                    }
-	           	                   	});
-                            	}
-                           	}
-                        });
+	                            	}
+	                           	}
+	                        });
+                    	}
                     }, function (e) {
                     		//console.log("Error!" + e.message);
-                    		
                     		if (onerror != null)
                     		{
                     			onerror(e);

文件差異過大導致無法顯示
+ 1 - 1
src/main/webapp/js/embed-static.min.js


文件差異過大導致無法顯示
+ 2 - 2
src/main/webapp/js/extensions.min.js


文件差異過大導致無法顯示
+ 1 - 1
src/main/webapp/js/reader.min.js


文件差異過大導致無法顯示
+ 653 - 647
src/main/webapp/js/viewer.min.js


+ 10 - 208
src/main/webapp/plugins/update.js

@@ -103,217 +103,19 @@ Draw.loadPlugin(function(editorUi)
 		
 		function parseResponse(xml)
 		{
-			if (xml != null && xml.length > 0)
+			var doc = editorUi.updateDiagram(xml);
+			var node = (doc != null) ? doc.documentElement : null;
+			
+			if (node != null && node.nodeName == 'updates')
 			{
-				var doc = mxUtils.parseXml(xml);
-				var node = (doc != null) ? doc.documentElement : null;
+				if (node.hasAttribute('url'))
+				{
+					updateUrl = node.getAttribute('url');
+				}
 				
-				if (node != null && node.nodeName == 'updates')
+				if (node.hasAttribute('interval'))
 				{
-					if (node.hasAttribute('url'))
-					{
-						updateUrl = node.getAttribute('url');
-					}
-					
-					if (node.hasAttribute('interval'))
-					{
-						updateInterval = node.getAttribute('interval');
-					}
-					
-					var model = graph.getModel();
-					model.beginUpdate();
-					var fit = null;
-
-					try
-					{
-						node = node.firstChild;
-						
-						while (node != null)
-						{
-							if (node.nodeName == 'update')
-							{
-								// Resolves the cell ID
-								var cell = model.getCell(node.getAttribute('id'));
-								
-								if (cell != null)
-								{
-									// Changes the value
-									try
-									{
-										var value = node.getAttribute('value');
-										
-										if (value != null)
-										{
-											var valueNode = mxUtils.parseXml(value).documentElement;
-	
-											if (valueNode != null)
-											{
-												if (valueNode.getAttribute('replace-value') == '1')
-												{
-													model.setValue(cell, valueNode);
-												}
-												else
-												{
-													var attrs = valueNode.attributes;
-													
-													for (var j = 0; j < attrs.length; j++)
-													{
-														graph.setAttributeForCell(cell, attrs[j].nodeName,
-															(attrs[j].nodeValue.length > 0) ? attrs[j].nodeValue : null);
-													}
-												}
-											}
-										}
-									}
-									catch (e)
-									{
-										console.log('Error in value for ' + cell.id + ': ' + e);
-									}
-									
-									// Changes the style
-									try
-									{
-										var style = node.getAttribute('style');
-										
-										if (style != null)
-										{
-											graph.model.setStyle(cell, style);
-										}
-									}
-									catch (e)
-									{
-										console.log('Error in style for ' + cell.id + ': ' + e);
-									}
-									
-									// Adds or removes an overlay icon
-									try
-									{
-										var icon = node.getAttribute('icon');
-										
-										if (icon != null)
-										{
-											var desc = (icon.length > 0) ? JSON.parse(icon) : null;
-											
-											if (desc == null || !desc.append)
-											{
-												graph.removeCellOverlays(cell);
-											}
-											
-											if (desc != null)
-											{
-												graph.addCellOverlay(cell, createOverlay(desc));
-											}
-										}
-									}
-									catch (e)
-									{
-										console.log('Error in icon for ' + cell.id + ': ' + e);
-									}
-									
-									// Replaces the geometry
-									try
-									{
-										var geo = node.getAttribute('geometry');
-										
-										if (geo != null)
-										{
-											geo = JSON.parse(geo);
-											var curr = graph.getCellGeometry(cell);
-											
-											if (curr != null)
-											{
-												curr = curr.clone();
-												
-												// Partially overwrites geometry
-												for (key in geo)
-												{
-													var val = parseFloat(geo[key]);
-													
-													if (key == 'dx')
-													{
-														curr.x += val; 
-													}
-													else if (key == 'dy')
-													{
-														curr.y += val;
-													}
-													else if (key == 'dw')
-													{
-														curr.width += val;
-													}
-													else if (key == 'dh')
-													{
-														curr.height += val;
-													}
-													else
-													{
-														curr[key] = parseFloat(geo[key]);
-													}
-												}
-												
-												graph.model.setGeometry(cell, curr);
-											}
-										}
-									}
-									catch (e)
-									{
-										console.log('Error in icon for ' + cell.id + ': ' + e);
-									}
-								} // if cell != null
-							} // if node.nodeName == 'update
-							else if (node.nodeName == 'model')
-							{
-								// Finds first child element
-								var dataNode = node.firstChild;
-								
-								while (dataNode != null && dataNode.nodeType != mxConstants.NODETYPE_ELEMENT)
-								{
-									dataNode = dataNode.nextSibling;
-								}
-								
-								if (dataNode != null)
-								{
-									var dec = new mxCodec(node.firstChild);
-									dec.decode(dataNode, model);
-								}
-							}
-							else if (node.nodeName == 'view')
-							{
-								if (node.hasAttribute('scale'))
-								{
-									graph.view.scale = parseFloat(node.getAttribute('scale'));
-								}
-								
-								if (node.hasAttribute('dx') || node.hasAttribute('dy'))
-								{
-									graph.view.translate = new mxPoint(parseFloat(node.getAttribute('dx') || 0),
-										parseFloat(node.getAttribute('dy') || 0));
-								}
-							}
-							else if (node.nodeName == 'fit')
-							{
-								if (node.hasAttribute('max-scale'))
-								{
-									fit = parseFloat(node.getAttribute('max-scale'));
-								}
-								else
-								{
-									fit = 1;
-								}
-							}
-							
-							node = node.nextSibling;
-						} // end of while
-					}
-					finally
-					{
-						model.endUpdate();
-					}
-					
-					if (fit != null && editorUi.chromelessResize)
-					{
-						editorUi.chromelessResize(true, fit);
-					}
+					updateInterval = node.getAttribute('interval');
 				}
 			}
 		};

二進制
src/main/webapp/templates/business/accd.png


二進制
src/main/webapp/templates/business/archimate.png


二進制
src/main/webapp/templates/business/bpmn.png


二進制
src/main/webapp/templates/business/business_model_1.png


二進制
src/main/webapp/templates/business/business_model_2.png


二進制
src/main/webapp/templates/business/business_model_canvas_1.png


文件差異過大導致無法顯示
+ 1 - 0
src/main/webapp/templates/business/business_model_canvas_1.xml


二進制
src/main/webapp/templates/business/ishikawa_1.png


二進制
src/main/webapp/templates/business/ishikawa_2.png


二進制
src/main/webapp/templates/business/pert_1.png


二進制
src/main/webapp/templates/business/pert_2.png


文件差異過大導致無法顯示
+ 1 - 0
src/main/webapp/templates/business/swimlane.xml


二進制
src/main/webapp/templates/business/timeline_1.png


二進制
src/main/webapp/templates/business/timeline_2.png


文件差異過大導致無法顯示
+ 1 - 2
src/main/webapp/templates/business/timeline_2.xml


二進制
src/main/webapp/templates/business/timeline_3.png


文件差異過大導致無法顯示
+ 1 - 0
src/main/webapp/templates/business/timeline_3.xml


二進制
src/main/webapp/templates/business/timeline_4.png


文件差異過大導致無法顯示
+ 1 - 0
src/main/webapp/templates/business/timeline_4.xml


二進制
src/main/webapp/templates/charts/bar_chart_1.png


文件差異過大導致無法顯示
+ 1 - 0
src/main/webapp/templates/charts/bar_chart_1.xml


二進制
src/main/webapp/templates/charts/coc.png


二進制
src/main/webapp/templates/charts/org_chart_1.png


文件差異過大導致無法顯示
+ 1 - 2
src/main/webapp/templates/charts/org_chart_1.xml


二進制
src/main/webapp/templates/charts/org_chart_2.png


二進制
src/main/webapp/templates/charts/work_breakdown_structure.png


文件差異過大導致無法顯示
+ 1 - 0
src/main/webapp/templates/charts/work_breakdown_structure.xml


二進制
src/main/webapp/templates/engineering/cabinet.png


文件差異過大導致無法顯示
+ 1 - 2
src/main/webapp/templates/engineering/cabinet.xml


二進制
src/main/webapp/templates/engineering/electrical_1.png


二進制
src/main/webapp/templates/engineering/electrical_2.png


二進制
src/main/webapp/templates/flowcharts/cross_functional_flowchart.png


二進制
src/main/webapp/templates/flowcharts/cross_functional_flowchart_1.png


src/main/webapp/templates/flowcharts/cross_functional_flowchart.xml → src/main/webapp/templates/flowcharts/cross_functional_flowchart_1.xml


二進制
src/main/webapp/templates/flowcharts/cross_functional_flowchart_2.png


文件差異過大導致無法顯示
+ 2 - 0
src/main/webapp/templates/flowcharts/cross_functional_flowchart_2.xml


二進制
src/main/webapp/templates/flowcharts/data_flow_1.png


二進制
src/main/webapp/templates/flowcharts/data_flow_2.png


二進制
src/main/webapp/templates/flowcharts/data_flow_3.png


二進制
src/main/webapp/templates/flowcharts/epc.png


二進制
src/main/webapp/templates/flowcharts/flowchart_1.png


文件差異過大導致無法顯示
+ 1 - 0
src/main/webapp/templates/flowcharts/flowchart_1.xml


二進制
src/main/webapp/templates/flowcharts/flowchart_2.png


文件差異過大導致無法顯示
+ 1 - 0
src/main/webapp/templates/flowcharts/flowchart_2.xml


二進制
src/main/webapp/templates/flowcharts/workflow_1.png


文件差異過大導致無法顯示
+ 2 - 0
src/main/webapp/templates/flowcharts/workflow_1.xml


+ 25 - 5
src/main/webapp/templates/index.xml

@@ -4,34 +4,50 @@
 <template url="business/bpmn.xml" libs="general;bpmn"/>
 <template url="business/business_model_1.xml" libs="general;signs"/>
 <template url="business/business_model_2.xml" libs="general"/>
+<template url="business/business_model_canvas_1.xml" libs="general;signs"/>
 <template url="business/ishikawa_1.xml" libs="general"/>
 <template url="business/ishikawa_2.xml" libs="general"/>
 <template url="business/pert_1.xml" libs="general"/>
 <template url="business/pert_2.xml" libs="general"/>
 <template url="business/timeline_1.xml" libs="general"/>
 <template url="business/timeline_2.xml" libs="general"/>
+<template url="business/timeline_3.xml" libs="general"/>
+<template url="business/timeline_4.xml" libs="general"/>
+<template url="charts/bar_chart_1.xml" libs="general"/>
 <template url="charts/coc.xml" libs="general"/>
 <template url="charts/org_chart_1.xml" libs="general"/>
 <template url="charts/org_chart_2.xml" libs="general"/>
+<template url="charts/work_breakdown_structure.xml" libs="general"/>
 <template url="engineering/cabinet.xml" libs="general;cabinets"/>
 <template url="engineering/electrical_1.xml" libs="general;electrical"/>
 <template url="engineering/electrical_2.xml" libs="general;electrical"/>
-<template url="flowcharts/cross_functional_flowchart.xml" libs="general;flowchart"/>
+<template url="flowcharts/cross_functional_flowchart_1.xml" libs="general;flowchart"/>
+<template url="flowcharts/cross_functional_flowchart_2.xml" libs="general;flowchart"/>
 <template url="flowcharts/data_flow_1.xml" libs="general;uml"/>
 <template url="flowcharts/data_flow_2.xml" libs="general;uml"/>
 <template url="flowcharts/data_flow_3.xml" libs="general;uml"/>
 <template url="flowcharts/epc.xml" libs="general;flowchart"/>
+<template url="flowcharts/flowchart_1.xml" libs="general;flowchart"/>
+<template url="flowcharts/flowchart_2.xml" libs="general;flowchart"/>
+<template url="flowcharts/workflow_1.xml" libs="general;flowchart"/>
 <template url="layout/blog_wireframe.xml" libs="general;mockups"/>
 <template url="layout/bootstrap.xml" libs="general;bootstrap"/>
-<template url="layout/wireframe.xml" libs="general;mockups"/>
-<template url="maps/concept_map.xml" libs="general"/>
+<template url="layout/wireframe_1.xml" libs="general;mockups"/>
+<template url="layout/wireframe_2.xml" libs="general;mockups"/>
+<template url="maps/concept_map_1.xml" libs="general"/>
+<template url="maps/concept_map_2.xml" libs="general"/>
+<template url="maps/living_beings_mind_map.xml" libs="general"/>
+<template url="maps/mind_map.xml" libs="general"/>
 <template url="maps/site_map.xml" libs="general"/>
 <template url="network/active_directory.xml" libs="general;citrix"/>
 <template url="network/aws.xml" libs="general;aws3"/>
 <template url="network/aws_3d.xml" libs="general;aws3d"/>
-<template url="network/azure.xml" libs="general;azure;mscae"/>
-<template url="network/cisco.xml" libs="general;cisco"/>
+<template url="network/azure_1.xml" libs="general;azure;mscae"/>
+<template url="network/azure_2.xml" libs="general;azure;mscae"/>
+<template url="network/cisco_1.xml" libs="general;cisco"/>
+<template url="network/cisco_2.xml" libs="general;cisco"/>
 <template url="network/citrix.xml" libs="general;citrix"/>
+<template url="network/enterprise_1.xml" libs="general;citrix"/>
 <template url="network/ibm_bda_reference_architecture.xml" libs="general;ibm"/>
 <template url="network/ibm_cognitive_conversation.xml" libs="general;ibm"/>
 <template url="network/ibm_cognitive_discovery.xml" libs="general;ibm"/>
@@ -45,11 +61,14 @@
 <template url="network/veeam.xml" libs="general;veeam"/>
 <template url="network/wireless_home_network.xml" libs="general;network;clipart"/>
 <template url="other/block.xml" libs="general;"/>
+<template url="other/cycle_1.xml" libs="general;"/>
 <template url="other/decision_tree.xml" libs="general;"/>
 <template url="other/educational.xml" libs="general;"/>
 <template url="other/floor_plan.xml" libs="general;floorplan"/>
 <template url="other/infographic_1.xml" libs="general;mockups;signs"/>
 <template url="other/infographic_2.xml" libs="general;mockups;signs"/>
+<template url="other/infographic_3.xml" libs="general;mockups;signs"/>
+<template url="other/infographic_4.xml" libs="general;mockups;signs"/>
 <template url="other/lan_plan.xml" libs="general;floorplan"/>
 <template url="software/class_1.xml" libs="general;uml"/>
 <template url="software/class_2.xml" libs="general;uml"/>
@@ -78,4 +97,5 @@
 <template url="venn/venn_3.xml" libs="general"/>
 <template url="venn/venn_4.xml" libs="general"/>
 <template url="venn/venn_5.xml" libs="general"/>
+<template url="venn/venn_6.xml" libs="general"/>
 </templates>

二進制
src/main/webapp/templates/layout/blog_wireframe.png


二進制
src/main/webapp/templates/layout/bootstrap.png


二進制
src/main/webapp/templates/layout/wireframe.png


二進制
src/main/webapp/templates/layout/wireframe_1.png


src/main/webapp/templates/layout/wireframe.xml → src/main/webapp/templates/layout/wireframe_1.xml


二進制
src/main/webapp/templates/layout/wireframe_2.png


文件差異過大導致無法顯示
+ 2 - 0
src/main/webapp/templates/layout/wireframe_2.xml


二進制
src/main/webapp/templates/maps/concept_map.png


二進制
src/main/webapp/templates/maps/concept_map_1.png


src/main/webapp/templates/maps/concept_map.xml → src/main/webapp/templates/maps/concept_map_1.xml


二進制
src/main/webapp/templates/maps/concept_map_2.png


文件差異過大導致無法顯示
+ 2 - 0
src/main/webapp/templates/maps/concept_map_2.xml


二進制
src/main/webapp/templates/maps/living_beings_mind_map.png


文件差異過大導致無法顯示
+ 1 - 0
src/main/webapp/templates/maps/living_beings_mind_map.xml


二進制
src/main/webapp/templates/maps/mind_map.png


文件差異過大導致無法顯示
+ 1 - 0
src/main/webapp/templates/maps/mind_map.xml


二進制
src/main/webapp/templates/maps/site_map.png


文件差異過大導致無法顯示
+ 1 - 2
src/main/webapp/templates/maps/site_map.xml


二進制
src/main/webapp/templates/network/active_directory.png


二進制
src/main/webapp/templates/network/aws.png


二進制
src/main/webapp/templates/network/aws_3d.png


二進制
src/main/webapp/templates/network/azure.png


二進制
src/main/webapp/templates/network/azure_1.png


src/main/webapp/templates/network/azure.xml → src/main/webapp/templates/network/azure_1.xml


二進制
src/main/webapp/templates/network/azure_2.png


文件差異過大導致無法顯示
+ 1 - 0
src/main/webapp/templates/network/azure_2.xml


二進制
src/main/webapp/templates/network/cisco.png


文件差異過大導致無法顯示
+ 0 - 2
src/main/webapp/templates/network/cisco.xml


二進制
src/main/webapp/templates/network/cisco_1.png


文件差異過大導致無法顯示
+ 1 - 0
src/main/webapp/templates/network/cisco_1.xml


+ 0 - 0
src/main/webapp/templates/network/cisco_2.png


部分文件因文件數量過多而無法顯示