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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -568,8 +568,8 @@ define([
});
// Also listen to "save success" event
doc.addEventListener(gapi.drive.realtime.EventType.DOCUMENT_SAVE_STATE_CHANGED, function(e) {
if(e.isPending === false && e.isSaving === false) {
doc.addEventListener(gapi.drive.realtime.EventType.DOCUMENT_SAVE_STATE_CHANGED, function(evt) {
if(evt.isPending === false && evt.isSaving === false) {
updateCRCs();
}
});
@ -587,16 +587,8 @@ define([
setUndoRedoButtonStates = pagedownEditor.uiManager.setUndoRedoButtonStates;
// Set temporary actions for undo/redo buttons
pagedownEditor.uiManager.buttons.undo.execute = function() {
if(model.canUndo) {
model.undo();
}
};
pagedownEditor.uiManager.buttons.redo.execute = function() {
if(model.canRedo) {
model.redo();
}
};
pagedownEditor.uiManager.buttons.undo.execute = model.undo;
pagedownEditor.uiManager.buttons.redo.execute = model.redo;
// Add event handler for model's UndoRedoStateChanged events
pagedownEditor.uiManager.setUndoRedoButtonStates = _.debounce(function() {
@ -620,7 +612,7 @@ define([
gdriveProvider.stopRealtimeSync();
}
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();
}
});

View File

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

View File

@ -10,6 +10,40 @@ define([
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
utils.getURLParameter = function(name) {
// Parameter can be either a search parameter (&name=...) or a hash fragment parameter (#!name=...)