Skip to content

Commit f2f5650

Browse files
committed
try our best to handle context-menu clicks
1 parent 4202a6e commit f2f5650

File tree

2 files changed

+34
-4
lines changed

2 files changed

+34
-4
lines changed

lib/codemirror.css

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,5 @@ span.CodeMirror-selected {
4545
background: Highlight !important;
4646
}
4747

48-
4948
.CodeMirror-matchingbracket {color: #0f0 !important;}
5049
.CodeMirror-nonmatchingbracket {color: #f22 !important;}

lib/codemirror.js

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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 = /gecko\/\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

Comments
 (0)