@@ -54,7 +54,7 @@ var defaultExtraKeys = {
5454
5555var idleTime = 300000 ; //5 mins
5656var updateViewDebounce = 200 ;
57- var cursorMenuThrottle = 100 ;
57+ var cursorMenuThrottle = 50 ;
5858var cursorActivityDebounce = 50 ;
5959var cursorAnimatePeriod = 100 ;
6060var 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
18991901function 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 ;
24672486var upSideDown = false ;
24682487
24692488var checkCursorMenu = _ . throttle ( checkCursorMenuInner , cursorMenuThrottle ) ;
24702489
24712490function 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