@@ -59,7 +59,7 @@ var CodeMirror = (function() {
5959 var shiftSelecting , reducedSelection ;
6060 // Variables used by startOperation/endOperation to track what
6161 // happened during the operation.
62- var updateInput , changes , textChanged , selectionChanged ;
62+ var updateInput , changes , textChanged , selectionChanged , leaveInputAlone ;
6363 // Current visible range (may be bigger than the view window).
6464 var showingFrom = 0 , showingTo = 0 , lastHeight = 0 , curKeyId = null ;
6565 // editing will hold an object describing the things we put in the
@@ -75,6 +75,10 @@ var CodeMirror = (function() {
7575
7676 // Register our event handlers.
7777 connect ( wrapper , "mousedown" , operation ( onMouseDown ) ) ;
78+ // Gecko browsers fire contextmenu *after* opening the menu, at
79+ // which point we can't mess with it anymore. Context menu is
80+ // handled in onMouseDown for Gecko.
81+ if ( ! gecko ) connect ( wrapper , "contextmenu" , operation ( onContextMenu ) ) ;
7882 connect ( code , "dblclick" , operation ( onDblClick ) ) ;
7983 connect ( wrapper , "scroll" , function ( ) { updateDisplay ( [ ] ) ; if ( options . onScroll ) options . onScroll ( instance ) ; } ) ;
8084 connect ( window , "resize" , function ( ) { updateDisplay ( true ) ; } ) ;
@@ -89,6 +93,7 @@ var CodeMirror = (function() {
8993 connect ( wrapper , "drop" , operation ( onDrop ) ) ;
9094 connect ( wrapper , "paste" , function ( ) { input . focus ( ) ; fastPoll ( ) ; } ) ;
9195 connect ( input , "paste" , function ( ) { fastPoll ( ) ; } ) ;
96+ connect ( input , "cut" , function ( ) { fastPoll ( ) ; } ) ;
9297
9398 if ( document . activeElement == input ) onFocus ( ) ;
9499 else onBlur ( ) ;
@@ -194,12 +199,13 @@ var CodeMirror = (function() {
194199 return e . stop ( ) ;
195200 }
196201
202+ if ( gecko && e . button ( ) == 3 ) onContextMenu ( e ) ;
203+ if ( e . button ( ) != 1 ) return ;
197204 // For button 1, if it was clicked inside the editor
198205 // (posFromMouse returning non-null), we have to adjust the
199206 // selection.
200207 var start = posFromMouse ( e ) , last = start , going ;
201208 if ( ! start ) { if ( e . target ( ) == wrapper ) e . stop ( ) ; return ; }
202- if ( e . button ( ) != 1 ) return ; // TODO can we make copy/cut context menu work?
203209 setCursor ( start . line , start . ch , false ) ;
204210
205211 if ( ! focused ) onFocus ( ) ;
@@ -1053,6 +1059,29 @@ var CodeMirror = (function() {
10531059 var line = showingFrom + Math . floor ( y / lineHeight ( ) ) ;
10541060 return clipPos ( { line : line , ch : charFromX ( clipLine ( line ) , x ) } ) ;
10551061 }
1062+ function onContextMenu ( e ) {
1063+ var pos = posFromMouse ( e ) ;
1064+ if ( ! pos || window . opera ) return ; // Opera is difficult.
1065+ if ( posEq ( sel . from , sel . to ) || posLess ( pos , sel . from ) || ! posLess ( pos , sel . to ) )
1066+ setCursor ( pos . line , pos . ch ) ;
1067+
1068+ var oldCSS = input . style . cssText ;
1069+ input . style . cssText = "position: fixed; width: 30px; height: 30px; top: " + ( e . pageY ( ) - 1 ) +
1070+ "px; left: " + ( e . pageX ( ) - 1 ) + "px; z-index: 1000; background: white; " +
1071+ "border-width: 0; outline: none; overflow: hidden;" ;
1072+ var val = input . value = getSelection ( ) ;
1073+ input . focus ( ) ;
1074+ setSelRange ( input , 0 , val . length ) ;
1075+ if ( gecko ) e . stop ( ) ;
1076+ leaveInputAlone = true ;
1077+ setTimeout ( function ( ) {
1078+ if ( input . value != val ) operation ( replaceSelection ) ( input . value , "end" ) ;
1079+ input . style . cssText = oldCSS ;
1080+ leaveInputAlone = false ;
1081+ prepareInput ( ) ;
1082+ slowPoll ( ) ;
1083+ } , 50 ) ;
1084+ }
10561085
10571086 // Cursor-blinking
10581087 function restartBlink ( ) {
@@ -1183,7 +1212,7 @@ var CodeMirror = (function() {
11831212
11841213 // updateInput can be set to a boolean value to force/prevent an
11851214 // update.
1186- if ( updateInput === true || ( updateInput !== false && selectionChanged ) )
1215+ if ( ! leaveInputAlone && ( updateInput === true || ( updateInput !== false && selectionChanged ) ) )
11871216 prepareInput ( ) ;
11881217
11891218 if ( selectionChanged && options . onCursorActivity )
@@ -1742,6 +1771,8 @@ var CodeMirror = (function() {
17421771 pre . innerHTML = " " ; return ! pre . innerHTML ;
17431772 } ) ( ) ;
17441773
1774+ var gecko = / g e c k o \/ \d { 7 } / i. test ( navigator . userAgent ) ;
1775+
17451776 var lineSep = "\n" ;
17461777 // Feature-detect whether newlines in textareas are converted to \r\n
17471778 ( function ( ) {
0 commit comments