Fixed scrollsync perf issue

This commit is contained in:
benweet 2014-05-23 09:02:07 +01:00
parent 33cdc60610
commit c0b1c9107d

View File

@ -8,17 +8,13 @@ define([
var scrollSync = new Extension("scrollSync", "Scroll Sync", true, true); var scrollSync = new Extension("scrollSync", "Scroll Sync", true, true);
scrollSync.settingsBlock = scrollSyncSettingsBlockHTML; scrollSync.settingsBlock = scrollSyncSettingsBlockHTML;
$.easing.easeOutSine = function( p ) {
return Math.cos((1 - p) * Math.PI / 2 );
};
var sectionList; var sectionList;
scrollSync.onSectionsCreated = function(sectionListParam) { scrollSync.onSectionsCreated = function(sectionListParam) {
sectionList = sectionListParam; sectionList = sectionListParam;
}; };
var $editorElt; var editorElt;
var $previewElt; var previewElt;
var mdSectionList = []; var mdSectionList = [];
var htmlSectionList = []; var htmlSectionList = [];
var lastEditorScrollTop; var lastEditorScrollTop;
@ -27,16 +23,15 @@ define([
mdSectionList = []; mdSectionList = [];
var mdSectionOffset; var mdSectionOffset;
var scrollHeight; var scrollHeight;
var editorScrollTop = $editorElt.scrollTop(); _.each(editorElt.querySelectorAll(".wmd-input-section"), function(delimiterElt) {
$editorElt.find(".wmd-input-section").each(function() {
if(mdSectionOffset === undefined) { if(mdSectionOffset === undefined) {
// Force start to 0 for the first section // Force start to 0 for the first section
mdSectionOffset = 0; mdSectionOffset = 0;
return; return;
} }
var $delimiterElt = $(this.firstChild); delimiterElt = delimiterElt.firstChild;
// Consider div scroll position // Consider div scroll position
var newSectionOffset = $delimiterElt.position().top + editorScrollTop; var newSectionOffset = delimiterElt.offsetTop;
mdSectionList.push({ mdSectionList.push({
startOffset: mdSectionOffset, startOffset: mdSectionOffset,
endOffset: newSectionOffset, endOffset: newSectionOffset,
@ -45,7 +40,7 @@ define([
mdSectionOffset = newSectionOffset; mdSectionOffset = newSectionOffset;
}); });
// Last section // Last section
scrollHeight = $editorElt.prop('scrollHeight'); scrollHeight = editorElt.scrollHeight;
mdSectionList.push({ mdSectionList.push({
startOffset: mdSectionOffset, startOffset: mdSectionOffset,
endOffset: scrollHeight, endOffset: scrollHeight,
@ -55,16 +50,14 @@ define([
// Find corresponding sections in the preview // Find corresponding sections in the preview
htmlSectionList = []; htmlSectionList = [];
var htmlSectionOffset; var htmlSectionOffset;
var previewScrollTop = $previewElt.scrollTop(); _.each(previewElt.querySelectorAll(".wmd-preview-section"), function(delimiterElt) {
$previewElt.find(".wmd-preview-section").each(function() {
if(htmlSectionOffset === undefined) { if(htmlSectionOffset === undefined) {
// Force start to 0 for the first section // Force start to 0 for the first section
htmlSectionOffset = 0; htmlSectionOffset = 0;
return; return;
} }
var $delimiterElt = $(this);
// Consider div scroll position // Consider div scroll position
var newSectionOffset = $delimiterElt.position().top + previewScrollTop; var newSectionOffset = delimiterElt.offsetTop;
htmlSectionList.push({ htmlSectionList.push({
startOffset: htmlSectionOffset, startOffset: htmlSectionOffset,
endOffset: newSectionOffset, endOffset: newSectionOffset,
@ -73,7 +66,7 @@ define([
htmlSectionOffset = newSectionOffset; htmlSectionOffset = newSectionOffset;
}); });
// Last section // Last section
scrollHeight = $previewElt.prop('scrollHeight'); scrollHeight = previewElt.scrollHeight;
htmlSectionList.push({ htmlSectionList.push({
startOffset: htmlSectionOffset, startOffset: htmlSectionOffset,
endOffset: scrollHeight, endOffset: scrollHeight,
@ -91,6 +84,7 @@ define([
var isScrollPreview = false; var isScrollPreview = false;
var isEditorMoving = false; var isEditorMoving = false;
var isPreviewMoving = false; var isPreviewMoving = false;
function getDestScrollTop(srcScrollTop, srcSectionList, destSectionList) { function getDestScrollTop(srcScrollTop, srcSectionList, destSectionList) {
// Find the section corresponding to the offset // Find the section corresponding to the offset
var sectionIndex; var sectionIndex;
@ -109,6 +103,7 @@ define([
var timeoutId; var timeoutId;
var currentEndCb; var currentEndCb;
function animate(elt, startValue, endValue, stepCb, endCb) { function animate(elt, startValue, endValue, stepCb, endCb) {
if(currentEndCb) { if(currentEndCb) {
clearTimeout(timeoutId); clearTimeout(timeoutId);
@ -117,11 +112,12 @@ define([
currentEndCb = endCb; currentEndCb = endCb;
var diff = endValue - startValue; var diff = endValue - startValue;
var startTime = Date.now(); var startTime = Date.now();
function tick() { function tick() {
var currentTime = Date.now(); var currentTime = Date.now();
var progress = (currentTime - startTime) / 200; var progress = (currentTime - startTime) / 200;
if(progress < 1) { if(progress < 1) {
var scrollTop = startValue + diff * Math.cos((1 - progress) * Math.PI / 2 ); var scrollTop = startValue + diff * Math.cos((1 - progress) * Math.PI / 2);
elt.scrollTop = scrollTop; elt.scrollTop = scrollTop;
stepCb(scrollTop); stepCb(scrollTop);
timeoutId = setTimeout(tick, 1); timeoutId = setTimeout(tick, 1);
@ -132,6 +128,7 @@ define([
endCb(); endCb();
} }
} }
tick(); tick();
} }
@ -139,9 +136,9 @@ define([
if(!isPreviewVisible || mdSectionList.length === 0 || mdSectionList.length !== htmlSectionList.length) { if(!isPreviewVisible || mdSectionList.length === 0 || mdSectionList.length !== htmlSectionList.length) {
return; return;
} }
var editorScrollTop = $editorElt.scrollTop(); var editorScrollTop = editorElt.scrollTop;
editorScrollTop < 0 && (editorScrollTop = 0); editorScrollTop < 0 && (editorScrollTop = 0);
var previewScrollTop = $previewElt.scrollTop(); var previewScrollTop = previewElt.scrollTop;
var destScrollTop; var destScrollTop;
// Perform the animation if diff > 9px // Perform the animation if diff > 9px
if(isScrollEditor === true) { if(isScrollEditor === true) {
@ -154,14 +151,14 @@ define([
destScrollTop = getDestScrollTop(editorScrollTop, mdSectionList, htmlSectionList); destScrollTop = getDestScrollTop(editorScrollTop, mdSectionList, htmlSectionList);
destScrollTop = _.min([ destScrollTop = _.min([
destScrollTop, destScrollTop,
$previewElt.prop('scrollHeight') - $previewElt.outerHeight() previewElt.scrollHeight - previewElt.offsetHeight
]); ]);
if(Math.abs(destScrollTop - previewScrollTop) <= 9) { if(Math.abs(destScrollTop - previewScrollTop) <= 9) {
// Skip the animation if diff is <= 9 // Skip the animation if diff is <= 9
lastPreviewScrollTop = previewScrollTop; lastPreviewScrollTop = previewScrollTop;
return; return;
} }
animate($previewElt[0], previewScrollTop, destScrollTop, function(currentScrollTop) { animate(previewElt, previewScrollTop, destScrollTop, function(currentScrollTop) {
isPreviewMoving = true; isPreviewMoving = true;
lastPreviewScrollTop = currentScrollTop; lastPreviewScrollTop = currentScrollTop;
}, function() { }, function() {
@ -178,14 +175,14 @@ define([
destScrollTop = getDestScrollTop(previewScrollTop, htmlSectionList, mdSectionList); destScrollTop = getDestScrollTop(previewScrollTop, htmlSectionList, mdSectionList);
destScrollTop = _.min([ destScrollTop = _.min([
destScrollTop, destScrollTop,
$editorElt.prop('scrollHeight') - $editorElt.outerHeight() editorElt.scrollHeight - editorElt.offsetHeight
]); ]);
if(Math.abs(destScrollTop - editorScrollTop) <= 9) { if(Math.abs(destScrollTop - editorScrollTop) <= 9) {
// Skip the animation if diff is <= 9 // Skip the animation if diff is <= 9
lastEditorScrollTop = editorScrollTop; lastEditorScrollTop = editorScrollTop;
return; return;
} }
animate($editorElt[0], editorScrollTop, destScrollTop, function(currentScrollTop) { animate(editorElt, editorScrollTop, destScrollTop, function(currentScrollTop) {
isEditorMoving = true; isEditorMoving = true;
lastEditorScrollTop = currentScrollTop; lastEditorScrollTop = currentScrollTop;
}, function() { }, function() {
@ -205,10 +202,10 @@ define([
var scrollAdjust = false; var scrollAdjust = false;
scrollSync.onReady = function() { scrollSync.onReady = function() {
$previewElt = $(".preview-container"); previewElt = document.querySelector(".preview-container");
$editorElt = $("#wmd-input"); editorElt = document.querySelector("#wmd-input");
$previewElt.scroll(function() { $(previewElt).scroll(function() {
if(isPreviewMoving === false && scrollAdjust === false) { if(isPreviewMoving === false && scrollAdjust === false) {
isScrollPreview = true; isScrollPreview = true;
isScrollEditor = false; isScrollEditor = false;
@ -216,7 +213,7 @@ define([
} }
scrollAdjust = false; scrollAdjust = false;
}); });
$editorElt.scroll(function() { $(editorElt).scroll(function() {
if(isEditorMoving === false) { if(isEditorMoving === false) {
isScrollEditor = true; isScrollEditor = true;
isScrollPreview = false; isScrollPreview = false;
@ -234,32 +231,33 @@ define([
$('.extension-preview-buttons .table-of-contents').on('click', 'a', function(evt) { $('.extension-preview-buttons .table-of-contents').on('click', 'a', function(evt) {
evt.preventDefault(); evt.preventDefault();
var id = this.hash; var id = this.hash;
var $anchorElt = $previewElt.find(id); var anchorElt = previewElt.querySelector(id);
if(!$anchorElt.length) { if(!anchorElt) {
return; return;
} }
var previewScrollTop = $anchorElt.offset().top - $previewElt.offset().top + $previewElt.scrollTop(); var previewScrollTop = anchorElt.getBoundingClientRect().top - previewElt.getBoundingClientRect().top + previewElt.scrollTop;
$previewElt.scrollTop(previewScrollTop); previewElt.scrollTop = previewScrollTop;
var editorScrollTop = getDestScrollTop(previewScrollTop, htmlSectionList, mdSectionList); var editorScrollTop = getDestScrollTop(previewScrollTop, htmlSectionList, mdSectionList);
$editorElt.scrollTop(editorScrollTop); editorElt.scrollTop = editorScrollTop;
}); });
}; };
var $previewContentsElt; var previewContentsElt;
var previousHeight;
scrollSync.onPagedownConfigure = function(editor) { scrollSync.onPagedownConfigure = function(editor) {
$previewContentsElt = $("#preview-contents"); previewContentsElt = document.getElementById("preview-contents");
editor.getConverter().hooks.chain("postConversion", function(text) { editor.getConverter().hooks.chain("postConversion", function(text) {
// To avoid losing scrolling position before elements are fully loaded // To avoid losing scrolling position before elements are fully loaded
$previewContentsElt.height($previewContentsElt.height()); previousHeight = previewContentsElt.offsetHeight;
previewContentsElt.style.height = previousHeight + 'px';
return text; return text;
}); });
}; };
scrollSync.onPreviewFinished = function() { scrollSync.onPreviewFinished = function() {
// Now set the correct height // Now set the correct height
var previousHeight = $previewContentsElt.height(); previewContentsElt.style.removeProperty('height');
$previewContentsElt.height("auto"); var newHeight = previewContentsElt.offsetHeight;
var newHeight = $previewContentsElt.height();
isScrollEditor = true; isScrollEditor = true;
if(newHeight < previousHeight) { if(newHeight < previousHeight) {
// We expect a scroll adjustment // We expect a scroll adjustment