Pārlūkot izejas kodu

10.0.38 release

Gaudenz Alder 6 gadi atpakaļ
vecāks
revīzija
1ed073e0e6

+ 16 - 0
ChangeLog

@@ -1,3 +1,19 @@
+15-JAN-2019: 10.0.38
+
+- Fixes inconsistency in collaborative editing
+- Handles possible call stack errors
+- Uses mxGraph 3.9.13 beta 10
+- Adds IC shapes
+
+14-JAN-2019: 10.0.37
+
+- Improves error logging
+
+14-JAN-2019: 10.0.36
+
+- Uses mxGraph 3.9.13 beta 9
+- Adds debug output
+
 13-JAN-2019: 10.0.35
 
 - Fixes device option in splash

+ 1 - 1
VERSION

@@ -1 +1 @@
-10.0.35
+10.0.38

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 22 - 19
etc/mxgraph/mxClient.js


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

@@ -1,7 +1,7 @@
 CACHE MANIFEST
 
 # THIS FILE WAS GENERATED. DO NOT MODIFY!
-# 01/13/2019 10:31 AM
+# 01/15/2019 09:41 AM
 
 app.html
 index.html?offline=1

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


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1311 - 1307
src/main/webapp/js/app.min.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1093 - 1089
src/main/webapp/js/atlas-viewer.min.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1211 - 1207
src/main/webapp/js/atlas.min.js


+ 2 - 2
src/main/webapp/js/diagramly/App.js

@@ -2633,8 +2633,8 @@ App.prototype.pickFile = function(mode)
 				}
 				
 				this.fileLoaded((mode == App.MODE_BROWSER) ?
-						new StorageFile(this, xml, filename) :
-						new LocalFile(this, xml, filename));
+					new StorageFile(this, xml, filename) :
+					new LocalFile(this, xml, filename));
 			}));
 			
 			// Extends dialog close to show splash screen

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

@@ -2775,7 +2775,6 @@ var NewDialog = function(editorUi, compact, showName, callback, createOnly, canc
 	}
 
 	var hasTabs = false;
-	
 	var i0 = 0;
 	
 	// Dynamic loading
@@ -2795,7 +2794,22 @@ var NewDialog = function(editorUi, compact, showName, callback, createOnly, canc
 			}
 		}
 	};
-
+	
+	var spinner = new Spinner({
+		lines: 12, // The number of lines to draw
+		length: 10, // The length of each line
+		width: 5, // The line thickness
+		radius: 10, // The radius of the inner circle
+		rotate: 0, // The rotation offset
+		color: '#000', // #rgb or #rrggbb
+		speed: 1.5, // Rounds per second
+		trail: 60, // Afterglow percentage
+		shadow: false, // Whether to render a shadow
+		hwaccel: false, // Whether to use hardware acceleration
+		top: '40%',
+		zIndex: 2e9 // The z-index (defaults to 2000000000)
+	});
+	
 	var createButton = mxUtils.button(createButtonLabel || mxResources.get('create'), function()
 	{
 		createButton.setAttribute('disabled', 'disabled');
@@ -2864,29 +2878,12 @@ var NewDialog = function(editorUi, compact, showName, callback, createOnly, canc
 			
 			div.scrollTop = 0;
 			div.innerHTML = '';
-			
-			var spinner = new Spinner({
-				lines: 12, // The number of lines to draw
-				length: 10, // The length of each line
-				width: 5, // The line thickness
-				radius: 10, // The radius of the inner circle
-				rotate: 0, // The rotation offset
-				color: '#000', // #rgb or #rrggbb
-				speed: 1.5, // Rounds per second
-				trail: 60, // Afterglow percentage
-				shadow: false, // Whether to render a shadow
-				hwaccel: false, // Whether to use hardware acceleration
-				top: '40%',
-				zIndex: 2e9 // The z-index (defaults to 2000000000)
-			});
 			spinner.spin(div);
-			
 			i0 = 0;
 
-			var callback = function(list, errorMsg) 
+			var callback2 = function(list, errorMsg) 
 			{
 				spinner.stop();
-				
 				templates = list;
 				
 				if (errorMsg)
@@ -2905,9 +2902,13 @@ var NewDialog = function(editorUi, compact, showName, callback, createOnly, canc
 			}
 			
 			if (isSearch)
-				searchDocsCallback(searchInput.value, callback);
+			{
+				searchDocsCallback(searchInput.value, callback2);
+			}
 			else
-				recentDocsCallback(callback);
+			{
+				recentDocsCallback(callback2);
+			}
 		}
 		
 		if (recentDocsCallback)
@@ -3097,8 +3098,12 @@ var NewDialog = function(editorUi, compact, showName, callback, createOnly, canc
 					realUrl = TEMPLATE_PATH + '/' + realUrl;
 				}
 				
+				spinner.spin(div);
+				
 				mxUtils.get(realUrl, mxUtils.bind(this, function(req)
 				{
+					spinner.stop();
+					
 					if (req.getStatus() >= 200 && req.getStatus() <= 299)
 					{
 						selectElement(elt, req.getText(), libs);

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

@@ -356,7 +356,10 @@ EditorUi.prototype.patchPage = function(page, diff, resolver, updateEdgeParents)
 			page.root = root;
 		}
 
-		// Removes cells
+		// Inserts and updates previous and parent (hierarchy update)
+		this.patchCellRecursive(page, model, model.root, parentLookup, diff);
+
+		// Removes cells after parents have been updated above
 		if (diff[EditorUi.DIFF_REMOVE] != null)
 		{
 			for (var i = 0; i < diff[EditorUi.DIFF_REMOVE].length; i++)
@@ -370,10 +373,7 @@ EditorUi.prototype.patchPage = function(page, diff, resolver, updateEdgeParents)
 			}
 		}
 		
-		// Patches cell structure
-		this.patchCellRecursive(page, model, model.root, parentLookup, diff);
-
-		// Applies patches and changes terminals after all cells are inserted
+		// Updates cell states and terminals
 		if (diff[EditorUi.DIFF_UPDATE] != null)
 		{
 			var res = (resolver != null && resolver.cells != null) ? 
@@ -387,7 +387,7 @@ EditorUi.prototype.patchPage = function(page, diff, resolver, updateEdgeParents)
 			}
 		}
 
-		// Sets terminals for inserted cells after all cells are inserted
+		// Updates terminals for inserted cells
 		if (diff[EditorUi.DIFF_INSERT] != null)
 		{
 			for (var i = 0; i < diff[EditorUi.DIFF_INSERT].length; i++)
@@ -403,7 +403,7 @@ EditorUi.prototype.patchPage = function(page, diff, resolver, updateEdgeParents)
 			}
 		}
 
-		// Updates edge parents after all patches have been applied
+		// Delayed update of edge parents
 		model.updateEdgeParent = prev;
 		
 		if (updateEdgeParents && pendingUpdates.length > 0)

+ 85 - 38
src/main/webapp/js/diagramly/DrawioFile.js

@@ -20,6 +20,28 @@ DrawioFile = function(ui, data)
 	 */
 	this.data = data || '';
 	this.shadowData = this.data;
+	
+	// Creates the stats object
+	this.stats = {
+		joined: 0, /* number of join messages received */
+		merged: 0, /* number of calls to merge */
+		opened: 0, /* number of calls to open */
+		closed: 0, /* number of calls to close */
+		destroyed: 0, /* number of calls to close */
+		fileMerged: 0, /* number of calls to mergeFile */
+		fileSaved: 0, /* number of calls to fileSaved */
+		reload: 0, /* number of times the file was reloaded */
+		checksumErrors: 0, /* number of checksum errors */
+		bytesSent: 0, /* number of bytes send in messages */
+		bytesReceived: 0, /* number of bytes received in messages */
+		msgSent: 0, /* number of messages sent */
+		msgReceived: 0, /* number of messages received */
+		cacheHits: 0, /* number of times the cache returned patches */
+		cacheMiss: 0, /* number of times we have missed a cache entry */
+		cacheFail: 0, /* number of times we have failed to read the cache */
+		conflicts: 0, /* number of write conflicts when saving a file */
+		timeouts: 0 /* number of time we have given up to retry after a write conflict */
+	};
 };
 
 /**
@@ -116,25 +138,6 @@ DrawioFile.prototype.invalidChecksum = false;
  */
 DrawioFile.prototype.reportEnabled = true;
 
-/**
- * Specifies if notify events should be ignored.
- */
-DrawioFile.prototype.stats = {
-	joined: 0, /* number of join messages received */
-	merged: 0, /* number of calls to merge */
-	reload: 0, /* number of times the file was reloaded */
-	checksumErrors: 0, /* number of checksum errors */
-	bytesSent: 0, /* number of bytes send in messages */
-	bytesReceived: 0, /* number of bytes received in messages */
-	msgSent: 0, /* number of messages sent */
-	msgReceived: 0, /* number of messages received */
-	cacheHits: 0, /* number of times the cache returned patches */
-	cacheMiss: 0, /* number of times we have missed a cache entry */
-	cacheFail: 0, /* number of times we have failed to read the cache */
-	conflicts: 0, /* number of write conflicts when saving a file */
-	timeouts: 0 /* number of time we have given up to retry after a write conflict */
-};
-
 /**
  * Specifies if notify events should be ignored.
  */
@@ -173,30 +176,54 @@ DrawioFile.prototype.synchronizeFile = function(success, error)
 */
 DrawioFile.prototype.updateFile = function(success, error, abort, shadow)
 {
-	this.getLatestVersion(mxUtils.bind(this, function(latestFile)
+	if (this.ui.getCurrentFile() != this)
 	{
-		try
+		if (error != null)
 		{
-			if (abort == null || !abort())
+			error(e);
+		}
+	}
+	else if (abort == null || !abort())
+	{
+		this.getLatestVersion(mxUtils.bind(this, function(latestFile)
+		{
+			try
 			{
-				if (latestFile != null)
+				if (this.ui.getCurrentFile() != this)
 				{
-					this.mergeFile(latestFile, success, error, shadow);
+					if (error != null)
+					{
+						error(e);
+					}
 				}
-				else
+				else if (abort == null || !abort())
 				{
-					this.reloadFile(success, error);
+					if (this.ui.getCurrentFile() == this)
+					{
+						if (latestFile != null)
+						{
+							this.mergeFile(latestFile, success, error, shadow);
+						}
+						else
+						{
+							this.reloadFile(success, error);
+						}
+					}
+					else if (error != null)
+					{
+						error(e);
+					}
 				}
 			}
-		}
-		catch (e)
-		{
-			if (error != null)
+			catch (e)
 			{
-				error(e);
+				if (error != null)
+				{
+					error(e);
+				}
 			}
-		}
-	}), error);
+		}), error);
+	}
 };
 
 /**
@@ -206,6 +233,8 @@ DrawioFile.prototype.mergeFile = function(file, success, error, diffShadow)
 {
 	try
 	{
+		this.stats.fileMerged++;
+				
 		// Takes copy of current shadow document
 		var shadow = (this.shadowPages != null) ? this.shadowPages :
 			this.ui.getPagesForNode(mxUtils.parseXml(
@@ -248,9 +277,9 @@ DrawioFile.prototype.mergeFile = function(file, success, error, diffShadow)
 				var data = this.compressReportData(this.getAnonymizedXmlForPages(patched));
 				
 				this.checksumError(error, patches,
-					'Checksum: ' + checksum +
-					((patchedDetails != null) ? ('\nDetails: ' +
+					((patchedDetails != null) ? ('Details: ' +
 						JSON.stringify(patchedDetails)) : '') +
+					'\nChecksum: ' + checksum +
 					'\nCurrent: ' + current +
 					((currentDetails != null) ? ('\nCurrent Details: ' +
 						JSON.stringify(currentDetails)) : '') +
@@ -932,6 +961,7 @@ DrawioFile.prototype.getData = function()
  */
 DrawioFile.prototype.open = function()
 {
+	this.stats.opened++;
 	var data = this.getData();
 	
 	if (data != null)
@@ -939,7 +969,12 @@ DrawioFile.prototype.open = function()
 		this.ui.setFileData(data);
 		
 		// Updates shadow in case any page IDs have been updated
-		this.shadowData = mxUtils.getXml(this.ui.getXmlFileData());
+		// only if the file has not been modified and reopened
+		if (!this.isModified())
+		{
+			this.shadowData = mxUtils.getXml(this.ui.getXmlFileData());
+			this.shadowPages = null;
+		}
 	}
 
 	this.installListeners();
@@ -1004,7 +1039,11 @@ DrawioFile.prototype.startSync = function()
 		(urlParams['rt'] == '1' || !this.ui.editor.chromeless ||
 		this.ui.editor.editable))
 	{
-		this.sync = new DrawioFileSync(this);
+		if (this.sync == null)
+		{
+			this.sync = new DrawioFileSync(this);
+		}
+		
 		this.sync.start();
 	}
 };
@@ -1606,6 +1645,7 @@ DrawioFile.prototype.fileSaved = function(savedData, lastDesc, success, error)
 {
 	try
 	{
+		this.stats.fileSaved++;
 		this.inConflictState = false;
 		this.invalidChecksum = false;
 		this.checkPages();
@@ -1639,7 +1679,9 @@ DrawioFile.prototype.fileSaved = function(savedData, lastDesc, success, error)
 
 		try
 		{
-			this.sendErrorReport('Error in fileSaved', null, e);
+			this.sendErrorReport('Error in fileSaved',
+				'SavedData:\n' + this.compressReportData(
+				this.ui.anonymizeString(savedData), 25000), e);
 		}
 		catch (e2)
 		{
@@ -1779,6 +1821,9 @@ DrawioFile.prototype.contentChanged = function()
  */
 DrawioFile.prototype.close = function(unloading)
 {
+	this.updateFileData();
+	this.stats.closed++;
+	
 	if (this.isAutosave() && this.isModified())
 	{
 		this.save(this.isAutosaveRevision(), null, null, unloading);
@@ -1823,6 +1868,8 @@ DrawioFile.prototype.removeListeners = function()
  */
 DrawioFile.prototype.destroy = function()
 {
+	this.stats.destroyed++;
+	
 	try
 	{
 		if (!this.ui.isOffline() && this.reportEnabled &&

+ 136 - 116
src/main/webapp/js/diagramly/DrawioFileSync.js

@@ -60,6 +60,88 @@ DrawioFileSync = function(file)
 		mxEvent.addListener(document, 'touchstart', this.activityListener);
 		mxEvent.addListener(document, 'touchmove', this.activityListener);	
 	}
+
+	// Listens to errors in the pusher API
+	this.pusherErrorListener = mxUtils.bind(this, function(err)
+	{
+		if (err.error != null && err.error.data != null &&
+			err.error.data.code === 4004)
+		{
+			EditorUi.logError('Error: Pusher Limit', null, this.file.getId());
+		}
+	});
+
+    // Listens to connection state changes
+	this.connectionListener = mxUtils.bind(this, function()
+	{
+		this.updateOnlineState();
+		this.updateStatus();
+		
+		if (this.isConnected())
+		{
+			if (!this.announced)
+			{
+				var user = this.file.getCurrentUser();
+				var join = {a: 'join'};
+				
+				if (user != null)
+				{
+					join.name = user.displayName;
+					join.uid = user.id;
+				}
+
+				mxUtils.post(this.cacheUrl, this.getIdParameters() +
+					'&msg=' + encodeURIComponent(this.objectToString(
+					this.createMessage(join))));
+				this.file.stats.msgSent++;
+				this.announced = true;
+			}
+
+			// Catchup on any lost edits
+			this.fileChangedNotify();
+		}
+	});
+	
+	// Listens to remove messages
+	this.changeListener = mxUtils.bind(this, function(data)
+	{
+		this.file.stats.msgReceived++;
+		this.lastActivity = new Date();
+
+		if (this.enabled && !this.file.inConflictState &&
+			!this.redirectDialogShowing)
+		{
+			try
+			{
+				var msg = this.stringToObject(data);
+				
+				if (msg != null)
+				{
+					EditorUi.debug('Sync.message', [this], msg, data.length, 'bytes');
+
+					// Handles protocol mismatch
+					if (msg.v > DrawioFileSync.PROTOCOL)
+					{
+						this.file.redirectToNewApp(mxUtils.bind(this, function()
+						{
+							// Callback adds cancel option
+						}));
+					}
+					else if (msg.v === DrawioFileSync.PROTOCOL && msg.d != null)
+					{
+						this.handleMessageData(msg.d);
+					}
+				}
+			}
+			catch (e)
+			{
+				if (window.console != null && urlParams['test'] == '1')
+				{
+					console.log(e);
+				}
+			}
+		}
+	});
 };
 
 /**
@@ -158,16 +240,10 @@ DrawioFileSync.prototype.start = function()
 			try
 			{
 				// Error listener must be installed before trying to create channel
-				this.pusherErrorListener = mxUtils.bind(this, function(err)
+				if (this.pusher.connection != null)
 				{
-					if (err.error != null && err.error.data != null &&
-						err.error.data.code === 4004)
-					{
-						EditorUi.logError('Error: Pusher Limit', null, this.file.getId());
-					}
-				});
-	
-				this.pusher.connection.bind('error', this.pusherErrorListener);
+					this.pusher.connection.bind('error', this.pusherErrorListener);
+				}
 			}
 			catch (e)
 			{
@@ -463,84 +539,13 @@ DrawioFileSync.prototype.resetUpdateStatusThread = function()
  */
 DrawioFileSync.prototype.installListeners = function()
 {
-	if (this.pusher != null)
+	if (this.pusher != null && this.pusher.connection != null)
 	{
-	    // Listens to remote model changes
-		this.connectionListener = mxUtils.bind(this, function()
-		{
-			this.updateOnlineState();
-			this.updateStatus();
-			
-			if (this.isConnected())
-			{
-				if (!this.announced)
-				{
-					var user = this.file.getCurrentUser();
-					var join = {a: 'join'};
-					
-					if (user != null)
-					{
-						join.name = user.displayName;
-						join.uid = user.id;
-					}
-	
-					mxUtils.post(this.cacheUrl, this.getIdParameters() +
-						'&msg=' + encodeURIComponent(this.objectToString(
-						this.createMessage(join))));
-					this.file.stats.msgSent++;
-					this.announced = true;
-				}
-
-				// Catchup on any lost edits
-				this.fileChangedNotify();
-			}
-		});
-		
 		this.pusher.connection.bind('state_change', this.connectionListener);
 	}
     
 	if (this.channel != null)
     {
-		this.changeListener = mxUtils.bind(this, function(data)
-		{
-			this.file.stats.msgReceived++;
-			this.lastActivity = new Date();
-
-			if (this.enabled && !this.file.inConflictState &&
-				!this.redirectDialogShowing)
-			{
-				try
-				{
-					var msg = this.stringToObject(data);
-					
-					if (msg != null)
-					{
-						EditorUi.debug('Sync.message', [this], msg, data.length, 'bytes');
-
-						// Handles protocol mismatch
-						if (msg.v > DrawioFileSync.PROTOCOL)
-						{
-							this.file.redirectToNewApp(mxUtils.bind(this, function()
-							{
-								// Callback adds cancel option
-							}));
-						}
-						else if (msg.v === DrawioFileSync.PROTOCOL && msg.d != null)
-						{
-							this.handleMessageData(msg.d);
-						}
-					}
-				}
-				catch (e)
-				{
-					if (window.console != null && urlParams['test'] == '1')
-					{
-						console.log(e);
-					}
-				}
-			}
-		});
-		
     	this.channel.bind('changed', this.changeListener);
     }
 };
@@ -619,16 +624,21 @@ DrawioFileSync.prototype.fileChanged = function(success, error, abort)
 {
 	var thread = window.setTimeout(mxUtils.bind(this, function()
 	{
-		if (abort == null || !abort())
+		if (this.ui.getCurrentFile() != this.file ||
+			this.file.sync != this)
+		{
+			if (error != null)
+			{
+				error();
+			}
+		}
+		else if (abort == null || !abort())
 		{
 			this.file.loadPatchDescriptor(mxUtils.bind(this, function(desc)
 			{
-				if (abort == null || !abort())
-				{
-					this.catchup(this.file.getDescriptorEtag(desc),
-						this.file.getDescriptorSecret(desc),
-						success, error, abort);
-				}
+				this.catchup(this.file.getDescriptorEtag(desc),
+					this.file.getDescriptorSecret(desc),
+					success, error, abort);
 			}), error);
 		}
 	}), 0);
@@ -688,7 +698,15 @@ DrawioFileSync.prototype.catchup = function(etag, secret, success, error, abort)
 			success();
 		}
 	}
-	else
+	else if (this.ui.getCurrentFile() != this.file ||
+		this.file.sync != this)
+	{
+		if (error != null)
+		{
+			error();
+		}
+	}
+	else if (abort == null || !abort())
 	{
 		// Cache entry may not have been uploaded to cache before new
 		// etag is visible to client so retry once after cache miss
@@ -698,13 +716,21 @@ DrawioFileSync.prototype.catchup = function(etag, secret, success, error, abort)
 		var doCatchup = mxUtils.bind(this, function()
 		{
 			// Ignores patch if shadow has changed
-			if (current != this.file.getCurrentEtag())
+			if (current == etag)
 			{
 				if (success != null)
 				{
 					success();
 				}
 			}
+			else if (this.ui.getCurrentFile() != this.file ||
+				this.file.sync != this)
+			{
+				if (error != null)
+				{
+					error();
+				}
+			}
 			else if (abort == null || !abort())
 			{
 				mxUtils.get(this.cacheUrl + '?id=' + encodeURIComponent(this.channelId) +
@@ -715,13 +741,21 @@ DrawioFileSync.prototype.catchup = function(etag, secret, success, error, abort)
 					this.file.stats.bytesReceived += req.getText().length;	
 					
 					// Ignores patch if shadow has changed
-					if (current != this.file.getCurrentEtag())
+					if (current == etag)
 					{
 						if (success != null)
 						{
 							success();
 						}
 					}
+					else if (this.ui.getCurrentFile() != this.file ||
+						this.file.sync != this)
+					{
+						if (error != null)
+						{
+							error();
+						}
+					}
 					else if (abort == null || !abort())
 					{
 						var checksum = null;
@@ -847,6 +881,7 @@ DrawioFileSync.prototype.merge = function(patches, checksum, etag, success, erro
 {
 	try
 	{
+		this.file.stats.merged++;
 		this.lastModified = new Date();
 		this.file.shadowPages = (this.file.shadowPages != null) ?
 			this.file.shadowPages : this.ui.getPagesForNode(
@@ -860,8 +895,6 @@ DrawioFileSync.prototype.merge = function(patches, checksum, etag, success, erro
 
 		if (!this.file.ignorePatches(patches))
 		{
-			this.file.stats.merged++;
-			
 			// Patches the shadow document
 			for (var i = 0; i < patches.length; i++)
 			{
@@ -909,6 +942,8 @@ DrawioFileSync.prototype.merge = function(patches, checksum, etag, success, erro
 			}
 			else
 			{
+				this.file.stats.lastMerge = details; 
+				
 				// Patches the current document
 				this.file.patch(patches,
 					(DrawioFile.LAST_WRITE_WINS) ?
@@ -1028,6 +1063,9 @@ DrawioFileSync.prototype.fileSaved = function(pages, lastDesc, success, error)
 			var details = {v: EditorUi.VERSION, t: new Date().toISOString(), ua: navigator.userAgent};
 			var checksum = this.ui.getHashValueForPages(pages, details);
 			var diff = this.ui.diffPages(shadow, pages);
+
+			// Debugging
+			details.lastChecksum = this.ui.getHashValueForPages(shadow);
 			
 			// Data is stored in cache and message is sent to all listeners
 			var etag = this.file.getDescriptorEtag(lastDesc);
@@ -1135,34 +1173,16 @@ DrawioFileSync.prototype.stop = function()
 	{
 		EditorUi.debug('Sync.stop', [this]);
 	
-		if (this.changeListener != null && this.channel != null)
-		{
-			this.channel.unbind('changed', this.changeListener);
-			this.changeListener = null;
-		}
-	
-		if (this.connectionListener != null)
-		{
-			if (this.pusher.connection != null)
-			{
-				this.pusher.connection.unbind('state_change', this.connectionListener);
-			}
-			
-			this.connectionListener = null;
-		}
-	
-		if (this.pusherErrorListener != null)
+		if (this.pusher.connection != null)
 		{
-			if (this.pusher.connection != null)
-			{
-				this.pusher.connection.unbind('error', this.pusherErrorListener);
-			}
-			
-			this.pusherErrorListener = null;
+			this.pusher.connection.unbind('state_change', this.connectionListener);
+			this.pusher.connection.unbind('error', this.pusherErrorListener);
 		}
 	
 		if (this.channel != null) 
 		{
+			this.channel.unbind('changed', this.changeListener);
+			
 			// See https://github.com/pusher/pusher-js/issues/75
 			// this.pusher.unsubscribe(this.channelId);
 			this.channel = null;

+ 2 - 1
src/main/webapp/js/diagramly/Editor.js

@@ -3294,7 +3294,8 @@
 	mxStencilRegistry.libraries['ios7ui'] = [SHAPES_PATH + '/ios7/mxIOS7Ui.js', STENCIL_PATH + '/ios7/misc.xml'];
 	mxStencilRegistry.libraries['android'] = [SHAPES_PATH + '/mxAndroid.js', STENCIL_PATH + '/android/android.xml'];
 	mxStencilRegistry.libraries['electrical/transmission'] = [SHAPES_PATH + '/mxElectrical.js', STENCIL_PATH + '/electrical/transmission.xml'];
-//	mxStencilRegistry.libraries['electrical/logic_gates'] = [SHAPES_PATH + '/mxElectrical.js', STENCIL_PATH + '/electrical/logic_gates.xml'];
+	mxStencilRegistry.libraries['electrical/logic_gates'] = [SHAPES_PATH + '/mxElectrical.js', STENCIL_PATH + '/electrical/logic_gates.xml'];
+	mxStencilRegistry.libraries['electrical/abstract'] = [SHAPES_PATH + '/mxElectrical.js', STENCIL_PATH + '/electrical/abstract.xml'];
 	mxStencilRegistry.libraries['infographic'] = [SHAPES_PATH + '/mxInfographic.js'];
 	mxStencilRegistry.libraries['mockup/buttons'] = [SHAPES_PATH + '/mockup/mxMockupButtons.js'];
 	mxStencilRegistry.libraries['mockup/containers'] = [SHAPES_PATH + '/mockup/mxMockupContainers.js'];

+ 115 - 104
src/main/webapp/js/diagramly/EditorUi.js

@@ -9416,138 +9416,145 @@
 				
 					reader.onload = mxUtils.bind(this, function(e)
 					{
-						var data = e.target.result;
-						var name = file.name;
-						
-						if (name != null && name.length > 0)
+						try
 						{
-							if (!this.useCanvasForExport && /(\.png)$/i.test(name))
-							{
-								name = name.substring(0, name.length - 4) + '.xml';
-							}
+							var data = e.target.result;
+							var name = file.name;
 							
-							var handleResult = mxUtils.bind(this, function(xml)
+							if (name != null && name.length > 0)
 							{
-								var dot = name.lastIndexOf('.');
+								if (!this.useCanvasForExport && /(\.png)$/i.test(name))
+								{
+									name = name.substring(0, name.length - 4) + '.xml';
+								}
 								
-								if (dot >= 0)
+								var handleResult = mxUtils.bind(this, function(xml)
 								{
-									name = name.substring(0, name.lastIndexOf('.')) + '.xml';
+									var dot = name.lastIndexOf('.');
+									
+									if (dot >= 0)
+									{
+										name = name.substring(0, name.lastIndexOf('.')) + '.xml';
+									}
+									else
+									{
+										name = name + '.xml';
+									}
+									
+									if (xml.substring(0, 10) == '<mxlibrary')
+									{
+										// Creates new temporary file if library is dropped in splash screen
+										if (this.getCurrentFile() == null && urlParams['embed'] != '1')
+										{
+											this.openLocalFile(this.emptyDiagramXml, this.defaultFilename, temp);
+										}
+									
+					    				try
+						    			{
+					    					this.loadLibrary(new LocalLibrary(this, xml, name));
+						    			}
+					    				catch (e)
+						    			{
+						    				this.handleError(e, mxResources.get('errorLoadingFile'));
+						    			}
+									}
+									else
+									{
+										this.openLocalFile(xml, name, temp);
+									}
+								});
+								
+								if  (/(\.v(dx|sdx?))($|\?)/i.test(name) || /(\.vs(x|sx?))($|\?)/i.test(name))
+								{
+									this.importVisio(file, mxUtils.bind(this, function(xml)
+									{
+										this.spinner.stop();
+										handleResult(xml);
+									}));
 								}
-								else
+								else if (/(\.*<graphml )/.test(data)) 
 								{
-									name = name + '.xml';
+									this.importGraphML(data, mxUtils.bind(this, function(xml)
+									{
+										this.spinner.stop();
+										handleResult(xml);
+									}));
 								}
-								
-								if (xml.substring(0, 10) == '<mxlibrary')
+								else if (Graph.fileSupport && !this.isOffline() && new XMLHttpRequest().upload &&
+									this.isRemoteFileFormat(data, name))
+								{
+									this.parseFile(file, mxUtils.bind(this, function(xhr)
+									{
+										if (xhr.readyState == 4)
+										{
+											this.spinner.stop();
+											
+											if (xhr.status >= 200 && xhr.status <= 299)
+											{
+												handleResult(xhr.responseText);
+											}
+											else
+											{
+												this.handleError({message: mxResources.get((xhr.status == 413) ?
+				            						'drawingTooLarge' : 'invalidOrMissingFile')},
+				            						mxResources.get('errorLoadingFile'));
+											}
+										}
+									}));
+								}
+								else if (this.isLucidChartData(data))
 								{
+									if (/(\.json)$/i.test(name))
+									{
+										name = name.substring(0, name.length - 5) + '.xml';
+									}
+	
+									// LATER: Add import step that produces cells and use callback
+									this.convertLucidChart(data, mxUtils.bind(this, function(xml)
+									{
+										this.spinner.stop();
+										this.openLocalFile(xml, name, temp);
+									}), mxUtils.bind(this, function(e)
+									{
+										this.spinner.stop();
+										this.handleError(e);
+									}));
+								}
+								else if (e.target.result.substring(0, 10) == '<mxlibrary')
+				    			{
+									this.spinner.stop();
+									
 									// Creates new temporary file if library is dropped in splash screen
 									if (this.getCurrentFile() == null && urlParams['embed'] != '1')
 									{
 										this.openLocalFile(this.emptyDiagramXml, this.defaultFilename, temp);
 									}
-								
+									
 				    				try
 					    			{
-				    					this.loadLibrary(new LocalLibrary(this, xml, name));
+					    				this.loadLibrary(new LocalLibrary(this, e.target.result, file.name));
 					    			}
-				    				catch (e)
+					    			catch (e)
 					    			{
 					    				this.handleError(e, mxResources.get('errorLoadingFile'));
 					    			}
-								}
+				    			}
 								else
 								{
-									this.openLocalFile(xml, name, temp);
-								}
-							});
-							
-							if  (/(\.v(dx|sdx?))($|\?)/i.test(name) || /(\.vs(x|sx?))($|\?)/i.test(name))
-							{
-								this.importVisio(file, mxUtils.bind(this, function(xml)
-								{
-									this.spinner.stop();
-									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))
-							{
-								this.parseFile(file, mxUtils.bind(this, function(xhr)
-								{
-									if (xhr.readyState == 4)
+									if (file.type.substring(0, 9) == 'image/png')
 									{
-										this.spinner.stop();
-										
-										if (xhr.status >= 200 && xhr.status <= 299)
-										{
-											handleResult(xhr.responseText);
-										}
-										else
-										{
-											this.handleError({message: mxResources.get((xhr.status == 413) ?
-			            						'drawingTooLarge' : 'invalidOrMissingFile')},
-			            						mxResources.get('errorLoadingFile'));
-										}
+										data = this.extractGraphModelFromPng(data);
 									}
-								}));
-							}
-							else if (this.isLucidChartData(data))
-							{
-								if (/(\.json)$/i.test(name))
-								{
-									name = name.substring(0, name.length - 5) + '.xml';
-								}
-
-								// LATER: Add import step that produces cells and use callback
-								this.convertLucidChart(data, mxUtils.bind(this, function(xml)
-								{
-									this.spinner.stop();
-									this.openLocalFile(xml, name, temp);
-								}), mxUtils.bind(this, function(e)
-								{
+									
 									this.spinner.stop();
-									this.handleError(e);
-								}));
-							}
-							else if (e.target.result.substring(0, 10) == '<mxlibrary')
-			    			{
-								this.spinner.stop();
-								
-								// Creates new temporary file if library is dropped in splash screen
-								if (this.getCurrentFile() == null && urlParams['embed'] != '1')
-								{
-									this.openLocalFile(this.emptyDiagramXml, this.defaultFilename, temp);
-								}
-								
-			    				try
-				    			{
-				    				this.loadLibrary(new LocalLibrary(this, e.target.result, file.name));
-				    			}
-				    			catch (e)
-				    			{
-				    				this.handleError(e, mxResources.get('errorLoadingFile'));
-				    			}
-			    			}
-							else
-							{
-								if (file.type.substring(0, 9) == 'image/png')
-								{
-									data = this.extractGraphModelFromPng(data);
+									this.openLocalFile(data, name, temp);
 								}
-								
-								this.spinner.stop();
-								this.openLocalFile(data, name, temp);
 							}
 						}
+						catch (e)
+						{
+							this.handleError(e);
+						}
 					});
 					
 					reader.onerror = mxUtils.bind(this, function(e)
@@ -9632,6 +9639,10 @@
 				}));
 			}
 		}
+		else
+		{
+			throw new Error(mxResources.get('notADiagramFile'));
+		}
 	};
 	
 	/**

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

@@ -537,8 +537,8 @@ EditorUi.initMinimalTheme = function()
             menu.addSeparator();
             this.addMenuItems(menu, ['editData'], null, evt);
             menu.addSeparator();
-            this.addSubmenu('view', menu, null, mxResources.get('options'));
             this.addSubmenu('layout', menu);
+            this.addSubmenu('view', menu, null, mxResources.get('options'));
             this.addMenuItems(menu, ['-', 'exitGroup'], null, evt);
         }
         else if (graph.isEnabled())

+ 19 - 15
src/main/webapp/js/diagramly/sidebar/Sidebar-Electrical.js

@@ -66,31 +66,35 @@
 
 		this.addPaletteFunctions('electrical\LogicGates', 'Electrical / Logic Gates', false,
 		[
-			this.createVertexTemplateEntry(mel + 'and;', 100, 60, '', 'AND', null, null, this.getTagsForStencil(gnmel, 'and', dtmel).join(' ')),
-			this.createVertexTemplateEntry(mel + 'buffer;', 100, 60, '', 'Buffer', null, null, this.getTagsForStencil(gnmel, 'buffer', dtmel).join(' ')),
+			this.createVertexTemplateEntry(mel + 'logic_gate;operation=and;', 100, 60, '', 'AND', null, null, this.getTagsForStencil(gnmel, 'and', dtmel).join(' ')),
+			this.createVertexTemplateEntry(mel + 'buffer2;', 100, 60, '', 'Buffer', null, null, this.getTagsForStencil(gnmel, 'buffer', dtmel).join(' ')),
 			this.createVertexTemplateEntry(mel + 'd_type_flip-flop;', 100, 80, '', 'D Type Flip-Flop', null, null, this.getTagsForStencil(gnmel, 'd_type_flip-flop', dtmel).join(' ')),
 			this.createVertexTemplateEntry(mel + 'd_type_flip-flop_with_clear;', 100, 90, '', 'D Type Flip-Flop With Clear', null, null, this.getTagsForStencil(gnmel, 'd_type_flip-flop_with_clear', dtmel).join(' ')),
 			this.createVertexTemplateEntry(mel + 'd_type_rs_flip-flop;', 100, 100, '', 'D Type RS Flip-Flop', null, null, this.getTagsForStencil(gnmel, 'd_type_rs_flip-flop', dtmel).join(' ')),
-			this.createVertexTemplateEntry(mel + 'inverter;', 100, 60, '', 'Inverter', null, null, this.getTagsForStencil(gnmel, 'inverter', dtmel).join(' ')),
+			this.createVertexTemplateEntry(mel + 'buffer2;negating=1;', 100, 60, '', 'Inverter', null, null, this.getTagsForStencil(gnmel, 'inverter', dtmel).join(' ')),
 			this.createVertexTemplateEntry(mel + 'inverting_contact;', 5, 5, '', 'Inverting Contact', null, null, this.getTagsForStencil(gnmel, 'inverting_contact', dtmel).join(' ')),
 			this.createVertexTemplateEntry(mel + 'jk_flip-flop;', 100, 80, '', 'JK Flip-Flop', null, null, this.getTagsForStencil(gnmel, 'jk_flip-flop', dtmel).join(' ')),
 			this.createVertexTemplateEntry(mel + 'jk_flip-flop_with_clear;', 100, 90, '', 'JK Flip-Flop With Clear', null, null, this.getTagsForStencil(gnmel, 'jk_flip-flop_with_clear', dtmel).join(' ')),
 			this.createVertexTemplateEntry(mel + 'jk_flip-flop_with_sr;', 100, 100, '', 'JK Flip-Flop With SR', null, null, this.getTagsForStencil(gnmel, 'jk_flip-flop_with_sr', dtmel).join(' ')),
-			this.createVertexTemplateEntry(mel + 'nand;', 100, 60, '', 'NAND', null, null, this.getTagsForStencil(gnmel, 'nand', dtmel).join(' ')),
-			this.createVertexTemplateEntry(mel + 'nor;', 100, 60, '', 'NOR', null, null, this.getTagsForStencil(gnmel, 'nor', dtmel).join(' ')),
-			this.createVertexTemplateEntry(mel + 'or;', 100, 60, '', 'OR', null, null, this.getTagsForStencil(gnmel, 'or', dtmel).join(' ')),
+			this.createVertexTemplateEntry(mel + 'logic_gate;operation=and;negating=1;', 100, 60, '', 'NAND', null, null, this.getTagsForStencil(gnmel, 'nand not and', dtmel).join(' ')),
+			this.createVertexTemplateEntry(mel + 'logic_gate;operation=or;', 100, 60, '', 'OR', null, null, this.getTagsForStencil(gnmel, 'or', dtmel).join(' ')),
+			this.createVertexTemplateEntry(mel + 'logic_gate;operation=or;negating=1;', 100, 60, '', 'NOR', null, null, this.getTagsForStencil(gnmel, 'nor', dtmel).join(' ')),
 			this.createVertexTemplateEntry(mel + 'rs_latch;', 100, 80, '', 'RS Latch', null, null, this.getTagsForStencil(gnmel, 'rs_latch', dtmel).join(' ')),
 			this.createVertexTemplateEntry(mel + 'synchronous_rs_latch;', 100, 80, '', 'RS Latch (Synchronous)', null, null, this.getTagsForStencil(gnmel, 'synchronous_rs_latch', dtmel).join(' ')),
 			this.createVertexTemplateEntry(mel + 'schmitt_trigger;', 100, 60, '', 'Schmitt Trigger', null, null, this.getTagsForStencil(gnmel, 'schmitt_trigger', dtmel).join(' ')),
 			this.createVertexTemplateEntry(mel + 't_type_flip-flop;', 100, 80, '', 'T Type Flip-Flop', null, null, this.getTagsForStencil(gnmel, 't_type_flip-flop', dtmel).join(' ')),
-			this.createVertexTemplateEntry(mel + 'xnor;', 100, 60, '', 'XNOR', null, null, this.getTagsForStencil(gnmel, 'xnor', dtmel).join(' ')),
-			this.createVertexTemplateEntry(mel + 'xor;', 100, 60, '', 'XOR', null, null, this.getTagsForStencil(gnmel, 'xor', dtmel).join(' ')),
+			this.createVertexTemplateEntry(mel + 'logic_gate;operation=xor;', 100, 60, '', 'XOR', null, null, this.getTagsForStencil(gnmel, 'xor', dtmel).join(' ')),
+			this.createVertexTemplateEntry(mel + 'logic_gate;operation=xor;negating=1;', 100, 60, '', 'XNOR', null, null, this.getTagsForStencil(gnmel, 'xnor', dtmel).join(' ')),
 			this.createVertexTemplateEntry(meiecl + 'and;', 60, 80, '', 'AND (IEC)', null, null, this.getTagsForStencil(gnmeiecl, 'and', dtmeiecl).join(' ')),
 			this.createVertexTemplateEntry(meiecl + 'nand;', 66, 80, '', 'NAND (IEC)', null, null, this.getTagsForStencil(gnmeiecl, 'nand', dtmeiecl).join(' ')),
 			this.createVertexTemplateEntry(meiecl + 'or;', 60, 80, '', 'OR (IEC)', null, null, this.getTagsForStencil(gnmeiecl, 'or', dtmeiecl).join(' ')),
 			this.createVertexTemplateEntry(meiecl + 'nor;', 66, 80, '', 'NOR (IEC)', null, null, this.getTagsForStencil(gnmeiecl, 'nor', dtmeiecl).join(' ')),
 			this.createVertexTemplateEntry(meiecl + 'not;', 66, 80, '', 'NOT (IEC)', null, null, this.getTagsForStencil(gnmeiecl, 'xor', dtmeiecl).join(' ')),
-			this.createVertexTemplateEntry(meiecl + 'xor;', 60, 80, '', 'XOR (IEC)', null, null, this.getTagsForStencil(gnmeiecl, 'xor', dtmeiecl).join(' '))
+			this.createVertexTemplateEntry(meiecl + 'xor;', 60, 80, '', 'XOR (IEC)', null, null, this.getTagsForStencil(gnmeiecl, 'xor', dtmeiecl).join(' ')),
+			this.createVertexTemplateEntry('shadow=0;dashed=0;align=center;fillColor=#ffffff;html=1;strokeWidth=1;shape=mxgraph.electrical.logic_gates.dual_inline_ic;', 
+					100, 200, 'IC', 'Dual In-Line IC', null, null, this.getTagsForStencil(gnmel, 'dual inline in line ic integrated circuit', dtmel).join(' ')),
+			this.createVertexTemplateEntry('shadow=0;dashed=0;align=center;fillColor=#ffffff;html=1;strokeWidth=1;shape=mxgraph.electrical.logic_gates.qfp_ic;', 
+					200, 200, 'IC', 'Quad Flat Package IC', null, null, this.getTagsForStencil(gnmel, 'quad flat package qfp ic integrated circuit', dtmel).join(' '))
 		]);
 
 		this.addPaletteFunctions('electrical\Resistors', 'Electrical / Resistors', false,
@@ -505,12 +509,12 @@
 					100, 90, '', 'Controlled Amplifier', null, null, this.getTagsForStencil(gnmea, 'controlled_amplifier', dtmea).join(' ')),
 			this.createVertexTemplateEntry(mea + 'dac;', 
 					70, 46, '', 'DAC', null, null, this.getTagsForStencil(gnmea, 'dac', dtmea).join(' ')),
-			this.createVertexTemplateEntry(mea + 'mux;',
-					60, 90, '', 'Mux', null, null, this.getTagsForStencil(gnmea, 'mux', dtmea).join(' ')),
-			this.createVertexTemplateEntry(mea + 'demux;', 
-					60, 90, '', 'Demux', null, null, this.getTagsForStencil(gnmea, 'demux', dtmea).join(' ')),
-			this.createVertexTemplateEntry(mea + 'mux-demux;', 
-					60, 90, '', 'Mux-Demux', null, null, this.getTagsForStencil(gnmea, 'mux-demux', dtmea).join(' ')),
+			this.createVertexTemplateEntry(
+					'shadow=0;dashed=0;align=center;fillColor=#ffffff;html=1;strokeWidth=1;shape=mxgraph.electrical.abstract.mux2;',
+					80, 120, 'Mux', 'Mux', null, null, this.getTagsForStencil(gnmea, 'mux', dtmea).join(' ')),
+			this.createVertexTemplateEntry(
+					'shadow=0;dashed=0;align=center;fillColor=#ffffff;html=1;strokeWidth=1;shape=mxgraph.electrical.abstract.mux2;operation=demux;',
+					80, 120, 'Demux', 'Demux', null, null, this.getTagsForStencil(gnmea, 'mux', dtmea).join(' ')),
 			this.createVertexTemplateEntry(mea + 'operational_amp_1;', 
 					98, 90, '', 'Operational Amp', null, null, this.getTagsForStencil(gnmea, 'operational_amp_1', dtmea).join(' ')),
 			this.createVertexTemplateEntry(mea + 'operational_amp_2;', 

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 129 - 128
src/main/webapp/js/embed-static.min.js


+ 19 - 2
src/main/webapp/js/mxgraph/Graph.js

@@ -61,7 +61,7 @@ mxGraphView.prototype.gridColor = '#e0e0e0';
 mxSvgCanvas2D.prototype.foAltText = '[Not supported by viewer]';
 
 // Hook for custom constraints
-mxShape.prototype.getConstraints = function(style)
+mxShape.prototype.getConstraints = function(style, w, h)
 {
 	return null;
 };
@@ -4885,7 +4885,24 @@ if (typeof mxVertexHandler != 'undefined')
 		{
 			if (terminal != null)
 			{
-				var constraints = (terminal.shape != null) ? terminal.shape.getConstraints(terminal.style) : null;
+				var constraints = null;
+				
+				if (terminal.shape != null)
+				{
+					var dir = terminal.shape.direction;
+					var bounds = terminal.shape.bounds;
+					var scale = terminal.shape.scale;
+					var w = bounds.width / scale, h = bounds.height / scale;
+					
+					if (dir == mxConstants.DIRECTION_NORTH || dir == mxConstants.DIRECTION_SOUTH)
+					{
+						var tmp = w;
+						w = h;
+						h = tmp;
+					}
+					
+					constraints = terminal.shape.getConstraints(terminal.style, w, h);
+				}				
 				
 				if (constraints != null)
 				{

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 129 - 128
src/main/webapp/js/reader.min.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 36 - 4
src/main/webapp/js/shapes.min.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1093 - 1089
src/main/webapp/js/viewer.min.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1069 - 0
src/main/webapp/shapes/mxElectrical.js