Bläddra i källkod

10.5.7 release

Gaudenz Alder 6 år sedan
förälder
incheckning
f3565a9b43

+ 5 - 0
ChangeLog

@@ -1,3 +1,8 @@
+26-MAR-2019: 10.5.7
+
+- Adds comments in Confluence cloud viewer
+- Improves Google file not found dialog
+
 25-MAR-2019: 10.5.6
 
 - Adds file ID and mime type in GDriveConnector macro editor

+ 1 - 1
VERSION

@@ -1 +1 @@
-10.5.6
+10.5.7

+ 2 - 0
etc/build/build.xml

@@ -192,6 +192,8 @@
 				<file name="Pages.js" />
 				<file name="Trees.js" />
 				<file name="Minimal.js" />
+				<file name="DrawioComment.js" />
+				<file name="DrawioUser.js" />
 			</sources>
 					
 			<sources dir="${basedir}">

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

@@ -1,7 +1,7 @@
 CACHE MANIFEST
 
 # THIS FILE WAS GENERATED. DO NOT MODIFY!
-# 03/25/2019 08:30 PM
+# 03/25/2019 10:19 PM
 
 app.html
 index.html?offline=1

BIN
src/main/webapp/images/save.png


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 611 - 608
src/main/webapp/js/app.min.js


+ 0 - 821
src/main/webapp/js/diagramly/Dialogs.js

@@ -762,132 +762,6 @@ var SplashDialog = function(editorUi)
 	this.container = div;
 };
 
-/**
- * 
- */
-var ConfirmDialog = function(editorUi, message, okFn, cancelFn, okLabel, cancelLabel, okImg, cancelImg, showRememberOption, imgSrc)
-{
-	var div = document.createElement('div');
-	div.style.textAlign = 'center';
-	
-	var p2 = document.createElement('div');
-	p2.style.padding = '6px';
-	p2.style.overflow = 'auto';
-	p2.style.maxHeight = '44px';
-	p2.style.lineHeight = '1.2em';
-	
-	if (mxClient.IS_QUIRKS)
-	{
-		p2.style.height = '60px';
-	}
-	
-	mxUtils.write(p2, message);
-	div.appendChild(p2);
-	
-	if (imgSrc != null)
-	{
-		var p3 = document.createElement('div');
-		p3.style.padding = '6px 0 6px 0';
-		var img = document.createElement('img');
-		img.setAttribute('src', imgSrc);
-		p3.appendChild(img);
-		div.appendChild(p3);
-	}
-	
-	var btns = document.createElement('div');
-	btns.style.textAlign = 'center';
-	btns.style.whiteSpace = 'nowrap';
-
-	var cb = document.createElement('input');
-	cb.setAttribute('type', 'checkbox');
-
-	var cancelBtn = mxUtils.button(cancelLabel || mxResources.get('cancel'), function()
-	{
-		editorUi.hideDialog();
-		
-		if (cancelFn != null)
-		{
-			cancelFn(cb.checked);
-		}
-	});
-	cancelBtn.className = 'geBtn';
-	
-	if (cancelImg != null)
-	{
-		cancelBtn.innerHTML = cancelImg + '<br>' + cancelBtn.innerHTML;
-		cancelBtn.style.paddingBottom = '8px';
-		cancelBtn.style.paddingTop = '8px';
-		cancelBtn.style.height = 'auto';
-		cancelBtn.style.width = '40%';
-	}
-	
-	if (editorUi.editor.cancelFirst)
-	{
-		btns.appendChild(cancelBtn);
-	}
-	
-	var okBtn = mxUtils.button(okLabel || mxResources.get('ok'), function()
-	{
-		editorUi.hideDialog();
-		
-		if (okFn != null)
-		{
-			okFn(cb.checked);
-		}
-	});
-	btns.appendChild(okBtn);
-	
-	if (okImg != null)
-	{
-		okBtn.innerHTML = okImg + '<br>' + okBtn.innerHTML + '<br>';
-		okBtn.style.paddingBottom = '8px';
-		okBtn.style.paddingTop = '8px';
-		okBtn.style.height = 'auto';
-		okBtn.className = 'geBtn';
-		okBtn.style.width = '40%';
-	}
-	else
-	{
-		okBtn.className = 'geBtn gePrimaryBtn';
-	}
-	
-	if (!editorUi.editor.cancelFirst)
-	{
-		btns.appendChild(cancelBtn);
-	}
-
-	div.appendChild(btns);
-	
-	if (showRememberOption)
-	{
-		btns.style.marginTop = '10px';
-		var p2 = document.createElement('p');
-		p2.style.marginTop = '20px';
-		p2.appendChild(cb);
-		var span = document.createElement('span');
-		mxUtils.write(span, ' ' + mxResources.get('rememberThisSetting'));
-		p2.appendChild(span);
-		div.appendChild(p2);
-		
-		mxEvent.addListener(span, 'click', function(evt)
-		{
-			cb.checked = !cb.checked;
-			mxEvent.consume(evt);
-		});
-	}
-	else
-	{
-		btns.style.marginTop = '12px';
-	}
-
-	this.init = function()
-	{
-		okBtn.focus();
-	};
-	
-	this.container = div;
-};
-
 /**
  * Constructs a new embed dialog
  */
@@ -9624,698 +9498,3 @@ var BtnDialog = function(editorUi, peer, btnLbl, fn)
 	
 	this.container = div;
 };
-
-/**
- * 
- */
-var CommentsWindow = function(editorUi, x, y, w, h)
-{
-	var readOnly = !editorUi.canComment();
-	var canReplyToReplies = editorUi.canReplyToReplies();
-	
-	var div = document.createElement('div');
-	div.className = 'geCommentsWin';
-	div.style.background = (Dialog.backdropColor == 'white') ? 'whiteSmoke' : Dialog.backdropColor;
-
-	var tbarHeight = (!EditorUi.compactUi) ? '30px' : '26px';
-	
-	var listDiv = document.createElement('div');
-	listDiv.className = 'geCommentsList';
-	listDiv.style.backgroundColor = (Dialog.backdropColor == 'white') ? 'whiteSmoke' : Dialog.backdropColor;
-	listDiv.style.bottom = (parseInt(tbarHeight) + 7) + 'px';
-	div.appendChild(listDiv);
-	
-	var noComments = document.createElement('span');
-	noComments.style.cssText = 'display:none;padding-top:10px;text-align:center;';
-	mxUtils.write(noComments, mxResources.get('noCommentsFound'));
-	
-	var selectionComment = null;
-	
-	var ldiv = document.createElement('div');
-	
-	ldiv.className = 'geToolbarContainer geCommentsToolbar';
-	ldiv.style.height = tbarHeight;
-	ldiv.style.padding = (!EditorUi.compactUi) ? '1px' : '4px 0px 3px 0px';
-	ldiv.style.backgroundColor = (Dialog.backdropColor == 'white') ? 'whiteSmoke' : Dialog.backdropColor;
-	
-	if (mxClient.IS_QUIRKS)
-	{
-		ldiv.style.filter = 'none';
-	}
-	
-	var link = document.createElement('a');
-	link.className = 'geButton';
-	
-	if (mxClient.IS_QUIRKS)
-	{
-		link.style.filter = 'none';
-	}
-	
-	function updateNoComments()
-	{
-		var divs = listDiv.getElementsByTagName('div');
-		var visibleCount = 0;
-		
-		for (var i = 0; i < divs.length; i++)
-		{
-			if (divs[i].style.display != 'none' && divs[i].parentNode == listDiv)
-			{
-				visibleCount++;
-			}
-		}
-		
-		noComments.style.display = (visibleCount == 0) ? 'block' : 'none';
-	};
-	
-	function editComment(comment, cdiv, saveCallback, deleteOnCancel)
-	{
-		var commentTxt = cdiv.querySelector('.geCommentTxt');
-		var actionsDiv = cdiv.querySelector('.geCommentActionsList');
-		
-		var textArea = document.createElement('textarea');
-		textArea.className = 'geCommentEditTxtArea';
-		textArea.style.minHeight = commentTxt.offsetHeight + 'px';
-		textArea.value = commentTxt.innerHTML;
-		cdiv.insertBefore(textArea, commentTxt);
-		
-		var btnDiv = document.createElement('div');
-		btnDiv.className = 'geCommentEditBtns';
-		
-		function reset()
-		{
-			cdiv.removeChild(textArea);
-			cdiv.removeChild(btnDiv);
-			actionsDiv.style.display = 'block';
-			commentTxt.style.display = 'block';	
-		};
-		
-		var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
-		{
-			if (deleteOnCancel)
-			{
-				cdiv.parentNode.removeChild(cdiv);
-				updateNoComments();
-			}
-			else
-			{
-				reset();
-			}
-		});
-		
-		cancelBtn.className = 'geCommentEditBtn';
-		btnDiv.appendChild(cancelBtn);
-		
-		var saveBtn = mxUtils.button(mxResources.get('save'), function()
-		{
-			commentTxt.innerHTML = '';
-			comment.content = textArea.value;
-			mxUtils.write(commentTxt, comment.content);
-			reset();
-			saveCallback(comment);
-		});
-		
-		// Updates modified state and handles placeholder text
-		mxEvent.addListener(textArea, 'keydown', mxUtils.bind(this, function(evt)
-		{
-			if (!mxEvent.isConsumed(evt))
-			{
-				if ((mxEvent.isControlDown(evt) || (mxClient.IS_MAC &&
-					mxEvent.isMetaDown(evt))) && evt.keyCode == 13 /* Ctrl+Enter */)
-				{
-					saveBtn.click();
-					mxEvent.consume(evt);
-				}
-				else if (evt.keyCode == 27 /* Escape */)
-				{
-					cancelBtn.click();
-					mxEvent.consume(evt);
-				}
-			}
-		}));
-		
-		// Focused to include in viewport before focusin textbox
-		saveBtn.focus();
-		saveBtn.className = 'geCommentEditBtn gePrimaryBtn';
-		btnDiv.appendChild(saveBtn);
-
-		cdiv.insertBefore(btnDiv, commentTxt);
-		actionsDiv.style.display = 'none';
-		commentTxt.style.display = 'none';
-		textArea.focus();
-	};
-	
-	function writeCommentDate(comment, dateDiv)
-	{
-		dateDiv.innerHTML = '';
-		var str = editorUi.timeSince(new Date(comment.modifiedDate));
-		
-		if (str == null)
-		{
-			str = mxResources.get('lessThanAMinute');
-		}
-		
-		mxUtils.write(dateDiv, mxResources.get('timeAgo', [str], '{1} ago'));	
-	};
-	
-	function showBusy(commentDiv)
-	{
-		var busyImg = document.createElement('img');
-		busyImg.className = 'geCommentBusyImg';
-		busyImg.src= '/images/spin.gif';
-		commentDiv.appendChild(busyImg);
-		commentDiv.busyImg = busyImg;
-	};
-	
-	function showError(commentDiv)
-	{
-		commentDiv.style.border = '1px solid red';
-		commentDiv.removeChild(commentDiv.busyImg);
-	};
-	
-	function showDone(commentDiv)
-	{
-		commentDiv.style.border = '';
-		commentDiv.removeChild(commentDiv.busyImg);
-	};
-
-	function addComment(comment, parentArr, parent, level, showResolved)
-	{
-		//Skip resolved comments if showResolved is not set
-		if (!showResolved && comment.isResolved)
-		{
-			return;
-		}
-
-		noComments.style.display = 'none';
-		
-		var cdiv = document.createElement('div');
-		cdiv.className = 'geCommentContainer';
-		cdiv.setAttribute('data-commentId', comment.id);
-		cdiv.style.marginLeft = (level * 20 + 5) + 'px';
-
-		if (comment.isResolved && uiTheme != 'dark')
-		{
-			cdiv.style.backgroundColor = 'ghostWhite';
-		}
-		
-		var headerDiv = document.createElement('div');
-		headerDiv.className = 'geCommentHeader';
-		
-		var userImg = document.createElement('img');
-		userImg.className = 'geCommentUserImg';
-		userImg.src = comment.user.pictureUrl || Editor.userImage;
-		headerDiv.appendChild(userImg);
-		
-		var headerTxt = document.createElement('div');
-		headerTxt.className = 'geCommentHeaderTxt';
-		headerDiv.appendChild(headerTxt);
-		
-		var usernameDiv = document.createElement('div');
-		usernameDiv.className = 'geCommentUsername';
-		mxUtils.write(usernameDiv, comment.user.displayName || '');
-		headerTxt.appendChild(usernameDiv);
-		
-		var dateDiv = document.createElement('div');
-		dateDiv.className = 'geCommentDate';
-		dateDiv.setAttribute('data-commentId', comment.id);
-		writeCommentDate(comment, dateDiv);
-		headerTxt.appendChild(dateDiv);
-		cdiv.appendChild(headerDiv);
-		
-		var commentTxtDiv = document.createElement('div');
-		commentTxtDiv.className = 'geCommentTxt';
-		mxUtils.write(commentTxtDiv, comment.content || '');
-		cdiv.appendChild(commentTxtDiv);
-		
-		var actionsDiv = document.createElement('div');
-		actionsDiv.className = 'geCommentActions';
-		var actionsList = document.createElement('ul');
-		actionsList.className = 'geCommentActionsList';
-		actionsDiv.appendChild(actionsList);
-		
-		function addAction(name, evtHandler, hide)
-		{
-			var action = document.createElement('li');
-			action.className = 'geCommentAction';
-			var actionLnk = document.createElement('a');
-			actionLnk.className = 'geCommentActionLnk';
-			mxUtils.write(actionLnk, name);
-			action.appendChild(actionLnk);
-			
-			mxEvent.addListener(actionLnk, 'click', function(evt)
-			{
-				evtHandler(evt, comment);
-				evt.preventDefault();
-				mxEvent.consume(evt);
-			});
-			
-			actionsList.appendChild(action);
-			
-			if (hide) action.style.display = 'none';
-		};
-		
-		function collectReplies()
-		{
-			var replies = [];
-			var pdiv = cdiv;
-			
-			function collectReplies(comment) 
-			{
-				replies.push(pdiv);
-				
-				if (comment.replies != null)
-				{
-					for (var i = 0; i < comment.replies.length; i++) 
-					{
-						pdiv = pdiv.nextSibling;
-						collectReplies(comment.replies[i]); 
-					}
-				}	
-			}
-			
-			collectReplies(comment);
-			
-			return {pdiv: pdiv, replies: replies};
-		};
-		
-		function addReply(initContent, editIt, saveCallback, doResolve, doReopen)
-		{
-			var pdiv = collectReplies().pdiv;
-			
-			var newReply = editorUi.newComment(initContent, editorUi.getCurrentUser());
-			newReply.pCommentId = comment.id;
-			
-			if (comment.replies == null) comment.replies = [];
-			
-			var replyComment = addComment(newReply, comment.replies, pdiv, level + 1);
-
-			function doAddReply()
-			{
-				showBusy(replyComment);
-				
-				comment.addReply(newReply, function(id)
-				{
-					newReply.id = id;
-					comment.replies.push(newReply);
-					showDone(replyComment);
-					
-					if (saveCallback) saveCallback();
-					
-				}, function(err)
-				{
-					doEdit();
-					showError(replyComment);
-					editorUi.handleError(err, null, null, null,
-						mxUtils.htmlEntities(mxResources.get('objectNotFound')));
-				}, doResolve, doReopen);				
-			};
-			
-			function doEdit()
-			{
-				editComment(newReply, replyComment, function(newReply)
-				{
-					doAddReply();
-				}, true);
-			};
-
-			if (editIt)
-			{
-				doEdit();
-			}
-			else
-			{
-				doAddReply();
-			}
-		};
-		
-		if (!readOnly && (level == 0 || canReplyToReplies))
-		{
-			addAction(mxResources.get('reply'), function()
-			{
-				addReply('', true);
-			}, comment.isResolved);
-		}
-		
-		var user = editorUi.getCurrentUser();
-		
-		if (user != null && user.id == comment.user.id && !readOnly)
-		{
-			addAction(mxResources.get('edit'), function()
-			{
-				function doEditComment()
-				{
-					editComment(comment, cdiv, function()
-					{
-						showBusy(cdiv);
-						
-						comment.editComment(comment.content, function()
-						{
-							showDone(cdiv);
-						}, function(err)
-						{
-							showError(cdiv);
-							doEditComment();
-							editorUi.handleError(err, null, null, null,
-								mxUtils.htmlEntities(mxResources.get('objectNotFound')));
-						});
-					});
-				};
-				
-				doEditComment();
-			}, comment.isResolved);
-			
-			addAction(mxResources.get('delete'), function()
-			{
-				editorUi.confirm(mxResources.get('areYouSure'), function()
-				{
-					showBusy(cdiv);
-					
-					comment.deleteComment(function()
-					{
-						var replies = collectReplies(comment).replies;
-						
-						for (var i = 0; i < replies.length; i++)
-						{
-							listDiv.removeChild(replies[i]);
-						}
-						
-						for (var i = 0; i < parentArr.length; i++)
-						{
-							if (parentArr[i] == comment) 
-							{
-								parentArr.splice(i, 1);
-								break;
-							}
-						}
-						
-						noComments.style.display = (listDiv.getElementsByTagName('div').length == 0) ? 'block' : 'none';
-					}, function(err)
-					{
-						showError(cdiv);
-						editorUi.handleError(err, null, null, null,
-							mxUtils.htmlEntities(mxResources.get('objectNotFound')));
-					});
-				});
-			}, comment.isResolved);
-		}
-		
-		if (!readOnly && level == 0) //Resolve is a top-level action only
-		{
-			function toggleResolve(evt)
-			{
-				function doToggle()
-				{
-					var resolveActionLnk = evt.target;
-					resolveActionLnk.innerHTML = '';
-
-					comment.isResolved = !comment.isResolved;
-					mxUtils.write(resolveActionLnk, comment.isResolved? mxResources.get('reopen') : mxResources.get('resolve'));
-					var actionsDisplay = comment.isResolved? 'none' : '';
-					var replies = collectReplies(comment).replies;
-
-					
-					var color = (uiTheme == 'dark') ? 'transparent' : (comment.isResolved? 'ghostWhite' : 'white');
-					
-					for (var i = 0; i < replies.length; i++)
-					{
-						replies[i].style.backgroundColor = color;
-						
-						var forOpenActions = replies[i].querySelectorAll('.geCommentAction');
-						
-						for (var j = 0; j < forOpenActions.length; j ++) 
-						{
-							if (forOpenActions[j] == resolveActionLnk.parentNode) continue;
-							
-							forOpenActions[j].style.display = actionsDisplay;
-						}
-
-						if (!resolvedChecked)
-						{
-							replies[i].style.display = 'none';
-						}
-					}
-					
-					updateNoComments();
-				};
-				
-				if (comment.isResolved)
-				{
-					addReply(mxResources.get('reOpened') + ': ', true, doToggle, false, true);
-				}
-				else
-				{
-					addReply(mxResources.get('markedAsResolved'), false, doToggle, true);
-				}
-			};
-			
-			addAction(comment.isResolved? mxResources.get('reopen') : mxResources.get('resolve'), toggleResolve);
-		}
-		
-		cdiv.appendChild(actionsDiv);
-		
-		if (parent != null) 
-		{
-			listDiv.insertBefore(cdiv, parent.nextSibling);
-		}
-		else
-		{
-			listDiv.appendChild(cdiv);
-		}
-		
-		for (var i = 0; comment.replies != null && i < comment.replies.length; i++)
-		{
-			var reply = comment.replies[i];
-			reply.isResolved = comment.isResolved; //copy isResolved to child comments (replies)
-			addComment(reply, comment.replies, null, level + 1, showResolved);
-		}
-		
-		return cdiv;
-	};
-
-	if (!readOnly)
-	{
-		var addLink = link.cloneNode();
-		addLink.innerHTML = '<div class="geSprite geSprite-plus" style="display:inline-block;"></div>';
-		addLink.setAttribute('title', mxResources.get('create') + '...');
-		
-		mxEvent.addListener(addLink, 'click', function(evt)
-		{
-			var newComment = editorUi.newComment('', editorUi.getCurrentUser());
-			var newCommentDiv = addComment(newComment, comments, null, 0);
-			
-			function doAddComment()
-			{
-				editComment(newComment, newCommentDiv, function(newComment)
-				{
-					showBusy(newCommentDiv);
-					
-					editorUi.addComment(newComment, function(id)
-					{
-						newComment.id = id;
-						comments.push(newComment);
-						showDone(newCommentDiv);
-					}, function(err)
-					{
-						showError(newCommentDiv);
-						doAddComment();
-						editorUi.handleError(err, null, null, null,
-							mxUtils.htmlEntities(mxResources.get('objectNotFound')));
-					});
-				}, true);
-			}
-			
-			doAddComment();
-			evt.preventDefault();
-			mxEvent.consume(evt);
-		});
-		
-		ldiv.appendChild(addLink);
-	}
-
-	var resolvedLink = link.cloneNode();
-	resolvedLink.innerHTML = '<img src="/images/check.png" style="width: 16px; padding: 2px;">';
-	resolvedLink.setAttribute('title', mxResources.get('showResolved'));
-	var resolvedChecked = false;
-	
-	if (uiTheme == 'dark')
-	{
-		resolvedLink.style.filter = 'invert(100%)';
-	}
-	
-	mxEvent.addListener(resolvedLink, 'click', function(evt)
-	{
-		resolvedChecked = !resolvedChecked;
-		
-		this.className = resolvedChecked? 'geButton geCheckedBtn' : 'geButton';
-		refresh();
-		
-		evt.preventDefault();
-		mxEvent.consume(evt);
-	});
-	
-	ldiv.appendChild(resolvedLink);
-	
-	var refreshLink = link.cloneNode();
-	refreshLink.innerHTML = '<img src="/images/update16.png" style="width: 16px; padding: 2px;">';
-	refreshLink.setAttribute('title', mxResources.get('refresh'));
-
-	if (uiTheme == 'dark')
-	{
-		refreshLink.style.filter = 'invert(100%)';
-	}
-	
-	mxEvent.addListener(refreshLink, 'click', function(evt)
-	{
-		refresh();
-		
-		evt.preventDefault();
-		mxEvent.consume(evt);
-	});
-	
-	ldiv.appendChild(refreshLink);
-
-	div.appendChild(ldiv);	
-
-	var comments = [];
-
-	var refresh = mxUtils.bind(this, function()
-	{
-		listDiv.innerHTML = '<div style="padding-top:10px;text-align:center;"><img src="/images/spin.gif" valign="middle"> ' +
-			mxUtils.htmlEntities(mxResources.get('loading')) + '...</div>';
-		
-		canReplyToReplies = editorUi.canReplyToReplies();
-		
-		if (editorUi.commentsSupported())
-		{
-			editorUi.getComments(function(list)
-			{
-				function sortReplies(replies)
-				{
-					if (replies != null)
-					{
-						//Sort replies old to new
-						replies.sort(function(r1, r2)
-						{
-							return new Date(r1.modifiedDate) - new Date(r2.modifiedDate);
-						});
-						
-						for (var i = 0; i < replies.length; i++)
-						{
-							sortReplies(replies[i].replies);
-						}						
-					}
-				};
-				
-				//Sort comments old to new
-				list.sort(function(c1, c2)
-				{
-					return new Date(c1.modifiedDate) - new Date(c2.modifiedDate);
-				});
-
-				listDiv.innerHTML = '';
-				listDiv.appendChild(noComments);
-				noComments.style.display = 'block';
-				comments = list;
-				
-				for (var i = 0; i < comments.length; i++)
-				{
-					sortReplies(comments[i].replies);
-					addComment(comments[i], comments, null, 0, resolvedChecked);
-				}
-			}, function()
-			{
-				listDiv.innerHTML = mxUtils.htmlEntities(mxResources.get('error'));
-			});
-		}
-		else
-		{
-			//TODO if comments are not supported, close the dialog
-			listDiv.innerHTML = mxUtils.htmlEntities(mxResources.get('error'));
-		}
-	});
-
-	refresh();
-	
-	this.refreshComments = refresh;
-
-	//Refresh the modified date of each comment if the window is visible
-	var refreshCommentsTime = mxUtils.bind(this, function()
-	{
-		if (!this.window.isVisible()) return; //only update if it is visible
-		
-		var modDateDivs = listDiv.querySelectorAll('.geCommentDate');
-		var modDateDivsMap = {};
-		
-		for (var i = 0; i < modDateDivs.length; i++)
-		{
-			var div = modDateDivs[i];
-			modDateDivsMap[div.getAttribute('data-commentId')] = div;
-		}
-		
-		function processComment(comment) 
-		{
-			var div = modDateDivsMap[comment.id];
-			
-			if (div == null) return; //resolved comments
-			
-			writeCommentDate(comment, div);
-			
-			for (var i = 0; comment.replies != null && i < comment.replies.length; i++)
-			{
-				processComment(comment.replies[i]);
-			}
-		};
-		
-		for (var i = 0; i < comments.length; i++)
-		{
-			processComment(comments[i]);
-		}
-	});
-
-	//Periodically refresh time every one minute
-	setInterval(refreshCommentsTime, 60000);
-	this.refreshCommentsTime = refreshCommentsTime;
-	
-	this.window = new mxWindow(mxResources.get('comments'), div, x, y, w, h, true, true);
-	this.window.minimumSize = new mxRectangle(0, 0, 300, 200);
-	this.window.destroyOnClose = false;
-	this.window.setMaximizable(false);
-	this.window.setResizable(true);
-	this.window.setClosable(true);
-	this.window.setVisible(true);
-	
-	this.window.addListener(mxEvent.SHOW, mxUtils.bind(this, function()
-	{
-		this.window.fit();
-	}));
-	
-	this.window.setLocation = function(x, y)
-	{
-		var iw = window.innerWidth || document.body.clientWidth || document.documentElement.clientWidth;
-		var ih = window.innerHeight || document.body.clientHeight || document.documentElement.clientHeight;
-		
-		x = Math.max(0, Math.min(x, iw - this.table.clientWidth));
-		y = Math.max(0, Math.min(y, ih - this.table.clientHeight - 48));
-
-		if (this.getX() != x || this.getY() != y)
-		{
-			mxWindow.prototype.setLocation.apply(this, arguments);
-		}
-	};
-	
-	var resizeListener = mxUtils.bind(this, function()
-	{
-		var x = this.window.getX();
-		var y = this.window.getY();
-		
-		this.window.setLocation(x, y);
-	});
-	
-	mxEvent.addListener(window, 'resize', resizeListener);
-
-	this.destroy = function()
-	{
-		mxEvent.removeListener(window, 'resize', resizeListener);
-		this.window.destroy();
-	}
-};

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

@@ -2035,6 +2035,22 @@ DrawioFile.prototype.commentsSupported = function()
 	return false; //The default is false and files that support it must explicitly state that
 };
 
+/**
+ * Show refresh button?
+ */
+DrawioFile.prototype.commentsRefreshNeeded = function()
+{
+	return true;
+};
+
+/**
+ * Show save button?
+ */
+DrawioFile.prototype.commentsSaveNeeded = function()
+{
+	return false;
+};
+
 /**
  * Get comments of the file
  */

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 5 - 0
src/main/webapp/js/diagramly/Editor.js


+ 895 - 10
src/main/webapp/js/diagramly/EditorUi.js

@@ -3567,25 +3567,44 @@
 					else
 					{
 						msg = (notFoundMessage != null) ? notFoundMessage :
-							mxUtils.htmlEntities(mxResources.get('fileNotFoundOrDenied'));
+							mxUtils.htmlEntities(mxResources.get('fileNotFoundOrDenied') +
+							((this.drive != null && this.drive.user != null) ? ' (' + this.drive.user.displayName +
+							', ' + this.drive.user.email+ ')' : ''));
 					}
 					
 					var id = window.location.hash;
 					
-					if (id != null && id.substring(0, 2) == '#G' && resp != null && resp.error != null &&
-						((resp.error.errors != null && resp.error.errors.length > 0 &&
-						resp.error.errors[0].reason == 'fileAccess') ||
+					// #U handles case where we tried to fallback to Google File and
+					// hash property still shows the public URL we tried to load
+					if (id != null && (id.substring(0, 2) == '#G' ||
+						id.substring(0, 45) == '#Uhttps%3A%2F%2Fdrive.google.com%2Fuc%3Fid%3D') &&
+						((resp != null && resp.error != null && ((resp.error.errors != null &&
+						resp.error.errors.length > 0 && resp.error.errors[0].reason == 'fileAccess') ||
 						(resp.error.data != null && resp.error.data.length > 0 &&
-						resp.error.data[0].reason == 'fileAccess')))
+						resp.error.data[0].reason == 'fileAccess'))) ||
+						e.code == 404 || e.status == 404))
 					{
-						id = id.substring(2);
+						id = (id.substring(0, 2) == '#U') ? id.substring(45, id.lastIndexOf('%26ex')) : id.substring(2);
 						
 						// Special case where the button must have a different label and function
-						this.showError(title, msg, mxResources.get('cancel'), null, retry,
-							mxResources.get('tryOpeningViaThisPage'), mxUtils.bind(this, function()
+						this.showError(title, msg, mxResources.get('openInNewWindow'), mxUtils.bind(this, function()
+						{
+							this.editor.graph.openLink('https://drive.google.com/open?id=' + id);
+							this.handleError(resp, title, fn, invokeFnOnClose, notFoundMessage)
+						}), retry, mxResources.get('changeUser'), mxUtils.bind(this, function()
+						{
+							if (this.spinner.spin(document.body, mxResources.get('loading')))
 							{
-								this.editor.graph.openLink('https://drive.google.com/open?id=' + id);
-							}), null, null, 380);
+								this.drive.clearUserId();
+								gapi.auth.signOut();
+								
+								// Reload page to reset client auth
+								window.location.reload();
+							}
+						}), mxResources.get('cancel'), mxUtils.bind(this, function()
+						{
+							window.location.hash = '';
+						}), 480, 150);
 								
 						return;
 					}
@@ -12073,6 +12092,26 @@
 		return file != null? file.commentsSupported() : false;
 	};
 
+	/**
+	 * Show refresh button?
+	 */
+	EditorUi.prototype.commentsRefreshNeeded = function()
+	{
+		var file = this.getCurrentFile();
+		
+		return file != null? file.commentsRefreshNeeded() : true;
+	};
+	
+	/**
+	 * Show save button?
+	 */
+	EditorUi.prototype.commentsSaveNeeded = function()
+	{
+		var file = this.getCurrentFile();
+
+		return file != null? file.commentsSaveNeeded() : false;
+	};
+	
 	/**
 	 * Get comments
 	 */
@@ -12144,3 +12183,849 @@
 		}
 	};
 })();
+
+/**
+ * Comments Window, It is used by both editor and viewer. So, it is here in a common place
+ */
+var CommentsWindow = function(editorUi, x, y, w, h, saveCallback)
+{
+	var readOnly = !editorUi.canComment();
+	var canReplyToReplies = editorUi.canReplyToReplies();
+	
+	var div = document.createElement('div');
+	div.className = 'geCommentsWin';
+	div.style.background = (Dialog.backdropColor == 'white') ? 'whiteSmoke' : Dialog.backdropColor;
+
+	var tbarHeight = (!EditorUi.compactUi) ? '30px' : '26px';
+	
+	var listDiv = document.createElement('div');
+	listDiv.className = 'geCommentsList';
+	listDiv.style.backgroundColor = (Dialog.backdropColor == 'white') ? 'whiteSmoke' : Dialog.backdropColor;
+	listDiv.style.bottom = (parseInt(tbarHeight) + 7) + 'px';
+	div.appendChild(listDiv);
+	
+	var noComments = document.createElement('span');
+	noComments.style.cssText = 'display:none;padding-top:10px;text-align:center;';
+	mxUtils.write(noComments, mxResources.get('noCommentsFound'));
+	
+	var selectionComment = null;
+	
+	var ldiv = document.createElement('div');
+	
+	ldiv.className = 'geToolbarContainer geCommentsToolbar';
+	ldiv.style.height = tbarHeight;
+	ldiv.style.padding = (!EditorUi.compactUi) ? '1px' : '4px 0px 3px 0px';
+	ldiv.style.backgroundColor = (Dialog.backdropColor == 'white') ? 'whiteSmoke' : Dialog.backdropColor;
+	
+	if (mxClient.IS_QUIRKS)
+	{
+		ldiv.style.filter = 'none';
+	}
+	
+	var link = document.createElement('a');
+	link.className = 'geButton';
+	
+	if (mxClient.IS_QUIRKS)
+	{
+		link.style.filter = 'none';
+	}
+	
+	function updateNoComments()
+	{
+		var divs = listDiv.getElementsByTagName('div');
+		var visibleCount = 0;
+		
+		for (var i = 0; i < divs.length; i++)
+		{
+			if (divs[i].style.display != 'none' && divs[i].parentNode == listDiv)
+			{
+				visibleCount++;
+			}
+		}
+		
+		noComments.style.display = (visibleCount == 0) ? 'block' : 'none';
+	};
+	
+	function editComment(comment, cdiv, saveCallback, deleteOnCancel)
+	{
+		var commentTxt = cdiv.querySelector('.geCommentTxt');
+		var actionsDiv = cdiv.querySelector('.geCommentActionsList');
+		
+		var textArea = document.createElement('textarea');
+		textArea.className = 'geCommentEditTxtArea';
+		textArea.style.minHeight = commentTxt.offsetHeight + 'px';
+		textArea.value = commentTxt.innerHTML;
+		cdiv.insertBefore(textArea, commentTxt);
+		
+		var btnDiv = document.createElement('div');
+		btnDiv.className = 'geCommentEditBtns';
+		
+		function reset()
+		{
+			cdiv.removeChild(textArea);
+			cdiv.removeChild(btnDiv);
+			actionsDiv.style.display = 'block';
+			commentTxt.style.display = 'block';	
+		};
+		
+		var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
+		{
+			if (deleteOnCancel)
+			{
+				cdiv.parentNode.removeChild(cdiv);
+				updateNoComments();
+			}
+			else
+			{
+				reset();
+			}
+		});
+		
+		cancelBtn.className = 'geCommentEditBtn';
+		btnDiv.appendChild(cancelBtn);
+		
+		var saveBtn = mxUtils.button(mxResources.get('save'), function()
+		{
+			commentTxt.innerHTML = '';
+			comment.content = textArea.value;
+			mxUtils.write(commentTxt, comment.content);
+			reset();
+			saveCallback(comment);
+		});
+		
+		// Updates modified state and handles placeholder text
+		mxEvent.addListener(textArea, 'keydown', mxUtils.bind(this, function(evt)
+		{
+			if (!mxEvent.isConsumed(evt))
+			{
+				if ((mxEvent.isControlDown(evt) || (mxClient.IS_MAC &&
+					mxEvent.isMetaDown(evt))) && evt.keyCode == 13 /* Ctrl+Enter */)
+				{
+					saveBtn.click();
+					mxEvent.consume(evt);
+				}
+				else if (evt.keyCode == 27 /* Escape */)
+				{
+					cancelBtn.click();
+					mxEvent.consume(evt);
+				}
+			}
+		}));
+		
+		// Focused to include in viewport before focusin textbox
+		saveBtn.focus();
+		saveBtn.className = 'geCommentEditBtn gePrimaryBtn';
+		btnDiv.appendChild(saveBtn);
+
+		cdiv.insertBefore(btnDiv, commentTxt);
+		actionsDiv.style.display = 'none';
+		commentTxt.style.display = 'none';
+		textArea.focus();
+	};
+	
+	function writeCommentDate(comment, dateDiv)
+	{
+		dateDiv.innerHTML = '';
+		var str = editorUi.timeSince(new Date(comment.modifiedDate));
+		
+		if (str == null)
+		{
+			str = mxResources.get('lessThanAMinute');
+		}
+		
+		mxUtils.write(dateDiv, mxResources.get('timeAgo', [str], '{1} ago'));	
+	};
+	
+	function showBusy(commentDiv)
+	{
+		var busyImg = document.createElement('img');
+		busyImg.className = 'geCommentBusyImg';
+		busyImg.src= '/images/spin.gif';
+		commentDiv.appendChild(busyImg);
+		commentDiv.busyImg = busyImg;
+	};
+	
+	function showError(commentDiv)
+	{
+		commentDiv.style.border = '1px solid red';
+		commentDiv.removeChild(commentDiv.busyImg);
+	};
+	
+	function showDone(commentDiv)
+	{
+		commentDiv.style.border = '';
+		commentDiv.removeChild(commentDiv.busyImg);
+	};
+
+	function addComment(comment, parentArr, parent, level, showResolved)
+	{
+		//Skip resolved comments if showResolved is not set
+		if (!showResolved && comment.isResolved)
+		{
+			return;
+		}
+
+		noComments.style.display = 'none';
+		
+		var cdiv = document.createElement('div');
+		cdiv.className = 'geCommentContainer';
+		cdiv.setAttribute('data-commentId', comment.id);
+		cdiv.style.marginLeft = (level * 20 + 5) + 'px';
+
+		if (comment.isResolved && uiTheme != 'dark')
+		{
+			cdiv.style.backgroundColor = 'ghostWhite';
+		}
+		
+		var headerDiv = document.createElement('div');
+		headerDiv.className = 'geCommentHeader';
+		
+		var userImg = document.createElement('img');
+		userImg.className = 'geCommentUserImg';
+		userImg.src = comment.user.pictureUrl || Editor.userImage;
+		headerDiv.appendChild(userImg);
+		
+		var headerTxt = document.createElement('div');
+		headerTxt.className = 'geCommentHeaderTxt';
+		headerDiv.appendChild(headerTxt);
+		
+		var usernameDiv = document.createElement('div');
+		usernameDiv.className = 'geCommentUsername';
+		mxUtils.write(usernameDiv, comment.user.displayName || '');
+		headerTxt.appendChild(usernameDiv);
+		
+		var dateDiv = document.createElement('div');
+		dateDiv.className = 'geCommentDate';
+		dateDiv.setAttribute('data-commentId', comment.id);
+		writeCommentDate(comment, dateDiv);
+		headerTxt.appendChild(dateDiv);
+		cdiv.appendChild(headerDiv);
+		
+		var commentTxtDiv = document.createElement('div');
+		commentTxtDiv.className = 'geCommentTxt';
+		mxUtils.write(commentTxtDiv, comment.content || '');
+		cdiv.appendChild(commentTxtDiv);
+		
+		var actionsDiv = document.createElement('div');
+		actionsDiv.className = 'geCommentActions';
+		var actionsList = document.createElement('ul');
+		actionsList.className = 'geCommentActionsList';
+		actionsDiv.appendChild(actionsList);
+		
+		function addAction(name, evtHandler, hide)
+		{
+			var action = document.createElement('li');
+			action.className = 'geCommentAction';
+			var actionLnk = document.createElement('a');
+			actionLnk.className = 'geCommentActionLnk';
+			mxUtils.write(actionLnk, name);
+			action.appendChild(actionLnk);
+			
+			mxEvent.addListener(actionLnk, 'click', function(evt)
+			{
+				evtHandler(evt, comment);
+				evt.preventDefault();
+				mxEvent.consume(evt);
+			});
+			
+			actionsList.appendChild(action);
+			
+			if (hide) action.style.display = 'none';
+		};
+		
+		function collectReplies()
+		{
+			var replies = [];
+			var pdiv = cdiv;
+			
+			function collectReplies(comment) 
+			{
+				replies.push(pdiv);
+				
+				if (comment.replies != null)
+				{
+					for (var i = 0; i < comment.replies.length; i++) 
+					{
+						pdiv = pdiv.nextSibling;
+						collectReplies(comment.replies[i]); 
+					}
+				}	
+			}
+			
+			collectReplies(comment);
+			
+			return {pdiv: pdiv, replies: replies};
+		};
+		
+		function addReply(initContent, editIt, saveCallback, doResolve, doReopen)
+		{
+			var pdiv = collectReplies().pdiv;
+			
+			var newReply = editorUi.newComment(initContent, editorUi.getCurrentUser());
+			newReply.pCommentId = comment.id;
+			
+			if (comment.replies == null) comment.replies = [];
+			
+			var replyComment = addComment(newReply, comment.replies, pdiv, level + 1);
+
+			function doAddReply()
+			{
+				showBusy(replyComment);
+				
+				comment.addReply(newReply, function(id)
+				{
+					newReply.id = id;
+					comment.replies.push(newReply);
+					showDone(replyComment);
+					
+					if (saveCallback) saveCallback();
+					
+				}, function(err)
+				{
+					doEdit();
+					showError(replyComment);
+					editorUi.handleError(err, null, null, null,
+						mxUtils.htmlEntities(mxResources.get('objectNotFound')));
+				}, doResolve, doReopen);				
+			};
+			
+			function doEdit()
+			{
+				editComment(newReply, replyComment, function(newReply)
+				{
+					doAddReply();
+				}, true);
+			};
+
+			if (editIt)
+			{
+				doEdit();
+			}
+			else
+			{
+				doAddReply();
+			}
+		};
+		
+		if (!readOnly && (level == 0 || canReplyToReplies))
+		{
+			addAction(mxResources.get('reply'), function()
+			{
+				addReply('', true);
+			}, comment.isResolved);
+		}
+		
+		var user = editorUi.getCurrentUser();
+		
+		if (user != null && user.id == comment.user.id && !readOnly)
+		{
+			addAction(mxResources.get('edit'), function()
+			{
+				function doEditComment()
+				{
+					editComment(comment, cdiv, function()
+					{
+						showBusy(cdiv);
+						
+						comment.editComment(comment.content, function()
+						{
+							showDone(cdiv);
+						}, function(err)
+						{
+							showError(cdiv);
+							doEditComment();
+							editorUi.handleError(err, null, null, null,
+								mxUtils.htmlEntities(mxResources.get('objectNotFound')));
+						});
+					});
+				};
+				
+				doEditComment();
+			}, comment.isResolved);
+			
+			addAction(mxResources.get('delete'), function()
+			{
+				editorUi.confirm(mxResources.get('areYouSure'), function()
+				{
+					showBusy(cdiv);
+					
+					comment.deleteComment(function()
+					{
+						var replies = collectReplies(comment).replies;
+						
+						for (var i = 0; i < replies.length; i++)
+						{
+							listDiv.removeChild(replies[i]);
+						}
+						
+						for (var i = 0; i < parentArr.length; i++)
+						{
+							if (parentArr[i] == comment) 
+							{
+								parentArr.splice(i, 1);
+								break;
+							}
+						}
+						
+						noComments.style.display = (listDiv.getElementsByTagName('div').length == 0) ? 'block' : 'none';
+					}, function(err)
+					{
+						showError(cdiv);
+						editorUi.handleError(err, null, null, null,
+							mxUtils.htmlEntities(mxResources.get('objectNotFound')));
+					});
+				});
+			}, comment.isResolved);
+		}
+		
+		if (!readOnly && level == 0) //Resolve is a top-level action only
+		{
+			function toggleResolve(evt)
+			{
+				function doToggle()
+				{
+					var resolveActionLnk = evt.target;
+					resolveActionLnk.innerHTML = '';
+
+					comment.isResolved = !comment.isResolved;
+					mxUtils.write(resolveActionLnk, comment.isResolved? mxResources.get('reopen') : mxResources.get('resolve'));
+					var actionsDisplay = comment.isResolved? 'none' : '';
+					var replies = collectReplies(comment).replies;
+
+					
+					var color = (uiTheme == 'dark') ? 'transparent' : (comment.isResolved? 'ghostWhite' : 'white');
+					
+					for (var i = 0; i < replies.length; i++)
+					{
+						replies[i].style.backgroundColor = color;
+						
+						var forOpenActions = replies[i].querySelectorAll('.geCommentAction');
+						
+						for (var j = 0; j < forOpenActions.length; j ++) 
+						{
+							if (forOpenActions[j] == resolveActionLnk.parentNode) continue;
+							
+							forOpenActions[j].style.display = actionsDisplay;
+						}
+
+						if (!resolvedChecked)
+						{
+							replies[i].style.display = 'none';
+						}
+					}
+					
+					updateNoComments();
+				};
+				
+				if (comment.isResolved)
+				{
+					addReply(mxResources.get('reOpened') + ': ', true, doToggle, false, true);
+				}
+				else
+				{
+					addReply(mxResources.get('markedAsResolved'), false, doToggle, true);
+				}
+			};
+			
+			addAction(comment.isResolved? mxResources.get('reopen') : mxResources.get('resolve'), toggleResolve);
+		}
+		
+		cdiv.appendChild(actionsDiv);
+		
+		if (parent != null) 
+		{
+			listDiv.insertBefore(cdiv, parent.nextSibling);
+		}
+		else
+		{
+			listDiv.appendChild(cdiv);
+		}
+		
+		for (var i = 0; comment.replies != null && i < comment.replies.length; i++)
+		{
+			var reply = comment.replies[i];
+			reply.isResolved = comment.isResolved; //copy isResolved to child comments (replies)
+			addComment(reply, comment.replies, null, level + 1, showResolved);
+		}
+		
+		return cdiv;
+	};
+
+	if (!readOnly)
+	{
+		var addLink = link.cloneNode();
+		addLink.innerHTML = '<div class="geSprite geSprite-plus" style="display:inline-block;"></div>';
+		addLink.setAttribute('title', mxResources.get('create') + '...');
+		
+		mxEvent.addListener(addLink, 'click', function(evt)
+		{
+			var newComment = editorUi.newComment('', editorUi.getCurrentUser());
+			var newCommentDiv = addComment(newComment, comments, null, 0);
+			
+			function doAddComment()
+			{
+				editComment(newComment, newCommentDiv, function(newComment)
+				{
+					showBusy(newCommentDiv);
+					
+					editorUi.addComment(newComment, function(id)
+					{
+						newComment.id = id;
+						comments.push(newComment);
+						showDone(newCommentDiv);
+					}, function(err)
+					{
+						showError(newCommentDiv);
+						doAddComment();
+						editorUi.handleError(err, null, null, null,
+							mxUtils.htmlEntities(mxResources.get('objectNotFound')));
+					});
+				}, true);
+			}
+			
+			doAddComment();
+			evt.preventDefault();
+			mxEvent.consume(evt);
+		});
+		
+		ldiv.appendChild(addLink);
+	}
+
+	var resolvedLink = link.cloneNode();
+	resolvedLink.innerHTML = '<img src="/images/check.png" style="width: 16px; padding: 2px;">';
+	resolvedLink.setAttribute('title', mxResources.get('showResolved'));
+	var resolvedChecked = false;
+	
+	if (uiTheme == 'dark')
+	{
+		resolvedLink.style.filter = 'invert(100%)';
+	}
+	
+	mxEvent.addListener(resolvedLink, 'click', function(evt)
+	{
+		resolvedChecked = !resolvedChecked;
+		
+		this.className = resolvedChecked? 'geButton geCheckedBtn' : 'geButton';
+		refresh();
+		
+		evt.preventDefault();
+		mxEvent.consume(evt);
+	});
+	
+	ldiv.appendChild(resolvedLink);
+	
+	if (editorUi.commentsRefreshNeeded())
+	{
+		var refreshLink = link.cloneNode();
+		refreshLink.innerHTML = '<img src="/images/update16.png" style="width: 16px; padding: 2px;">';
+		refreshLink.setAttribute('title', mxResources.get('refresh'));
+	
+		if (uiTheme == 'dark')
+		{
+			refreshLink.style.filter = 'invert(100%)';
+		}
+		
+		mxEvent.addListener(refreshLink, 'click', function(evt)
+		{
+			refresh();
+			
+			evt.preventDefault();
+			mxEvent.consume(evt);
+		});
+		
+		ldiv.appendChild(refreshLink);
+	}
+	
+	if (editorUi.commentsSaveNeeded())
+	{
+		var saveLink = link.cloneNode();
+		saveLink.innerHTML = '<img src="/images/save.png" style="width: 20px; padding: 2px;">';
+		saveLink.setAttribute('title', mxResources.get('save'));
+	
+		if (uiTheme == 'dark')
+		{
+			saveLink.style.filter = 'invert(100%)';
+		}
+		
+		mxEvent.addListener(saveLink, 'click', function(evt)
+		{
+			saveCallback();
+			
+			evt.preventDefault();
+			mxEvent.consume(evt);
+		});
+		
+		ldiv.appendChild(saveLink);
+	}
+
+	div.appendChild(ldiv);	
+
+	var comments = [];
+
+	var refresh = mxUtils.bind(this, function()
+	{
+		listDiv.innerHTML = '<div style="padding-top:10px;text-align:center;"><img src="/images/spin.gif" valign="middle"> ' +
+			mxUtils.htmlEntities(mxResources.get('loading')) + '...</div>';
+		
+		canReplyToReplies = editorUi.canReplyToReplies();
+		
+		if (editorUi.commentsSupported())
+		{
+			editorUi.getComments(function(list)
+			{
+				function sortReplies(replies)
+				{
+					if (replies != null)
+					{
+						//Sort replies old to new
+						replies.sort(function(r1, r2)
+						{
+							return new Date(r1.modifiedDate) - new Date(r2.modifiedDate);
+						});
+						
+						for (var i = 0; i < replies.length; i++)
+						{
+							sortReplies(replies[i].replies);
+						}						
+					}
+				};
+				
+				//Sort comments old to new
+				list.sort(function(c1, c2)
+				{
+					return new Date(c1.modifiedDate) - new Date(c2.modifiedDate);
+				});
+
+				listDiv.innerHTML = '';
+				listDiv.appendChild(noComments);
+				noComments.style.display = 'block';
+				comments = list;
+				
+				for (var i = 0; i < comments.length; i++)
+				{
+					sortReplies(comments[i].replies);
+					addComment(comments[i], comments, null, 0, resolvedChecked);
+				}
+			}, function()
+			{
+				listDiv.innerHTML = mxUtils.htmlEntities(mxResources.get('error'));
+			});
+		}
+		else
+		{
+			//TODO if comments are not supported, close the dialog
+			listDiv.innerHTML = mxUtils.htmlEntities(mxResources.get('error'));
+		}
+	});
+
+	refresh();
+	
+	this.refreshComments = refresh;
+
+	//Refresh the modified date of each comment if the window is visible
+	var refreshCommentsTime = mxUtils.bind(this, function()
+	{
+		if (!this.window.isVisible()) return; //only update if it is visible
+		
+		var modDateDivs = listDiv.querySelectorAll('.geCommentDate');
+		var modDateDivsMap = {};
+		
+		for (var i = 0; i < modDateDivs.length; i++)
+		{
+			var div = modDateDivs[i];
+			modDateDivsMap[div.getAttribute('data-commentId')] = div;
+		}
+		
+		function processComment(comment) 
+		{
+			var div = modDateDivsMap[comment.id];
+			
+			if (div == null) return; //resolved comments
+			
+			writeCommentDate(comment, div);
+			
+			for (var i = 0; comment.replies != null && i < comment.replies.length; i++)
+			{
+				processComment(comment.replies[i]);
+			}
+		};
+		
+		for (var i = 0; i < comments.length; i++)
+		{
+			processComment(comments[i]);
+		}
+	});
+
+	//Periodically refresh time every one minute
+	setInterval(refreshCommentsTime, 60000);
+	this.refreshCommentsTime = refreshCommentsTime;
+	
+	this.window = new mxWindow(mxResources.get('comments'), div, x, y, w, h, true, true);
+	this.window.minimumSize = new mxRectangle(0, 0, 300, 200);
+	this.window.destroyOnClose = false;
+	this.window.setMaximizable(false);
+	this.window.setResizable(true);
+	this.window.setClosable(true);
+	this.window.setVisible(true);
+	
+	this.window.addListener(mxEvent.SHOW, mxUtils.bind(this, function()
+	{
+		this.window.fit();
+	}));
+	
+	this.window.setLocation = function(x, y)
+	{
+		var iw = window.innerWidth || document.body.clientWidth || document.documentElement.clientWidth;
+		var ih = window.innerHeight || document.body.clientHeight || document.documentElement.clientHeight;
+		
+		x = Math.max(0, Math.min(x, iw - this.table.clientWidth));
+		y = Math.max(0, Math.min(y, ih - this.table.clientHeight - 48));
+
+		if (this.getX() != x || this.getY() != y)
+		{
+			mxWindow.prototype.setLocation.apply(this, arguments);
+		}
+	};
+	
+	var resizeListener = mxUtils.bind(this, function()
+	{
+		var x = this.window.getX();
+		var y = this.window.getY();
+		
+		this.window.setLocation(x, y);
+	});
+	
+	mxEvent.addListener(window, 'resize', resizeListener);
+
+	this.destroy = function()
+	{
+		mxEvent.removeListener(window, 'resize', resizeListener);
+		this.window.destroy();
+	}
+};
+
+/**
+ * 
+ */
+var ConfirmDialog = function(editorUi, message, okFn, cancelFn, okLabel, cancelLabel, okImg, cancelImg, showRememberOption, imgSrc)
+{
+	var div = document.createElement('div');
+	div.style.textAlign = 'center';
+	
+	var p2 = document.createElement('div');
+	p2.style.padding = '6px';
+	p2.style.overflow = 'auto';
+	p2.style.maxHeight = '44px';
+	p2.style.lineHeight = '1.2em';
+	
+	if (mxClient.IS_QUIRKS)
+	{
+		p2.style.height = '60px';
+	}
+	
+	mxUtils.write(p2, message);
+	div.appendChild(p2);
+	
+	if (imgSrc != null)
+	{
+		var p3 = document.createElement('div');
+		p3.style.padding = '6px 0 6px 0';
+		var img = document.createElement('img');
+		img.setAttribute('src', imgSrc);
+		p3.appendChild(img);
+		div.appendChild(p3);
+	}
+	
+	var btns = document.createElement('div');
+	btns.style.textAlign = 'center';
+	btns.style.whiteSpace = 'nowrap';
+
+	var cb = document.createElement('input');
+	cb.setAttribute('type', 'checkbox');
+
+	var cancelBtn = mxUtils.button(cancelLabel || mxResources.get('cancel'), function()
+	{
+		editorUi.hideDialog();
+		
+		if (cancelFn != null)
+		{
+			cancelFn(cb.checked);
+		}
+	});
+	cancelBtn.className = 'geBtn';
+	
+	if (cancelImg != null)
+	{
+		cancelBtn.innerHTML = cancelImg + '<br>' + cancelBtn.innerHTML;
+		cancelBtn.style.paddingBottom = '8px';
+		cancelBtn.style.paddingTop = '8px';
+		cancelBtn.style.height = 'auto';
+		cancelBtn.style.width = '40%';
+	}
+	
+	if (editorUi.editor.cancelFirst)
+	{
+		btns.appendChild(cancelBtn);
+	}
+	
+	var okBtn = mxUtils.button(okLabel || mxResources.get('ok'), function()
+	{
+		editorUi.hideDialog();
+		
+		if (okFn != null)
+		{
+			okFn(cb.checked);
+		}
+	});
+	btns.appendChild(okBtn);
+	
+	if (okImg != null)
+	{
+		okBtn.innerHTML = okImg + '<br>' + okBtn.innerHTML + '<br>';
+		okBtn.style.paddingBottom = '8px';
+		okBtn.style.paddingTop = '8px';
+		okBtn.style.height = 'auto';
+		okBtn.className = 'geBtn';
+		okBtn.style.width = '40%';
+	}
+	else
+	{
+		okBtn.className = 'geBtn gePrimaryBtn';
+	}
+	
+	if (!editorUi.editor.cancelFirst)
+	{
+		btns.appendChild(cancelBtn);
+	}
+
+	div.appendChild(btns);
+	
+	if (showRememberOption)
+	{
+		btns.style.marginTop = '10px';
+		var p2 = document.createElement('p');
+		p2.style.marginTop = '20px';
+		p2.appendChild(cb);
+		var span = document.createElement('span');
+		mxUtils.write(span, ' ' + mxResources.get('rememberThisSetting'));
+		p2.appendChild(span);
+		div.appendChild(p2);
+		
+		mxEvent.addListener(span, 'click', function(evt)
+		{
+			cb.checked = !cb.checked;
+			mxEvent.consume(evt);
+		});
+	}
+	else
+	{
+		btns.style.marginTop = '12px';
+	}
+
+	this.init = function()
+	{
+		okBtn.focus();
+	};
+	
+	this.container = div;
+};

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 575 - 550
src/main/webapp/js/viewer.min.js


+ 6 - 1
src/main/webapp/plugins/cConf-1-4-8.js

@@ -286,7 +286,12 @@ Draw.loadPlugin(function(ui)
 	{
 		return true;
 	};
-			
+	
+	ui.commentsRefreshNeeded = function()
+	{
+		return false;
+	};
+
 	function confCommentToDrawio(cComment, pCommentId)
 	{
 		var comment = new DrawioComment(null, cComment.id, cComment.content,