codemirror-rails 0.3.0 → 0.3.1

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.
@@ -1,6 +1,6 @@
1
1
  module Codemirror
2
2
  module Rails
3
- VERSION = '0.3.0'
4
- CODEMIRROR_VERSION = '2.15'
3
+ VERSION = '0.3.1'
4
+ CODEMIRROR_VERSION = '2.16'
5
5
  end
6
6
  end
@@ -20,7 +20,7 @@ var CodeMirror = (function() {
20
20
  // This mess creates the base DOM structure for the editor.
21
21
  wrapper.innerHTML =
22
22
  '<div style="overflow: hidden; position: relative; width: 1px; height: 0px;">' + // Wraps and hides input textarea
23
- '<textarea style="position: absolute; width: 2px;" wrap="off" ' +
23
+ '<textarea style="position: absolute; width: 10000px;" wrap="off" ' +
24
24
  'autocorrect="off" autocapitalize="off"></textarea></div>' +
25
25
  '<div class="CodeMirror-scroll cm-s-' + options.theme + '">' +
26
26
  '<div style="position: relative">' + // Set to the height of the text, causes scrolling
@@ -43,6 +43,15 @@ var CodeMirror = (function() {
43
43
  if (options.tabindex != null) input.tabindex = options.tabindex;
44
44
  if (!options.gutter && !options.lineNumbers) gutter.style.display = "none";
45
45
 
46
+ // Check for problem with IE innerHTML not working when we have a
47
+ // P (or similar) parent node.
48
+ try { stringWidth("x"); }
49
+ catch (e) {
50
+ if (e.message.match(/unknown runtime/i))
51
+ e = new Error("A CodeMirror inside a P-style element does not work in Internet Explorer. (innerHTML bug)");
52
+ throw e;
53
+ }
54
+
46
55
  // Delayed object wrap timeouts, making sure only one is active. blinker holds an interval.
47
56
  var poll = new Delayed(), highlight = new Delayed(), blinker;
48
57
 
@@ -50,7 +59,7 @@ var CodeMirror = (function() {
50
59
  // (see Line constructor), work an array of lines that should be
51
60
  // parsed, and history the undo history (instance of History
52
61
  // constructor).
53
- var mode, lines = [new Line("")], work, history = new History(), focused;
62
+ var mode, lines = [new Line("")], work, focused;
54
63
  loadMode();
55
64
  // The selection. These are always maintained to point at valid
56
65
  // positions. Inverted is used to remember that the user is
@@ -60,7 +69,7 @@ var CodeMirror = (function() {
60
69
  // whether the user is holding shift. reducedSelection is a hack
61
70
  // to get around the fact that we can't create inverted
62
71
  // selections. See below.
63
- var shiftSelecting, reducedSelection, lastClick, lastDoubleClick;
72
+ var shiftSelecting, reducedSelection, lastClick, lastDoubleClick, draggingText;
64
73
  // Variables used by startOperation/endOperation to track what
65
74
  // happened during the operation.
66
75
  var updateInput, changes, textChanged, selectionChanged, leaveInputAlone, gutterDirty;
@@ -77,9 +86,11 @@ var CodeMirror = (function() {
77
86
 
78
87
  // Initialize the content.
79
88
  operation(function(){setValue(options.value || ""); updateInput = false;})();
89
+ var history = new History();
80
90
 
81
91
  // Register our event handlers.
82
92
  connect(scroller, "mousedown", operation(onMouseDown));
93
+ connect(scroller, "dblclick", operation(onDoubleClick));
83
94
  connect(lineSpace, "dragstart", onDragStart);
84
95
  // Gecko browsers fire contextmenu *after* opening the menu, at
85
96
  // which point we can't mess with it anymore. Context menu is
@@ -92,6 +103,7 @@ var CodeMirror = (function() {
92
103
  });
93
104
  connect(window, "resize", function() {updateDisplay(true);});
94
105
  connect(input, "keyup", operation(onKeyUp));
106
+ connect(input, "input", function() {fastPoll(curKeyId);});
95
107
  connect(input, "keydown", operation(onKeyDown));
96
108
  connect(input, "keypress", operation(onKeyPress));
97
109
  connect(input, "focus", onFocus);
@@ -103,8 +115,8 @@ var CodeMirror = (function() {
103
115
  connect(scroller, "paste", function(){focusInput(); fastPoll();});
104
116
  connect(input, "paste", function(){fastPoll();});
105
117
  connect(input, "cut", function(){fastPoll();});
106
-
107
- // IE throws unspecified error in certain cases, when
118
+
119
+ // IE throws unspecified error in certain cases, when
108
120
  // trying to access activeElement before onload
109
121
  var hasFocus; try { hasFocus = (targetDocument.activeElement == input); } catch(e) { }
110
122
  if (hasFocus) setTimeout(onFocus, 20);
@@ -137,6 +149,7 @@ var CodeMirror = (function() {
137
149
  if (isLine(n)) indentLine(n, dir == null ? "smart" : dir ? "add" : "subtract");
138
150
  }),
139
151
  historySize: function() {return {undo: history.done.length, redo: history.undone.length};},
152
+ clearHistory: function() {history = new History();},
140
153
  matchBrackets: operation(function(){matchBrackets(true);}),
141
154
  getTokenAt: function(pos) {
142
155
  pos = clipPos(pos);
@@ -157,7 +170,7 @@ var CodeMirror = (function() {
157
170
  return clipPos({line: line, ch: charFromX(clipLine(line), coords.x - off.left)});
158
171
  },
159
172
  getSearchCursor: function(query, pos, caseFold) {return new SearchCursor(query, pos, caseFold);},
160
- markText: operation(function(a, b, c){return operation(markText(a, b, c));}),
173
+ markText: operation(markText),
161
174
  setMarker: operation(addGutterMarker),
162
175
  clearMarker: operation(removeGutterMarker),
163
176
  setLineClass: operation(setLineClass),
@@ -211,6 +224,17 @@ var CodeMirror = (function() {
211
224
  replaceRange: operation(replaceRange),
212
225
  getRange: function(from, to) {return getRange(clipPos(from), clipPos(to));},
213
226
 
227
+ coordsFromIndex: function(index) {
228
+ var total = lines.length, pos = 0, line, ch, len;
229
+
230
+ for (line = 0; line < total; line++) {
231
+ len = lines[line].text.length + 1;
232
+ if (pos + len > index) { ch = index - pos; break; }
233
+ pos += len;
234
+ }
235
+ return clipPos({line: line, ch: ch});
236
+ },
237
+
214
238
  operation: function(f){return operation(f)();},
215
239
  refresh: function(){updateDisplay(true);},
216
240
  getInputField: function(){return input;},
@@ -220,11 +244,9 @@ var CodeMirror = (function() {
220
244
  };
221
245
 
222
246
  function setValue(code) {
223
- history = null;
224
247
  var top = {line: 0, ch: 0};
225
248
  updateLines(top, {line: lines.length - 1, ch: lines[lines.length-1].text.length},
226
249
  splitLines(code), top, top);
227
- history = new History();
228
250
  updateInput = true;
229
251
  }
230
252
  function getValue(code) {
@@ -248,7 +270,7 @@ var CodeMirror = (function() {
248
270
  }
249
271
 
250
272
  var start = posFromMouse(e);
251
-
273
+
252
274
  switch (e_button(e)) {
253
275
  case 3:
254
276
  if (gecko && !mac) onContextMenu(e);
@@ -263,7 +285,7 @@ var CodeMirror = (function() {
263
285
  if (!start) {if (e_target(e) == scroller) e_preventDefault(e); return;}
264
286
 
265
287
  if (!focused) onFocus();
266
-
288
+
267
289
  var now = +new Date;
268
290
  if (lastDoubleClick > now - 400) {
269
291
  e_preventDefault(e);
@@ -278,6 +300,16 @@ var CodeMirror = (function() {
278
300
  if (dragAndDrop && !posEq(sel.from, sel.to) &&
279
301
  !posLess(start, sel.from) && !posLess(sel.to, start)) {
280
302
  // Let the drag handler handle this.
303
+ var up = connect(targetDocument, "mouseup", operation(function(e2) {
304
+ draggingText = false;
305
+ up();
306
+ if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
307
+ e_preventDefault(e2);
308
+ setCursor(start.line, start.ch, true);
309
+ focusInput();
310
+ }
311
+ }), true);
312
+ draggingText = true;
281
313
  return;
282
314
  }
283
315
  e_preventDefault(e);
@@ -311,6 +343,13 @@ var CodeMirror = (function() {
311
343
  move(); up();
312
344
  }), true);
313
345
  }
346
+ function onDoubleClick(e) {
347
+ var start = posFromMouse(e);
348
+ if (!start) return;
349
+ lastDoubleClick = +new Date;
350
+ e_preventDefault(e);
351
+ selectWordAt(start);
352
+ }
314
353
  function onDrop(e) {
315
354
  e.preventDefault();
316
355
  var pos = posFromMouse(e, true), files = e.dataTransfer.files;
@@ -320,7 +359,11 @@ var CodeMirror = (function() {
320
359
  var reader = new FileReader;
321
360
  reader.onload = function() {
322
361
  text[i] = reader.result;
323
- if (++read == n) replaceRange(text.join(""), clipPos(pos), clipPos(pos));
362
+ if (++read == n) {
363
+ pos = clipPos(pos);
364
+ var end = replaceRange(text.join(""), pos, pos);
365
+ setSelectionUser(pos, end);
366
+ }
324
367
  };
325
368
  reader.readAsText(file);
326
369
  }
@@ -330,7 +373,13 @@ var CodeMirror = (function() {
330
373
  else {
331
374
  try {
332
375
  var text = e.dataTransfer.getData("Text");
333
- if (text) replaceRange(text, pos, pos);
376
+ if (text) {
377
+ var end = replaceRange(text, pos, pos);
378
+ var curFrom = sel.from, curTo = sel.to;
379
+ setSelectionUser(pos, end);
380
+ if (draggingText) replaceRange("", curFrom, curTo);
381
+ focusInput();
382
+ }
334
383
  }
335
384
  catch(e){}
336
385
  }
@@ -471,21 +520,25 @@ var CodeMirror = (function() {
471
520
  else {
472
521
  lastLine = firstLine.split(to.ch, newText[newText.length-1]);
473
522
  var spliceargs = [from.line + 1, nlines];
474
- firstLine.replace(from.ch, firstLine.text.length, newText[0]);
475
- for (var i = 1, e = newText.length - 1; i < e; ++i) spliceargs.push(new Line(newText[i]));
523
+ firstLine.replace(from.ch, null, newText[0]);
524
+ for (var i = 1, e = newText.length - 1; i < e; ++i)
525
+ spliceargs.push(Line.inheritMarks(newText[i], firstLine));
476
526
  spliceargs.push(lastLine);
477
527
  lines.splice.apply(lines, spliceargs);
478
528
  }
479
529
  }
480
530
  else if (newText.length == 1) {
481
- firstLine.replace(from.ch, firstLine.text.length, newText[0] + lastLine.text.slice(to.ch));
531
+ firstLine.replace(from.ch, null, newText[0]);
532
+ lastLine.replace(null, to.ch, "");
533
+ firstLine.append(lastLine);
482
534
  lines.splice(from.line + 1, nlines);
483
535
  }
484
536
  else {
485
537
  var spliceargs = [from.line + 1, nlines - 1];
486
- firstLine.replace(from.ch, firstLine.text.length, newText[0]);
487
- lastLine.replace(0, to.ch, newText[newText.length-1]);
488
- for (var i = 1, e = newText.length - 1; i < e; ++i) spliceargs.push(new Line(newText[i]));
538
+ firstLine.replace(from.ch, null, newText[0]);
539
+ lastLine.replace(null, to.ch, newText[newText.length-1]);
540
+ for (var i = 1, e = newText.length - 1; i < e; ++i)
541
+ spliceargs.push(Line.inheritMarks(newText[i], firstLine));
489
542
  lines.splice.apply(lines, spliceargs);
490
543
  }
491
544
 
@@ -699,7 +752,7 @@ var CodeMirror = (function() {
699
752
  function scrollEditorIntoView() {
700
753
  if (!cursor.getBoundingClientRect) return;
701
754
  var rect = cursor.getBoundingClientRect();
702
- var winH = window.innerHeight || document.body.offsetHeight || document.documentElement.offsetHeight;
755
+ var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
703
756
  if (rect.top < 0 || rect.bottom > winH) cursor.scrollIntoView();
704
757
  }
705
758
  function scrollCursorIntoView() {
@@ -755,7 +808,7 @@ var CodeMirror = (function() {
755
808
  intact2.push(range);
756
809
  else {
757
810
  if (change.from > range.from)
758
- intact2.push({from: range.from, to: change.from, domStart: range.domStart})
811
+ intact2.push({from: range.from, to: change.from, domStart: range.domStart});
759
812
  if (change.to < range.to)
760
813
  intact2.push({from: change.to + diff, to: range.to + diff,
761
814
  domStart: range.domStart + (change.to - range.from)});
@@ -1091,11 +1144,9 @@ var CodeMirror = (function() {
1091
1144
 
1092
1145
  function markText(from, to, className) {
1093
1146
  from = clipPos(from); to = clipPos(to);
1094
- var accum = [];
1147
+ var set = [];
1095
1148
  function add(line, from, to, className) {
1096
- var line = lines[line], mark = line.addMark(from, to, className);
1097
- mark.line = line;
1098
- accum.push(mark);
1149
+ mark = lines[line].addMark(from, to, className, set);
1099
1150
  }
1100
1151
  if (from.line == to.line) add(from.line, from.ch, to.ch, className);
1101
1152
  else {
@@ -1105,19 +1156,40 @@ var CodeMirror = (function() {
1105
1156
  add(to.line, 0, to.ch, className);
1106
1157
  }
1107
1158
  changes.push({from: from.line, to: to.line + 1});
1108
- return function() {
1109
- var start, end;
1110
- for (var i = 0; i < accum.length; ++i) {
1111
- var mark = accum[i], found = indexOf(lines, mark.line);
1112
- mark.line.removeMark(mark);
1113
- if (found > -1) {
1114
- if (start == null) start = found;
1115
- end = found;
1159
+ return new TextMarker(set);
1160
+ }
1161
+
1162
+ function TextMarker(set) { this.set = set; }
1163
+ TextMarker.prototype.clear = operation(function() {
1164
+ for (var i = 0, e = this.set.length; i < e; ++i) {
1165
+ var mk = this.set[i].marked;
1166
+ for (var j = 0; j < mk.length; ++j) {
1167
+ if (mk[j].set == this.set) mk.splice(j--, 1);
1168
+ }
1169
+ }
1170
+ // We don't know the exact lines that changed. Refreshing is
1171
+ // cheaper than finding them.
1172
+ changes.push({from: 0, to: lines.length});
1173
+ });
1174
+ TextMarker.prototype.find = function() {
1175
+ var from, to;
1176
+ for (var i = 0, e = this.set.length; i < e; ++i) {
1177
+ var line = this.set[i], mk = line.marked;
1178
+ for (var j = 0; j < mk.length; ++j) {
1179
+ var mark = mk[j];
1180
+ if (mark.set == this.set) {
1181
+ if (mark.from != null || mark.to != null) {
1182
+ var found = indexOf(lines, line);
1183
+ if (found > -1) {
1184
+ if (mark.from != null) from = {line: found, ch: mark.from};
1185
+ if (mark.to != null) to = {line: found, ch: mark.to};
1186
+ }
1187
+ }
1116
1188
  }
1117
1189
  }
1118
- if (start != null) changes.push({from: start, to: end + 1});
1119
- };
1120
- }
1190
+ }
1191
+ return {from: from, to: to};
1192
+ };
1121
1193
 
1122
1194
  function addGutterMarker(line, text, className) {
1123
1195
  if (typeof line == "number") line = lines[clipLine(line)];
@@ -1255,7 +1327,7 @@ var CodeMirror = (function() {
1255
1327
  prepareInput();
1256
1328
  slowPoll();
1257
1329
  }
1258
-
1330
+
1259
1331
  if (gecko) {
1260
1332
  e_stop(e);
1261
1333
  var mouseup = connect(window, "mouseup", function() {
@@ -1312,10 +1384,8 @@ var CodeMirror = (function() {
1312
1384
  if (!found) found = {pos: null, match: false};
1313
1385
  var style = found.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
1314
1386
  var one = markText({line: head.line, ch: pos}, {line: head.line, ch: pos+1}, style),
1315
- two = found.pos != null
1316
- ? markText({line: i, ch: found.pos}, {line: i, ch: found.pos + 1}, style)
1317
- : function() {};
1318
- var clear = operation(function(){one(); two();});
1387
+ two = found.pos != null && markText({line: i, ch: found.pos}, {line: i, ch: found.pos + 1}, style);
1388
+ var clear = operation(function(){one.clear(); two && two.clear();});
1319
1389
  if (autoclear) setTimeout(clear, 800);
1320
1390
  else bracketHighlighted = clear;
1321
1391
  }
@@ -1348,6 +1418,7 @@ var CodeMirror = (function() {
1348
1418
  line.highlight(mode, state);
1349
1419
  line.stateAfter = copyState(mode, state);
1350
1420
  }
1421
+ changes.push({from: start, to: n});
1351
1422
  if (n < lines.length && !lines[n].stateAfter) work.push(n);
1352
1423
  return state;
1353
1424
  }
@@ -1758,10 +1829,23 @@ var CodeMirror = (function() {
1758
1829
  this.text = text;
1759
1830
  this.marked = this.gutterMarker = this.className = null;
1760
1831
  }
1832
+ Line.inheritMarks = function(text, orig) {
1833
+ var ln = new Line(text), mk = orig.marked;
1834
+ if (mk) {
1835
+ for (var i = 0; i < mk.length; ++i) {
1836
+ if (mk[i].to == null) {
1837
+ var newmk = ln.marked || (ln.marked = []), mark = mk[i];
1838
+ newmk.push({from: null, to: null, style: mark.style, set: mark.set});
1839
+ mark.set.push(ln);
1840
+ }
1841
+ }
1842
+ }
1843
+ return ln;
1844
+ }
1761
1845
  Line.prototype = {
1762
1846
  // Replace a piece of a line, keeping the styles around it intact.
1763
- replace: function(from, to, text) {
1764
- var st = [], mk = this.marked;
1847
+ replace: function(from, to_, text) {
1848
+ var st = [], mk = this.marked, to = to_ == null ? this.text.length : to_;
1765
1849
  copyStyles(0, from, this.styles, st);
1766
1850
  if (text) st.push(text, null);
1767
1851
  copyStyles(to, this.text.length, this.styles, st);
@@ -1770,33 +1854,78 @@ var CodeMirror = (function() {
1770
1854
  this.stateAfter = null;
1771
1855
  if (mk) {
1772
1856
  var diff = text.length - (to - from), end = this.text.length;
1773
- function fix(n) {return n <= Math.min(to, to + diff) ? n : n + diff;}
1857
+ var changeStart = Math.min(from, from + diff);
1774
1858
  for (var i = 0; i < mk.length; ++i) {
1775
1859
  var mark = mk[i], del = false;
1776
- if (mark.from >= end) del = true;
1777
- else {mark.from = fix(mark.from); if (mark.to != null) mark.to = fix(mark.to);}
1778
- if (del || mark.from >= mark.to) {mk.splice(i, 1); i--;}
1860
+ if (mark.from != null && mark.from >= end) del = true;
1861
+ else {
1862
+ if (mark.from != null && mark.from >= from) {
1863
+ mark.from += diff;
1864
+ if (mark.from <= 0) mark.from = from == null ? null : 0;
1865
+ }
1866
+ else if (to_ == null) mark.to = null;
1867
+ if (mark.to != null && mark.to > from) {
1868
+ mark.to += diff;
1869
+ if (mark.to < 0) del = true;
1870
+ }
1871
+ }
1872
+ if (del || (mark.from != null && mark.to != null && mark.from >= mark.to)) mk.splice(i--, 1);
1779
1873
  }
1780
1874
  }
1781
1875
  },
1782
- // Split a line in two, again keeping styles intact.
1876
+ // Split a part off a line, keeping styles and markers intact.
1783
1877
  split: function(pos, textBefore) {
1784
- var st = [textBefore, null];
1878
+ var st = [textBefore, null], mk = this.marked;
1785
1879
  copyStyles(pos, this.text.length, this.styles, st);
1786
- return new Line(textBefore + this.text.slice(pos), st);
1880
+ var taken = new Line(textBefore + this.text.slice(pos), st);
1881
+ if (mk) {
1882
+ for (var i = 0; i < mk.length; ++i) {
1883
+ var mark = mk[i];
1884
+ if (mark.to > pos || mark.to == null) {
1885
+ if (!taken.marked) taken.marked = [];
1886
+ taken.marked.push({
1887
+ from: mark.from < pos || mark.from == null ? null : mark.from - pos + textBefore.length,
1888
+ to: mark.to == null ? null : mark.to - pos + textBefore.length,
1889
+ style: mark.style, set: mark.set
1890
+ });
1891
+ mark.set.push(taken);
1892
+ }
1893
+ }
1894
+ }
1895
+ return taken;
1787
1896
  },
1788
- addMark: function(from, to, style) {
1789
- var mk = this.marked, mark = {from: from, to: to, style: style};
1790
- if (this.marked == null) this.marked = [];
1791
- this.marked.push(mark);
1792
- this.marked.sort(function(a, b){return a.from - b.from;});
1793
- return mark;
1897
+ append: function(line) {
1898
+ if (!line.text.length) return;
1899
+ var mylen = this.text.length, mk = line.marked;
1900
+ this.text += line.text;
1901
+ copyStyles(0, line.text.length, line.styles, this.styles);
1902
+ if (mk && mk.length) {
1903
+ var mymk = this.marked || (this.marked = []);
1904
+ for (var i = 0; i < mymk.length; ++i)
1905
+ if (mymk[i].to == null) mymk[i].to = mylen;
1906
+ outer: for (var i = 0; i < mk.length; ++i) {
1907
+ var mark = mk[i];
1908
+ if (!mark.from) {
1909
+ for (var j = 0; j < mymk.length; ++j) {
1910
+ var mymark = mymk[j];
1911
+ if (mymark.to == mylen && mymark.set == mark.set) {
1912
+ mymark.to = mark.to == null ? null : mark.to + mylen;
1913
+ continue outer;
1914
+ }
1915
+ }
1916
+ }
1917
+ mymk.push(mark);
1918
+ mark.set.push(this);
1919
+ mark.from += mylen;
1920
+ if (mark.to != null) mark.to += mylen;
1921
+ }
1922
+ }
1794
1923
  },
1795
- removeMark: function(mark) {
1796
- var mk = this.marked;
1797
- if (!mk) return;
1798
- for (var i = 0; i < mk.length; ++i)
1799
- if (mk[i] == mark) {mk.splice(i, 1); break;}
1924
+ addMark: function(from, to, style, set) {
1925
+ set.push(this);
1926
+ if (this.marked == null) this.marked = [];
1927
+ this.marked.push({from: from, to: to, style: style, set: set});
1928
+ this.marked.sort(function(a, b){return (a.from || 0) - (b.from || 0);});
1800
1929
  },
1801
1930
  // Run the given mode's parser over a line, update the styles
1802
1931
  // array, which contains alternating fragments of text and CSS
@@ -1864,10 +1993,10 @@ var CodeMirror = (function() {
1864
1993
  span(" ", sfrom != null && sto == null ? "CodeMirror-selected" : null);
1865
1994
  else if (!marked && sfrom == null)
1866
1995
  for (var i = 0, ch = 0; ch < len; i+=2) {
1867
- var str = st[i], l = str.length;
1996
+ var str = st[i], style = st[i+1], l = str.length;
1868
1997
  if (ch + l > len) str = str.slice(0, len - ch);
1869
1998
  ch += l;
1870
- span(str, "cm-" + st[i+1]);
1999
+ span(str, style && "cm-" + style);
1871
2000
  }
1872
2001
  else {
1873
2002
  var pos = 0, i = 0, text = "", style, sg = 0;
@@ -2080,11 +2209,17 @@ var CodeMirror = (function() {
2080
2209
  function posLess(a, b) {return a.line < b.line || (a.line == b.line && a.ch < b.ch);}
2081
2210
  function copyPos(x) {return {line: x.line, ch: x.ch};}
2082
2211
 
2083
- var escapeElement = document.createElement("div");
2212
+ var escapeElement = document.createElement("pre");
2084
2213
  function htmlEscape(str) {
2085
- escapeElement.innerText = escapeElement.textContent = str;
2214
+ if (badTextContent) {
2215
+ escapeElement.innerHTML = "";
2216
+ escapeElement.appendChild(document.createTextNode(str));
2217
+ } else {
2218
+ escapeElement.textContent = str;
2219
+ }
2086
2220
  return escapeElement.innerHTML;
2087
2221
  }
2222
+ var badTextContent = htmlEscape("\t") != "\t";
2088
2223
  CodeMirror.htmlEscape = htmlEscape;
2089
2224
 
2090
2225
  // Used to position the cursor after an undo/redo by finding the