mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-29 16:14:22 -05:00
Improved checkCursorMenu and checkCursorTag performance and fully rewrite its position method for UX and verified
This commit is contained in:
parent
ea703145c5
commit
a55ece023a
1 changed files with 82 additions and 48 deletions
|
@ -54,7 +54,7 @@ var defaultExtraKeys = {
|
||||||
|
|
||||||
var idleTime = 300000; //5 mins
|
var idleTime = 300000; //5 mins
|
||||||
var updateViewDebounce = 200;
|
var updateViewDebounce = 200;
|
||||||
var cursorMenuThrottle = 100;
|
var cursorMenuThrottle = 50;
|
||||||
var cursorActivityDebounce = 50;
|
var cursorActivityDebounce = 50;
|
||||||
var cursorAnimatePeriod = 100;
|
var cursorAnimatePeriod = 100;
|
||||||
var supportContainers = ['success', 'info', 'warning', 'danger'];
|
var supportContainers = ['success', 'info', 'warning', 'danger'];
|
||||||
|
@ -531,6 +531,8 @@ var ui = {
|
||||||
view: $(".ui-view-area"),
|
view: $(".ui-view-area"),
|
||||||
codemirror: $(".ui-edit-area .CodeMirror"),
|
codemirror: $(".ui-edit-area .CodeMirror"),
|
||||||
codemirrorScroll: $(".ui-edit-area .CodeMirror .CodeMirror-scroll"),
|
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")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1897,33 +1899,41 @@ function emitUserStatus(force) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkCursorTag(coord, ele) {
|
function checkCursorTag(coord, ele) {
|
||||||
if (!ele) return;
|
if (!ele) return; // return if element not exists
|
||||||
var curosrtagMargin = 60;
|
// set margin
|
||||||
var cursor = editor.getCursor();
|
var tagRightMargin = 0;
|
||||||
//var viewport = editor.getViewport();
|
var tagBottomMargin = 2;
|
||||||
//var viewportHeight = (viewport.to - viewport.from) * editor.defaultTextHeight();
|
// use sizer to get the real doc size (won't count status bar and gutters)
|
||||||
|
var docWidth = ui.area.codemirrorSizer.width();
|
||||||
|
var docHeight = ui.area.codemirrorSizer.height();
|
||||||
|
// get editor size (status bar not count in)
|
||||||
var editorWidth = ui.area.codemirror.width();
|
var editorWidth = ui.area.codemirror.width();
|
||||||
var editorHeight = ui.area.codemirror.height();
|
var editorHeight = ui.area.codemirror.height();
|
||||||
var width = ele.width();
|
// get element size
|
||||||
var height = ele.height();
|
var width = ele.outerWidth();
|
||||||
if (!lineHeightMap)
|
var height = ele.outerHeight();
|
||||||
buildMapInner();
|
var padding = (ele.outerWidth() - ele.width()) / 2;
|
||||||
|
// get coord position
|
||||||
var left = coord.left;
|
var left = coord.left;
|
||||||
var top = lineHeightMap[cursor.line] * defaultTextHeight; //coord.top;
|
var top = coord.top;
|
||||||
top -= ele.closest('.CodeMirror-sizer > *').position().top;
|
// get doc top offset (to workaround with viewport)
|
||||||
|
var docTopOffset = ui.area.codemirrorSizerInner.position().top;
|
||||||
|
// set offset
|
||||||
var offsetLeft = -3;
|
var offsetLeft = -3;
|
||||||
var offsetTop = defaultTextHeight;
|
var offsetTop = defaultTextHeight;
|
||||||
var statusBarHeight = 0;
|
// only do when have width and height
|
||||||
if (statusBar)
|
|
||||||
statusBarHeight = statusBar.outerHeight();
|
|
||||||
if (width > 0 && height > 0) {
|
if (width > 0 && height > 0) {
|
||||||
if (left + width + offsetLeft > editorWidth - curosrtagMargin) {
|
// flip x when element right bound larger than doc width
|
||||||
offsetLeft = -(width + 10);
|
if (left + width + offsetLeft + tagRightMargin > docWidth) {
|
||||||
|
offsetLeft = -(width + tagRightMargin) + padding + offsetLeft;
|
||||||
}
|
}
|
||||||
if (top + height + offsetTop > Math.max(editor.doc.height, editorHeight) + curosrtagMargin - statusBarHeight * 2 && top - height > curosrtagMargin) {
|
// flip y when element bottom bound larger than doc height
|
||||||
offsetTop = -(height + 4);
|
// and element top position is larger than element height
|
||||||
|
if (top + docTopOffset + height + offsetTop + tagBottomMargin > Math.max(editor.doc.height, editorHeight) && top + docTopOffset > height + tagBottomMargin) {
|
||||||
|
offsetTop = -(height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// set position
|
||||||
ele[0].style.left = offsetLeft + 'px';
|
ele[0].style.left = offsetLeft + 'px';
|
||||||
ele[0].style.top = offsetTop + 'px';
|
ele[0].style.top = offsetTop + 'px';
|
||||||
}
|
}
|
||||||
|
@ -2464,56 +2474,80 @@ if ($('.cursor-menu').length <= 0) {
|
||||||
$("<div class='cursor-menu'>").insertAfter('.CodeMirror-cursors');
|
$("<div class='cursor-menu'>").insertAfter('.CodeMirror-cursors');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function reverseSortCursorMenu(dropdown) {
|
||||||
|
var items = dropdown.find('.textcomplete-item');
|
||||||
|
items.sort(function (a, b) {
|
||||||
|
return $(b).attr('data-index') - $(a).attr('data-index');
|
||||||
|
});
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastUpSideDown = false;
|
||||||
var upSideDown = false;
|
var upSideDown = false;
|
||||||
|
|
||||||
var checkCursorMenu = _.throttle(checkCursorMenuInner, cursorMenuThrottle);
|
var checkCursorMenu = _.throttle(checkCursorMenuInner, cursorMenuThrottle);
|
||||||
|
|
||||||
function checkCursorMenuInner() {
|
function checkCursorMenuInner() {
|
||||||
var menuMargin = 60;
|
// get element
|
||||||
var dropdown = $('.cursor-menu .dropdown-menu');
|
var dropdown = $('.cursor-menu > .dropdown-menu');
|
||||||
|
// return if not exists
|
||||||
if (dropdown.length <= 0) return;
|
if (dropdown.length <= 0) return;
|
||||||
|
// set margin
|
||||||
|
var menuRightMargin = 10;
|
||||||
|
var menuBottomMargin = 4;
|
||||||
|
// use sizer to get the real doc size (won't count status bar and gutters)
|
||||||
|
var docWidth = ui.area.codemirrorSizer.width();
|
||||||
|
var docHeight = ui.area.codemirrorSizer.height();
|
||||||
|
// get editor size (status bar not count in)
|
||||||
|
var editorWidth = ui.area.codemirror.width();
|
||||||
|
var editorHeight = ui.area.codemirror.height();
|
||||||
|
// get element size
|
||||||
|
var width = dropdown.outerWidth();
|
||||||
|
var height = dropdown.outerHeight();
|
||||||
|
// get cursor
|
||||||
var cursor = editor.getCursor();
|
var cursor = editor.getCursor();
|
||||||
var scrollInfo = editor.getScrollInfo();
|
// set element cursor data
|
||||||
if (!dropdown.hasClass('other-cursor'))
|
if (!dropdown.hasClass('other-cursor'))
|
||||||
dropdown.addClass('other-cursor');
|
dropdown.addClass('other-cursor');
|
||||||
dropdown.attr('data-line', cursor.line);
|
dropdown.attr('data-line', cursor.line);
|
||||||
dropdown.attr('data-ch', cursor.ch);
|
dropdown.attr('data-ch', cursor.ch);
|
||||||
|
// get coord position
|
||||||
var coord = editor.charCoords({
|
var coord = editor.charCoords({
|
||||||
line: cursor.line,
|
line: cursor.line,
|
||||||
ch: cursor.ch
|
ch: cursor.ch
|
||||||
}, 'windows');
|
}, 'windows');
|
||||||
//var viewport = editor.getViewport();
|
|
||||||
//var viewportHeight = (viewport.to - viewport.from) * editor.defaultTextHeight();
|
|
||||||
var editorWidth = ui.area.codemirror.width();
|
|
||||||
var editorHeight = ui.area.codemirror.height();
|
|
||||||
var width = dropdown.outerWidth();
|
|
||||||
var height = dropdown.outerHeight();
|
|
||||||
if (!lineHeightMap)
|
|
||||||
buildMapInner();
|
|
||||||
var left = coord.left;
|
var left = coord.left;
|
||||||
var top = lineHeightMap[cursor.line] * defaultTextHeight; //coord.top;
|
var top = coord.top;
|
||||||
top -= dropdown.closest('.CodeMirror-sizer > *').position().top;
|
// get doc top offset (to workaround with viewport)
|
||||||
|
var docTopOffset = ui.area.codemirrorSizerInner.position().top;
|
||||||
|
// set offset
|
||||||
var offsetLeft = 0;
|
var offsetLeft = 0;
|
||||||
var offsetTop = defaultTextHeight;
|
var offsetTop = defaultTextHeight;
|
||||||
var statusBarHeight = 0;
|
// only do when have width and height
|
||||||
if (statusBar)
|
if (width > 0 && height > 0) {
|
||||||
statusBarHeight = statusBar.outerHeight();
|
// make element right bound not larger than doc width
|
||||||
if (left + width + offsetLeft > editorWidth - menuMargin)
|
if (left + width + offsetLeft + menuRightMargin > docWidth)
|
||||||
offsetLeft = -(left + width - editorWidth + menuMargin);
|
offsetLeft = -(left + width - docWidth + menuRightMargin);
|
||||||
if (top + height + offsetTop > Math.max(editor.doc.height, editorHeight) + menuMargin - statusBarHeight * 2 && top - height > menuMargin) {
|
// flip y when element bottom bound larger than doc height
|
||||||
offsetTop = -(height + 4);
|
// and element top position is larger than element height
|
||||||
upSideDown = true;
|
if (top + docTopOffset + height + offsetTop + menuBottomMargin > Math.max(editor.doc.height, editorHeight) && top + docTopOffset > height + menuBottomMargin) {
|
||||||
var items = dropdown.find('.textcomplete-item');
|
offsetTop = -(height + menuBottomMargin);
|
||||||
items.sort(function (a, b) {
|
// reverse sort menu because upSideDown
|
||||||
return $(b).attr('data-index') - $(a).attr('data-index');
|
dropdown.html(reverseSortCursorMenu(dropdown));
|
||||||
});
|
lastUpSideDown = upSideDown;
|
||||||
dropdown.html(items);
|
upSideDown = true;
|
||||||
dropdown.scrollTop(dropdown[0].scrollHeight);
|
} else {
|
||||||
} else {
|
lastUpSideDown = upSideDown;
|
||||||
upSideDown = false;
|
upSideDown = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// make menu scroll top only if upSideDown changed
|
||||||
|
if (upSideDown !== lastUpSideDown)
|
||||||
|
dropdown.scrollTop(dropdown[0].scrollHeight);
|
||||||
|
// set element offset data
|
||||||
dropdown.attr('data-offset-left', offsetLeft);
|
dropdown.attr('data-offset-left', offsetLeft);
|
||||||
dropdown.attr('data-offset-top', offsetTop);
|
dropdown.attr('data-offset-top', offsetTop);
|
||||||
|
// set position
|
||||||
dropdown[0].style.left = left + offsetLeft + 'px';
|
dropdown[0].style.left = left + offsetLeft + 'px';
|
||||||
dropdown[0].style.top = top + offsetTop + 'px';
|
dropdown[0].style.top = top + offsetTop + 'px';
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue