codemirror-rails 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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