codemirror-rails 0.3.2 → 2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
})();
|