Update to improve syncscroll performance and add toggle for sync scrolling
This commit is contained in:
parent
bf1dc237a9
commit
b28750f256
3 changed files with 132 additions and 136 deletions
|
@ -112,6 +112,17 @@ body {
|
|||
background-color: white;
|
||||
box-shadow: 5px 0px 10px #e7e7e7;
|
||||
}
|
||||
.ui-edit-area .ui-sync-toggle {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
padding: 3px 1px 0 0;
|
||||
border-radius: 50%;
|
||||
border-color: #e7e7e7;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
.ui-view-area {
|
||||
/*overflow-y: scroll;*/
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
|
|
@ -552,7 +552,11 @@ var ui = {
|
|||
codemirrorScroll: $(".ui-edit-area .CodeMirror .CodeMirror-scroll"),
|
||||
codemirrorSizer: $(".ui-edit-area .CodeMirror .CodeMirror-sizer"),
|
||||
codemirrorSizerInner: $(".ui-edit-area .CodeMirror .CodeMirror-sizer > div"),
|
||||
markdown: $(".ui-view-area .markdown-body")
|
||||
markdown: $(".ui-view-area .markdown-body"),
|
||||
resize: {
|
||||
handle: $('.ui-resizable-handle'),
|
||||
syncToggle: $('.ui-sync-toggle')
|
||||
}
|
||||
},
|
||||
modal: {
|
||||
snippetImportProjects: $("#snippetImportModalProjects"),
|
||||
|
@ -705,30 +709,6 @@ $(window).error(function () {
|
|||
//setNeedRefresh();
|
||||
});
|
||||
|
||||
//when page hash change
|
||||
window.onhashchange = locationHashChanged;
|
||||
|
||||
function locationHashChanged(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
if (currentMode != modeType.both) {
|
||||
return;
|
||||
}
|
||||
var hashtarget = $("[id$='" + location.hash.substr(1) + "']");
|
||||
if (hashtarget.length > 0) {
|
||||
var linenumber = hashtarget.attr('data-startline');
|
||||
if (linenumber) {
|
||||
editor.setOption('viewportMargin', Infinity);
|
||||
editor.setOption('viewportMargin', viewportMargin);
|
||||
var t = editor.charCoords({
|
||||
line: linenumber,
|
||||
ch: 0
|
||||
}, "local").top;
|
||||
editor.scrollTo(null, t - defaultTextHeight * 1.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var windowResizeDebounce = 200;
|
||||
var windowResize = _.debounce(windowResizeInner, windowResizeDebounce);
|
||||
|
||||
|
@ -814,10 +794,38 @@ function checkEditorStyle() {
|
|||
handles: 'e',
|
||||
maxWidth: $(window).width() * 0.7,
|
||||
minWidth: $(window).width() * 0.2,
|
||||
resize: function (e) {
|
||||
ui.area.resize.syncToggle.stop(true, true).show();
|
||||
},
|
||||
stop: function (e) {
|
||||
lastEditorWidth = ui.area.edit.width();
|
||||
}
|
||||
});
|
||||
if (!ui.area.resize.handle.length) {
|
||||
ui.area.resize.handle = $('.ui-resizable-handle');
|
||||
}
|
||||
if (!ui.area.resize.syncToggle.length) {
|
||||
ui.area.resize.syncToggle = $('<button class="btn btn-lg btn-default ui-sync-toggle" title="Toggle sync scrolling"><i class="fa fa-link fa-fw"></i></button>');
|
||||
ui.area.resize.syncToggle.click(function () {
|
||||
syncscroll = !syncscroll;
|
||||
checkSyncToggle();
|
||||
});
|
||||
ui.area.resize.handle.append(ui.area.resize.syncToggle);
|
||||
ui.area.resize.syncToggle.hide();
|
||||
ui.area.resize.handle.hover(function () {
|
||||
ui.area.resize.syncToggle.stop(true, true).delay(200).fadeIn(100);
|
||||
}, function () {
|
||||
ui.area.resize.syncToggle.stop(true, true).delay(300).fadeOut(300);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function checkSyncToggle() {
|
||||
if (syncscroll) {
|
||||
ui.area.resize.syncToggle.find('i').removeClass('fa-unlink').addClass('fa-link');
|
||||
} else {
|
||||
ui.area.resize.syncToggle.find('i').removeClass('fa-link').addClass('fa-unlink');
|
||||
}
|
||||
}
|
||||
|
||||
function checkEditorScrollbar() {
|
||||
|
@ -984,10 +992,10 @@ function changeMode(type) {
|
|||
ui.area.edit.css('width', lastEditorWidth + 'px');
|
||||
else
|
||||
ui.area.edit.css('width', '');
|
||||
ui.area.edit.find('.ui-resizable-handle').show();
|
||||
ui.area.resize.handle.show();
|
||||
} else {
|
||||
ui.area.edit.css('width', '');
|
||||
ui.area.edit.find('.ui-resizable-handle').hide();
|
||||
ui.area.resize.handle.hide();
|
||||
}
|
||||
|
||||
windowResizeInner();
|
||||
|
@ -995,6 +1003,7 @@ function changeMode(type) {
|
|||
restoreInfo();
|
||||
|
||||
if (lastMode == modeType.view && currentMode == modeType.both) {
|
||||
preventSyncScrollToView = true;
|
||||
syncScrollToEdit();
|
||||
}
|
||||
|
||||
|
|
|
@ -105,10 +105,13 @@ md.use(window.markdownitContainer, 'info', { render: renderContainer });
|
|||
md.use(window.markdownitContainer, 'warning', { render: renderContainer });
|
||||
md.use(window.markdownitContainer, 'danger', { render: renderContainer });
|
||||
|
||||
var preventSyncScroll = false;
|
||||
var syncscroll = true;
|
||||
|
||||
var preventSyncScrollToEdit = false;
|
||||
var preventSyncScrollToView = false;
|
||||
|
||||
var editScrollThrottle = 1;
|
||||
var viewScrollThrottle = 20;
|
||||
var viewScrollThrottle = 10;
|
||||
var buildMapThrottle = 100;
|
||||
|
||||
var viewScrolling = false;
|
||||
|
@ -126,71 +129,6 @@ if (editor.getOption('scrollbarStyle') === 'native') {
|
|||
}
|
||||
ui.area.view.on('scroll', _.throttle(syncScrollToEdit, viewScrollThrottle));
|
||||
|
||||
var preventViewScroll = false;
|
||||
|
||||
function syncScrollToEdit(e) {
|
||||
if (currentMode != modeType.both) return;
|
||||
if (preventViewScroll) {
|
||||
if (typeof preventViewScroll === 'number') {
|
||||
preventViewScroll--;
|
||||
} else {
|
||||
preventViewScroll = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!scrollMap || !lineHeightMap) {
|
||||
buildMap(true);
|
||||
return;
|
||||
}
|
||||
if (editScrolling) return;
|
||||
var scrollTop = ui.area.view[0].scrollTop;
|
||||
var lineIndex = 0;
|
||||
for (var i = 0, l = scrollMap.length; i < l; i++) {
|
||||
if (scrollMap[i] > scrollTop) {
|
||||
break;
|
||||
} else {
|
||||
lineIndex = i;
|
||||
}
|
||||
}
|
||||
var lineNo = 0;
|
||||
var lineDiff = 0;
|
||||
for (var i = 0, l = lineHeightMap.length; i < l; i++) {
|
||||
if (lineHeightMap[i] > lineIndex) {
|
||||
break;
|
||||
} else {
|
||||
lineNo = lineHeightMap[i];
|
||||
lineDiff = lineHeightMap[i + 1] - lineNo;
|
||||
}
|
||||
}
|
||||
|
||||
var scrollInfo = editor.getScrollInfo();
|
||||
var textHeight = editor.defaultTextHeight();
|
||||
var posTo = 0;
|
||||
var topDiffPercent = 0;
|
||||
var posToNextDiff = 0;
|
||||
var preLastLineHeight = scrollInfo.height - scrollInfo.clientHeight - textHeight;
|
||||
var preLastLineNo = Math.round(preLastLineHeight / textHeight);
|
||||
|
||||
if (scrollInfo.height > scrollInfo.clientHeight && lineNo >= preLastLineNo) {
|
||||
posTo = preLastLineHeight;
|
||||
topDiffPercent = (scrollTop - scrollMap[preLastLineNo]) / (viewBottom - scrollMap[preLastLineNo]);
|
||||
posToNextDiff = Math.ceil(textHeight * topDiffPercent);
|
||||
} else {
|
||||
posTo = lineNo * textHeight;
|
||||
topDiffPercent = (scrollTop - scrollMap[lineNo]) / (scrollMap[lineNo + lineDiff] - scrollMap[lineNo]);
|
||||
posToNextDiff = Math.ceil(textHeight * lineDiff * topDiffPercent);
|
||||
}
|
||||
|
||||
editor.scrollTo(0, posTo + posToNextDiff);
|
||||
preventSyncScroll = true;
|
||||
|
||||
viewScrolling = true;
|
||||
clearTimeout(viewScrollingTimer);
|
||||
viewScrollingTimer = setTimeout(function () {
|
||||
viewScrolling = false;
|
||||
}, viewScrollingDelay);
|
||||
}
|
||||
|
||||
var scrollMap, lineHeightMap, viewTop, viewBottom;
|
||||
|
||||
viewAjaxCallback = clearMap;
|
||||
|
@ -279,60 +217,98 @@ function buildMapInner(syncBack) {
|
|||
scrollMap = _scrollMap;
|
||||
lineHeightMap = _lineHeightMap;
|
||||
|
||||
if (loaded && syncBack)
|
||||
if (loaded && syncBack) {
|
||||
syncScrollToView();
|
||||
syncScrollToEdit();
|
||||
}
|
||||
}
|
||||
|
||||
function getPartByEditorLineNo(lineNo) {
|
||||
var part = null;
|
||||
ui.area.markdown.find('.part').each(function (n, el) {
|
||||
if (part) return;
|
||||
var $el = $(el),
|
||||
t = $el.data('startline') - 1,
|
||||
f = $el.data('endline') - 1;
|
||||
if (t === '' || f === '') {
|
||||
return;
|
||||
}
|
||||
if (lineNo >= t && lineNo <= f) {
|
||||
part = $el;
|
||||
}
|
||||
});
|
||||
if (part)
|
||||
return {
|
||||
startline: part.data('startline') - 1,
|
||||
endline: part.data('endline') - 1,
|
||||
linediff: Math.abs(part.data('endline') - part.data('startline')) + 1,
|
||||
element: part
|
||||
};
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
function getEditorLineNoByTop(top) {
|
||||
for (var i = 0; i < lineHeightMap.length; i++)
|
||||
if (lineHeightMap[i] * editor.defaultTextHeight() > top)
|
||||
return i;
|
||||
return null;
|
||||
}
|
||||
|
||||
function syncScrollToView(event, _lineNo) {
|
||||
if (currentMode != modeType.both) return;
|
||||
if (preventSyncScroll) {
|
||||
if (typeof preventSyncScroll === 'number') {
|
||||
preventSyncScroll--;
|
||||
function syncScrollToEdit(e) {
|
||||
if (currentMode != modeType.both || !syncscroll) return;
|
||||
if (preventSyncScrollToEdit) {
|
||||
if (typeof preventSyncScrollToEdit === 'number') {
|
||||
preventSyncScrollToEdit--;
|
||||
} else {
|
||||
preventSyncScroll = false;
|
||||
preventSyncScrollToEdit = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
var lineNo, posTo;
|
||||
var scrollInfo = editor.getScrollInfo();
|
||||
if (!scrollMap || !lineHeightMap) {
|
||||
buildMap(true);
|
||||
return;
|
||||
}
|
||||
if (editScrolling) return;
|
||||
|
||||
var scrollTop = ui.area.view[0].scrollTop;
|
||||
var lineIndex = 0;
|
||||
for (var i = 0, l = scrollMap.length; i < l; i++) {
|
||||
if (scrollMap[i] > scrollTop) {
|
||||
break;
|
||||
} else {
|
||||
lineIndex = i;
|
||||
}
|
||||
}
|
||||
var lineNo = 0;
|
||||
var lineDiff = 0;
|
||||
for (var i = 0, l = lineHeightMap.length; i < l; i++) {
|
||||
if (lineHeightMap[i] > lineIndex) {
|
||||
break;
|
||||
} else {
|
||||
lineNo = lineHeightMap[i];
|
||||
lineDiff = lineHeightMap[i + 1] - lineNo;
|
||||
}
|
||||
}
|
||||
|
||||
var posTo = 0;
|
||||
var topDiffPercent = 0;
|
||||
var posToNextDiff = 0;
|
||||
var scrollInfo = editor.getScrollInfo();
|
||||
var textHeight = editor.defaultTextHeight();
|
||||
var preLastLineHeight = scrollInfo.height - scrollInfo.clientHeight - textHeight;
|
||||
var preLastLineNo = Math.round(preLastLineHeight / textHeight);
|
||||
var preLastLinePos = scrollMap[preLastLineNo];
|
||||
|
||||
if (scrollInfo.height > scrollInfo.clientHeight && scrollTop >= preLastLinePos) {
|
||||
posTo = preLastLineHeight;
|
||||
topDiffPercent = (scrollTop - preLastLinePos) / (viewBottom - preLastLinePos);
|
||||
posToNextDiff = Math.ceil(textHeight * topDiffPercent);
|
||||
} else {
|
||||
posTo = lineNo * textHeight;
|
||||
topDiffPercent = (scrollTop - scrollMap[lineNo]) / (scrollMap[lineNo + lineDiff] - scrollMap[lineNo]);
|
||||
posToNextDiff = Math.ceil(textHeight * lineDiff * topDiffPercent);
|
||||
}
|
||||
|
||||
editor.scrollTo(0, posTo + posToNextDiff);
|
||||
preventSyncScrollToView = true;
|
||||
|
||||
viewScrolling = true;
|
||||
clearTimeout(viewScrollingTimer);
|
||||
viewScrollingTimer = setTimeout(function () {
|
||||
viewScrolling = false;
|
||||
}, viewScrollingDelay);
|
||||
}
|
||||
|
||||
function syncScrollToView(event, _lineNo) {
|
||||
if (currentMode != modeType.both || !syncscroll) return;
|
||||
if (preventSyncScrollToView) {
|
||||
if (typeof preventSyncScrollToView === 'number') {
|
||||
preventSyncScrollToView--;
|
||||
} else {
|
||||
preventSyncScrollToView = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!scrollMap || !lineHeightMap) {
|
||||
buildMap(true);
|
||||
return;
|
||||
}
|
||||
if (viewScrolling) return;
|
||||
|
||||
if (!_lineNo) {
|
||||
var lineNo, posTo;
|
||||
var topDiffPercent, posToNextDiff;
|
||||
var scrollInfo = editor.getScrollInfo();
|
||||
var textHeight = editor.defaultTextHeight();
|
||||
lineNo = Math.floor(scrollInfo.top / textHeight);
|
||||
// if reach the last line, will start lerp to the bottom
|
||||
|
@ -349,11 +325,11 @@ function syncScrollToView(event, _lineNo) {
|
|||
posTo += Math.floor(posToNextDiff);
|
||||
}
|
||||
} else {
|
||||
if (viewScrolling) return;
|
||||
posTo = scrollMap[lineHeightMap[_lineNo]];
|
||||
}
|
||||
|
||||
ui.area.view.stop(true, true).scrollTop(posTo);
|
||||
preventViewScroll = true;
|
||||
preventSyncScrollToEdit = true;
|
||||
|
||||
editScrolling = true;
|
||||
clearTimeout(editScrollingTimer);
|
||||
|
|
Loading…
Reference in a new issue