codemirror-rails 0.3.2 → 2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/codemirror/rails/version.rb +2 -2
- data/vendor/assets/javascripts/codemirror.js +501 -525
- data/vendor/assets/javascripts/codemirror/modes/clike.js +3 -1
- data/vendor/assets/javascripts/codemirror/modes/groovy.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/htmlembedded.js +68 -0
- data/vendor/assets/javascripts/codemirror/modes/javascript.js +3 -1
- data/vendor/assets/javascripts/codemirror/modes/markdown.js +4 -4
- data/vendor/assets/javascripts/codemirror/modes/php.js +3 -3
- data/vendor/assets/javascripts/codemirror/modes/python.js +17 -4
- data/vendor/assets/javascripts/codemirror/modes/rst.js +14 -21
- data/vendor/assets/javascripts/codemirror/modes/smalltalk.js +137 -130
- data/vendor/assets/javascripts/codemirror/modes/xml.js +32 -13
- data/vendor/assets/javascripts/codemirror/modes/xmlpure.js +6 -2
- data/vendor/assets/stylesheets/codemirror.css +41 -14
- data/vendor/assets/stylesheets/codemirror/modes/diff.css +3 -3
- data/vendor/assets/stylesheets/codemirror/themes/cobalt.css +1 -0
- data/vendor/assets/stylesheets/codemirror/themes/eclipse.css +3 -2
- data/vendor/assets/stylesheets/codemirror/themes/elegant.css +1 -0
- data/vendor/assets/stylesheets/codemirror/themes/monokai.css +22 -21
- data/vendor/assets/stylesheets/codemirror/themes/neat.css +1 -0
- data/vendor/assets/stylesheets/codemirror/themes/night.css +1 -0
- data/vendor/assets/stylesheets/codemirror/themes/rubyblue.css +1 -0
- metadata +5 -4
@@ -1,5 +1,5 @@
|
|
1
|
-
// CodeMirror
|
2
|
-
|
1
|
+
// CodeMirror version 2.2
|
2
|
+
//
|
3
3
|
// All functions that need access to the editor's state live inside
|
4
4
|
// the CodeMirror function. Below that, at the bottom of the file,
|
5
5
|
// some utilities are defined.
|
@@ -21,10 +21,10 @@ var CodeMirror = (function() {
|
|
21
21
|
wrapper.className = "CodeMirror" + (options.lineWrapping ? " CodeMirror-wrap" : "");
|
22
22
|
// This mess creates the base DOM structure for the editor.
|
23
23
|
wrapper.innerHTML =
|
24
|
-
'<div style="overflow: hidden; position: relative; width:
|
25
|
-
'<textarea style="position: absolute; width:
|
24
|
+
'<div style="overflow: hidden; position: relative; width: 3px; height: 0px;">' + // Wraps and hides input textarea
|
25
|
+
'<textarea style="position: absolute; padding: 0; width: 1px;" wrap="off" ' +
|
26
26
|
'autocorrect="off" autocapitalize="off"></textarea></div>' +
|
27
|
-
'<div class="CodeMirror-scroll
|
27
|
+
'<div class="CodeMirror-scroll" tabindex="-1">' +
|
28
28
|
'<div style="position: relative">' + // Set to the height of the text, causes scrolling
|
29
29
|
'<div style="position: relative">' + // Moved around its parent to cover visible view
|
30
30
|
'<div class="CodeMirror-gutter"><div class="CodeMirror-gutter-text"></div></div>' +
|
@@ -41,15 +41,18 @@ var CodeMirror = (function() {
|
|
41
41
|
mover = code.firstChild, gutter = mover.firstChild, gutterText = gutter.firstChild,
|
42
42
|
lineSpace = gutter.nextSibling.firstChild, measure = lineSpace.firstChild,
|
43
43
|
cursor = measure.nextSibling, lineDiv = cursor.nextSibling;
|
44
|
+
themeChanged();
|
45
|
+
// Needed to hide big blue blinking cursor on Mobile Safari
|
46
|
+
if (/AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent)) input.style.width = "0px";
|
44
47
|
if (!webkit) lineSpace.draggable = true;
|
45
|
-
if (options.tabindex != null) input.
|
48
|
+
if (options.tabindex != null) input.tabIndex = options.tabindex;
|
46
49
|
if (!options.gutter && !options.lineNumbers) gutter.style.display = "none";
|
47
50
|
|
48
51
|
// Check for problem with IE innerHTML not working when we have a
|
49
52
|
// P (or similar) parent node.
|
50
53
|
try { stringWidth("x"); }
|
51
54
|
catch (e) {
|
52
|
-
if (e.message.match(/
|
55
|
+
if (e.message.match(/runtime/i))
|
53
56
|
e = new Error("A CodeMirror inside a P-style element does not work in Internet Explorer. (innerHTML bug)");
|
54
57
|
throw e;
|
55
58
|
}
|
@@ -67,36 +70,25 @@ var CodeMirror = (function() {
|
|
67
70
|
// selecting bottom-to-top.
|
68
71
|
var sel = {from: {line: 0, ch: 0}, to: {line: 0, ch: 0}, inverted: false};
|
69
72
|
// Selection-related flags. shiftSelecting obviously tracks
|
70
|
-
// whether the user is holding shift.
|
71
|
-
|
72
|
-
// selections. See below.
|
73
|
-
var shiftSelecting, reducedSelection, lastClick, lastDoubleClick, draggingText;
|
73
|
+
// whether the user is holding shift.
|
74
|
+
var shiftSelecting, lastClick, lastDoubleClick, draggingText, overwrite = false;
|
74
75
|
// Variables used by startOperation/endOperation to track what
|
75
76
|
// happened during the operation.
|
76
|
-
var updateInput, changes, textChanged, selectionChanged, leaveInputAlone,
|
77
|
+
var updateInput, userSelChange, changes, textChanged, selectionChanged, leaveInputAlone,
|
78
|
+
gutterDirty, callbacks;
|
77
79
|
// Current visible range (may be bigger than the view window).
|
78
|
-
var displayOffset = 0, showingFrom = 0, showingTo = 0,
|
79
|
-
// editing will hold an object describing the things we put in the
|
80
|
-
// textarea, to help figure out whether something changed.
|
80
|
+
var displayOffset = 0, showingFrom = 0, showingTo = 0, lastSizeC = 0;
|
81
81
|
// bracketHighlighted is used to remember that a backet has been
|
82
82
|
// marked.
|
83
|
-
var
|
83
|
+
var bracketHighlighted;
|
84
84
|
// Tracks the maximum line length so that the horizontal scrollbar
|
85
85
|
// can be kept static when scrolling.
|
86
|
-
var maxLine = "", maxWidth;
|
86
|
+
var maxLine = "", maxWidth, tabText = computeTabText();
|
87
87
|
|
88
88
|
// Initialize the content.
|
89
89
|
operation(function(){setValue(options.value || ""); updateInput = false;})();
|
90
90
|
var history = new History();
|
91
91
|
|
92
|
-
var slowPollInterval = 2000;
|
93
|
-
// Gecko and Opera Linux do not reliably fire any event when starting an IME compose
|
94
|
-
var alwaysPollForIME = (!win && !mac) && (gecko || window.opera);
|
95
|
-
if (options.pollForIME && alwaysPollForIME) slowPollInterval = 50;
|
96
|
-
function keyMightStartIME(keyCode) {
|
97
|
-
return (win && ((gecko && keyCode == 229) || (window.opera && keyCode == 197))) || (mac && gecko);
|
98
|
-
}
|
99
|
-
|
100
92
|
// Register our event handlers.
|
101
93
|
connect(scroller, "mousedown", operation(onMouseDown));
|
102
94
|
connect(scroller, "dblclick", operation(onDoubleClick));
|
@@ -113,7 +105,7 @@ var CodeMirror = (function() {
|
|
113
105
|
});
|
114
106
|
connect(window, "resize", function() {updateDisplay(true);});
|
115
107
|
connect(input, "keyup", operation(onKeyUp));
|
116
|
-
connect(input, "input",
|
108
|
+
connect(input, "input", fastPoll);
|
117
109
|
connect(input, "keydown", operation(onKeyDown));
|
118
110
|
connect(input, "keypress", operation(onKeyPress));
|
119
111
|
connect(input, "focus", onFocus);
|
@@ -123,8 +115,8 @@ var CodeMirror = (function() {
|
|
123
115
|
connect(scroller, "dragover", e_stop);
|
124
116
|
connect(scroller, "drop", operation(onDrop));
|
125
117
|
connect(scroller, "paste", function(){focusInput(); fastPoll();});
|
126
|
-
connect(input, "paste",
|
127
|
-
connect(input, "cut", function(){
|
118
|
+
connect(input, "paste", fastPoll);
|
119
|
+
connect(input, "cut", operation(function(){replaceSelection("");}));
|
128
120
|
|
129
121
|
// IE throws unspecified error in certain cases, when
|
130
122
|
// trying to access activeElement before onload
|
@@ -148,10 +140,10 @@ var CodeMirror = (function() {
|
|
148
140
|
var oldVal = options[option];
|
149
141
|
options[option] = value;
|
150
142
|
if (option == "mode" || option == "indentUnit") loadMode();
|
151
|
-
else if (option == "readOnly" && value
|
152
|
-
else if (option == "theme")
|
143
|
+
else if (option == "readOnly" && value) {onBlur(); input.blur();}
|
144
|
+
else if (option == "theme") themeChanged();
|
153
145
|
else if (option == "lineWrapping" && oldVal != value) operation(wrappingChanged)();
|
154
|
-
else if (option == "
|
146
|
+
else if (option == "tabSize") operation(tabsChanged)();
|
155
147
|
if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber" || option == "theme")
|
156
148
|
operation(gutterChanged)();
|
157
149
|
},
|
@@ -161,6 +153,7 @@ var CodeMirror = (function() {
|
|
161
153
|
indentLine: operation(function(n, dir) {
|
162
154
|
if (isLine(n)) indentLine(n, dir == null ? "smart" : dir ? "add" : "subtract");
|
163
155
|
}),
|
156
|
+
indentSelection: operation(indentSelected),
|
164
157
|
historySize: function() {return {undo: history.done.length, redo: history.undone.length};},
|
165
158
|
clearHistory: function() {history = new History();},
|
166
159
|
matchBrackets: operation(function(){matchBrackets(true);}),
|
@@ -181,7 +174,6 @@ var CodeMirror = (function() {
|
|
181
174
|
var off = eltOffset(lineSpace);
|
182
175
|
return coordsChar(coords.x - off.left, coords.y - off.top);
|
183
176
|
},
|
184
|
-
getSearchCursor: function(query, pos, caseFold) {return new SearchCursor(query, pos, caseFold);},
|
185
177
|
markText: operation(markText),
|
186
178
|
setBookmark: setBookmark,
|
187
179
|
setMarker: operation(addGutterMarker),
|
@@ -189,6 +181,14 @@ var CodeMirror = (function() {
|
|
189
181
|
setLineClass: operation(setLineClass),
|
190
182
|
hideLine: operation(function(h) {return setLineHidden(h, true);}),
|
191
183
|
showLine: operation(function(h) {return setLineHidden(h, false);}),
|
184
|
+
onDeleteLine: function(line, f) {
|
185
|
+
if (typeof line == "number") {
|
186
|
+
if (!isLine(line)) return null;
|
187
|
+
line = getLine(line);
|
188
|
+
}
|
189
|
+
(line.handlers || (line.handlers = [])).push(f);
|
190
|
+
return line;
|
191
|
+
},
|
192
192
|
lineInfo: lineInfo,
|
193
193
|
addWidget: function(pos, node, scroll, vert, horiz) {
|
194
194
|
pos = localCoords(clipPos(pos));
|
@@ -219,17 +219,21 @@ var CodeMirror = (function() {
|
|
219
219
|
},
|
220
220
|
|
221
221
|
lineCount: function() {return doc.size;},
|
222
|
+
clipPos: clipPos,
|
222
223
|
getCursor: function(start) {
|
223
224
|
if (start == null) start = sel.inverted;
|
224
225
|
return copyPos(start ? sel.from : sel.to);
|
225
226
|
},
|
226
227
|
somethingSelected: function() {return !posEq(sel.from, sel.to);},
|
227
|
-
setCursor: operation(function(line, ch) {
|
228
|
-
if (ch == null && typeof line.line == "number") setCursor(line.line, line.ch);
|
229
|
-
else setCursor(line, ch);
|
228
|
+
setCursor: operation(function(line, ch, user) {
|
229
|
+
if (ch == null && typeof line.line == "number") setCursor(line.line, line.ch, user);
|
230
|
+
else setCursor(line, ch, user);
|
231
|
+
}),
|
232
|
+
setSelection: operation(function(from, to, user) {
|
233
|
+
(user ? setSelectionUser : setSelection)(clipPos(from), clipPos(to || from));
|
230
234
|
}),
|
231
|
-
setSelection: operation(function(from, to) {setSelection(clipPos(from), clipPos(to || from));}),
|
232
235
|
getLine: function(line) {if (isLine(line)) return getLine(line).text;},
|
236
|
+
getLineHandle: function(line) {if (isLine(line)) return getLine(line);},
|
233
237
|
setLine: operation(function(line, text) {
|
234
238
|
if (isLine(line)) replaceRange(text, {line: line, ch: 0}, {line: line, ch: getLine(line).text.length});
|
235
239
|
}),
|
@@ -239,7 +243,14 @@ var CodeMirror = (function() {
|
|
239
243
|
replaceRange: operation(replaceRange),
|
240
244
|
getRange: function(from, to) {return getRange(clipPos(from), clipPos(to));},
|
241
245
|
|
242
|
-
|
246
|
+
execCommand: function(cmd) {return commands[cmd](instance);},
|
247
|
+
// Stuff used by commands, probably not much use to outside code.
|
248
|
+
moveH: operation(moveH),
|
249
|
+
deleteH: operation(deleteH),
|
250
|
+
moveV: operation(moveV),
|
251
|
+
toggleOverwrite: function() {overwrite = !overwrite;},
|
252
|
+
|
253
|
+
posFromIndex: function(off) {
|
243
254
|
var lineNo = 0, ch;
|
244
255
|
doc.iter(0, doc.size, function(line) {
|
245
256
|
var sz = line.text.length + 1;
|
@@ -249,6 +260,14 @@ var CodeMirror = (function() {
|
|
249
260
|
});
|
250
261
|
return clipPos({line: lineNo, ch: ch});
|
251
262
|
},
|
263
|
+
indexFromPos: function (coords) {
|
264
|
+
if (coords.line < 0 || coords.ch < 0) return 0;
|
265
|
+
var index = coords.ch;
|
266
|
+
doc.iter(0, coords.line, function (line) {
|
267
|
+
index += line.text.length + 1;
|
268
|
+
});
|
269
|
+
return index;
|
270
|
+
},
|
252
271
|
|
253
272
|
operation: function(f){return operation(f)();},
|
254
273
|
refresh: function(){updateDisplay(true);},
|
@@ -278,6 +297,7 @@ var CodeMirror = (function() {
|
|
278
297
|
}
|
279
298
|
|
280
299
|
function onMouseDown(e) {
|
300
|
+
setShift(e.shiftKey);
|
281
301
|
// Check whether this is a click in a widget
|
282
302
|
for (var n = e_target(e); n != wrapper; n = n.parentNode)
|
283
303
|
if (n.parentNode == code && n != mover) return;
|
@@ -419,85 +439,76 @@ var CodeMirror = (function() {
|
|
419
439
|
e.dataTransfer.setDragImage(escapeElement, 0, 0);
|
420
440
|
e.dataTransfer.setData("Text", txt);
|
421
441
|
}
|
442
|
+
function handleKeyBinding(e) {
|
443
|
+
var name = keyNames[e.keyCode], next = keyMap[options.keyMap].auto, bound, dropShift;
|
444
|
+
if (name == null || e.altGraphKey) {
|
445
|
+
if (next) options.keyMap = next;
|
446
|
+
return null;
|
447
|
+
}
|
448
|
+
if (e.altKey) name = "Alt-" + name;
|
449
|
+
if (e.ctrlKey) name = "Ctrl-" + name;
|
450
|
+
if (e.metaKey) name = "Cmd-" + name;
|
451
|
+
if (e.shiftKey && (bound = lookupKey("Shift-" + name, options.extraKeys, options.keyMap))) {
|
452
|
+
dropShift = true;
|
453
|
+
} else {
|
454
|
+
bound = lookupKey(name, options.extraKeys, options.keyMap);
|
455
|
+
}
|
456
|
+
if (typeof bound == "string") {
|
457
|
+
if (commands.propertyIsEnumerable(bound)) bound = commands[bound];
|
458
|
+
else bound = null;
|
459
|
+
}
|
460
|
+
if (next && (bound || !isModifierKey(e))) options.keyMap = next;
|
461
|
+
if (!bound) return false;
|
462
|
+
if (dropShift) {
|
463
|
+
var prevShift = shiftSelecting;
|
464
|
+
shiftSelecting = null;
|
465
|
+
bound(instance);
|
466
|
+
shiftSelecting = prevShift;
|
467
|
+
} else bound(instance);
|
468
|
+
e_preventDefault(e);
|
469
|
+
return true;
|
470
|
+
}
|
471
|
+
var lastStoppedKey = null;
|
422
472
|
function onKeyDown(e) {
|
423
473
|
if (!focused) onFocus();
|
424
|
-
|
425
474
|
var code = e.keyCode;
|
426
475
|
// IE does strange things with escape.
|
427
476
|
if (ie && code == 27) { e.returnValue = false; }
|
428
|
-
|
429
|
-
var mod = (mac ? e.metaKey : e.ctrlKey) && !e.altKey, anyMod = e.ctrlKey || e.altKey || e.metaKey;
|
430
|
-
if (code == 16 || e.shiftKey) shiftSelecting = shiftSelecting || (sel.inverted ? sel.to : sel.from);
|
431
|
-
else shiftSelecting = null;
|
477
|
+
setShift(code == 16 || e.shiftKey);
|
432
478
|
// First give onKeyEvent option a chance to handle this.
|
433
479
|
if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
|
434
|
-
|
435
|
-
if (
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
if (mod && code == 65) {selectAll(); return e_preventDefault(e);} // ctrl-a
|
441
|
-
if (!options.readOnly) {
|
442
|
-
if (!anyMod && code == 13) {return;} // enter
|
443
|
-
if (!anyMod && code == 9 && handleTab(e.shiftKey)) return e_preventDefault(e); // tab
|
444
|
-
if (mod && code == 90) {undo(); return e_preventDefault(e);} // ctrl-z
|
445
|
-
if (mod && ((e.shiftKey && code == 90) || code == 89)) {redo(); return e_preventDefault(e);} // ctrl-shift-z, ctrl-y
|
446
|
-
}
|
447
|
-
if (code == 36) { if (options.smartHome) { smartHome(); return e_preventDefault(e); } }
|
448
|
-
|
449
|
-
// Key id to use in the movementKeys map. We also pass it to
|
450
|
-
// fastPoll in order to 'self learn'. We need this because
|
451
|
-
// reducedSelection, the hack where we collapse the selection to
|
452
|
-
// its start when it is inverted and a movement key is pressed
|
453
|
-
// (and later restore it again), shouldn't be used for
|
454
|
-
// non-movement keys.
|
455
|
-
curKeyId = (mod ? "c" : "") + (e.altKey ? "a" : "") + code;
|
456
|
-
if (sel.inverted && movementKeys[curKeyId] === true) {
|
457
|
-
var range = selRange(input);
|
458
|
-
if (range) {
|
459
|
-
reducedSelection = {anchor: range.start};
|
460
|
-
setSelRange(input, range.start, range.start);
|
461
|
-
}
|
480
|
+
var handled = handleKeyBinding(e);
|
481
|
+
if (window.opera) {
|
482
|
+
lastStoppedKey = handled ? e.keyCode : null;
|
483
|
+
// Opera has no cut event... we try to at least catch the key combo
|
484
|
+
if (!handled && (mac ? e.metaKey : e.ctrlKey) && e.keyCode == 88)
|
485
|
+
replaceSelection("");
|
462
486
|
}
|
463
|
-
// Don't save the key as a movementkey unless it had a modifier
|
464
|
-
if (!mod && !e.altKey) curKeyId = null;
|
465
|
-
fastPoll(curKeyId);
|
466
|
-
|
467
|
-
if (options.pollForIME && keyMightStartIME(code)) slowPollInterval = 50;
|
468
|
-
}
|
469
|
-
function onKeyUp(e) {
|
470
|
-
if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
|
471
|
-
if (reducedSelection) {
|
472
|
-
reducedSelection = null;
|
473
|
-
updateInput = true;
|
474
|
-
}
|
475
|
-
if (e.keyCode == 16) shiftSelecting = null;
|
476
|
-
|
477
|
-
if (slowPollInterval < 2000 && !alwaysPollForIME) slowPollInterval = 2000;
|
478
487
|
}
|
479
488
|
function onKeyPress(e) {
|
489
|
+
if (window.opera && e.keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
|
480
490
|
if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
|
491
|
+
if (window.opera && !e.which && handleKeyBinding(e)) return;
|
481
492
|
if (options.electricChars && mode.electricChars) {
|
482
493
|
var ch = String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode);
|
483
494
|
if (mode.electricChars.indexOf(ch) > -1)
|
484
|
-
setTimeout(operation(function() {indentLine(sel.to.line, "smart");}),
|
495
|
+
setTimeout(operation(function() {indentLine(sel.to.line, "smart");}), 75);
|
485
496
|
}
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
497
|
+
fastPoll();
|
498
|
+
}
|
499
|
+
function onKeyUp(e) {
|
500
|
+
if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
|
501
|
+
if (e.keyCode == 16) shiftSelecting = null;
|
491
502
|
}
|
492
503
|
|
493
504
|
function onFocus() {
|
494
|
-
if (options.readOnly
|
505
|
+
if (options.readOnly) return;
|
495
506
|
if (!focused) {
|
496
507
|
if (options.onFocus) options.onFocus(instance);
|
497
508
|
focused = true;
|
498
509
|
if (wrapper.className.search(/\bCodeMirror-focused\b/) == -1)
|
499
510
|
wrapper.className += " CodeMirror-focused";
|
500
|
-
if (!leaveInputAlone)
|
511
|
+
if (!leaveInputAlone) resetInput(true);
|
501
512
|
}
|
502
513
|
slowPoll();
|
503
514
|
restartBlink();
|
@@ -544,10 +555,23 @@ var CodeMirror = (function() {
|
|
544
555
|
doc.iter(from.line, to.line, function(line) {
|
545
556
|
if (line.text.length == maxLineLength) {recomputeMaxLength = true; return true;}
|
546
557
|
});
|
558
|
+
if (from.line != to.line || newText.length > 1) gutterDirty = true;
|
547
559
|
|
548
560
|
var nlines = to.line - from.line, firstLine = getLine(from.line), lastLine = getLine(to.line);
|
549
561
|
// First adjust the line structure, taking some care to leave highlighting intact.
|
550
|
-
if (
|
562
|
+
if (from.ch == 0 && to.ch == 0 && newText[newText.length - 1] == "") {
|
563
|
+
// This is a whole-line replace. Treated specially to make
|
564
|
+
// sure line objects move the way they are supposed to.
|
565
|
+
var added = [], prevLine = null;
|
566
|
+
if (from.line) {
|
567
|
+
prevLine = getLine(from.line - 1);
|
568
|
+
prevLine.fixMarkEnds(lastLine);
|
569
|
+
} else lastLine.fixMarkStarts();
|
570
|
+
for (var i = 0, e = newText.length - 1; i < e; ++i)
|
571
|
+
added.push(Line.inheritMarks(newText[i], prevLine));
|
572
|
+
if (nlines) doc.remove(from.line, nlines, callbacks);
|
573
|
+
if (added.length) doc.insert(from.line, added);
|
574
|
+
} else if (firstLine == lastLine) {
|
551
575
|
if (newText.length == 1)
|
552
576
|
firstLine.replace(from.ch, to.ch, newText[0]);
|
553
577
|
else {
|
@@ -560,21 +584,19 @@ var CodeMirror = (function() {
|
|
560
584
|
added.push(lastLine);
|
561
585
|
doc.insert(from.line + 1, added);
|
562
586
|
}
|
563
|
-
}
|
564
|
-
else if (newText.length == 1) {
|
587
|
+
} else if (newText.length == 1) {
|
565
588
|
firstLine.replace(from.ch, null, newText[0]);
|
566
589
|
lastLine.replace(null, to.ch, "");
|
567
590
|
firstLine.append(lastLine);
|
568
|
-
doc.remove(from.line + 1, nlines);
|
569
|
-
}
|
570
|
-
else {
|
591
|
+
doc.remove(from.line + 1, nlines, callbacks);
|
592
|
+
} else {
|
571
593
|
var added = [];
|
572
594
|
firstLine.replace(from.ch, null, newText[0]);
|
573
595
|
lastLine.replace(null, to.ch, newText[newText.length-1]);
|
574
596
|
firstLine.fixMarkEnds(lastLine);
|
575
597
|
for (var i = 1, e = newText.length - 1; i < e; ++i)
|
576
598
|
added.push(Line.inheritMarks(newText[i], firstLine));
|
577
|
-
if (nlines > 1) doc.remove(from.line + 1, nlines - 1);
|
599
|
+
if (nlines > 1) doc.remove(from.line + 1, nlines - 1, callbacks);
|
578
600
|
doc.insert(from.line + 1, added);
|
579
601
|
}
|
580
602
|
if (options.lineWrapping) {
|
@@ -618,7 +640,11 @@ var CodeMirror = (function() {
|
|
618
640
|
startWorker(100);
|
619
641
|
// Remember that these lines changed, for updating the display
|
620
642
|
changes.push({from: from.line, to: to.line + 1, diff: lendiff});
|
621
|
-
|
643
|
+
var changeObj = {from: from, to: to, text: newText};
|
644
|
+
if (textChanged) {
|
645
|
+
for (var cur = textChanged; cur.next; cur = cur.next) {}
|
646
|
+
cur.next = changeObj;
|
647
|
+
} else textChanged = changeObj;
|
622
648
|
|
623
649
|
// Update the selection
|
624
650
|
function updateLine(n) {return n <= Math.min(to.line, to.line + lendiff) ? n : n + lendiff;}
|
@@ -676,124 +702,64 @@ var CodeMirror = (function() {
|
|
676
702
|
var pollingFast = false; // Ensures slowPoll doesn't cancel fastPoll
|
677
703
|
function slowPoll() {
|
678
704
|
if (pollingFast) return;
|
679
|
-
poll.set(
|
705
|
+
poll.set(options.pollInterval, function() {
|
680
706
|
startOperation();
|
681
707
|
readInput();
|
682
708
|
if (focused) slowPoll();
|
683
709
|
endOperation();
|
684
710
|
});
|
685
711
|
}
|
686
|
-
function fastPoll(
|
712
|
+
function fastPoll() {
|
687
713
|
var missed = false;
|
688
714
|
pollingFast = true;
|
689
715
|
function p() {
|
690
716
|
startOperation();
|
691
717
|
var changed = readInput();
|
692
|
-
if (changed &&
|
693
|
-
if (changed == "moved" && movementKeys[keyId] == null) movementKeys[keyId] = true;
|
694
|
-
if (changed == "changed") movementKeys[keyId] = false;
|
695
|
-
}
|
696
|
-
if (!changed && !missed) {missed = true; poll.set(80, p);}
|
718
|
+
if (!changed && !missed) {missed = true; poll.set(60, p);}
|
697
719
|
else {pollingFast = false; slowPoll();}
|
698
720
|
endOperation();
|
699
721
|
}
|
700
722
|
poll.set(20, p);
|
701
723
|
}
|
702
724
|
|
703
|
-
//
|
704
|
-
//
|
705
|
-
//
|
725
|
+
// Previnput is a hack to work with IME. If we reset the textarea
|
726
|
+
// on every change, that breaks IME. So we look for changes
|
727
|
+
// compared to the previous content instead. (Modern browsers have
|
728
|
+
// events that indicate IME taking place, but these are not widely
|
729
|
+
// supported or compatible enough yet to rely on.)
|
730
|
+
var prevInput = "";
|
706
731
|
function readInput() {
|
707
|
-
if (leaveInputAlone || !focused) return;
|
708
|
-
var
|
709
|
-
if (
|
710
|
-
|
711
|
-
var
|
712
|
-
|
713
|
-
if (
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
var pos = 0;
|
721
|
-
for (;;) {
|
722
|
-
var found = text.indexOf("\n", pos);
|
723
|
-
if (found == -1 || (text.charAt(found-1) == "\r" ? found - 1 : found) >= n)
|
724
|
-
return {line: startLine, ch: n - pos};
|
725
|
-
++startLine;
|
726
|
-
pos = found + 1;
|
727
|
-
}
|
728
|
-
}
|
729
|
-
var from = computeOffset(sr.start, editing.from),
|
730
|
-
to = computeOffset(sr.end, editing.from);
|
731
|
-
// Here we have to take the reducedSelection hack into account,
|
732
|
-
// so that you can, for example, press shift-up at the start of
|
733
|
-
// your selection and have the right thing happen.
|
734
|
-
if (rs) {
|
735
|
-
var head = sr.start == rs.anchor ? to : from;
|
736
|
-
var tail = shiftSelecting ? sel.to : sr.start == rs.anchor ? from : to;
|
737
|
-
if (sel.inverted = posLess(head, tail)) { from = head; to = tail; }
|
738
|
-
else { reducedSelection = null; from = tail; to = head; }
|
739
|
-
}
|
740
|
-
|
741
|
-
// In some cases (cursor on same line as before), we don't have
|
742
|
-
// to update the textarea content at all.
|
743
|
-
if (from.line == to.line && from.line == sel.from.line && from.line == sel.to.line && !shiftSelecting)
|
744
|
-
updateInput = false;
|
745
|
-
|
746
|
-
// Magic mess to extract precise edited range from the changed
|
747
|
-
// string.
|
748
|
-
if (changed) {
|
749
|
-
var start = 0, end = text.length, len = Math.min(end, editing.text.length);
|
750
|
-
var c, line = editing.from, nl = -1;
|
751
|
-
while (start < len && (c = text.charAt(start)) == editing.text.charAt(start)) {
|
752
|
-
++start;
|
753
|
-
if (c == "\n") {line++; nl = start;}
|
754
|
-
}
|
755
|
-
var ch = nl > -1 ? start - nl : start, endline = editing.to - 1, edend = editing.text.length;
|
756
|
-
for (;;) {
|
757
|
-
c = editing.text.charAt(edend);
|
758
|
-
if (text.charAt(end) != c) {++end; ++edend; break;}
|
759
|
-
if (c == "\n") endline--;
|
760
|
-
if (edend <= start || end <= start) break;
|
761
|
-
--end; --edend;
|
762
|
-
}
|
763
|
-
var nl = editing.text.lastIndexOf("\n", edend - 1), endch = nl == -1 ? edend : edend - nl - 1;
|
764
|
-
updateLines({line: line, ch: ch}, {line: endline, ch: endch}, splitLines(text.slice(start, end)), from, to);
|
765
|
-
if (line != endline || from.line != line) updateInput = true;
|
766
|
-
}
|
767
|
-
else setSelection(from, to);
|
768
|
-
|
769
|
-
editing.text = text; editing.start = sr.start; editing.end = sr.end;
|
770
|
-
return changed ? "changed" : moved ? "moved" : false;
|
732
|
+
if (leaveInputAlone || !focused || hasSelection(input)) return false;
|
733
|
+
var text = input.value;
|
734
|
+
if (text == prevInput) return false;
|
735
|
+
shiftSelecting = null;
|
736
|
+
var same = 0, l = Math.min(prevInput.length, text.length);
|
737
|
+
while (same < l && prevInput[same] == text[same]) ++same;
|
738
|
+
if (same < prevInput.length)
|
739
|
+
sel.from = {line: sel.from.line, ch: sel.from.ch - (prevInput.length - same)};
|
740
|
+
else if (overwrite && posEq(sel.from, sel.to))
|
741
|
+
sel.to = {line: sel.to.line, ch: Math.min(getLine(sel.to.line).text.length, sel.to.ch + (text.length - same))};
|
742
|
+
replaceSelection(text.slice(same), "end");
|
743
|
+
prevInput = text;
|
744
|
+
return true;
|
771
745
|
}
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
doc.iter(from, to, function(line) { text.push(line.text); });
|
779
|
-
text = input.value = text.join(lineSep);
|
780
|
-
var startch = sel.from.ch, endch = sel.to.ch;
|
781
|
-
doc.iter(from, sel.from.line, function(line) {
|
782
|
-
startch += lineSep.length + line.text.length;
|
783
|
-
});
|
784
|
-
doc.iter(from, sel.to.line, function(line) {
|
785
|
-
endch += lineSep.length + line.text.length;
|
786
|
-
});
|
787
|
-
editing = {text: text, from: from, to: to, start: startch, end: endch};
|
788
|
-
setSelRange(input, startch, reducedSelection ? startch : endch);
|
746
|
+
function resetInput(user) {
|
747
|
+
if (!posEq(sel.from, sel.to)) {
|
748
|
+
prevInput = "";
|
749
|
+
input.value = getSelection();
|
750
|
+
input.select();
|
751
|
+
} else if (user) prevInput = input.value = "";
|
789
752
|
}
|
753
|
+
|
790
754
|
function focusInput() {
|
791
|
-
if (options.readOnly
|
755
|
+
if (!options.readOnly) input.focus();
|
792
756
|
}
|
793
757
|
|
794
758
|
function scrollEditorIntoView() {
|
795
759
|
if (!cursor.getBoundingClientRect) return;
|
796
760
|
var rect = cursor.getBoundingClientRect();
|
761
|
+
// IE returns bogus coordinates when the instance sits inside of an iframe and the cursor is hidden
|
762
|
+
if (ie && rect.top == rect.bottom) return;
|
797
763
|
var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
|
798
764
|
if (rect.top < 0 || rect.bottom > winH) cursor.scrollIntoView();
|
799
765
|
}
|
@@ -816,7 +782,7 @@ var CodeMirror = (function() {
|
|
816
782
|
scroller.scrollLeft = Math.max(0, x1 - 10 - gutterw);
|
817
783
|
scrolled = true;
|
818
784
|
}
|
819
|
-
else if (x2 > screenw + screenleft) {
|
785
|
+
else if (x2 > screenw + screenleft - 3) {
|
820
786
|
scroller.scrollLeft = x2 + 10 - screenw;
|
821
787
|
scrolled = true;
|
822
788
|
if (x2 > code.clientWidth) result = false;
|
@@ -835,7 +801,7 @@ var CodeMirror = (function() {
|
|
835
801
|
// Uses a set of changes plus the current scroll position to
|
836
802
|
// determine which DOM updates have to be made, and makes the
|
837
803
|
// updates.
|
838
|
-
function updateDisplay(changes) {
|
804
|
+
function updateDisplay(changes, suppressCallback) {
|
839
805
|
if (!scroller.clientWidth) {
|
840
806
|
showingFrom = showingTo = displayOffset = 0;
|
841
807
|
return;
|
@@ -871,8 +837,10 @@ var CodeMirror = (function() {
|
|
871
837
|
|
872
838
|
// Position the mover div to align with the lines it's supposed
|
873
839
|
// to be showing (which will cover the visible display)
|
874
|
-
var different = from != showingFrom || to != showingTo ||
|
875
|
-
|
840
|
+
var different = from != showingFrom || to != showingTo || lastSizeC != scroller.clientHeight + th;
|
841
|
+
// This is just a bogus formula that detects when the editor is
|
842
|
+
// resized or the font size changes.
|
843
|
+
if (different) lastSizeC = scroller.clientHeight + th;
|
876
844
|
showingFrom = from; showingTo = to;
|
877
845
|
displayOffset = heightAtLine(doc, from);
|
878
846
|
mover.style.top = (displayOffset * th) + "px";
|
@@ -908,6 +876,8 @@ var CodeMirror = (function() {
|
|
908
876
|
gutter.style.display = gutterDisplay;
|
909
877
|
if (different || gutterDirty) updateGutter();
|
910
878
|
updateCursor();
|
879
|
+
if (!suppressCallback && options.onUpdate) options.onUpdate(instance);
|
880
|
+
return true;
|
911
881
|
}
|
912
882
|
|
913
883
|
function computeIntact(intact, changes) {
|
@@ -966,7 +936,7 @@ var CodeMirror = (function() {
|
|
966
936
|
if (nextIntact && nextIntact.to == j) nextIntact = intact.shift();
|
967
937
|
if (!nextIntact || nextIntact.from > j) {
|
968
938
|
if (line.hidden) scratch.innerHTML = "<pre></pre>";
|
969
|
-
else scratch.innerHTML = line.getHTML(ch1, ch2, true);
|
939
|
+
else scratch.innerHTML = line.getHTML(ch1, ch2, true, tabText);
|
970
940
|
lineDiv.insertBefore(scratch.firstChild, curNode);
|
971
941
|
} else {
|
972
942
|
curNode = curNode.nextSibling;
|
@@ -991,7 +961,7 @@ var CodeMirror = (function() {
|
|
991
961
|
else if (text == null)
|
992
962
|
text = "\u00a0";
|
993
963
|
html.push((marker && marker.style ? '<pre class="' + marker.style + '">' : "<pre>"), text);
|
994
|
-
for (var j = 1; j < line.height; ++j) html.push("<br
|
964
|
+
for (var j = 1; j < line.height; ++j) html.push("<br/> ");
|
995
965
|
html.push("</pre>");
|
996
966
|
}
|
997
967
|
++i;
|
@@ -1008,9 +978,9 @@ var CodeMirror = (function() {
|
|
1008
978
|
function updateCursor() {
|
1009
979
|
var head = sel.inverted ? sel.from : sel.to, lh = textHeight();
|
1010
980
|
var pos = localCoords(head, true);
|
1011
|
-
var
|
1012
|
-
inputDiv.style.top =
|
1013
|
-
inputDiv.style.left = (pos.x -
|
981
|
+
var wrapOff = eltOffset(wrapper), lineOff = eltOffset(lineDiv);
|
982
|
+
inputDiv.style.top = (pos.y + lineOff.top - wrapOff.top) + "px";
|
983
|
+
inputDiv.style.left = (pos.x + lineOff.left - wrapOff.left) + "px";
|
1014
984
|
if (posEq(sel.from, sel.to)) {
|
1015
985
|
cursor.style.top = pos.y + "px";
|
1016
986
|
cursor.style.left = (options.lineWrapping ? Math.min(pos.x, lineSpace.offsetWidth) : pos.x) + "px";
|
@@ -1019,6 +989,10 @@ var CodeMirror = (function() {
|
|
1019
989
|
else cursor.style.display = "none";
|
1020
990
|
}
|
1021
991
|
|
992
|
+
function setShift(val) {
|
993
|
+
if (val) shiftSelecting = shiftSelecting || (sel.inverted ? sel.to : sel.from);
|
994
|
+
else shiftSelecting = null;
|
995
|
+
}
|
1022
996
|
function setSelectionUser(from, to) {
|
1023
997
|
var sh = shiftSelecting && clipPos(shiftSelecting);
|
1024
998
|
if (sh) {
|
@@ -1026,11 +1000,13 @@ var CodeMirror = (function() {
|
|
1026
1000
|
else if (posLess(to, sh)) to = sh;
|
1027
1001
|
}
|
1028
1002
|
setSelection(from, to);
|
1003
|
+
userSelChange = true;
|
1029
1004
|
}
|
1030
1005
|
// Update the selection. Last two args are only used by
|
1031
1006
|
// updateLines, since they have to be expressed in the line
|
1032
1007
|
// numbers before the update.
|
1033
1008
|
function setSelection(from, to, oldFrom, oldTo) {
|
1009
|
+
goalColumn = null;
|
1034
1010
|
if (oldFrom == null) {oldFrom = sel.from.line; oldTo = sel.to.line;}
|
1035
1011
|
if (posEq(sel.from, from) && posEq(sel.to, to)) return;
|
1036
1012
|
if (posLess(to, from)) {var tmp = to; to = from; from = tmp;}
|
@@ -1103,76 +1079,87 @@ var CodeMirror = (function() {
|
|
1103
1079
|
else return pos;
|
1104
1080
|
}
|
1105
1081
|
|
1106
|
-
function
|
1107
|
-
var
|
1108
|
-
var
|
1109
|
-
|
1082
|
+
function findPosH(dir, unit) {
|
1083
|
+
var end = sel.inverted ? sel.from : sel.to, line = end.line, ch = end.ch;
|
1084
|
+
var lineObj = getLine(line);
|
1085
|
+
function findNextLine() {
|
1086
|
+
for (var l = line + dir, e = dir < 0 ? -1 : doc.size; l != e; l += dir) {
|
1087
|
+
var lo = getLine(l);
|
1088
|
+
if (!lo.hidden) { line = l; lineObj = lo; return true; }
|
1089
|
+
}
|
1090
|
+
}
|
1091
|
+
function moveOnce(boundToLine) {
|
1092
|
+
if (ch == (dir < 0 ? 0 : lineObj.text.length)) {
|
1093
|
+
if (!boundToLine && findNextLine()) ch = dir < 0 ? lineObj.text.length : 0;
|
1094
|
+
else return false;
|
1095
|
+
} else ch += dir;
|
1096
|
+
return true;
|
1097
|
+
}
|
1098
|
+
if (unit == "char") moveOnce();
|
1099
|
+
else if (unit == "column") moveOnce(true);
|
1100
|
+
else if (unit == "word") {
|
1101
|
+
var sawWord = false;
|
1102
|
+
for (;;) {
|
1103
|
+
if (dir < 0) if (!moveOnce()) break;
|
1104
|
+
if (isWordChar(lineObj.text.charAt(ch))) sawWord = true;
|
1105
|
+
else if (sawWord) {if (dir < 0) {dir = 1; moveOnce();} break;}
|
1106
|
+
if (dir > 0) if (!moveOnce()) break;
|
1107
|
+
}
|
1108
|
+
}
|
1109
|
+
return {line: line, ch: ch};
|
1110
|
+
}
|
1111
|
+
function moveH(dir, unit) {
|
1112
|
+
var pos = dir < 0 ? sel.from : sel.to;
|
1113
|
+
if (shiftSelecting || posEq(sel.from, sel.to)) pos = findPosH(dir, unit);
|
1114
|
+
setCursor(pos.line, pos.ch, true);
|
1110
1115
|
}
|
1111
|
-
function
|
1112
|
-
|
1113
|
-
|
1116
|
+
function deleteH(dir, unit) {
|
1117
|
+
if (!posEq(sel.from, sel.to)) replaceRange("", sel.from, sel.to);
|
1118
|
+
else if (dir < 0) replaceRange("", findPosH(dir, unit), sel.to);
|
1119
|
+
else replaceRange("", sel.from, findPosH(dir, unit));
|
1120
|
+
userSelChange = true;
|
1114
1121
|
}
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1122
|
+
var goalColumn = null;
|
1123
|
+
function moveV(dir, unit) {
|
1124
|
+
var dist = 0, pos = localCoords(sel.inverted ? sel.from : sel.to, true);
|
1125
|
+
if (goalColumn != null) pos.x = goalColumn;
|
1126
|
+
if (unit == "page") dist = scroller.clientHeight;
|
1127
|
+
else if (unit == "line") dist = textHeight();
|
1128
|
+
var target = coordsChar(pos.x, pos.y + dist * dir + 2);
|
1129
|
+
setCursor(target.line, target.ch, true);
|
1130
|
+
goalColumn = pos.x;
|
1118
1131
|
}
|
1132
|
+
|
1119
1133
|
function selectWordAt(pos) {
|
1120
1134
|
var line = getLine(pos.line).text;
|
1121
1135
|
var start = pos.ch, end = pos.ch;
|
1122
|
-
while (start > 0 &&
|
1123
|
-
while (end < line.length &&
|
1136
|
+
while (start > 0 && isWordChar(line.charAt(start - 1))) --start;
|
1137
|
+
while (end < line.length && isWordChar(line.charAt(end))) ++end;
|
1124
1138
|
setSelectionUser({line: pos.line, ch: start}, {line: pos.line, ch: end});
|
1125
1139
|
}
|
1126
1140
|
function selectLine(line) {
|
1127
1141
|
setSelectionUser({line: line, ch: 0}, {line: line, ch: getLine(line).text.length});
|
1128
1142
|
}
|
1129
|
-
function
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
}
|
1134
|
-
function handleTab(shift) {
|
1135
|
-
function indentSelected(mode) {
|
1136
|
-
if (posEq(sel.from, sel.to)) return indentLine(sel.from.line, mode);
|
1137
|
-
var e = sel.to.line - (sel.to.ch ? 0 : 1);
|
1138
|
-
for (var i = sel.from.line; i <= e; ++i) indentLine(i, mode);
|
1139
|
-
}
|
1140
|
-
shiftSelecting = null;
|
1141
|
-
switch (options.tabMode) {
|
1142
|
-
case "default":
|
1143
|
-
return false;
|
1144
|
-
case "indent":
|
1145
|
-
indentSelected("smart");
|
1146
|
-
break;
|
1147
|
-
case "classic":
|
1148
|
-
if (posEq(sel.from, sel.to)) {
|
1149
|
-
if (shift) indentLine(sel.from.line, "smart");
|
1150
|
-
else replaceSelection("\t", "end");
|
1151
|
-
break;
|
1152
|
-
}
|
1153
|
-
case "shift":
|
1154
|
-
indentSelected(shift ? "subtract" : "add");
|
1155
|
-
break;
|
1156
|
-
}
|
1157
|
-
return true;
|
1158
|
-
}
|
1159
|
-
function smartHome() {
|
1160
|
-
var firstNonWS = Math.max(0, getLine(sel.from.line).text.search(/\S/));
|
1161
|
-
setCursor(sel.from.line, sel.from.ch <= firstNonWS && sel.from.ch ? 0 : firstNonWS, true);
|
1143
|
+
function indentSelected(mode) {
|
1144
|
+
if (posEq(sel.from, sel.to)) return indentLine(sel.from.line, mode);
|
1145
|
+
var e = sel.to.line - (sel.to.ch ? 0 : 1);
|
1146
|
+
for (var i = sel.from.line; i <= e; ++i) indentLine(i, mode);
|
1162
1147
|
}
|
1163
1148
|
|
1164
1149
|
function indentLine(n, how) {
|
1150
|
+
if (!how) how = "add";
|
1165
1151
|
if (how == "smart") {
|
1166
1152
|
if (!mode.indent) how = "prev";
|
1167
1153
|
else var state = getStateBefore(n);
|
1168
1154
|
}
|
1169
1155
|
|
1170
|
-
var line = getLine(n), curSpace = line.indentation(
|
1156
|
+
var line = getLine(n), curSpace = line.indentation(options.tabSize),
|
1157
|
+
curSpaceString = line.text.match(/^\s*/)[0], indentation;
|
1171
1158
|
if (how == "prev") {
|
1172
|
-
if (n) indentation = getLine(n-1).indentation();
|
1159
|
+
if (n) indentation = getLine(n-1).indentation(options.tabSize);
|
1173
1160
|
else indentation = 0;
|
1174
1161
|
}
|
1175
|
-
else if (how == "smart") indentation = mode.indent(state, line.text.slice(curSpaceString.length));
|
1162
|
+
else if (how == "smart") indentation = mode.indent(state, line.text.slice(curSpaceString.length), line.text);
|
1176
1163
|
else if (how == "add") indentation = curSpace + options.indentUnit;
|
1177
1164
|
else if (how == "subtract") indentation = curSpace - options.indentUnit;
|
1178
1165
|
indentation = Math.max(0, indentation);
|
@@ -1185,7 +1172,7 @@ var CodeMirror = (function() {
|
|
1185
1172
|
else {
|
1186
1173
|
var indentString = "", pos = 0;
|
1187
1174
|
if (options.indentWithTabs)
|
1188
|
-
for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";}
|
1175
|
+
for (var i = Math.floor(indentation / options.tabSize); i; --i) {pos += options.tabSize; indentString += "\t";}
|
1189
1176
|
while (pos < indentation) {++pos; indentString += " ";}
|
1190
1177
|
}
|
1191
1178
|
|
@@ -1224,18 +1211,32 @@ var CodeMirror = (function() {
|
|
1224
1211
|
}
|
1225
1212
|
changes.push({from: 0, to: doc.size});
|
1226
1213
|
}
|
1214
|
+
function computeTabText() {
|
1215
|
+
for (var str = '<span class="cm-tab">', i = 0; i < options.tabSize; ++i) str += " ";
|
1216
|
+
return str + "</span>";
|
1217
|
+
}
|
1218
|
+
function tabsChanged() {
|
1219
|
+
tabText = computeTabText();
|
1220
|
+
updateDisplay(true);
|
1221
|
+
}
|
1222
|
+
function themeChanged() {
|
1223
|
+
scroller.className = scroller.className.replace(/\s*cm-s-\w+/g, "") +
|
1224
|
+
options.theme.replace(/(^|\s)\s*/g, " cm-s-");
|
1225
|
+
}
|
1227
1226
|
|
1228
1227
|
function TextMarker() { this.set = []; }
|
1229
1228
|
TextMarker.prototype.clear = operation(function() {
|
1229
|
+
var min = Infinity, max = -Infinity;
|
1230
1230
|
for (var i = 0, e = this.set.length; i < e; ++i) {
|
1231
|
-
var
|
1232
|
-
if (!mk) continue;
|
1231
|
+
var line = this.set[i], mk = line.marked;
|
1232
|
+
if (!mk || !line.parent) continue;
|
1233
|
+
var lineN = lineNo(line);
|
1234
|
+
min = Math.min(min, lineN); max = Math.max(max, lineN);
|
1233
1235
|
for (var j = 0; j < mk.length; ++j)
|
1234
1236
|
if (mk[j].set == this.set) mk.splice(j--, 1);
|
1235
1237
|
}
|
1236
|
-
|
1237
|
-
|
1238
|
-
changes.push({from: 0, to: doc.size});
|
1238
|
+
if (min != Infinity)
|
1239
|
+
changes.push({from: min, to: max + 1});
|
1239
1240
|
});
|
1240
1241
|
TextMarker.prototype.find = function() {
|
1241
1242
|
var from, to;
|
@@ -1261,7 +1262,7 @@ var CodeMirror = (function() {
|
|
1261
1262
|
from = clipPos(from); to = clipPos(to);
|
1262
1263
|
var tm = new TextMarker();
|
1263
1264
|
function add(line, from, to, className) {
|
1264
|
-
|
1265
|
+
getLine(line).addMark(new MarkedText(from, to, className, tm.set));
|
1265
1266
|
}
|
1266
1267
|
if (from.line == to.line) add(from.line, from.ch, to.ch, className);
|
1267
1268
|
else {
|
@@ -1299,6 +1300,7 @@ var CodeMirror = (function() {
|
|
1299
1300
|
else no = lineNo(handle);
|
1300
1301
|
if (no == null) return null;
|
1301
1302
|
if (op(line, no)) changes.push({from: no, to: no + 1});
|
1303
|
+
else return null;
|
1302
1304
|
return line;
|
1303
1305
|
}
|
1304
1306
|
function setLineClass(handle, className) {
|
@@ -1349,7 +1351,7 @@ var CodeMirror = (function() {
|
|
1349
1351
|
if (x <= 0) return 0;
|
1350
1352
|
var lineObj = getLine(line), text = lineObj.text;
|
1351
1353
|
function getX(len) {
|
1352
|
-
measure.innerHTML = "<pre><span>" + lineObj.getHTML(null, null, false, len) + "</span></pre>";
|
1354
|
+
measure.innerHTML = "<pre><span>" + lineObj.getHTML(null, null, false, tabText, len) + "</span></pre>";
|
1353
1355
|
return measure.firstChild.firstChild.offsetWidth;
|
1354
1356
|
}
|
1355
1357
|
var from = 0, fromX = 0, to = text.length, toX;
|
@@ -1379,10 +1381,10 @@ var CodeMirror = (function() {
|
|
1379
1381
|
// Include extra text at the end to make sure the measured line is wrapped in the right way.
|
1380
1382
|
if (options.lineWrapping) {
|
1381
1383
|
var end = line.text.indexOf(" ", ch + 2);
|
1382
|
-
extra = line.text.slice(ch + 1, end < 0 ? line.text.length : end + (ie ? 5 : 0));
|
1384
|
+
extra = htmlEscape(line.text.slice(ch + 1, end < 0 ? line.text.length : end + (ie ? 5 : 0)));
|
1383
1385
|
}
|
1384
|
-
measure.innerHTML = "<pre>" + line.getHTML(null, null, false, ch) +
|
1385
|
-
'<span id="CodeMirror-temp-' + tempId + '">' + (line.text.charAt(ch) || " ") + "</span>" +
|
1386
|
+
measure.innerHTML = "<pre>" + line.getHTML(null, null, false, tabText, ch) +
|
1387
|
+
'<span id="CodeMirror-temp-' + tempId + '">' + htmlEscape(line.text.charAt(ch) || " ") + "</span>" +
|
1386
1388
|
extra + "</pre>";
|
1387
1389
|
var elt = document.getElementById("CodeMirror-temp-" + tempId);
|
1388
1390
|
var top = elt.offsetTop, left = elt.offsetLeft;
|
@@ -1410,7 +1412,7 @@ var CodeMirror = (function() {
|
|
1410
1412
|
if (y < 0) y = 0;
|
1411
1413
|
var th = textHeight(), cw = charWidth(), heightPos = displayOffset + Math.floor(y / th);
|
1412
1414
|
var lineNo = lineAtHeight(doc, heightPos);
|
1413
|
-
if (lineNo >= doc.size) return {line: doc.size - 1, ch:
|
1415
|
+
if (lineNo >= doc.size) return {line: doc.size - 1, ch: getLine(doc.size - 1).text.length};
|
1414
1416
|
var lineObj = getLine(lineNo), text = lineObj.text;
|
1415
1417
|
var tw = options.lineWrapping, innerOff = tw ? heightPos - heightAtLine(doc, lineNo) : 0;
|
1416
1418
|
if (x <= 0 && innerOff == 0) return {line: lineNo, ch: 0};
|
@@ -1447,18 +1449,25 @@ var CodeMirror = (function() {
|
|
1447
1449
|
return {x: off.left + local.x, y: off.top + local.y, yBot: off.top + local.yBot};
|
1448
1450
|
}
|
1449
1451
|
|
1450
|
-
var cachedHeight,
|
1452
|
+
var cachedHeight, cachedHeightFor, measureText;
|
1451
1453
|
function textHeight() {
|
1452
|
-
|
1453
|
-
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
1454
|
+
if (measureText == null) {
|
1455
|
+
measureText = "<pre>";
|
1456
|
+
for (var i = 0; i < 49; ++i) measureText += "x<br/>";
|
1457
|
+
measureText += "x</pre>";
|
1458
|
+
}
|
1459
|
+
var offsetHeight = lineDiv.clientHeight;
|
1460
|
+
if (offsetHeight == cachedHeightFor) return cachedHeight;
|
1461
|
+
cachedHeightFor = offsetHeight;
|
1462
|
+
measure.innerHTML = measureText;
|
1463
|
+
cachedHeight = measure.firstChild.offsetHeight / 50 || 1;
|
1464
|
+
measure.innerHTML = "";
|
1465
|
+
return cachedHeight;
|
1466
|
+
}
|
1467
|
+
var cachedWidth, cachedWidthFor = 0;
|
1459
1468
|
function charWidth() {
|
1460
|
-
if (scroller.clientWidth ==
|
1461
|
-
|
1469
|
+
if (scroller.clientWidth == cachedWidthFor) return cachedWidth;
|
1470
|
+
cachedWidthFor = scroller.clientWidth;
|
1462
1471
|
return (cachedWidth = stringWidth("x"));
|
1463
1472
|
}
|
1464
1473
|
function paddingTop() {return lineSpace.offsetTop;}
|
@@ -1490,14 +1499,14 @@ var CodeMirror = (function() {
|
|
1490
1499
|
leaveInputAlone = true;
|
1491
1500
|
var val = input.value = getSelection();
|
1492
1501
|
focusInput();
|
1493
|
-
|
1502
|
+
input.select();
|
1494
1503
|
function rehide() {
|
1495
1504
|
var newVal = splitLines(input.value).join("\n");
|
1496
1505
|
if (newVal != val) operation(replaceSelection)(newVal, "end");
|
1497
1506
|
inputDiv.style.position = "relative";
|
1498
1507
|
input.style.cssText = oldCSS;
|
1499
1508
|
leaveInputAlone = false;
|
1500
|
-
|
1509
|
+
resetInput(true);
|
1501
1510
|
slowPoll();
|
1502
1511
|
}
|
1503
1512
|
|
@@ -1574,7 +1583,7 @@ var CodeMirror = (function() {
|
|
1574
1583
|
if (search == 0) return 0;
|
1575
1584
|
var line = getLine(search-1);
|
1576
1585
|
if (line.stateAfter) return search;
|
1577
|
-
var indented = line.indentation();
|
1586
|
+
var indented = line.indentation(options.tabSize);
|
1578
1587
|
if (minline == null || minindent > indented) {
|
1579
1588
|
minline = search - 1;
|
1580
1589
|
minindent = indented;
|
@@ -1587,7 +1596,7 @@ var CodeMirror = (function() {
|
|
1587
1596
|
if (!state) state = startState(mode);
|
1588
1597
|
else state = copyState(mode, state);
|
1589
1598
|
doc.iter(start, n, function(line) {
|
1590
|
-
line.highlight(mode, state);
|
1599
|
+
line.highlight(mode, state, options.tabSize);
|
1591
1600
|
line.stateAfter = copyState(mode, state);
|
1592
1601
|
});
|
1593
1602
|
if (start < n) changes.push({from: start, to: n});
|
@@ -1597,7 +1606,7 @@ var CodeMirror = (function() {
|
|
1597
1606
|
function highlightLines(start, end) {
|
1598
1607
|
var state = getStateBefore(start);
|
1599
1608
|
doc.iter(start, end, function(line) {
|
1600
|
-
line.highlight(mode, state);
|
1609
|
+
line.highlight(mode, state, options.tabSize);
|
1601
1610
|
line.stateAfter = copyState(mode, state);
|
1602
1611
|
});
|
1603
1612
|
}
|
@@ -1622,14 +1631,15 @@ var CodeMirror = (function() {
|
|
1622
1631
|
if (realChange) changes.push({from: task, to: i + 1});
|
1623
1632
|
return (bail = true);
|
1624
1633
|
}
|
1625
|
-
var changed = line.highlight(mode, state);
|
1634
|
+
var changed = line.highlight(mode, state, options.tabSize);
|
1626
1635
|
if (changed) realChange = true;
|
1627
1636
|
line.stateAfter = copyState(mode, state);
|
1628
1637
|
if (compare) {
|
1629
1638
|
if (hadState && compare(hadState, state)) return true;
|
1630
1639
|
} else {
|
1631
1640
|
if (changed !== false || !hadState) unchanged = 0;
|
1632
|
-
else if (++unchanged > 3)
|
1641
|
+
else if (++unchanged > 3 && (!mode.indent || mode.indent(hadState, "") == mode.indent(state, "")))
|
1642
|
+
return true;
|
1633
1643
|
}
|
1634
1644
|
++i;
|
1635
1645
|
});
|
@@ -1649,12 +1659,13 @@ var CodeMirror = (function() {
|
|
1649
1659
|
// be awkward, slow, and error-prone), but instead updates are
|
1650
1660
|
// batched and then all combined and executed at once.
|
1651
1661
|
function startOperation() {
|
1652
|
-
updateInput =
|
1662
|
+
updateInput = userSelChange = textChanged = null;
|
1663
|
+
changes = []; selectionChanged = false; callbacks = [];
|
1653
1664
|
}
|
1654
1665
|
function endOperation() {
|
1655
|
-
var reScroll = false;
|
1666
|
+
var reScroll = false, updated;
|
1656
1667
|
if (selectionChanged) reScroll = !scrollCursorIntoView();
|
1657
|
-
if (changes.length) updateDisplay(changes);
|
1668
|
+
if (changes.length) updated = updateDisplay(changes, true);
|
1658
1669
|
else {
|
1659
1670
|
if (selectionChanged) updateCursor();
|
1660
1671
|
if (gutterDirty) updateGutter();
|
@@ -1662,22 +1673,22 @@ var CodeMirror = (function() {
|
|
1662
1673
|
if (reScroll) scrollCursorIntoView();
|
1663
1674
|
if (selectionChanged) {scrollEditorIntoView(); restartBlink();}
|
1664
1675
|
|
1665
|
-
// updateInput can be set to a boolean value to force/prevent an
|
1666
|
-
// update.
|
1667
1676
|
if (focused && !leaveInputAlone &&
|
1668
1677
|
(updateInput === true || (updateInput !== false && selectionChanged)))
|
1669
|
-
|
1678
|
+
resetInput(userSelChange);
|
1670
1679
|
|
1671
1680
|
if (selectionChanged && options.matchBrackets)
|
1672
1681
|
setTimeout(operation(function() {
|
1673
1682
|
if (bracketHighlighted) {bracketHighlighted(); bracketHighlighted = null;}
|
1674
|
-
matchBrackets(false);
|
1683
|
+
if (posEq(sel.from, sel.to)) matchBrackets(false);
|
1675
1684
|
}), 20);
|
1676
|
-
var tc = textChanged; //
|
1685
|
+
var tc = textChanged, cbs = callbacks; // these can be reset by callbacks
|
1677
1686
|
if (selectionChanged && options.onCursorActivity)
|
1678
1687
|
options.onCursorActivity(instance);
|
1679
1688
|
if (tc && options.onChange && instance)
|
1680
1689
|
options.onChange(instance, tc);
|
1690
|
+
for (var i = 0; i < cbs.length; ++i) cbs[i](instance);
|
1691
|
+
if (updated && options.onUpdate) options.onUpdate(instance);
|
1681
1692
|
}
|
1682
1693
|
var nestedOperation = 0;
|
1683
1694
|
function operation(f) {
|
@@ -1689,120 +1700,6 @@ var CodeMirror = (function() {
|
|
1689
1700
|
};
|
1690
1701
|
}
|
1691
1702
|
|
1692
|
-
function SearchCursor(query, pos, caseFold) {
|
1693
|
-
this.atOccurrence = false;
|
1694
|
-
if (caseFold == null) caseFold = typeof query == "string" && query == query.toLowerCase();
|
1695
|
-
|
1696
|
-
if (pos && typeof pos == "object") pos = clipPos(pos);
|
1697
|
-
else pos = {line: 0, ch: 0};
|
1698
|
-
this.pos = {from: pos, to: pos};
|
1699
|
-
|
1700
|
-
// The matches method is filled in based on the type of query.
|
1701
|
-
// It takes a position and a direction, and returns an object
|
1702
|
-
// describing the next occurrence of the query, or null if no
|
1703
|
-
// more matches were found.
|
1704
|
-
if (typeof query != "string") // Regexp match
|
1705
|
-
this.matches = function(reverse, pos) {
|
1706
|
-
if (reverse) {
|
1707
|
-
var line = getLine(pos.line).text.slice(0, pos.ch), match = line.match(query), start = 0;
|
1708
|
-
while (match) {
|
1709
|
-
var ind = line.indexOf(match[0]);
|
1710
|
-
start += ind;
|
1711
|
-
line = line.slice(ind + 1);
|
1712
|
-
var newmatch = line.match(query);
|
1713
|
-
if (newmatch) match = newmatch;
|
1714
|
-
else break;
|
1715
|
-
start++;
|
1716
|
-
}
|
1717
|
-
}
|
1718
|
-
else {
|
1719
|
-
var line = getLine(pos.line).text.slice(pos.ch), match = line.match(query),
|
1720
|
-
start = match && pos.ch + line.indexOf(match[0]);
|
1721
|
-
}
|
1722
|
-
if (match)
|
1723
|
-
return {from: {line: pos.line, ch: start},
|
1724
|
-
to: {line: pos.line, ch: start + match[0].length},
|
1725
|
-
match: match};
|
1726
|
-
};
|
1727
|
-
else { // String query
|
1728
|
-
if (caseFold) query = query.toLowerCase();
|
1729
|
-
var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
|
1730
|
-
var target = query.split("\n");
|
1731
|
-
// Different methods for single-line and multi-line queries
|
1732
|
-
if (target.length == 1)
|
1733
|
-
this.matches = function(reverse, pos) {
|
1734
|
-
var line = fold(getLine(pos.line).text), len = query.length, match;
|
1735
|
-
if (reverse ? (pos.ch >= len && (match = line.lastIndexOf(query, pos.ch - len)) != -1)
|
1736
|
-
: (match = line.indexOf(query, pos.ch)) != -1)
|
1737
|
-
return {from: {line: pos.line, ch: match},
|
1738
|
-
to: {line: pos.line, ch: match + len}};
|
1739
|
-
};
|
1740
|
-
else
|
1741
|
-
this.matches = function(reverse, pos) {
|
1742
|
-
var ln = pos.line, idx = (reverse ? target.length - 1 : 0), match = target[idx], line = fold(getLine(ln).text);
|
1743
|
-
var offsetA = (reverse ? line.indexOf(match) + match.length : line.lastIndexOf(match));
|
1744
|
-
if (reverse ? offsetA >= pos.ch || offsetA != match.length
|
1745
|
-
: offsetA <= pos.ch || offsetA != line.length - match.length)
|
1746
|
-
return;
|
1747
|
-
for (;;) {
|
1748
|
-
if (reverse ? !ln : ln == doc.size - 1) return;
|
1749
|
-
line = fold(getLine(ln += reverse ? -1 : 1).text);
|
1750
|
-
match = target[reverse ? --idx : ++idx];
|
1751
|
-
if (idx > 0 && idx < target.length - 1) {
|
1752
|
-
if (line != match) return;
|
1753
|
-
else continue;
|
1754
|
-
}
|
1755
|
-
var offsetB = (reverse ? line.lastIndexOf(match) : line.indexOf(match) + match.length);
|
1756
|
-
if (reverse ? offsetB != line.length - match.length : offsetB != match.length)
|
1757
|
-
return;
|
1758
|
-
var start = {line: pos.line, ch: offsetA}, end = {line: ln, ch: offsetB};
|
1759
|
-
return {from: reverse ? end : start, to: reverse ? start : end};
|
1760
|
-
}
|
1761
|
-
};
|
1762
|
-
}
|
1763
|
-
}
|
1764
|
-
|
1765
|
-
SearchCursor.prototype = {
|
1766
|
-
findNext: function() {return this.find(false);},
|
1767
|
-
findPrevious: function() {return this.find(true);},
|
1768
|
-
|
1769
|
-
find: function(reverse) {
|
1770
|
-
var self = this, pos = clipPos(reverse ? this.pos.from : this.pos.to);
|
1771
|
-
function savePosAndFail(line) {
|
1772
|
-
var pos = {line: line, ch: 0};
|
1773
|
-
self.pos = {from: pos, to: pos};
|
1774
|
-
self.atOccurrence = false;
|
1775
|
-
return false;
|
1776
|
-
}
|
1777
|
-
|
1778
|
-
for (;;) {
|
1779
|
-
if (this.pos = this.matches(reverse, pos)) {
|
1780
|
-
this.atOccurrence = true;
|
1781
|
-
return this.pos.match || true;
|
1782
|
-
}
|
1783
|
-
if (reverse) {
|
1784
|
-
if (!pos.line) return savePosAndFail(0);
|
1785
|
-
pos = {line: pos.line-1, ch: getLine(pos.line-1).text.length};
|
1786
|
-
}
|
1787
|
-
else {
|
1788
|
-
if (pos.line == doc.size - 1) return savePosAndFail(doc.size);
|
1789
|
-
pos = {line: pos.line+1, ch: 0};
|
1790
|
-
}
|
1791
|
-
}
|
1792
|
-
},
|
1793
|
-
|
1794
|
-
from: function() {if (this.atOccurrence) return copyPos(this.pos.from);},
|
1795
|
-
to: function() {if (this.atOccurrence) return copyPos(this.pos.to);},
|
1796
|
-
|
1797
|
-
replace: function(newText) {
|
1798
|
-
var self = this;
|
1799
|
-
if (this.atOccurrence)
|
1800
|
-
operation(function() {
|
1801
|
-
self.pos.to = replaceRange(newText, self.pos.from, self.pos.to);
|
1802
|
-
})();
|
1803
|
-
}
|
1804
|
-
};
|
1805
|
-
|
1806
1703
|
for (var ext in extensions)
|
1807
1704
|
if (extensions.propertyIsEnumerable(ext) &&
|
1808
1705
|
!instance.propertyIsEnumerable(ext))
|
@@ -1817,8 +1714,9 @@ var CodeMirror = (function() {
|
|
1817
1714
|
theme: "default",
|
1818
1715
|
indentUnit: 2,
|
1819
1716
|
indentWithTabs: false,
|
1820
|
-
|
1821
|
-
|
1717
|
+
tabSize: 4,
|
1718
|
+
keyMap: "default",
|
1719
|
+
extraKeys: null,
|
1822
1720
|
electricChars: true,
|
1823
1721
|
onKeyEvent: null,
|
1824
1722
|
lineWrapping: false,
|
@@ -1827,21 +1725,24 @@ var CodeMirror = (function() {
|
|
1827
1725
|
fixedGutter: false,
|
1828
1726
|
firstLineNumber: 1,
|
1829
1727
|
readOnly: false,
|
1830
|
-
smartHome: true,
|
1831
1728
|
onChange: null,
|
1832
1729
|
onCursorActivity: null,
|
1833
1730
|
onGutterClick: null,
|
1834
1731
|
onHighlightComplete: null,
|
1732
|
+
onUpdate: null,
|
1835
1733
|
onFocus: null, onBlur: null, onScroll: null,
|
1836
1734
|
matchBrackets: false,
|
1837
1735
|
workTime: 100,
|
1838
1736
|
workDelay: 200,
|
1737
|
+
pollInterval: 100,
|
1839
1738
|
undoDepth: 40,
|
1840
1739
|
tabindex: null,
|
1841
|
-
pollForIME: false,
|
1842
1740
|
document: window.document
|
1843
1741
|
};
|
1844
1742
|
|
1743
|
+
var mac = /Mac/.test(navigator.platform);
|
1744
|
+
var win = /Win/.test(navigator.platform);
|
1745
|
+
|
1845
1746
|
// Known modes, by name and by MIME
|
1846
1747
|
var modes = {}, mimeModes = {};
|
1847
1748
|
CodeMirror.defineMode = function(name, mode) {
|
@@ -1878,11 +1779,114 @@ var CodeMirror = (function() {
|
|
1878
1779
|
return list;
|
1879
1780
|
};
|
1880
1781
|
|
1881
|
-
var extensions = {};
|
1782
|
+
var extensions = CodeMirror.extensions = {};
|
1882
1783
|
CodeMirror.defineExtension = function(name, func) {
|
1883
1784
|
extensions[name] = func;
|
1884
1785
|
};
|
1885
1786
|
|
1787
|
+
var commands = CodeMirror.commands = {
|
1788
|
+
selectAll: function(cm) {cm.setSelection({line: 0, ch: 0}, {line: cm.lineCount() - 1});},
|
1789
|
+
killLine: function(cm) {
|
1790
|
+
var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to);
|
1791
|
+
if (!sel && cm.getLine(from.line).length == from.ch) cm.replaceRange("", from, {line: from.line + 1, ch: 0});
|
1792
|
+
else cm.replaceRange("", from, sel ? to : {line: from.line});
|
1793
|
+
},
|
1794
|
+
deleteLine: function(cm) {var l = cm.getCursor().line; cm.replaceRange("", {line: l, ch: 0}, {line: l});},
|
1795
|
+
undo: function(cm) {cm.undo();},
|
1796
|
+
redo: function(cm) {cm.redo();},
|
1797
|
+
goDocStart: function(cm) {cm.setCursor(0, 0, true);},
|
1798
|
+
goDocEnd: function(cm) {cm.setSelection({line: cm.lineCount() - 1}, null, true);},
|
1799
|
+
goLineStart: function(cm) {cm.setCursor(cm.getCursor().line, 0, true);},
|
1800
|
+
goLineStartSmart: function(cm) {
|
1801
|
+
var cur = cm.getCursor();
|
1802
|
+
var text = cm.getLine(cur.line), firstNonWS = Math.max(0, text.search(/\S/));
|
1803
|
+
cm.setCursor(cur.line, cur.ch <= firstNonWS && cur.ch ? 0 : firstNonWS, true);
|
1804
|
+
},
|
1805
|
+
goLineEnd: function(cm) {cm.setSelection({line: cm.getCursor().line}, null, true);},
|
1806
|
+
goLineUp: function(cm) {cm.moveV(-1, "line");},
|
1807
|
+
goLineDown: function(cm) {cm.moveV(1, "line");},
|
1808
|
+
goPageUp: function(cm) {cm.moveV(-1, "page");},
|
1809
|
+
goPageDown: function(cm) {cm.moveV(1, "page");},
|
1810
|
+
goCharLeft: function(cm) {cm.moveH(-1, "char");},
|
1811
|
+
goCharRight: function(cm) {cm.moveH(1, "char");},
|
1812
|
+
goColumnLeft: function(cm) {cm.moveH(-1, "column");},
|
1813
|
+
goColumnRight: function(cm) {cm.moveH(1, "column");},
|
1814
|
+
goWordLeft: function(cm) {cm.moveH(-1, "word");},
|
1815
|
+
goWordRight: function(cm) {cm.moveH(1, "word");},
|
1816
|
+
delCharLeft: function(cm) {cm.deleteH(-1, "char");},
|
1817
|
+
delCharRight: function(cm) {cm.deleteH(1, "char");},
|
1818
|
+
delWordLeft: function(cm) {cm.deleteH(-1, "word");},
|
1819
|
+
delWordRight: function(cm) {cm.deleteH(1, "word");},
|
1820
|
+
indentAuto: function(cm) {cm.indentSelection("smart");},
|
1821
|
+
indentMore: function(cm) {cm.indentSelection("add");},
|
1822
|
+
indentLess: function(cm) {cm.indentSelection("subtract");},
|
1823
|
+
insertTab: function(cm) {cm.replaceSelection("\t", "end");},
|
1824
|
+
transposeChars: function(cm) {
|
1825
|
+
var cur = cm.getCursor(), line = cm.getLine(cur.line);
|
1826
|
+
if (cur.ch > 0 && cur.ch < line.length - 1)
|
1827
|
+
cm.replaceRange(line.charAt(cur.ch) + line.charAt(cur.ch - 1),
|
1828
|
+
{line: cur.line, ch: cur.ch - 1}, {line: cur.line, ch: cur.ch + 1});
|
1829
|
+
},
|
1830
|
+
newlineAndIndent: function(cm) {
|
1831
|
+
cm.replaceSelection("\n", "end");
|
1832
|
+
cm.indentLine(cm.getCursor().line);
|
1833
|
+
},
|
1834
|
+
toggleOverwrite: function(cm) {cm.toggleOverwrite();}
|
1835
|
+
};
|
1836
|
+
|
1837
|
+
var keyMap = CodeMirror.keyMap = {};
|
1838
|
+
keyMap.basic = {
|
1839
|
+
"Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
|
1840
|
+
"End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
|
1841
|
+
"Delete": "delCharRight", "Backspace": "delCharLeft", "Tab": "indentMore", "Shift-Tab": "indentLess",
|
1842
|
+
"Enter": "newlineAndIndent", "Insert": "toggleOverwrite"
|
1843
|
+
};
|
1844
|
+
// Note that the save and find-related commands aren't defined by
|
1845
|
+
// default. Unknown commands are simply ignored.
|
1846
|
+
keyMap.pcDefault = {
|
1847
|
+
"Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
|
1848
|
+
"Ctrl-Home": "goDocStart", "Alt-Up": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Down": "goDocEnd",
|
1849
|
+
"Ctrl-Left": "goWordLeft", "Ctrl-Right": "goWordRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
|
1850
|
+
"Ctrl-Backspace": "delWordLeft", "Ctrl-Delete": "delWordRight", "Ctrl-S": "save", "Ctrl-F": "find",
|
1851
|
+
"Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
|
1852
|
+
fallthrough: "basic"
|
1853
|
+
};
|
1854
|
+
keyMap.macDefault = {
|
1855
|
+
"Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
|
1856
|
+
"Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goWordLeft",
|
1857
|
+
"Alt-Right": "goWordRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delWordLeft",
|
1858
|
+
"Ctrl-Alt-Backspace": "delWordRight", "Alt-Delete": "delWordRight", "Cmd-S": "save", "Cmd-F": "find",
|
1859
|
+
"Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
|
1860
|
+
fallthrough: ["basic", "emacsy"]
|
1861
|
+
};
|
1862
|
+
keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
|
1863
|
+
keyMap.emacsy = {
|
1864
|
+
"Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
|
1865
|
+
"Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
|
1866
|
+
"Ctrl-V": "goPageUp", "Shift-Ctrl-V": "goPageDown", "Ctrl-D": "delCharRight", "Ctrl-H": "delCharLeft",
|
1867
|
+
"Alt-D": "delWordRight", "Alt-Backspace": "delWordLeft", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
|
1868
|
+
};
|
1869
|
+
|
1870
|
+
function lookupKey(name, extraMap, map) {
|
1871
|
+
function lookup(name, map, ft) {
|
1872
|
+
var found = map[name];
|
1873
|
+
if (found != null) return found;
|
1874
|
+
if (ft == null) ft = map.fallthrough;
|
1875
|
+
if (ft == null) return map.catchall;
|
1876
|
+
if (typeof ft == "string") return lookup(name, keyMap[ft]);
|
1877
|
+
for (var i = 0, e = ft.length; i < e; ++i) {
|
1878
|
+
found = lookup(name, keyMap[ft[i]]);
|
1879
|
+
if (found != null) return found;
|
1880
|
+
}
|
1881
|
+
return null;
|
1882
|
+
}
|
1883
|
+
return extraMap ? lookup(name, extraMap, map) : lookup(name, keyMap[map]);
|
1884
|
+
}
|
1885
|
+
function isModifierKey(event) {
|
1886
|
+
var name = keyNames[event.keyCode];
|
1887
|
+
return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
|
1888
|
+
}
|
1889
|
+
|
1886
1890
|
CodeMirror.fromTextArea = function(textarea, options) {
|
1887
1891
|
if (!options) options = {};
|
1888
1892
|
options.value = textarea.value;
|
@@ -1910,6 +1914,7 @@ var CodeMirror = (function() {
|
|
1910
1914
|
textarea.parentNode.insertBefore(node, textarea.nextSibling);
|
1911
1915
|
}, options);
|
1912
1916
|
instance.save = save;
|
1917
|
+
instance.getTextArea = function() { return textarea; };
|
1913
1918
|
instance.toTextArea = function() {
|
1914
1919
|
save();
|
1915
1920
|
textarea.parentNode.removeChild(instance.getWrapperElement());
|
@@ -1943,9 +1948,10 @@ var CodeMirror = (function() {
|
|
1943
1948
|
CodeMirror.startState = startState;
|
1944
1949
|
|
1945
1950
|
// The character stream used by a mode's parser.
|
1946
|
-
function StringStream(string) {
|
1951
|
+
function StringStream(string, tabSize) {
|
1947
1952
|
this.pos = this.start = 0;
|
1948
1953
|
this.string = string;
|
1954
|
+
this.tabSize = tabSize || 8;
|
1949
1955
|
}
|
1950
1956
|
StringStream.prototype = {
|
1951
1957
|
eol: function() {return this.pos >= this.string.length;},
|
@@ -1977,8 +1983,8 @@ var CodeMirror = (function() {
|
|
1977
1983
|
if (found > -1) {this.pos = found; return true;}
|
1978
1984
|
},
|
1979
1985
|
backUp: function(n) {this.pos -= n;},
|
1980
|
-
column: function() {return countColumn(this.string, this.start);},
|
1981
|
-
indentation: function() {return countColumn(this.string);},
|
1986
|
+
column: function() {return countColumn(this.string, this.start, this.tabSize);},
|
1987
|
+
indentation: function() {return countColumn(this.string, null, this.tabSize);},
|
1982
1988
|
match: function(pattern, consume, caseInsensitive) {
|
1983
1989
|
if (typeof pattern == "string") {
|
1984
1990
|
function cased(str) {return caseInsensitive ? str.toLowerCase() : str;}
|
@@ -2010,7 +2016,7 @@ var CodeMirror = (function() {
|
|
2010
2016
|
if (this.to <= pos && this.to != null) return null;
|
2011
2017
|
var from = this.from < pos || this.from == null ? null : this.from - pos + lenBefore;
|
2012
2018
|
var to = this.to == null ? null : this.to - pos + lenBefore;
|
2013
|
-
return new MarkedText(from, to, this.style, this.set);
|
2019
|
+
return new MarkedText(from, to, this.style, this.set);
|
2014
2020
|
},
|
2015
2021
|
dup: function() { return new MarkedText(null, null, this.style, this.set); },
|
2016
2022
|
clipTo: function(fromOpen, from, toOpen, to, diff) {
|
@@ -2067,11 +2073,11 @@ var CodeMirror = (function() {
|
|
2067
2073
|
this.styles = styles || [text, null];
|
2068
2074
|
this.text = text;
|
2069
2075
|
this.height = 1;
|
2070
|
-
this.marked = this.gutterMarker = this.className = null;
|
2076
|
+
this.marked = this.gutterMarker = this.className = this.handlers = null;
|
2071
2077
|
this.stateAfter = this.parent = this.hidden = null;
|
2072
2078
|
}
|
2073
2079
|
Line.inheritMarks = function(text, orig) {
|
2074
|
-
var ln = new Line(text), mk = orig.marked;
|
2080
|
+
var ln = new Line(text), mk = orig && orig.marked;
|
2075
2081
|
if (mk) {
|
2076
2082
|
for (var i = 0; i < mk.length; ++i) {
|
2077
2083
|
if (mk[i].to == null && mk[i].style) {
|
@@ -2085,9 +2091,6 @@ var CodeMirror = (function() {
|
|
2085
2091
|
Line.prototype = {
|
2086
2092
|
// Replace a piece of a line, keeping the styles around it intact.
|
2087
2093
|
replace: function(from, to_, text) {
|
2088
|
-
// Reset line class if the whole text was replaced.
|
2089
|
-
if (!from && (to_ == null || to_ == this.text.length))
|
2090
|
-
this.className = this.gutterMarker = null;
|
2091
2094
|
var st = [], mk = this.marked, to = to_ == null ? this.text.length : to_;
|
2092
2095
|
copyStyles(0, from, this.styles, st);
|
2093
2096
|
if (text) st.push(text, null);
|
@@ -2164,6 +2167,12 @@ var CodeMirror = (function() {
|
|
2164
2167
|
if (close) mark.to = this.text.length;
|
2165
2168
|
}
|
2166
2169
|
},
|
2170
|
+
fixMarkStarts: function() {
|
2171
|
+
var mk = this.marked;
|
2172
|
+
if (!mk) return;
|
2173
|
+
for (var i = 0; i < mk.length; ++i)
|
2174
|
+
if (mk[i].from == null) mk[i].from = 0;
|
2175
|
+
},
|
2167
2176
|
addMark: function(mark) {
|
2168
2177
|
mark.attach(this);
|
2169
2178
|
if (this.marked == null) this.marked = [];
|
@@ -2173,8 +2182,8 @@ var CodeMirror = (function() {
|
|
2173
2182
|
// Run the given mode's parser over a line, update the styles
|
2174
2183
|
// array, which contains alternating fragments of text and CSS
|
2175
2184
|
// classes.
|
2176
|
-
highlight: function(mode, state) {
|
2177
|
-
var stream = new StringStream(this.text), st = this.styles, pos = 0;
|
2185
|
+
highlight: function(mode, state, tabSize) {
|
2186
|
+
var stream = new StringStream(this.text, tabSize), st = this.styles, pos = 0;
|
2178
2187
|
var changed = false, curWord = st[0], prevWord;
|
2179
2188
|
if (this.text == "" && mode.blankLine) mode.blankLine(state);
|
2180
2189
|
while (!stream.eol()) {
|
@@ -2215,10 +2224,10 @@ var CodeMirror = (function() {
|
|
2215
2224
|
className: style || null,
|
2216
2225
|
state: state};
|
2217
2226
|
},
|
2218
|
-
indentation: function() {return countColumn(this.text);},
|
2227
|
+
indentation: function(tabSize) {return countColumn(this.text, null, tabSize);},
|
2219
2228
|
// Produces an HTML fragment for the line, taking selection,
|
2220
2229
|
// marking, and highlighting into account.
|
2221
|
-
getHTML: function(sfrom, sto, includePre, endAt) {
|
2230
|
+
getHTML: function(sfrom, sto, includePre, tabText, endAt) {
|
2222
2231
|
var html = [], first = true;
|
2223
2232
|
if (includePre)
|
2224
2233
|
html.push(this.className ? '<pre class="' + this.className + '">': "<pre>");
|
@@ -2227,8 +2236,8 @@ var CodeMirror = (function() {
|
|
2227
2236
|
// Work around a bug where, in some compat modes, IE ignores leading spaces
|
2228
2237
|
if (first && ie && text.charAt(0) == " ") text = "\u00a0" + text.slice(1);
|
2229
2238
|
first = false;
|
2230
|
-
if (style) html.push('<span class="', style, '">', htmlEscape(text), "</span>");
|
2231
|
-
else html.push(htmlEscape(text));
|
2239
|
+
if (style) html.push('<span class="', style, '">', htmlEscape(text).replace(/\t/g, tabText), "</span>");
|
2240
|
+
else html.push(htmlEscape(text).replace(/\t/g, tabText));
|
2232
2241
|
}
|
2233
2242
|
var st = this.styles, allText = this.text, marked = this.marked;
|
2234
2243
|
if (sfrom == sto) sfrom = null;
|
@@ -2321,11 +2330,13 @@ var CodeMirror = (function() {
|
|
2321
2330
|
}
|
2322
2331
|
LeafChunk.prototype = {
|
2323
2332
|
chunkSize: function() { return this.lines.length; },
|
2324
|
-
remove: function(at, n) {
|
2333
|
+
remove: function(at, n, callbacks) {
|
2325
2334
|
for (var i = at, e = at + n; i < e; ++i) {
|
2326
2335
|
var line = this.lines[i];
|
2327
|
-
line.cleanUp();
|
2328
2336
|
this.height -= line.height;
|
2337
|
+
line.cleanUp();
|
2338
|
+
if (line.handlers)
|
2339
|
+
for (var j = 0; j < line.handlers.length; ++j) callbacks.push(line.handlers[j]);
|
2329
2340
|
}
|
2330
2341
|
this.lines.splice(at, n);
|
2331
2342
|
},
|
@@ -2356,13 +2367,13 @@ var CodeMirror = (function() {
|
|
2356
2367
|
}
|
2357
2368
|
BranchChunk.prototype = {
|
2358
2369
|
chunkSize: function() { return this.size; },
|
2359
|
-
remove: function(at, n) {
|
2370
|
+
remove: function(at, n, callbacks) {
|
2360
2371
|
this.size -= n;
|
2361
2372
|
for (var i = 0; i < this.children.length; ++i) {
|
2362
2373
|
var child = this.children[i], sz = child.chunkSize();
|
2363
2374
|
if (at < sz) {
|
2364
2375
|
var rm = Math.min(n, sz - at), oldHeight = child.height;
|
2365
|
-
child.remove(at, rm);
|
2376
|
+
child.remove(at, rm, callbacks);
|
2366
2377
|
this.height -= oldHeight - child.height;
|
2367
2378
|
if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }
|
2368
2379
|
if ((n -= rm) == 0) break;
|
@@ -2441,14 +2452,14 @@ var CodeMirror = (function() {
|
|
2441
2452
|
};
|
2442
2453
|
|
2443
2454
|
function getLineAt(chunk, n) {
|
2444
|
-
|
2445
|
-
for (var i = 0
|
2455
|
+
while (!chunk.lines) {
|
2456
|
+
for (var i = 0;; ++i) {
|
2446
2457
|
var child = chunk.children[i], sz = child.chunkSize();
|
2447
2458
|
if (n < sz) { chunk = child; break; }
|
2448
2459
|
n -= sz;
|
2449
2460
|
}
|
2450
|
-
if (chunk.lines) return chunk.lines[n];
|
2451
2461
|
}
|
2462
|
+
return chunk.lines[n];
|
2452
2463
|
}
|
2453
2464
|
function lineNo(line) {
|
2454
2465
|
if (line.parent == null) return null;
|
@@ -2543,6 +2554,10 @@ var CodeMirror = (function() {
|
|
2543
2554
|
else e.cancelBubble = true;
|
2544
2555
|
}
|
2545
2556
|
function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
|
2557
|
+
CodeMirror.e_stop = e_stop;
|
2558
|
+
CodeMirror.e_preventDefault = e_preventDefault;
|
2559
|
+
CodeMirror.e_stopPropagation = e_stopPropagation;
|
2560
|
+
|
2546
2561
|
function e_target(e) {return e.target || e.srcElement;}
|
2547
2562
|
function e_button(e) {
|
2548
2563
|
if (e.which) return e.which;
|
@@ -2554,16 +2569,17 @@ var CodeMirror = (function() {
|
|
2554
2569
|
// Event handler registration. If disconnect is true, it'll return a
|
2555
2570
|
// function that unregisters the handler.
|
2556
2571
|
function connect(node, type, handler, disconnect) {
|
2557
|
-
function wrapHandler(event) {handler(event || window.event);}
|
2558
2572
|
if (typeof node.addEventListener == "function") {
|
2559
|
-
node.addEventListener(type,
|
2560
|
-
if (disconnect) return function() {node.removeEventListener(type,
|
2573
|
+
node.addEventListener(type, handler, false);
|
2574
|
+
if (disconnect) return function() {node.removeEventListener(type, handler, false);};
|
2561
2575
|
}
|
2562
2576
|
else {
|
2577
|
+
var wrapHandler = function(event) {handler(event || window.event);};
|
2563
2578
|
node.attachEvent("on" + type, wrapHandler);
|
2564
2579
|
if (disconnect) return function() {node.detachEvent("on" + type, wrapHandler);};
|
2565
2580
|
}
|
2566
2581
|
}
|
2582
|
+
CodeMirror.connect = connect;
|
2567
2583
|
|
2568
2584
|
function Delayed() {this.id = null;}
|
2569
2585
|
Delayed.prototype = {set: function(ms, f) {clearTimeout(this.id); this.id = setTimeout(f, ms);}};
|
@@ -2589,16 +2605,9 @@ var CodeMirror = (function() {
|
|
2589
2605
|
if (te.value.indexOf("\r") > -1) lineSep = "\r\n";
|
2590
2606
|
}());
|
2591
2607
|
|
2592
|
-
var tabSize = 8;
|
2593
|
-
var mac = /Mac/.test(navigator.platform);
|
2594
|
-
var win = /Win/.test(navigator.platform);
|
2595
|
-
var movementKeys = {};
|
2596
|
-
for (var i = 35; i <= 40; ++i)
|
2597
|
-
movementKeys[i] = movementKeys["c" + i] = true;
|
2598
|
-
|
2599
2608
|
// Counts the column offset in a string, taking tabs into account.
|
2600
2609
|
// Used mostly to find indentation.
|
2601
|
-
function countColumn(string, end) {
|
2610
|
+
function countColumn(string, end, tabSize) {
|
2602
2611
|
if (end == null) {
|
2603
2612
|
end = string.search(/[^\s\u00a0]/);
|
2604
2613
|
if (end == -1) end = string.length;
|
@@ -2664,15 +2673,23 @@ var CodeMirror = (function() {
|
|
2664
2673
|
|
2665
2674
|
var escapeElement = document.createElement("pre");
|
2666
2675
|
function htmlEscape(str) {
|
2667
|
-
|
2668
|
-
escapeElement.innerHTML = "";
|
2669
|
-
escapeElement.appendChild(document.createTextNode(str));
|
2670
|
-
} else {
|
2671
|
-
escapeElement.textContent = str;
|
2672
|
-
}
|
2676
|
+
escapeElement.textContent = str;
|
2673
2677
|
return escapeElement.innerHTML;
|
2674
2678
|
}
|
2675
|
-
|
2679
|
+
// Recent (late 2011) Opera betas insert bogus newlines at the start
|
2680
|
+
// of the textContent, so we strip those.
|
2681
|
+
if (htmlEscape("a") == "\na")
|
2682
|
+
htmlEscape = function(str) {
|
2683
|
+
escapeElement.textContent = str;
|
2684
|
+
return escapeElement.innerHTML.slice(1);
|
2685
|
+
};
|
2686
|
+
// Some IEs don't preserve tabs through innerHTML
|
2687
|
+
else if (htmlEscape("\t") != "\t")
|
2688
|
+
htmlEscape = function(str) {
|
2689
|
+
escapeElement.innerHTML = "";
|
2690
|
+
escapeElement.appendChild(document.createTextNode(str));
|
2691
|
+
return escapeElement.innerHTML;
|
2692
|
+
};
|
2676
2693
|
CodeMirror.htmlEscape = htmlEscape;
|
2677
2694
|
|
2678
2695
|
// Used to position the cursor after an undo/redo by finding the
|
@@ -2691,95 +2708,54 @@ var CodeMirror = (function() {
|
|
2691
2708
|
if (collection[i] == elt) return i;
|
2692
2709
|
return -1;
|
2693
2710
|
}
|
2711
|
+
function isWordChar(ch) {
|
2712
|
+
return /\w/.test(ch) || ch.toUpperCase() != ch.toLowerCase();
|
2713
|
+
}
|
2694
2714
|
|
2695
2715
|
// See if "".split is the broken IE version, if so, provide an
|
2696
2716
|
// alternative way to split lines.
|
2697
|
-
var splitLines
|
2698
|
-
|
2699
|
-
|
2700
|
-
|
2701
|
-
|
2702
|
-
|
2703
|
-
|
2704
|
-
|
2705
|
-
|
2706
|
-
return result;
|
2707
|
-
};
|
2708
|
-
else
|
2709
|
-
splitLines = function(string){return string.split(/\r?\n/);};
|
2717
|
+
var splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
|
2718
|
+
var pos = 0, nl, result = [];
|
2719
|
+
while ((nl = string.indexOf("\n", pos)) > -1) {
|
2720
|
+
result.push(string.slice(pos, string.charAt(nl-1) == "\r" ? nl - 1 : nl));
|
2721
|
+
pos = nl + 1;
|
2722
|
+
}
|
2723
|
+
result.push(string.slice(pos));
|
2724
|
+
return result;
|
2725
|
+
} : function(string){return string.split(/\r?\n/);};
|
2710
2726
|
CodeMirror.splitLines = splitLines;
|
2711
2727
|
|
2712
|
-
|
2713
|
-
|
2714
|
-
|
2715
|
-
|
2716
|
-
|
2717
|
-
}
|
2718
|
-
if (
|
2719
|
-
|
2720
|
-
|
2721
|
-
// the anchor is put at the end, and the selection expanded to
|
2722
|
-
// the left. If you press shift-right, the anchor ends up at the
|
2723
|
-
// front. This is not what CodeMirror wants, so it does a
|
2724
|
-
// spurious modify() call to get out of limbo.
|
2725
|
-
setSelRange = function(te, start, end) {
|
2726
|
-
if (start == end)
|
2727
|
-
te.setSelectionRange(start, end);
|
2728
|
-
else {
|
2729
|
-
te.setSelectionRange(start, end - 1);
|
2730
|
-
window.getSelection().modify("extend", "forward", "character");
|
2731
|
-
}
|
2732
|
-
};
|
2733
|
-
else
|
2734
|
-
setSelRange = function(te, start, end) {
|
2735
|
-
try {te.setSelectionRange(start, end);}
|
2736
|
-
catch(e) {} // Fails on Firefox when textarea isn't part of the document
|
2737
|
-
};
|
2738
|
-
}
|
2739
|
-
// IE model. Don't ask.
|
2740
|
-
else {
|
2741
|
-
selRange = function(te) {
|
2742
|
-
try {var range = te.ownerDocument.selection.createRange();}
|
2743
|
-
catch(e) {return null;}
|
2744
|
-
if (!range || range.parentElement() != te) return null;
|
2745
|
-
var val = te.value, len = val.length, localRange = te.createTextRange();
|
2746
|
-
localRange.moveToBookmark(range.getBookmark());
|
2747
|
-
var endRange = te.createTextRange();
|
2748
|
-
endRange.collapse(false);
|
2749
|
-
|
2750
|
-
if (localRange.compareEndPoints("StartToEnd", endRange) > -1)
|
2751
|
-
return {start: len, end: len};
|
2752
|
-
|
2753
|
-
var start = -localRange.moveStart("character", -len);
|
2754
|
-
for (var i = val.indexOf("\r"); i > -1 && i < start; i = val.indexOf("\r", i+1), start++) {}
|
2755
|
-
|
2756
|
-
if (localRange.compareEndPoints("EndToEnd", endRange) > -1)
|
2757
|
-
return {start: start, end: len};
|
2758
|
-
|
2759
|
-
var end = -localRange.moveEnd("character", -len);
|
2760
|
-
for (var i = val.indexOf("\r"); i > -1 && i < end; i = val.indexOf("\r", i+1), end++) {}
|
2761
|
-
return {start: start, end: end};
|
2762
|
-
};
|
2763
|
-
setSelRange = function(te, start, end) {
|
2764
|
-
var range = te.createTextRange();
|
2765
|
-
range.collapse(true);
|
2766
|
-
var endrange = range.duplicate();
|
2767
|
-
var newlines = 0, txt = te.value;
|
2768
|
-
for (var pos = txt.indexOf("\n"); pos > -1 && pos < start; pos = txt.indexOf("\n", pos + 1))
|
2769
|
-
++newlines;
|
2770
|
-
range.move("character", start - newlines);
|
2771
|
-
for (; pos > -1 && pos < end; pos = txt.indexOf("\n", pos + 1))
|
2772
|
-
++newlines;
|
2773
|
-
endrange.move("character", end - newlines);
|
2774
|
-
range.setEndPoint("EndToEnd", endrange);
|
2775
|
-
range.select();
|
2776
|
-
};
|
2777
|
-
}
|
2728
|
+
var hasSelection = window.getSelection ? function(te) {
|
2729
|
+
try { return te.selectionStart != te.selectionEnd; }
|
2730
|
+
catch(e) { return false; }
|
2731
|
+
} : function(te) {
|
2732
|
+
try {var range = te.ownerDocument.selection.createRange();}
|
2733
|
+
catch(e) {}
|
2734
|
+
if (!range || range.parentElement() != te) return false;
|
2735
|
+
return range.compareEndPoints("StartToEnd", range) != 0;
|
2736
|
+
};
|
2778
2737
|
|
2779
2738
|
CodeMirror.defineMode("null", function() {
|
2780
2739
|
return {token: function(stream) {stream.skipToEnd();}};
|
2781
2740
|
});
|
2782
2741
|
CodeMirror.defineMIME("text/plain", "null");
|
2783
2742
|
|
2743
|
+
var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
|
2744
|
+
19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
|
2745
|
+
36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
|
2746
|
+
46: "Delete", 59: ";", 91: "Mod", 92: "Mod", 93: "Mod", 186: ";", 187: "=", 188: ",",
|
2747
|
+
189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", 221: "]", 222: "'", 63276: "PageUp",
|
2748
|
+
63277: "PageDown", 63275: "End", 63273: "Home", 63234: "Left", 63232: "Up", 63235: "Right",
|
2749
|
+
63233: "Down", 63302: "Insert", 63272: "Delete"};
|
2750
|
+
CodeMirror.keyNames = keyNames;
|
2751
|
+
(function() {
|
2752
|
+
// Number keys
|
2753
|
+
for (var i = 0; i < 10; i++) keyNames[i + 48] = String(i);
|
2754
|
+
// Alphabetic keys
|
2755
|
+
for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);
|
2756
|
+
// Function keys
|
2757
|
+
for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
|
2758
|
+
})();
|
2759
|
+
|
2784
2760
|
return CodeMirror;
|
2785
2761
|
})();
|