Implemented fast defer

This commit is contained in:
benweet 2014-04-09 00:20:48 +01:00
parent 6d8ed95352
commit ea77258cac
13 changed files with 112 additions and 94 deletions

View File

@ -214,9 +214,7 @@ define([
patch = diffMatchPatch.patch_make(oldContent, diffs); patch = diffMatchPatch.patch_make(oldContent, diffs);
var patchResult = diffMatchPatch.patch_apply(patch, remoteContent); var patchResult = diffMatchPatch.patch_apply(patch, remoteContent);
newContent = patchResult[0]; newContent = patchResult[0];
if(patchResult[1].some(function(patchSuccess) { if(!patchResult[1].every(_.identity)) {
return !patchSuccess;
})) {
// Remaining conflicts // Remaining conflicts
diffs = diffMatchPatch.diff_main(localContent, newContent); diffs = diffMatchPatch.diff_main(localContent, newContent);
diffs = cleanupDiffs(diffs); diffs = cleanupDiffs(diffs);
@ -328,8 +326,7 @@ define([
} }
if(contentChanged || discussionListChanged) { if(contentChanged || discussionListChanged) {
var self = this; editor.watcher.noWatch(_.bind(function() {
editor.watcher.noWatch(function() {
if(contentChanged) { if(contentChanged) {
if(!/\n$/.test(newContent)) { if(!/\n$/.test(newContent)) {
newContent += '\n'; newContent += '\n';
@ -363,11 +360,11 @@ define([
} }
editor.undoMgr.currentMode = 'sync'; editor.undoMgr.currentMode = 'sync';
editor.undoMgr.saveState(); editor.undoMgr.saveState();
eventMgr.onMessage('"' + remoteTitle + '" has been updated from ' + self.providerName + '.'); eventMgr.onMessage('"' + remoteTitle + '" has been updated from ' + this.providerName + '.');
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);
} }
// Return remote CRCs // Return remote CRCs

View File

@ -826,7 +826,7 @@ define([
if(openedTooltip && openedTooltip[0] === elt) { if(openedTooltip && openedTooltip[0] === elt) {
return; return;
} }
_.defer(function() { utils.defer(function() {
$(document).on("click.close-tooltip", function() { $(document).on("click.close-tooltip", function() {
openedTooltip && openedTooltip.tooltip('hide'); openedTooltip && openedTooltip.tooltip('hide');
openedTooltip = undefined; openedTooltip = undefined;

View File

@ -3,6 +3,7 @@
define([ define([
'jquery', 'jquery',
'underscore', 'underscore',
'utils',
'settings', 'settings',
'eventMgr', 'eventMgr',
'prism-core', 'prism-core',
@ -12,7 +13,7 @@ define([
'rangy', 'rangy',
'MutationObservers', 'MutationObservers',
'libs/prism-markdown' 'libs/prism-markdown'
], function ($, _, settings, eventMgr, Prism, diff_match_patch, jsondiffpatch, crel, rangy) { ], function ($, _, utils, settings, eventMgr, Prism, diff_match_patch, jsondiffpatch, crel, rangy) {
var editor = {}; var editor = {};
var scrollTop = 0; var scrollTop = 0;
@ -213,7 +214,7 @@ define([
} }
undoMgr.saveSelectionState(); undoMgr.saveSelectionState();
} }
var debouncedSave = _.debounce(save, 0); var debouncedSave = utils.debounce(save);
return function(debounced) { return function(debounced) {
debounced ? debouncedSave() : save(); debounced ? debouncedSave() : save();
}; };
@ -287,12 +288,10 @@ define([
} }
var selectionMgr = new SelectionMgr(); var selectionMgr = new SelectionMgr();
editor.selectionMgr = selectionMgr; editor.selectionMgr = selectionMgr;
$(document).on('selectionchange', function() { $(document).on('selectionchange', _.bind(selectionMgr.saveSelectionState, selectionMgr, true));
selectionMgr.saveSelectionState(true);
});
var adjustCursorPosition = (function() { var adjustCursorPosition = (function() {
var adjust = _.debounce(function() { var adjust = utils.debounce(function() {
var adjust = inputElt.offsetHeight / 2; var adjust = inputElt.offsetHeight / 2;
if(adjust > 130) { if(adjust > 130) {
adjust = 130; adjust = 130;
@ -305,7 +304,7 @@ define([
else if(selectionMgr.cursorY > cursorMaxY) { else if(selectionMgr.cursorY > cursorMaxY) {
inputElt.scrollTop += selectionMgr.cursorY - cursorMaxY; inputElt.scrollTop += selectionMgr.cursorY - cursorMaxY;
} }
}, 0); });
return function() { return function() {
if(inputElt === undefined) { if(inputElt === undefined) {
return; return;
@ -365,7 +364,7 @@ define([
}; };
this.setMode = function() {}; // For compatibility with PageDown this.setMode = function() {}; // For compatibility with PageDown
this.onButtonStateChange = function() {}; // To be overridden by PageDown this.onButtonStateChange = function() {}; // To be overridden by PageDown
this.saveState = _.debounce(function() { this.saveState = utils.debounce(function() {
redoStack = []; redoStack = [];
var currentTime = Date.now(); var currentTime = Date.now();
if(this.currentMode == 'comment' || (this.currentMode != lastMode && lastMode != 'newlines') || currentTime - lastTime > 1000) { if(this.currentMode == 'comment' || (this.currentMode != lastMode && lastMode != 'newlines') || currentTime - lastTime > 1000) {
@ -391,7 +390,7 @@ define([
lastMode = this.currentMode; lastMode = this.currentMode;
this.currentMode = undefined; this.currentMode = undefined;
this.onButtonStateChange(); this.onButtonStateChange();
}, 0); }, this);
this.saveSelectionState = _.debounce(function() { this.saveSelectionState = _.debounce(function() {
if(this.currentMode === undefined) { if(this.currentMode === undefined) {
selectionStartBefore = selectionMgr.selectionStart; selectionStartBefore = selectionMgr.selectionStart;
@ -404,7 +403,6 @@ define([
this.canRedo = function() { this.canRedo = function() {
return redoStack.length; return redoStack.length;
}; };
var self = this;
function restoreState(state, selectionStart, selectionEnd) { function restoreState(state, selectionStart, selectionEnd) {
// Update editor // Update editor
watcher.noWatch(function() { watcher.noWatch(function() {
@ -439,9 +437,9 @@ define([
selectionStartBefore = selectionStart; selectionStartBefore = selectionStart;
selectionEndBefore = selectionEnd; selectionEndBefore = selectionEnd;
currentState = state; currentState = state;
self.currentMode = undefined; this.currentMode = undefined;
lastMode = undefined; lastMode = undefined;
self.onButtonStateChange(); this.onButtonStateChange();
adjustCursorPosition(); adjustCursorPosition();
} }
this.undo = function() { this.undo = function() {
@ -450,7 +448,7 @@ define([
return; return;
} }
redoStack.push(currentState); redoStack.push(currentState);
restoreState(state, currentState.selectionStartBefore, currentState.selectionEndBefore); restoreState.call(this, state, currentState.selectionStartBefore, currentState.selectionEndBefore);
}; };
this.redo = function() { this.redo = function() {
var state = redoStack.pop(); var state = redoStack.pop();
@ -458,7 +456,7 @@ define([
return; return;
} }
undoStack.push(currentState); undoStack.push(currentState);
restoreState(state, state.selectionStartAfter, state.selectionEndAfter); restoreState.call(this, state, state.selectionStartAfter, state.selectionEndAfter);
}; };
this.init = function() { this.init = function() {
var content = fileDesc.content; var content = fileDesc.content;
@ -481,7 +479,7 @@ define([
function onComment() { function onComment() {
if(watcher.isWatching === true) { if(watcher.isWatching === true) {
undoMgr.currentMode = 'comment'; undoMgr.currentMode = undoMgr.currentMode || 'comment';
undoMgr.saveState(); undoMgr.saveState();
} }
} }
@ -490,19 +488,19 @@ define([
eventMgr.addListener('onCommentsChanged', onComment); eventMgr.addListener('onCommentsChanged', onComment);
function checkContentChange() { function checkContentChange() {
var currentTextContent = inputElt.textContent; var newTextContent = inputElt.textContent;
if(fileChanged === false) { if(fileChanged === false) {
if(currentTextContent == textContent) { if(newTextContent == textContent) {
return; return;
} }
if(!/\n$/.test(currentTextContent)) { if(!/\n$/.test(newTextContent)) {
currentTextContent += '\n'; newTextContent += '\n';
} }
undoMgr.currentMode = undoMgr.currentMode || 'typing'; undoMgr.currentMode = undoMgr.currentMode || 'typing';
var discussionList = _.values(fileDesc.discussionList); var discussionList = _.values(fileDesc.discussionList);
fileDesc.newDiscussion && discussionList.push(fileDesc.newDiscussion); fileDesc.newDiscussion && discussionList.push(fileDesc.newDiscussion);
var updateDiscussionList = adjustCommentOffsets(textContent, currentTextContent, discussionList); var updateDiscussionList = adjustCommentOffsets(textContent, newTextContent, discussionList);
textContent = currentTextContent; textContent = newTextContent;
if(updateDiscussionList === true) { if(updateDiscussionList === true) {
fileDesc.discussionList = fileDesc.discussionList; // Write discussionList in localStorage fileDesc.discussionList = fileDesc.discussionList; // Write discussionList in localStorage
} }
@ -513,11 +511,11 @@ define([
undoMgr.saveState(); undoMgr.saveState();
} }
else { else {
if(!/\n$/.test(currentTextContent)) { textContent = newTextContent;
currentTextContent += '\n'; if(!/\n$/.test(textContent)) {
fileDesc.content = currentTextContent; textContent += '\n';
fileDesc.content = textContent;
} }
textContent = currentTextContent;
selectionMgr.setSelectionStartEnd(fileDesc.editorStart, fileDesc.editorEnd); selectionMgr.setSelectionStartEnd(fileDesc.editorStart, fileDesc.editorEnd);
eventMgr.onFileOpen(fileDesc, textContent); eventMgr.onFileOpen(fileDesc, textContent);
previewElt.scrollTop = fileDesc.previewScrollTop; previewElt.scrollTop = fileDesc.previewScrollTop;
@ -575,10 +573,10 @@ define([
} }
editor.adjustCommentOffsets = adjustCommentOffsets; editor.adjustCommentOffsets = adjustCommentOffsets;
editor.init = function(elt1, elt2) { editor.init = function(inputEltParam, previewEltParam) {
inputElt = elt1; inputElt = inputEltParam;
$inputElt = $(inputElt); $inputElt = $(inputElt);
previewElt = elt2; previewElt = previewEltParam;
contentElt = crel('div', { contentElt = crel('div', {
class: 'editor-content', class: 'editor-content',
@ -676,9 +674,7 @@ define([
clearNewline = false; clearNewline = false;
} }
}) })
.on('mouseup', function() { .on('mouseup', _.bind(selectionMgr.saveSelectionState, selectionMgr, true))
selectionMgr.saveSelectionState(true);
})
.on('paste', function () { .on('paste', function () {
undoMgr.currentMode = 'paste'; undoMgr.currentMode = 'paste';
adjustCursorPosition(); adjustCursorPosition();

View File

@ -228,7 +228,7 @@ define([
logger.log("onAsyncPreview"); logger.log("onAsyncPreview");
function recursiveCall(callbackList) { function recursiveCall(callbackList) {
var callback = callbackList.length ? callbackList.shift() : function() { var callback = callbackList.length ? callbackList.shift() : function() {
_.defer(function() { setTimeout(function() {
var html = ""; var html = "";
_.each(previewContentsElt.children, function(elt) { _.each(previewContentsElt.children, function(elt) {
html += elt.innerHTML; html += elt.innerHTML;
@ -236,7 +236,7 @@ define([
var htmlWithComments = utils.trim(html); var htmlWithComments = utils.trim(html);
var htmlWithoutComments = htmlWithComments.replace(/ <span class="comment label label-danger">.*?<\/span> /g, ''); var htmlWithoutComments = htmlWithComments.replace(/ <span class="comment label label-danger">.*?<\/span> /g, '');
onPreviewFinished(htmlWithComments, htmlWithoutComments); onPreviewFinished(htmlWithComments, htmlWithoutComments);
}); }, 10);
}; };
callback(function() { callback(function() {
recursiveCall(callbackList); recursiveCall(callbackList);

View File

@ -44,14 +44,14 @@ define([
buttonHtmlCode.onReady = function() { buttonHtmlCode.onReady = function() {
var textareaElt = document.getElementById('input-html-code'); var textareaElt = document.getElementById('input-html-code');
$(".action-html-code").click(function() { $(".action-html-code").click(function() {
_.defer(function() { setTimeout(function() {
$("#input-html-code").each(function() { $("#input-html-code").each(function() {
if($(this).is(":hidden")) { if($(this).is(":hidden")) {
return; return;
} }
this.select(); this.select();
}); });
}); }, 10);
}).parent().on('show.bs.dropdown', function() { }).parent().on('show.bs.dropdown', function() {
try { try {
var htmlCode = _.template(buttonHtmlCode.config.template, { var htmlCode = _.template(buttonHtmlCode.config.template, {

View File

@ -170,7 +170,7 @@ define([
marginElt.appendChild(commentElt); marginElt.appendChild(commentElt);
commentEltMap[discussion.discussionIndex] = commentElt; commentEltMap[discussion.discussionIndex] = commentElt;
if(currentContext && currentContext.getDiscussion() == discussion) { if(currentContext && currentContext.getDiscussion() === discussion) {
inputElt.scrollTop += parseInt(commentElt.style.top) - inputElt.scrollTop - inputElt.offsetHeight * 3 / 4; inputElt.scrollTop += parseInt(commentElt.style.top) - inputElt.scrollTop - inputElt.offsetHeight * 3 / 4;
movePopover(commentElt); movePopover(commentElt);
} }
@ -179,6 +179,7 @@ define([
clearTimeout(refreshTimeoutId); clearTimeout(refreshTimeoutId);
refreshTimeoutId = setTimeout(refreshOne, 5); refreshTimeoutId = setTimeout(refreshOne, 5);
}, 50); }, 50);
comments.onLayoutResize = refreshDiscussions;
comments.onFileOpen = function(fileDesc) { comments.onFileOpen = function(fileDesc) {
currentFileDesc = fileDesc; currentFileDesc = fileDesc;
@ -237,10 +238,6 @@ define([
} }
}; };
comments.onLayoutResize = function() {
refreshDiscussions();
};
function getDiscussionComments() { function getDiscussionComments() {
var discussion = currentContext.getDiscussion(); var discussion = currentContext.getDiscussion();
var author = storage['author.name']; var author = storage['author.name'];
@ -310,29 +307,28 @@ define([
closeCurrentPopover(); closeCurrentPopover();
var context = new Context(evt.target, currentFileDesc); var context = new Context(evt.target, currentFileDesc);
currentContext = context; currentContext = context;
// If it's not an existing discussion
var discussion = context.getDiscussion();
if(!discussion) {
// Get selected text
var selectionStart = Math.min(selectionMgr.selectionStart, selectionMgr.selectionEnd);
var selectionEnd = Math.max(selectionMgr.selectionStart, selectionMgr.selectionEnd);
if(selectionStart === selectionEnd) {
var offset = selectionMgr.getClosestWordOffset(selectionStart);
selectionStart = offset.start;
selectionEnd = offset.end;
}
discussion = {
selectionStart: selectionStart,
selectionEnd: selectionEnd,
commentList: []
};
currentFileDesc.newDiscussion = discussion;
}
context.selectionRange = selectionMgr.setSelectionStartEnd(discussion.selectionStart, discussion.selectionEnd, undefined, true);
inputElt.scrollTop += parseInt(evt.target.style.top) - inputElt.scrollTop - inputElt.offsetHeight * 3 / 4; inputElt.scrollTop += parseInt(evt.target.style.top) - inputElt.scrollTop - inputElt.offsetHeight * 3 / 4;
// If it's an existing discussion
var discussion = context.getDiscussion();
if(discussion) {
context.selectionRange = selectionMgr.setSelectionStartEnd(discussion.selectionStart, discussion.selectionEnd, undefined, true);
return;
}
// Get selected text
var selectionStart = Math.min(selectionMgr.selectionStart, selectionMgr.selectionEnd);
var selectionEnd = Math.max(selectionMgr.selectionStart, selectionMgr.selectionEnd);
if(selectionStart === selectionEnd) {
var offset = selectionMgr.getClosestWordOffset(selectionStart);
selectionStart = offset.start;
selectionEnd = offset.end;
}
context.selectionRange = selectionMgr.setSelectionStartEnd(selectionStart, selectionEnd, undefined, true);
currentFileDesc.newDiscussion = {
selectionStart: selectionStart,
selectionEnd: selectionEnd,
commentList: []
};
}).on('shown.bs.popover', '#wmd-input > .editor-margin', function(evt) { }).on('shown.bs.popover', '#wmd-input > .editor-margin', function(evt) {
var context = currentContext; var context = currentContext;
var popoverElt = context.getPopoverElt(); var popoverElt = context.getPopoverElt();

View File

@ -130,9 +130,9 @@ define([
liIndex = -1; liIndex = -1;
} }
selectedLi = liEltList[(liIndex + liEltList.length) % liEltList.length]; selectedLi = liEltList[(liIndex + liEltList.length) % liEltList.length];
_.defer(function() { setTimeout(function() {
selectedLi.find("a").focus(); selectedLi.find("a").focus();
}); }, 10);
return false; return false;
}); });
var shortcutNext = documentSelector.config.shortcutNext.toLowerCase(); var shortcutNext = documentSelector.config.shortcutNext.toLowerCase();
@ -143,9 +143,9 @@ define([
} }
var liIndex = _.indexOf(liEltList, selectedLi) + 1; var liIndex = _.indexOf(liEltList, selectedLi) + 1;
selectedLi = liEltList[liIndex % liEltList.length]; selectedLi = liEltList[liIndex % liEltList.length];
_.defer(function() { setTimeout(function() {
selectedLi.find("a").focus(); selectedLi.find("a").focus();
}); }, 10);
return false; return false;
}); });
var delimiter1 = shortcutPrevious.indexOf("+"); var delimiter1 = shortcutPrevious.indexOf("+");

View File

@ -143,9 +143,9 @@ define([
$previewElt.scrollTop(lastPreviewScrollTop); $previewElt.scrollTop(lastPreviewScrollTop);
}, },
done: function() { done: function() {
_.defer(function() { setTimeout(function() {
isPreviewMoving = false; isPreviewMoving = false;
}); }, 10);
}, },
}).dequeue('scrollLinkFx'); }).dequeue('scrollLinkFx');
@ -179,9 +179,9 @@ define([
$editorElt.scrollTop(lastEditorScrollTop); $editorElt.scrollTop(lastEditorScrollTop);
}, },
done: function() { done: function() {
_.defer(function() { setTimeout(function() {
isEditorMoving = false; isEditorMoving = false;
}); }, 10);
}, },
}).dequeue('scrollLinkFx'); }).dequeue('scrollLinkFx');
} }

View File

@ -186,9 +186,9 @@ define([
} }
$fileTitleElt.addClass('hide'); $fileTitleElt.addClass('hide');
var fileTitleInput = $fileTitleInputElt.removeClass('hide'); var fileTitleInput = $fileTitleInputElt.removeClass('hide');
_.defer(function() { setTimeout(function() {
fileTitleInput.focus().get(0).select(); fileTitleInput.focus().get(0).select();
}); }, 10);
}); });
function applyTitle() { function applyTitle() {
$fileTitleInputElt.addClass('hide'); $fileTitleInputElt.addClass('hide');

View File

@ -8,7 +8,7 @@
</div> </div>
<a data-toggle="collapse" data-parent=".accordion-extensions" <a data-toggle="collapse" data-parent=".accordion-extensions"
class="accordion-toggle" href="#accordion-extensions-collapse-<%= extensionId %>"> class="accordion-toggle" href="#accordion-extensions-collapse-<%= extensionId %>">
<%= extensionName %> </a> <%= extensionName %> <i class="icon-down-dir"></i></a>
</div> </div>
<div id="accordion-extensions-collapse-<%= extensionId %>" class="collapse"> <div id="accordion-extensions-collapse-<%= extensionId %>" class="collapse">
<div class="accordion-inner clearfix"><%= settingsBlock %></div> <div class="accordion-inner clearfix"><%= settingsBlock %></div>

View File

@ -568,8 +568,8 @@ define([
}); });
// Also listen to "save success" event // Also listen to "save success" event
doc.addEventListener(gapi.drive.realtime.EventType.DOCUMENT_SAVE_STATE_CHANGED, function(e) { doc.addEventListener(gapi.drive.realtime.EventType.DOCUMENT_SAVE_STATE_CHANGED, function(evt) {
if(e.isPending === false && e.isSaving === false) { if(evt.isPending === false && evt.isSaving === false) {
updateCRCs(); updateCRCs();
} }
}); });
@ -587,16 +587,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 = function() { pagedownEditor.uiManager.buttons.undo.execute = model.undo;
if(model.canUndo) { pagedownEditor.uiManager.buttons.redo.execute = model.redo;
model.undo();
}
};
pagedownEditor.uiManager.buttons.redo.execute = function() {
if(model.canRedo) {
model.redo();
}
};
// 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() {
@ -620,7 +612,7 @@ define([
gdriveProvider.stopRealtimeSync(); gdriveProvider.stopRealtimeSync();
} }
else if(err.isFatal) { else if(err.isFatal) {
eventMgr.onError('An error has forced real time synchronization to stop.'); eventMgr.onError('Real time synchronization is temporarily unavailable.');
gdriveProvider.stopRealtimeSync(); gdriveProvider.stopRealtimeSync();
} }
}); });

View File

@ -1473,12 +1473,15 @@ input[type="file"] {
color: @input-color; color: @input-color;
} }
.icon-comment { .icon-comment {
font-size: 14px; font-size: 15px;
color: fade(@label-warning-bg, 60%); color: fade(@label-warning-bg, 60%);
} }
.reply .icon-comment { .reply .icon-comment {
color: fade(@label-danger-bg, 70%); color: fade(@label-danger-bg, 70%);
} }
.new-comment-block .icon-comment {
color: fade(@tertiary-color, 35%);
}
.input-comment-author { .input-comment-author {
border: none; border: none;
background: none; background: none;

View File

@ -10,6 +10,40 @@ define([
var utils = {}; var utils = {};
// Faster than setTimeout (see http://dbaron.org/log/20100309-faster-timeouts)
utils.defer = (function() {
var timeouts = [];
var messageName = "delay";
window.addEventListener("message", function(evt) {
if(evt.source == window && evt.data == messageName) {
evt.stopPropagation();
if(timeouts.length > 0) {
timeouts.shift()();
}
}
}, true);
return function(fn) {
timeouts.push(fn);
window.postMessage(messageName, "*");
};
})();
// Implements underscore debounce using our defer function
utils.debounce = function(func, context) {
var isExpected = false;
function later() {
isExpected = false;
func.call(context);
}
return function() {
if(isExpected === true) {
return;
}
isExpected = true;
utils.defer(later);
};
};
// Return a parameter from the URL // Return a parameter from the URL
utils.getURLParameter = function(name) { utils.getURLParameter = function(name) {
// Parameter can be either a search parameter (&name=...) or a hash fragment parameter (#!name=...) // Parameter can be either a search parameter (&name=...) or a hash fragment parameter (#!name=...)