Skip to content

Commit a55ece0

Browse files
committed
Improved checkCursorMenu and checkCursorTag performance and fully rewrite its position method for UX and verified
1 parent ea70314 commit a55ece0

1 file changed

Lines changed: 82 additions & 48 deletions

File tree

public/js/index.js

Lines changed: 82 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ var defaultExtraKeys = {
5454

5555
var idleTime = 300000; //5 mins
5656
var updateViewDebounce = 200;
57-
var cursorMenuThrottle = 100;
57+
var cursorMenuThrottle = 50;
5858
var cursorActivityDebounce = 50;
5959
var cursorAnimatePeriod = 100;
6060
var supportContainers = ['success', 'info', 'warning', 'danger'];
@@ -531,6 +531,8 @@ var ui = {
531531
view: $(".ui-view-area"),
532532
codemirror: $(".ui-edit-area .CodeMirror"),
533533
codemirrorScroll: $(".ui-edit-area .CodeMirror .CodeMirror-scroll"),
534+
codemirrorSizer: $(".ui-edit-area .CodeMirror .CodeMirror-sizer"),
535+
codemirrorSizerInner: $(".ui-edit-area .CodeMirror .CodeMirror-sizer > div"),
534536
markdown: $(".ui-view-area .markdown-body")
535537
}
536538
};
@@ -1897,33 +1899,41 @@ function emitUserStatus(force) {
18971899
}
18981900

18991901
function checkCursorTag(coord, ele) {
1900-
if (!ele) return;
1901-
var curosrtagMargin = 60;
1902-
var cursor = editor.getCursor();
1903-
//var viewport = editor.getViewport();
1904-
//var viewportHeight = (viewport.to - viewport.from) * editor.defaultTextHeight();
1902+
if (!ele) return; // return if element not exists
1903+
// set margin
1904+
var tagRightMargin = 0;
1905+
var tagBottomMargin = 2;
1906+
// use sizer to get the real doc size (won't count status bar and gutters)
1907+
var docWidth = ui.area.codemirrorSizer.width();
1908+
var docHeight = ui.area.codemirrorSizer.height();
1909+
// get editor size (status bar not count in)
19051910
var editorWidth = ui.area.codemirror.width();
19061911
var editorHeight = ui.area.codemirror.height();
1907-
var width = ele.width();
1908-
var height = ele.height();
1909-
if (!lineHeightMap)
1910-
buildMapInner();
1912+
// get element size
1913+
var width = ele.outerWidth();
1914+
var height = ele.outerHeight();
1915+
var padding = (ele.outerWidth() - ele.width()) / 2;
1916+
// get coord position
19111917
var left = coord.left;
1912-
var top = lineHeightMap[cursor.line] * defaultTextHeight; //coord.top;
1913-
top -= ele.closest('.CodeMirror-sizer > *').position().top;
1918+
var top = coord.top;
1919+
// get doc top offset (to workaround with viewport)
1920+
var docTopOffset = ui.area.codemirrorSizerInner.position().top;
1921+
// set offset
19141922
var offsetLeft = -3;
19151923
var offsetTop = defaultTextHeight;
1916-
var statusBarHeight = 0;
1917-
if (statusBar)
1918-
statusBarHeight = statusBar.outerHeight();
1924+
// only do when have width and height
19191925
if (width > 0 && height > 0) {
1920-
if (left + width + offsetLeft > editorWidth - curosrtagMargin) {
1921-
offsetLeft = -(width + 10);
1926+
// flip x when element right bound larger than doc width
1927+
if (left + width + offsetLeft + tagRightMargin > docWidth) {
1928+
offsetLeft = -(width + tagRightMargin) + padding + offsetLeft;
19221929
}
1923-
if (top + height + offsetTop > Math.max(editor.doc.height, editorHeight) + curosrtagMargin - statusBarHeight * 2 && top - height > curosrtagMargin) {
1924-
offsetTop = -(height + 4);
1930+
// flip y when element bottom bound larger than doc height
1931+
// and element top position is larger than element height
1932+
if (top + docTopOffset + height + offsetTop + tagBottomMargin > Math.max(editor.doc.height, editorHeight) && top + docTopOffset > height + tagBottomMargin) {
1933+
offsetTop = -(height);
19251934
}
19261935
}
1936+
// set position
19271937
ele[0].style.left = offsetLeft + 'px';
19281938
ele[0].style.top = offsetTop + 'px';
19291939
}
@@ -2464,56 +2474,80 @@ if ($('.cursor-menu').length <= 0) {
24642474
$("<div class='cursor-menu'>").insertAfter('.CodeMirror-cursors');
24652475
}
24662476

2477+
function reverseSortCursorMenu(dropdown) {
2478+
var items = dropdown.find('.textcomplete-item');
2479+
items.sort(function (a, b) {
2480+
return $(b).attr('data-index') - $(a).attr('data-index');
2481+
});
2482+
return items;
2483+
}
2484+
2485+
var lastUpSideDown = false;
24672486
var upSideDown = false;
24682487

24692488
var checkCursorMenu = _.throttle(checkCursorMenuInner, cursorMenuThrottle);
24702489

24712490
function checkCursorMenuInner() {
2472-
var menuMargin = 60;
2473-
var dropdown = $('.cursor-menu .dropdown-menu');
2491+
// get element
2492+
var dropdown = $('.cursor-menu > .dropdown-menu');
2493+
// return if not exists
24742494
if (dropdown.length <= 0) return;
2495+
// set margin
2496+
var menuRightMargin = 10;
2497+
var menuBottomMargin = 4;
2498+
// use sizer to get the real doc size (won't count status bar and gutters)
2499+
var docWidth = ui.area.codemirrorSizer.width();
2500+
var docHeight = ui.area.codemirrorSizer.height();
2501+
// get editor size (status bar not count in)
2502+
var editorWidth = ui.area.codemirror.width();
2503+
var editorHeight = ui.area.codemirror.height();
2504+
// get element size
2505+
var width = dropdown.outerWidth();
2506+
var height = dropdown.outerHeight();
2507+
// get cursor
24752508
var cursor = editor.getCursor();
2476-
var scrollInfo = editor.getScrollInfo();
2509+
// set element cursor data
24772510
if (!dropdown.hasClass('other-cursor'))
24782511
dropdown.addClass('other-cursor');
24792512
dropdown.attr('data-line', cursor.line);
24802513
dropdown.attr('data-ch', cursor.ch);
2514+
// get coord position
24812515
var coord = editor.charCoords({
24822516
line: cursor.line,
24832517
ch: cursor.ch
24842518
}, 'windows');
2485-
//var viewport = editor.getViewport();
2486-
//var viewportHeight = (viewport.to - viewport.from) * editor.defaultTextHeight();
2487-
var editorWidth = ui.area.codemirror.width();
2488-
var editorHeight = ui.area.codemirror.height();
2489-
var width = dropdown.outerWidth();
2490-
var height = dropdown.outerHeight();
2491-
if (!lineHeightMap)
2492-
buildMapInner();
24932519
var left = coord.left;
2494-
var top = lineHeightMap[cursor.line] * defaultTextHeight; //coord.top;
2495-
top -= dropdown.closest('.CodeMirror-sizer > *').position().top;
2520+
var top = coord.top;
2521+
// get doc top offset (to workaround with viewport)
2522+
var docTopOffset = ui.area.codemirrorSizerInner.position().top;
2523+
// set offset
24962524
var offsetLeft = 0;
24972525
var offsetTop = defaultTextHeight;
2498-
var statusBarHeight = 0;
2499-
if (statusBar)
2500-
statusBarHeight = statusBar.outerHeight();
2501-
if (left + width + offsetLeft > editorWidth - menuMargin)
2502-
offsetLeft = -(left + width - editorWidth + menuMargin);
2503-
if (top + height + offsetTop > Math.max(editor.doc.height, editorHeight) + menuMargin - statusBarHeight * 2 && top - height > menuMargin) {
2504-
offsetTop = -(height + 4);
2505-
upSideDown = true;
2506-
var items = dropdown.find('.textcomplete-item');
2507-
items.sort(function (a, b) {
2508-
return $(b).attr('data-index') - $(a).attr('data-index');
2509-
});
2510-
dropdown.html(items);
2511-
dropdown.scrollTop(dropdown[0].scrollHeight);
2512-
} else {
2513-
upSideDown = false;
2526+
// only do when have width and height
2527+
if (width > 0 && height > 0) {
2528+
// make element right bound not larger than doc width
2529+
if (left + width + offsetLeft + menuRightMargin > docWidth)
2530+
offsetLeft = -(left + width - docWidth + menuRightMargin);
2531+
// flip y when element bottom bound larger than doc height
2532+
// and element top position is larger than element height
2533+
if (top + docTopOffset + height + offsetTop + menuBottomMargin > Math.max(editor.doc.height, editorHeight) && top + docTopOffset > height + menuBottomMargin) {
2534+
offsetTop = -(height + menuBottomMargin);
2535+
// reverse sort menu because upSideDown
2536+
dropdown.html(reverseSortCursorMenu(dropdown));
2537+
lastUpSideDown = upSideDown;
2538+
upSideDown = true;
2539+
} else {
2540+
lastUpSideDown = upSideDown;
2541+
upSideDown = false;
2542+
}
25142543
}
2544+
// make menu scroll top only if upSideDown changed
2545+
if (upSideDown !== lastUpSideDown)
2546+
dropdown.scrollTop(dropdown[0].scrollHeight);
2547+
// set element offset data
25152548
dropdown.attr('data-offset-left', offsetLeft);
25162549
dropdown.attr('data-offset-top', offsetTop);
2550+
// set position
25172551
dropdown[0].style.left = left + offsetLeft + 'px';
25182552
dropdown[0].style.top = top + offsetTop + 'px';
25192553
}

0 commit comments

Comments
 (0)