Last commit before realtime drop
This commit is contained in:
parent
3b30813e3d
commit
5f380b461a
@ -374,7 +374,7 @@ define([
|
|||||||
if(conflictList.length) {
|
if(conflictList.length) {
|
||||||
eventMgr.onMessage('"' + remoteTitle + '" has conflicts that you have to review.');
|
eventMgr.onMessage('"' + remoteTitle + '" has conflicts that you have to review.');
|
||||||
}
|
}
|
||||||
}), this);
|
}, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return remote CRCs
|
// Return remote CRCs
|
||||||
|
@ -198,7 +198,7 @@ define([
|
|||||||
// Refresh conversation if popover is open
|
// Refresh conversation if popover is open
|
||||||
var context = currentContext;
|
var context = currentContext;
|
||||||
if(context.discussionIndex) {
|
if(context.discussionIndex) {
|
||||||
context.popoverElt.querySelector('.discussion-comment-list').innerHTML = getDiscussionComments();
|
context.getPopoverElt().querySelector('.discussion-comment-list').innerHTML = getDiscussionComments();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
cssApplier.undoToRange(context.rangyRange);
|
cssApplier.undoToRange(context.rangyRange);
|
||||||
|
@ -11,7 +11,7 @@ define([
|
|||||||
dialogManageSynchronization.onEventMgrCreated = function(eventMgrParameter) {
|
dialogManageSynchronization.onEventMgrCreated = function(eventMgrParameter) {
|
||||||
eventMgr = eventMgrParameter;
|
eventMgr = eventMgrParameter;
|
||||||
};
|
};
|
||||||
|
|
||||||
var synchronizer;
|
var synchronizer;
|
||||||
dialogManageSynchronization.onSynchronizerCreated = function(synchronizerParameter) {
|
dialogManageSynchronization.onSynchronizerCreated = function(synchronizerParameter) {
|
||||||
synchronizer = synchronizerParameter;
|
synchronizer = synchronizerParameter;
|
||||||
@ -34,7 +34,7 @@ define([
|
|||||||
$msgSyncListElt.addClass("hide");
|
$msgSyncListElt.addClass("hide");
|
||||||
$msgNoSyncElt.removeClass("hide");
|
$msgNoSyncElt.removeClass("hide");
|
||||||
}
|
}
|
||||||
|
|
||||||
var syncListHtml = _.reduce(fileDesc.syncLocations, function(result, syncAttributes) {
|
var syncListHtml = _.reduce(fileDesc.syncLocations, function(result, syncAttributes) {
|
||||||
return result + _.template(dialogManageSynchronizationLocationHTML, {
|
return result + _.template(dialogManageSynchronizationLocationHTML, {
|
||||||
syncAttributes: syncAttributes,
|
syncAttributes: syncAttributes,
|
||||||
@ -42,12 +42,11 @@ define([
|
|||||||
});
|
});
|
||||||
}, '');
|
}, '');
|
||||||
syncListElt.innerHTML = syncListHtml;
|
syncListElt.innerHTML = syncListHtml;
|
||||||
|
|
||||||
_.each(syncListElt.querySelectorAll('.remove-button'), function(removeButtonElt) {
|
_.each(syncListElt.querySelectorAll('.remove-button'), function(removeButtonElt) {
|
||||||
var $removeButtonElt = $(removeButtonElt);
|
var $removeButtonElt = $(removeButtonElt);
|
||||||
var syncAttributes = fileDesc.syncLocations[$removeButtonElt.data('syncIndex')];
|
var syncAttributes = fileDesc.syncLocations[$removeButtonElt.data('syncIndex')];
|
||||||
$removeButtonElt.click(function() {
|
$removeButtonElt.click(function() {
|
||||||
synchronizer.tryStopRealtimeSync();
|
|
||||||
fileDesc.removeSyncLocation(syncAttributes);
|
fileDesc.removeSyncLocation(syncAttributes);
|
||||||
eventMgr.onSyncRemoved(fileDesc, syncAttributes);
|
eventMgr.onSyncRemoved(fileDesc, syncAttributes);
|
||||||
});
|
});
|
||||||
@ -71,4 +70,4 @@ define([
|
|||||||
|
|
||||||
return dialogManageSynchronization;
|
return dialogManageSynchronization;
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -562,6 +562,30 @@ define([
|
|||||||
dataType: file.isRealtime ? 'json' : 'text',
|
dataType: file.isRealtime ? 'json' : 'text',
|
||||||
timeout: constants.AJAX_TIMEOUT
|
timeout: constants.AJAX_TIMEOUT
|
||||||
}).done(function(data) {
|
}).done(function(data) {
|
||||||
|
if(file.isRealtime) {
|
||||||
|
data = data.data.value;
|
||||||
|
data = {
|
||||||
|
content: data.content.value,
|
||||||
|
discussionList: (function() {
|
||||||
|
var discussionList = {};
|
||||||
|
data.discussionList && _.each(data.discussionList.value, function(discussionObject) {
|
||||||
|
var discussion = {
|
||||||
|
discussionIndex: discussionObject.value.discussionIndex.json,
|
||||||
|
selectionStart: discussionObject.value.selectionStart.json,
|
||||||
|
selectionEnd: discussionObject.value.selectionEnd.json,
|
||||||
|
};
|
||||||
|
var type = (discussionObject.value.type || {}).json;
|
||||||
|
type && (discussion.type = type);
|
||||||
|
var commentList = (discussionObject.value.commentList || {}).value || [];
|
||||||
|
commentList.length && (discussion.commentList = commentList.map(function(commentObject) {
|
||||||
|
return commentObject.json;
|
||||||
|
}));
|
||||||
|
discussionList[discussion.discussionIndex] = discussion;
|
||||||
|
});
|
||||||
|
return discussionList;
|
||||||
|
})()
|
||||||
|
};
|
||||||
|
}
|
||||||
file.content = data;
|
file.content = data;
|
||||||
objects.shift();
|
objects.shift();
|
||||||
task.chain(recursiveDownloadContent);
|
task.chain(recursiveDownloadContent);
|
||||||
|
@ -290,12 +290,32 @@ define([
|
|||||||
// Realtime closure
|
// Realtime closure
|
||||||
var realtimeContext;
|
var realtimeContext;
|
||||||
(function() {
|
(function() {
|
||||||
|
var inCompoundOperation = false;
|
||||||
|
function modelChangeWrapper(cb) {
|
||||||
|
realtimeContext.isChanging = true;
|
||||||
|
try { cb(); }
|
||||||
|
finally {
|
||||||
|
if(inCompoundOperation) {
|
||||||
|
try { realtimeContext.model.endCompoundOperation(); }
|
||||||
|
catch(e) {}
|
||||||
|
inCompoundOperation = false;
|
||||||
|
}
|
||||||
|
realtimeContext.isChanging = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function compound(cb) {
|
||||||
|
if(!inCompoundOperation) {
|
||||||
|
realtimeContext.model.beginCompoundOperation();
|
||||||
|
inCompoundOperation = true;
|
||||||
|
}
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
|
||||||
function toRealtimeDiscussion(context, discussion) {
|
function toRealtimeDiscussion(context, discussion) {
|
||||||
var realtimeCommentList = context.model.createList();
|
var realtimeCommentList = context.model.createList();
|
||||||
realtimeCommentList.addEventListener(gapi.drive.realtime.EventType.VALUES_ADDED, modelEventListener);
|
realtimeCommentList.addEventListener(gapi.drive.realtime.EventType.VALUES_ADDED, onModelChange);
|
||||||
realtimeCommentList.addEventListener(gapi.drive.realtime.EventType.VALUES_REMOVED, modelEventListener);
|
realtimeCommentList.addEventListener(gapi.drive.realtime.EventType.VALUES_REMOVED, onModelChange);
|
||||||
realtimeCommentList.addEventListener(gapi.drive.realtime.EventType.VALUES_SET, modelEventListener);
|
realtimeCommentList.addEventListener(gapi.drive.realtime.EventType.VALUES_SET, onModelChange);
|
||||||
discussion.commentList && discussion.commentList.forEach(function(comment) {
|
discussion.commentList && discussion.commentList.forEach(function(comment) {
|
||||||
realtimeCommentList.push({
|
realtimeCommentList.push({
|
||||||
author: comment.author,
|
author: comment.author,
|
||||||
@ -322,6 +342,10 @@ define([
|
|||||||
}
|
}
|
||||||
|
|
||||||
function fromRealtimeDiscussion(realtimeDiscussion) {
|
function fromRealtimeDiscussion(realtimeDiscussion) {
|
||||||
|
var realtimeCommentList = realtimeDiscussion.get('commentList');
|
||||||
|
realtimeCommentList.addEventListener(gapi.drive.realtime.EventType.VALUES_ADDED, onModelChange);
|
||||||
|
realtimeCommentList.addEventListener(gapi.drive.realtime.EventType.VALUES_REMOVED, onModelChange);
|
||||||
|
realtimeCommentList.addEventListener(gapi.drive.realtime.EventType.VALUES_SET, onModelChange);
|
||||||
var discussion = {
|
var discussion = {
|
||||||
discussionIndex: realtimeDiscussion.get('discussionIndex'),
|
discussionIndex: realtimeDiscussion.get('discussionIndex'),
|
||||||
selectionStart: realtimeDiscussion.get('selectionStart'),
|
selectionStart: realtimeDiscussion.get('selectionStart'),
|
||||||
@ -329,7 +353,7 @@ define([
|
|||||||
};
|
};
|
||||||
var type = realtimeDiscussion.get('type');
|
var type = realtimeDiscussion.get('type');
|
||||||
type && (discussion.type = type);
|
type && (discussion.type = type);
|
||||||
var commentList = realtimeDiscussion.get('commentList').asArray();
|
var commentList = realtimeCommentList.asArray();
|
||||||
commentList.length && (discussion.commentList = commentList);
|
commentList.length && (discussion.commentList = commentList);
|
||||||
return discussion;
|
return discussion;
|
||||||
}
|
}
|
||||||
@ -344,12 +368,14 @@ define([
|
|||||||
return localDiscussionList;
|
return localDiscussionList;
|
||||||
}
|
}
|
||||||
|
|
||||||
function mergeDiscussion(localDiscussion, realtimeDiscussion, isServerChange) {
|
function mergeDiscussion(localDiscussion, realtimeDiscussion, isModelChange) {
|
||||||
var commentsChanged = false;
|
var commentsChanged = false;
|
||||||
// We only pay attention to local selection modifications
|
// We don't pay attention to model selection modifications
|
||||||
if(!isServerChange) {
|
if(!isModelChange) {
|
||||||
realtimeDiscussion.set('selectionStart', localDiscussion.selectionStart);
|
compound(function() {
|
||||||
realtimeDiscussion.set('selectionEnd', localDiscussion.selectionEnd);
|
realtimeDiscussion.set('selectionStart', localDiscussion.selectionStart);
|
||||||
|
realtimeDiscussion.set('selectionEnd', localDiscussion.selectionEnd);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
function isInDiscussion(comment, commentList) {
|
function isInDiscussion(comment, commentList) {
|
||||||
return commentList.some(function(commentInDiscussion) {
|
return commentList.some(function(commentInDiscussion) {
|
||||||
@ -362,21 +388,25 @@ define([
|
|||||||
var localCommentList = localDiscussion.commentList;
|
var localCommentList = localDiscussion.commentList;
|
||||||
function checkLocalComment(comment, index) {
|
function checkLocalComment(comment, index) {
|
||||||
if(!isInDiscussion(comment, realtimeCommentList.asArray())) {
|
if(!isInDiscussion(comment, realtimeCommentList.asArray())) {
|
||||||
if(isServerChange) {
|
if(isModelChange) {
|
||||||
localCommentList.splice(index, 1);
|
localCommentList.splice(index, 1);
|
||||||
commentsChanged = true;
|
commentsChanged = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
realtimeCommentList.push(comment);
|
compound(function() {
|
||||||
|
realtimeCommentList.push(comment);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while(localCommentList.some(checkLocalComment)) {}
|
while(localCommentList.some(checkLocalComment)) {}
|
||||||
function checkRealtimeComment(comment, index) {
|
function checkRealtimeComment(comment, index) {
|
||||||
if(!isInDiscussion(comment, localCommentList)) {
|
if(!isInDiscussion(comment, localCommentList)) {
|
||||||
if(!isServerChange) {
|
if(!isModelChange) {
|
||||||
realtimeCommentList.remove(index);
|
compound(function() {
|
||||||
|
realtimeCommentList.remove(index);
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -389,17 +419,19 @@ define([
|
|||||||
return commentsChanged;
|
return commentsChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
function mergeDiscussionList(context, isServerChange) {
|
function mergeDiscussionList(context, isModelChange) {
|
||||||
var commentsChanged = false;
|
var commentsChanged = false;
|
||||||
var localDiscussionList = context.fileDesc.discussionList;
|
var localDiscussionList = context.fileDesc.discussionList;
|
||||||
_.values(localDiscussionList).forEach(function(localDiscussion) {
|
_.values(localDiscussionList).forEach(function(localDiscussion) {
|
||||||
var realtimeDiscussion = context.realtimeDiscussionList.get(localDiscussion.discussionIndex);
|
var realtimeDiscussion = context.realtimeDiscussionList.get(localDiscussion.discussionIndex);
|
||||||
if(realtimeDiscussion) {
|
if(realtimeDiscussion) {
|
||||||
commentsChanged |= mergeDiscussion(localDiscussion, realtimeDiscussion, isServerChange);
|
commentsChanged |= mergeDiscussion(localDiscussion, realtimeDiscussion, isModelChange);
|
||||||
}
|
}
|
||||||
else if(!isServerChange) {
|
else if(!isModelChange) {
|
||||||
realtimeDiscussion = toRealtimeDiscussion(context, localDiscussion);
|
compound(function() {
|
||||||
context.realtimeDiscussionList.set(localDiscussion.discussionIndex, realtimeDiscussion);
|
realtimeDiscussion = toRealtimeDiscussion(context, localDiscussion);
|
||||||
|
context.realtimeDiscussionList.set(localDiscussion.discussionIndex, realtimeDiscussion);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
delete localDiscussionList[localDiscussion.discussionIndex];
|
delete localDiscussionList[localDiscussion.discussionIndex];
|
||||||
@ -410,15 +442,17 @@ define([
|
|||||||
var realtimeDiscussion = context.realtimeDiscussionList.get(discussionIndex);
|
var realtimeDiscussion = context.realtimeDiscussionList.get(discussionIndex);
|
||||||
var localDiscussion = localDiscussionList[discussionIndex];
|
var localDiscussion = localDiscussionList[discussionIndex];
|
||||||
if(localDiscussion) {
|
if(localDiscussion) {
|
||||||
commentsChanged |= mergeDiscussion(localDiscussion, realtimeDiscussion, isServerChange);
|
commentsChanged |= mergeDiscussion(localDiscussion, realtimeDiscussion, isModelChange);
|
||||||
}
|
}
|
||||||
else if(isServerChange) {
|
else if(isModelChange) {
|
||||||
var discussion = fromRealtimeDiscussion(realtimeDiscussion);
|
var discussion = fromRealtimeDiscussion(realtimeDiscussion);
|
||||||
localDiscussionList[discussionIndex] = discussion;
|
localDiscussionList[discussionIndex] = discussion;
|
||||||
eventMgr.onDiscussionCreated(context.fileDesc, discussion);
|
eventMgr.onDiscussionCreated(context.fileDesc, discussion);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
context.realtimeDiscussionList.delete(discussionIndex);
|
compound(function() {
|
||||||
|
context.realtimeDiscussionList.delete(discussionIndex);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
context.fileDesc.discussionList = localDiscussionList; // Write in localStorage
|
context.fileDesc.discussionList = localDiscussionList; // Write in localStorage
|
||||||
@ -451,59 +485,55 @@ define([
|
|||||||
}
|
}
|
||||||
|
|
||||||
var onChange = (function() {
|
var onChange = (function() {
|
||||||
var debouncedOnChange = _.debounce(function() {
|
var debouncedOnChange = utils.debounce(function() {
|
||||||
var context = realtimeContext;
|
var context = realtimeContext;
|
||||||
if(!context) {
|
if(!context) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(context.isServerChange) {
|
if(context.isModelChange) {
|
||||||
logger.log('Realtime syncing remote changes');
|
logger.log('Realtime syncing model changes');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Model is supposed to be updated on local modifications
|
|
||||||
context.model.beginCompoundOperation();
|
|
||||||
logger.log('Realtime syncing local changes');
|
logger.log('Realtime syncing local changes');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check content modifications
|
modelChangeWrapper(function() {
|
||||||
var localContent = context.fileDesc.content;
|
// Check content modifications
|
||||||
var remoteContent = context.realtimeString.getText();
|
var localContent = context.fileDesc.content;
|
||||||
var contentChanged = localContent != remoteContent;
|
var remoteContent = context.realtimeString.getText();
|
||||||
if(contentChanged) {
|
var contentChanged = localContent != remoteContent;
|
||||||
if(context.isServerChange) {
|
if(contentChanged) {
|
||||||
editor.setValue(remoteContent);
|
if(context.isModelChange) {
|
||||||
|
editor.setValue(remoteContent);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
compound(function() {
|
||||||
|
context.realtimeString.setText(localContent);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
context.realtimeString.setText(localContent);
|
// Check discussion modifications
|
||||||
|
mergeDiscussionList(context, context.isModelChange);
|
||||||
|
|
||||||
|
// For local changes, CRCs are updated on "save success" event
|
||||||
|
if(context.isModelChange) {
|
||||||
|
updateStatus();
|
||||||
}
|
}
|
||||||
}
|
context.isModelChange = false;
|
||||||
|
});
|
||||||
// Check discussion modifications
|
});
|
||||||
mergeDiscussionList(context, context.isServerChange);
|
|
||||||
|
|
||||||
|
|
||||||
// For local changes, CRCs are updated on "save success" event
|
|
||||||
if(context.isServerChange) {
|
|
||||||
updateStatus();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
context.model.endCompoundOperation();
|
|
||||||
}
|
|
||||||
context.isServerChange = false;
|
|
||||||
}, 0);
|
|
||||||
return function(fileDesc) {
|
return function(fileDesc) {
|
||||||
if(realtimeContext && realtimeContext.fileDesc === fileDesc) {
|
if(realtimeContext && realtimeContext.fileDesc === fileDesc) {
|
||||||
debouncedOnChange();
|
debouncedOnChange();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
function modelEventListener(evt) {
|
function onModelChange() {
|
||||||
if(!realtimeContext) {
|
if(!realtimeContext || realtimeContext.isChanging) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(evt.isLocal === false) {
|
realtimeContext.isModelChange = true;
|
||||||
realtimeContext.isServerChange = true;
|
|
||||||
}
|
|
||||||
onChange(realtimeContext.fileDesc);
|
onChange(realtimeContext.fileDesc);
|
||||||
}
|
}
|
||||||
eventMgr.addListener('onContentChanged', onChange);
|
eventMgr.addListener('onContentChanged', onChange);
|
||||||
@ -513,6 +543,9 @@ define([
|
|||||||
|
|
||||||
// Start realtime synchronization
|
// Start realtime synchronization
|
||||||
gdriveProvider.startRealtimeSync = function(fileDesc, syncAttributes) {
|
gdriveProvider.startRealtimeSync = function(fileDesc, syncAttributes) {
|
||||||
|
if(realtimeContext !== undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var context = {
|
var context = {
|
||||||
fileDesc: fileDesc,
|
fileDesc: fileDesc,
|
||||||
syncAttributes: syncAttributes
|
syncAttributes: syncAttributes
|
||||||
@ -520,6 +553,9 @@ define([
|
|||||||
realtimeContext = context;
|
realtimeContext = context;
|
||||||
googleHelper.loadRealtime(syncAttributes.id, accountId, function(err, doc) {
|
googleHelper.loadRealtime(syncAttributes.id, accountId, function(err, doc) {
|
||||||
if(err || !doc) {
|
if(err || !doc) {
|
||||||
|
if(context === realtimeContext) {
|
||||||
|
realtimeContext = undefined;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -542,8 +578,8 @@ define([
|
|||||||
}
|
}
|
||||||
context.realtimeString = realtimeString;
|
context.realtimeString = realtimeString;
|
||||||
// Listen to content modifications
|
// Listen to content modifications
|
||||||
realtimeString.addEventListener(gapi.drive.realtime.EventType.TEXT_INSERTED, modelEventListener);
|
realtimeString.addEventListener(gapi.drive.realtime.EventType.TEXT_INSERTED, onModelChange);
|
||||||
realtimeString.addEventListener(gapi.drive.realtime.EventType.TEXT_DELETED, modelEventListener);
|
realtimeString.addEventListener(gapi.drive.realtime.EventType.TEXT_DELETED, onModelChange);
|
||||||
|
|
||||||
// Get or create discussion map
|
// Get or create discussion map
|
||||||
var realtimeDiscussionList = model.getRoot().get('discussionList');
|
var realtimeDiscussionList = model.getRoot().get('discussionList');
|
||||||
@ -554,14 +590,14 @@ define([
|
|||||||
}
|
}
|
||||||
context.realtimeDiscussionList = realtimeDiscussionList;
|
context.realtimeDiscussionList = realtimeDiscussionList;
|
||||||
// Listen to discussion modifications
|
// Listen to discussion modifications
|
||||||
realtimeDiscussionList.addEventListener(gapi.drive.realtime.EventType.VALUE_CHANGED, modelEventListener);
|
realtimeDiscussionList.addEventListener(gapi.drive.realtime.EventType.VALUE_CHANGED, onModelChange);
|
||||||
realtimeDiscussionList.keys().forEach(function(discussionIndex) {
|
realtimeDiscussionList.keys().forEach(function(discussionIndex) {
|
||||||
var realtimeDiscussion = context.realtimeDiscussionList.get(discussionIndex);
|
var realtimeDiscussion = context.realtimeDiscussionList.get(discussionIndex);
|
||||||
var realtimeCommentList = realtimeDiscussion.get('commentList');
|
var realtimeCommentList = realtimeDiscussion.get('commentList');
|
||||||
// Listen to comment modifications in every discussion
|
// Listen to comment modifications in every discussion
|
||||||
realtimeCommentList.addEventListener(gapi.drive.realtime.EventType.VALUES_ADDED, modelEventListener);
|
realtimeCommentList.addEventListener(gapi.drive.realtime.EventType.VALUES_ADDED, onModelChange);
|
||||||
realtimeCommentList.addEventListener(gapi.drive.realtime.EventType.VALUES_REMOVED, modelEventListener);
|
realtimeCommentList.addEventListener(gapi.drive.realtime.EventType.VALUES_REMOVED, onModelChange);
|
||||||
realtimeCommentList.addEventListener(gapi.drive.realtime.EventType.VALUES_SET, modelEventListener);
|
realtimeCommentList.addEventListener(gapi.drive.realtime.EventType.VALUES_SET, onModelChange);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Also listen to "save success" event
|
// Also listen to "save success" event
|
||||||
@ -577,6 +613,7 @@ define([
|
|||||||
var remoteDiscussionList = fromRealtimeDiscussionList(realtimeDiscussionList);
|
var remoteDiscussionList = fromRealtimeDiscussionList(realtimeDiscussionList);
|
||||||
var remoteDiscussionListJSON = JSON.stringify(remoteDiscussionList);
|
var remoteDiscussionListJSON = JSON.stringify(remoteDiscussionList);
|
||||||
gdriveProvider.syncMerge(fileDesc, syncAttributes, remoteContent, remoteTitle, remoteDiscussionList, remoteDiscussionListJSON);
|
gdriveProvider.syncMerge(fileDesc, syncAttributes, remoteContent, remoteTitle, remoteDiscussionList, remoteDiscussionListJSON);
|
||||||
|
onChange(context.fileDesc);
|
||||||
|
|
||||||
// Save undo/redo buttons default actions
|
// Save undo/redo buttons default actions
|
||||||
undoExecute = pagedownEditor.uiManager.buttons.undo.execute;
|
undoExecute = pagedownEditor.uiManager.buttons.undo.execute;
|
||||||
@ -584,8 +621,8 @@ define([
|
|||||||
setUndoRedoButtonStates = pagedownEditor.uiManager.setUndoRedoButtonStates;
|
setUndoRedoButtonStates = pagedownEditor.uiManager.setUndoRedoButtonStates;
|
||||||
|
|
||||||
// Set temporary actions for undo/redo buttons
|
// Set temporary actions for undo/redo buttons
|
||||||
pagedownEditor.uiManager.buttons.undo.execute = model.undo;
|
pagedownEditor.uiManager.buttons.undo.execute = _.bind(model.undo, model);
|
||||||
pagedownEditor.uiManager.buttons.redo.execute = model.redo;
|
pagedownEditor.uiManager.buttons.redo.execute = _.bind(model.redo, model);
|
||||||
|
|
||||||
// Add event handler for model's UndoRedoStateChanged events
|
// Add event handler for model's UndoRedoStateChanged events
|
||||||
pagedownEditor.uiManager.setUndoRedoButtonStates = _.debounce(function() {
|
pagedownEditor.uiManager.setUndoRedoButtonStates = _.debounce(function() {
|
||||||
@ -609,7 +646,7 @@ define([
|
|||||||
gdriveProvider.stopRealtimeSync();
|
gdriveProvider.stopRealtimeSync();
|
||||||
}
|
}
|
||||||
else if(err.isFatal) {
|
else if(err.isFatal) {
|
||||||
eventMgr.onError('Real time synchronization is temporarily unavailable.');
|
// Retry will be attempted shortly...
|
||||||
gdriveProvider.stopRealtimeSync();
|
gdriveProvider.stopRealtimeSync();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -619,6 +656,8 @@ define([
|
|||||||
gdriveProvider.stopRealtimeSync = function() {
|
gdriveProvider.stopRealtimeSync = function() {
|
||||||
logger.log("Stopping Google Drive realtime synchronization");
|
logger.log("Stopping Google Drive realtime synchronization");
|
||||||
if(realtimeContext !== undefined) {
|
if(realtimeContext !== undefined) {
|
||||||
|
try { realtimeContext.model.endCompoundOperation(); }
|
||||||
|
catch(e) {}
|
||||||
realtimeContext.document && realtimeContext.document.close();
|
realtimeContext.document && realtimeContext.document.close();
|
||||||
realtimeContext = undefined;
|
realtimeContext = undefined;
|
||||||
}
|
}
|
||||||
|
@ -63,8 +63,8 @@ define([
|
|||||||
|
|
||||||
// Clean fields from deleted files in local storage
|
// Clean fields from deleted files in local storage
|
||||||
Object.keys(storage).forEach(function(key) {
|
Object.keys(storage).forEach(function(key) {
|
||||||
var match = key.match(/(publish\.\S+?)\.\S+/);
|
var match = key.match(/publish\.\S+/);
|
||||||
if(match && !publishIndexMap.hasOwnProperty(match[1])) {
|
if(match && !publishIndexMap.hasOwnProperty(match[0])) {
|
||||||
storage.removeItem(key);
|
storage.removeItem(key);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -52,8 +52,8 @@ define([
|
|||||||
|
|
||||||
// Clean fields from deleted files in local storage
|
// Clean fields from deleted files in local storage
|
||||||
Object.keys(storage).forEach(function(key) {
|
Object.keys(storage).forEach(function(key) {
|
||||||
var match = key.match(/(sync\.\S+?)\.\S+/);
|
var match = key.match(/sync\.\S+/);
|
||||||
if(match && !syncIndexMap.hasOwnProperty(match[1])) {
|
if(match && !syncIndexMap.hasOwnProperty(match[0])) {
|
||||||
storage.removeItem(key);
|
storage.removeItem(key);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -241,28 +241,16 @@ define([
|
|||||||
* Realtime synchronization
|
* Realtime synchronization
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
var realtimeFileDesc;
|
|
||||||
var realtimeSyncAttributes;
|
|
||||||
var isOnline = true;
|
var isOnline = true;
|
||||||
|
|
||||||
// Determines if open file has real time sync location and tries to start
|
|
||||||
// real time sync
|
|
||||||
function onFileOpen(fileDesc) {
|
|
||||||
realtimeFileDesc = _.some(fileDesc.syncLocations, function(syncAttributes) {
|
|
||||||
realtimeSyncAttributes = syncAttributes;
|
|
||||||
return syncAttributes.isRealtime;
|
|
||||||
}) ? fileDesc : undefined;
|
|
||||||
tryStartRealtimeSync();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tries to start/stop real time sync on online/offline event
|
// Tries to start/stop real time sync on online/offline event
|
||||||
function onOfflineChanged(isOfflineParam) {
|
function onOfflineChanged(isOfflineParam) {
|
||||||
if(isOfflineParam === false) {
|
if(isOfflineParam === false) {
|
||||||
isOnline = true;
|
isOnline = true;
|
||||||
tryStartRealtimeSync();
|
startRealtimeSync();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
synchronizer.tryStopRealtimeSync();
|
stopRealtimeSync();
|
||||||
isOnline = false;
|
isOnline = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -270,24 +258,36 @@ define([
|
|||||||
// Starts real time synchronization if:
|
// Starts real time synchronization if:
|
||||||
// 1. current file has real time sync location
|
// 1. current file has real time sync location
|
||||||
// 2. we are online
|
// 2. we are online
|
||||||
function tryStartRealtimeSync() {
|
function startRealtimeSync() {
|
||||||
if(realtimeFileDesc !== undefined && isOnline === true) {
|
var fileDesc = fileMgr.currentFile;
|
||||||
realtimeSyncAttributes.provider.startRealtimeSync(realtimeFileDesc, realtimeSyncAttributes);
|
_.each(fileDesc.syncLocations, function(syncAttributes) {
|
||||||
}
|
syncAttributes.isRealtime && syncAttributes.provider.startRealtimeSync(fileDesc, syncAttributes);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stops previously started synchronization if any
|
// Stops previously started synchronization if any
|
||||||
synchronizer.tryStopRealtimeSync = function() {
|
function stopRealtimeSync() {
|
||||||
if(realtimeFileDesc !== undefined && isOnline === true) {
|
_.each(providerMap, function(provider) {
|
||||||
realtimeSyncAttributes.provider.stopRealtimeSync();
|
provider.stopRealtimeSync && provider.stopRealtimeSync();
|
||||||
}
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
// Triggers realtime synchronization from eventMgr events
|
// Triggers realtime synchronization from eventMgr events
|
||||||
if(window.viewerMode === false) {
|
if(window.viewerMode === false) {
|
||||||
eventMgr.addListener("onFileOpen", onFileOpen);
|
// On file open, try to start realtime sync
|
||||||
eventMgr.addListener("onFileClosed", synchronizer.tryStopRealtimeSync);
|
eventMgr.addListener("onFileOpen", startRealtimeSync);
|
||||||
|
// On new sync location, try to start realtime sync
|
||||||
|
eventMgr.addListener("onSyncExportSuccess", startRealtimeSync);
|
||||||
|
// On file close, stop any active realtime synchronization
|
||||||
|
eventMgr.addListener("onFileClosed", stopRealtimeSync);
|
||||||
|
// Start/stop realtime sync depending on network status
|
||||||
eventMgr.addListener("onOfflineChanged", onOfflineChanged);
|
eventMgr.addListener("onOfflineChanged", onOfflineChanged);
|
||||||
|
// Try to start realtime sync every 15 sec in case of error
|
||||||
|
eventMgr.addListener("onPeriodicRun", _.throttle(startRealtimeSync, 15000));
|
||||||
|
// Stop realtime sync if synchronized location is removed
|
||||||
|
eventMgr.addListener("onSyncRemoved", function(fileDesc, syncAttributes) {
|
||||||
|
fileDesc === fileMgr.currentFile && syncAttributes.isRealtime && syncAttributes.provider.stopRealtimeSync();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
@ -368,11 +368,6 @@ define([
|
|||||||
syncAttributes.isRealtime = true;
|
syncAttributes.isRealtime = true;
|
||||||
fileDesc.addSyncLocation(syncAttributes);
|
fileDesc.addSyncLocation(syncAttributes);
|
||||||
eventMgr.onSyncExportSuccess(fileDesc, syncAttributes);
|
eventMgr.onSyncExportSuccess(fileDesc, syncAttributes);
|
||||||
|
|
||||||
// Start the real time sync
|
|
||||||
realtimeFileDesc = fileDesc;
|
|
||||||
realtimeSyncAttributes = syncAttributes;
|
|
||||||
tryStartRealtimeSync();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -13,7 +13,7 @@ define([
|
|||||||
// Faster than setTimeout (see http://dbaron.org/log/20100309-faster-timeouts)
|
// Faster than setTimeout (see http://dbaron.org/log/20100309-faster-timeouts)
|
||||||
utils.defer = (function() {
|
utils.defer = (function() {
|
||||||
var timeouts = [];
|
var timeouts = [];
|
||||||
var messageName = "delay";
|
var messageName = "deferMsg";
|
||||||
window.addEventListener("message", function(evt) {
|
window.addEventListener("message", function(evt) {
|
||||||
if(evt.source == window && evt.data == messageName) {
|
if(evt.source == window && evt.data == messageName) {
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
|
Loading…
Reference in New Issue
Block a user