codemirror-rails 2.23 → 2.24

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. data/lib/codemirror/rails/version.rb +2 -2
  2. data/vendor/assets/javascripts/codemirror.js +163 -88
  3. data/vendor/assets/javascripts/codemirror/keymaps/emacs.js +1 -1
  4. data/vendor/assets/javascripts/codemirror/keymaps/vim.js +85 -202
  5. data/vendor/assets/javascripts/codemirror/modes/clike.js +1 -1
  6. data/vendor/assets/javascripts/codemirror/modes/gfm.js +1 -1
  7. data/vendor/assets/javascripts/codemirror/modes/htmlembedded.js +1 -1
  8. data/vendor/assets/javascripts/codemirror/modes/htmlmixed.js +3 -1
  9. data/vendor/assets/javascripts/codemirror/modes/javascript.js +4 -3
  10. data/vendor/assets/javascripts/codemirror/modes/less.js +27 -13
  11. data/vendor/assets/javascripts/codemirror/modes/markdown.js +1 -1
  12. data/vendor/assets/javascripts/codemirror/modes/php.js +1 -1
  13. data/vendor/assets/javascripts/codemirror/modes/pig.js +172 -0
  14. data/vendor/assets/javascripts/codemirror/modes/python.js +1 -0
  15. data/vendor/assets/javascripts/codemirror/modes/rpm-spec.css +5 -0
  16. data/vendor/assets/javascripts/codemirror/modes/rst.js +1 -1
  17. data/vendor/assets/javascripts/codemirror/modes/shell.js +103 -0
  18. data/vendor/assets/javascripts/codemirror/modes/tiki.js +316 -0
  19. data/vendor/assets/javascripts/codemirror/modes/xml.js +63 -6
  20. data/vendor/assets/javascripts/codemirror/utils/foldcode.js +13 -8
  21. data/vendor/assets/javascripts/codemirror/utils/loadmode.js +50 -0
  22. data/vendor/assets/javascripts/codemirror/utils/overlay.js +1 -1
  23. data/vendor/assets/javascripts/codemirror/utils/search.js +2 -2
  24. data/vendor/assets/stylesheets/codemirror.css +2 -0
  25. data/vendor/assets/stylesheets/codemirror/modes/tiki.css +26 -0
  26. data/vendor/assets/stylesheets/codemirror/themes/ambiance.css +82 -0
  27. data/vendor/assets/stylesheets/codemirror/themes/blackboard.css +25 -0
  28. data/vendor/assets/stylesheets/codemirror/themes/lesser-dark.css +1 -1
  29. metadata +12 -4
@@ -1,6 +1,6 @@
1
1
  module Codemirror
2
2
  module Rails
3
- VERSION = '2.23'
4
- CODEMIRROR_VERSION = '2.23'
3
+ VERSION = '2.24'
4
+ CODEMIRROR_VERSION = '2.24'
5
5
  end
6
6
  end
@@ -1,4 +1,4 @@
1
- // CodeMirror version 2.23
1
+ // CodeMirror version 2.24
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,
@@ -98,7 +98,6 @@ var CodeMirror = (function() {
98
98
  // Register our event handlers.
99
99
  connect(scroller, "mousedown", operation(onMouseDown));
100
100
  connect(scroller, "dblclick", operation(onDoubleClick));
101
- connect(lineSpace, "dragstart", onDragStart);
102
101
  connect(lineSpace, "selectstart", e_preventDefault);
103
102
  // Gecko browsers fire contextmenu *after* opening the menu, at
104
103
  // which point we can't mess with it anymore. Context menu is
@@ -118,9 +117,16 @@ var CodeMirror = (function() {
118
117
  connect(input, "focus", onFocus);
119
118
  connect(input, "blur", onBlur);
120
119
 
121
- connect(scroller, "dragenter", e_stop);
122
- connect(scroller, "dragover", e_stop);
123
- connect(scroller, "drop", operation(onDrop));
120
+ if (options.dragDrop) {
121
+ connect(lineSpace, "dragstart", onDragStart);
122
+ function drag_(e) {
123
+ if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return;
124
+ e_stop(e);
125
+ }
126
+ connect(scroller, "dragenter", drag_);
127
+ connect(scroller, "dragover", drag_);
128
+ connect(scroller, "drop", operation(onDrop));
129
+ }
124
130
  connect(scroller, "paste", function(){focusInput(); fastPoll();});
125
131
  connect(input, "paste", fastPoll);
126
132
  connect(input, "cut", operation(function(){
@@ -312,6 +318,7 @@ var CodeMirror = (function() {
312
318
  },
313
319
 
314
320
  operation: function(f){return operation(f)();},
321
+ compoundChange: function(f){return compoundChange(f);},
315
322
  refresh: function(){
316
323
  updateDisplay(true);
317
324
  if (scroller.scrollHeight > lastScrollPos)
@@ -336,7 +343,7 @@ var CodeMirror = (function() {
336
343
  splitLines(code), top, top);
337
344
  updateInput = true;
338
345
  }
339
- function getValue(code) {
346
+ function getValue() {
340
347
  var text = [];
341
348
  doc.iter(0, doc.size, function(line) { text.push(line.text); });
342
349
  return text.join("\n");
@@ -385,20 +392,22 @@ var CodeMirror = (function() {
385
392
  } else { lastClick = {time: now, pos: start}; }
386
393
 
387
394
  var last = start, going;
388
- if (dragAndDrop && !options.readOnly && !posEq(sel.from, sel.to) &&
395
+ if (options.dragDrop && dragAndDrop && !options.readOnly && !posEq(sel.from, sel.to) &&
389
396
  !posLess(start, sel.from) && !posLess(sel.to, start)) {
390
397
  // Let the drag handler handle this.
391
398
  if (webkit) lineSpace.draggable = true;
392
- var up = connect(document, "mouseup", operation(function(e2) {
399
+ function dragEnd(e2) {
393
400
  if (webkit) lineSpace.draggable = false;
394
401
  draggingText = false;
395
- up();
402
+ up(); drop();
396
403
  if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
397
404
  e_preventDefault(e2);
398
405
  setCursor(start.line, start.ch, true);
399
406
  focusInput();
400
407
  }
401
- }), true);
408
+ }
409
+ var up = connect(document, "mouseup", operation(dragEnd), true);
410
+ var drop = connect(scroller, "drop", operation(dragEnd), true);
402
411
  draggingText = true;
403
412
  // IE's approach to draggable
404
413
  if (lineSpace.dragDrop) lineSpace.dragDrop();
@@ -447,6 +456,7 @@ var CodeMirror = (function() {
447
456
  selectWordAt(start);
448
457
  }
449
458
  function onDrop(e) {
459
+ if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return;
450
460
  e.preventDefault();
451
461
  var pos = posFromMouse(e, true), files = e.dataTransfer.files;
452
462
  if (!pos || options.readOnly) return;
@@ -456,12 +466,12 @@ var CodeMirror = (function() {
456
466
  reader.onload = function() {
457
467
  text[i] = reader.result;
458
468
  if (++read == n) {
459
- pos = clipPos(pos);
460
- operation(function() {
469
+ pos = clipPos(pos);
470
+ operation(function() {
461
471
  var end = replaceRange(text.join(""), pos, pos);
462
472
  setSelectionUser(pos, end);
463
473
  })();
464
- }
474
+ }
465
475
  };
466
476
  reader.readAsText(file);
467
477
  }
@@ -472,12 +482,14 @@ var CodeMirror = (function() {
472
482
  try {
473
483
  var text = e.dataTransfer.getData("Text");
474
484
  if (text) {
475
- var curFrom = sel.from, curTo = sel.to;
476
- setSelectionUser(pos, pos);
477
- if (draggingText) replaceRange("", curFrom, curTo);
478
- replaceSelection(text);
479
- focusInput();
480
- }
485
+ compoundChange(function() {
486
+ var curFrom = sel.from, curTo = sel.to;
487
+ setSelectionUser(pos, pos);
488
+ if (draggingText) replaceRange("", curFrom, curTo);
489
+ replaceSelection(text);
490
+ focusInput();
491
+ });
492
+ }
481
493
  }
482
494
  catch(e){}
483
495
  }
@@ -529,15 +541,19 @@ var CodeMirror = (function() {
529
541
  if (e_prop(e, "ctrlKey")) name = "Ctrl-" + name;
530
542
  if (e_prop(e, "metaKey")) name = "Cmd-" + name;
531
543
 
544
+ var stopped = false;
545
+ function stop() { stopped = true; }
546
+
532
547
  if (e_prop(e, "shiftKey")) {
533
548
  handled = lookupKey("Shift-" + name, options.extraKeys, options.keyMap,
534
- function(b) {return doHandleBinding(b, true);})
549
+ function(b) {return doHandleBinding(b, true);}, stop)
535
550
  || lookupKey(name, options.extraKeys, options.keyMap, function(b) {
536
551
  if (typeof b == "string" && /^go[A-Z]/.test(b)) return doHandleBinding(b);
537
- });
552
+ }, stop);
538
553
  } else {
539
- handled = lookupKey(name, options.extraKeys, options.keyMap, doHandleBinding);
554
+ handled = lookupKey(name, options.extraKeys, options.keyMap, doHandleBinding, stop);
540
555
  }
556
+ if (stopped) handled = false;
541
557
  if (handled) {
542
558
  e_preventDefault(e);
543
559
  if (ie) { e.oldKeyCode = e.keyCode; e.keyCode = 0; }
@@ -546,7 +562,7 @@ var CodeMirror = (function() {
546
562
  }
547
563
  function handleCharBinding(e, ch) {
548
564
  var handled = lookupKey("'" + ch + "'", options.extraKeys,
549
- options.keyMap, doHandleBinding);
565
+ options.keyMap, function(b) { return doHandleBinding(b, true); });
550
566
  if (handled) e_preventDefault(e);
551
567
  return handled;
552
568
  }
@@ -648,7 +664,7 @@ var CodeMirror = (function() {
648
664
  if (suppressEdits) return;
649
665
  var recomputeMaxLength = false, maxLineLength = maxLine.length;
650
666
  if (!options.lineWrapping)
651
- doc.iter(from.line, to.line, function(line) {
667
+ doc.iter(from.line, to.line + 1, function(line) {
652
668
  if (line.text.length == maxLineLength) {recomputeMaxLength = true; return true;}
653
669
  });
654
670
  if (from.line != to.line || newText.length > 1) gutterDirty = true;
@@ -696,14 +712,14 @@ var CodeMirror = (function() {
696
712
  doc.insert(from.line + 1, added);
697
713
  }
698
714
  if (options.lineWrapping) {
699
- var perLine = scroller.clientWidth / charWidth() - 3;
715
+ var perLine = Math.max(5, scroller.clientWidth / charWidth() - 3);
700
716
  doc.iter(from.line, from.line + newText.length, function(line) {
701
717
  if (line.hidden) return;
702
718
  var guess = Math.ceil(line.text.length / perLine) || 1;
703
719
  if (guess != line.height) updateLineHeight(line, guess);
704
720
  });
705
721
  } else {
706
- doc.iter(from.line, i + newText.length, function(line) {
722
+ doc.iter(from.line, from.line + newText.length, function(line) {
707
723
  var l = line.text;
708
724
  if (l.length > maxLineLength) {
709
725
  maxLine = l; maxLineLength = l.length; maxWidth = null;
@@ -874,8 +890,9 @@ var CodeMirror = (function() {
874
890
 
875
891
  var screenw = scroller.clientWidth, screenleft = scroller.scrollLeft;
876
892
  var gutterw = options.fixedGutter ? gutter.clientWidth : 0;
877
- if (x1 < screenleft + gutterw) {
878
- if (x1 < 50) x1 = 0;
893
+ var atLeft = x1 < gutterw + pl + 10;
894
+ if (x1 < screenleft + gutterw || atLeft) {
895
+ if (atLeft) x1 = 0;
879
896
  scroller.scrollLeft = Math.max(0, x1 - 10 - gutterw);
880
897
  scrolled = true;
881
898
  }
@@ -890,10 +907,10 @@ var CodeMirror = (function() {
890
907
 
891
908
  function visibleLines() {
892
909
  var lh = textHeight(), top = scroller.scrollTop - paddingTop();
893
- var from_height = Math.max(0, Math.floor(top / lh));
894
- var to_height = Math.ceil((top + scroller.clientHeight) / lh);
895
- return {from: lineAtHeight(doc, from_height),
896
- to: lineAtHeight(doc, to_height)};
910
+ var fromHeight = Math.max(0, Math.floor(top / lh));
911
+ var toHeight = Math.ceil((top + scroller.clientHeight) / lh);
912
+ return {from: lineAtHeight(doc, fromHeight),
913
+ to: lineAtHeight(doc, toHeight)};
897
914
  }
898
915
  // Uses a set of changes plus the current scroll position to
899
916
  // determine which DOM updates have to be made, and makes the
@@ -924,7 +941,7 @@ var CodeMirror = (function() {
924
941
  if (range.from >= range.to) intact.splice(i--, 1);
925
942
  else intactLines += range.to - range.from;
926
943
  }
927
- if (intactLines == to - from) return;
944
+ if (intactLines == to - from && from == showingFrom && to == showingTo) return;
928
945
  intact.sort(function(a, b) {return a.domStart - b.domStart;});
929
946
 
930
947
  var th = textHeight(), gutterDisplay = gutter.style.display;
@@ -1108,12 +1125,14 @@ var CodeMirror = (function() {
1108
1125
  selectionDiv.style.display = "none";
1109
1126
  } else {
1110
1127
  var sameLine = fromPos.y == toPos.y, html = "";
1128
+ var clientWidth = lineSpace.clientWidth || lineSpace.offsetWidth;
1129
+ var clientHeight = lineSpace.clientHeight || lineSpace.offsetHeight;
1111
1130
  function add(left, top, right, height) {
1131
+ var rstyle = quirksMode ? "width: " + (!right ? clientWidth : clientWidth - right - left) + "px"
1132
+ : "right: " + right + "px";
1112
1133
  html += '<div class="CodeMirror-selected" style="position: absolute; left: ' + left +
1113
- 'px; top: ' + top + 'px; right: ' + right + 'px; height: ' + height + 'px"></div>';
1134
+ 'px; top: ' + top + 'px; ' + rstyle + '; height: ' + height + 'px"></div>';
1114
1135
  }
1115
- var clientWidth = lineSpace.clientWidth || lineSpace.offsetWidth;
1116
- var clientHeight = lineSpace.clientHeight || lineSpace.offsetHeight;
1117
1136
  if (sel.from.ch && fromPos.y >= 0) {
1118
1137
  var right = sameLine ? clientWidth - toPos.x : 0;
1119
1138
  add(fromPos.x, fromPos.y, right, th);
@@ -1189,13 +1208,14 @@ var CodeMirror = (function() {
1189
1208
  var line = getLine(lNo);
1190
1209
  if (!line.hidden) {
1191
1210
  var ch = pos.ch;
1192
- if (ch > oldCh || ch > line.text.length) ch = line.text.length;
1211
+ if (toEnd || ch > oldCh || ch > line.text.length) ch = line.text.length;
1193
1212
  return {line: lNo, ch: ch};
1194
1213
  }
1195
1214
  lNo += dir;
1196
1215
  }
1197
1216
  }
1198
1217
  var line = getLine(pos.line);
1218
+ var toEnd = pos.ch == line.text.length && pos.ch != oldCh;
1199
1219
  if (!line.hidden) return pos;
1200
1220
  if (pos.line >= oldLine) return getNonHidden(1) || getNonHidden(-1);
1201
1221
  else return getNonHidden(-1) || getNonHidden(1);
@@ -1355,7 +1375,7 @@ var CodeMirror = (function() {
1355
1375
  return (tabCache[w] = {html: str + "</span>", width: w});
1356
1376
  }
1357
1377
  function themeChanged() {
1358
- scroller.className = scroller.className.replace(/\s*cm-s-\w+/g, "") +
1378
+ scroller.className = scroller.className.replace(/\s*cm-s-\S+/g, "") +
1359
1379
  options.theme.replace(/(^|\s)\s*/g, " cm-s-");
1360
1380
  }
1361
1381
 
@@ -1506,8 +1526,7 @@ var CodeMirror = (function() {
1506
1526
  if (x <= 0) return 0;
1507
1527
  var lineObj = getLine(line), text = lineObj.text;
1508
1528
  function getX(len) {
1509
- measure.innerHTML = "<pre><span>" + lineObj.getHTML(makeTab, len) + "</span></pre>";
1510
- return measure.firstChild.firstChild.offsetWidth;
1529
+ return measureLine(lineObj, len).left;
1511
1530
  }
1512
1531
  var from = 0, fromX = 0, to = text.length, toX;
1513
1532
  // Guess a suitable upper bound for our search.
@@ -1530,19 +1549,13 @@ var CodeMirror = (function() {
1530
1549
  }
1531
1550
  }
1532
1551
 
1533
- var tempId = Math.floor(Math.random() * 0xffffff).toString(16);
1552
+ var tempId = "CodeMirror-temp-" + Math.floor(Math.random() * 0xffffff).toString(16);
1534
1553
  function measureLine(line, ch) {
1535
1554
  if (ch == 0) return {top: 0, left: 0};
1536
- var extra = "";
1537
- // Include extra text at the end to make sure the measured line is wrapped in the right way.
1538
- if (options.lineWrapping) {
1539
- var end = line.text.indexOf(" ", ch + 6);
1540
- extra = htmlEscape(line.text.slice(ch + 1, end < 0 ? line.text.length : end + (ie ? 5 : 0)));
1541
- }
1542
- measure.innerHTML = "<pre>" + line.getHTML(makeTab, ch) +
1543
- '<span id="CodeMirror-temp-' + tempId + '">' + htmlEscape(line.text.charAt(ch) || " ") + "</span>" +
1544
- extra + "</pre>";
1545
- var elt = document.getElementById("CodeMirror-temp-" + tempId);
1555
+ var wbr = options.lineWrapping && ch < line.text.length &&
1556
+ spanAffectsWrapping.test(line.text.slice(ch - 1, ch + 1));
1557
+ measure.innerHTML = "<pre>" + line.getHTML(makeTab, ch, tempId, wbr) + "</pre>";
1558
+ var elt = document.getElementById(tempId);
1546
1559
  var top = elt.offsetTop, left = elt.offsetLeft;
1547
1560
  // Older IEs report zero offsets for spans directly after a wrap
1548
1561
  if (ie && top == 0 && left == 0) {
@@ -1790,13 +1803,17 @@ var CodeMirror = (function() {
1790
1803
  var changed = line.highlight(mode, state, options.tabSize);
1791
1804
  if (changed) realChange = true;
1792
1805
  line.stateAfter = copyState(mode, state);
1806
+ var done = null;
1793
1807
  if (compare) {
1794
- if (hadState && compare(hadState, state)) return true;
1795
- } else {
1808
+ var same = hadState && compare(hadState, state);
1809
+ if (same != Pass) done = !!same;
1810
+ }
1811
+ if (done == null) {
1796
1812
  if (changed !== false || !hadState) unchanged = 0;
1797
1813
  else if (++unchanged > 3 && (!mode.indent || mode.indent(hadState, "") == mode.indent(state, "")))
1798
- return true;
1814
+ done = true;
1799
1815
  }
1816
+ if (done) return true;
1800
1817
  ++i;
1801
1818
  });
1802
1819
  if (bail) return;
@@ -1856,6 +1873,11 @@ var CodeMirror = (function() {
1856
1873
  };
1857
1874
  }
1858
1875
 
1876
+ function compoundChange(f) {
1877
+ history.startCompound();
1878
+ try { return f(); } finally { history.endCompound(); }
1879
+ }
1880
+
1859
1881
  for (var ext in extensions)
1860
1882
  if (extensions.propertyIsEnumerable(ext) &&
1861
1883
  !instance.propertyIsEnumerable(ext))
@@ -1877,12 +1899,14 @@ var CodeMirror = (function() {
1877
1899
  electricChars: true,
1878
1900
  autoClearEmptyLines: false,
1879
1901
  onKeyEvent: null,
1902
+ onDragEvent: null,
1880
1903
  lineWrapping: false,
1881
1904
  lineNumbers: false,
1882
1905
  gutter: false,
1883
1906
  fixedGutter: false,
1884
1907
  firstLineNumber: 1,
1885
1908
  readOnly: false,
1909
+ dragDrop: true,
1886
1910
  onChange: null,
1887
1911
  onCursorActivity: null,
1888
1912
  onGutterClick: null,
@@ -1906,6 +1930,10 @@ var CodeMirror = (function() {
1906
1930
  var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
1907
1931
  CodeMirror.defineMode = function(name, mode) {
1908
1932
  if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
1933
+ if (arguments.length > 2) {
1934
+ mode.dependencies = [];
1935
+ for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]);
1936
+ }
1909
1937
  modes[name] = mode;
1910
1938
  };
1911
1939
  CodeMirror.defineMIME = function(mime, spec) {
@@ -1922,10 +1950,7 @@ var CodeMirror = (function() {
1922
1950
  CodeMirror.getMode = function(options, spec) {
1923
1951
  var spec = CodeMirror.resolveMode(spec);
1924
1952
  var mfactory = modes[spec.name];
1925
- if (!mfactory) {
1926
- if (window.console) console.warn("No mode " + spec.name + " found, falling back to plain text.");
1927
- return CodeMirror.getMode(options, "text/plain");
1928
- }
1953
+ if (!mfactory) return CodeMirror.getMode(options, "text/plain");
1929
1954
  return mfactory(options, spec);
1930
1955
  };
1931
1956
  CodeMirror.listModes = function() {
@@ -2035,12 +2060,15 @@ var CodeMirror = (function() {
2035
2060
  if (typeof val == "string") return keyMap[val];
2036
2061
  else return val;
2037
2062
  }
2038
- function lookupKey(name, extraMap, map, handle) {
2063
+ function lookupKey(name, extraMap, map, handle, stop) {
2039
2064
  function lookup(map) {
2040
2065
  map = getKeyMap(map);
2041
2066
  var found = map[name];
2042
2067
  if (found != null && handle(found)) return true;
2043
- if (map.catchall) return handle(map.catchall);
2068
+ if (map.nofallthrough) {
2069
+ if (stop) stop();
2070
+ return true;
2071
+ }
2044
2072
  var fallthrough = map.fallthrough;
2045
2073
  if (fallthrough == null) return false;
2046
2074
  if (Object.prototype.toString.call(fallthrough) != "[object Array]")
@@ -2402,9 +2430,9 @@ var CodeMirror = (function() {
2402
2430
  indentation: function(tabSize) {return countColumn(this.text, null, tabSize);},
2403
2431
  // Produces an HTML fragment for the line, taking selection,
2404
2432
  // marking, and highlighting into account.
2405
- getHTML: function(makeTab, endAt) {
2433
+ getHTML: function(makeTab, wrapAt, wrapId, wrapWBR) {
2406
2434
  var html = [], first = true, col = 0;
2407
- function span(text, style) {
2435
+ function span_(text, style) {
2408
2436
  if (!text) return;
2409
2437
  // Work around a bug where, in some compat modes, IE ignores leading spaces
2410
2438
  if (first && ie && text.charAt(0) == " ") text = "\u00a0" + text.slice(1);
@@ -2432,24 +2460,50 @@ var CodeMirror = (function() {
2432
2460
  if (style) html.push('<span class="', style, '">', escaped, "</span>");
2433
2461
  else html.push(escaped);
2434
2462
  }
2463
+ var span = span_;
2464
+ if (wrapAt != null) {
2465
+ var outPos = 0, open = "<span id=\"" + wrapId + "\">";
2466
+ span = function(text, style) {
2467
+ var l = text.length;
2468
+ if (wrapAt >= outPos && wrapAt < outPos + l) {
2469
+ if (wrapAt > outPos) {
2470
+ span_(text.slice(0, wrapAt - outPos), style);
2471
+ // See comment at the definition of spanAffectsWrapping
2472
+ if (wrapWBR) html.push("<wbr>");
2473
+ }
2474
+ html.push(open);
2475
+ span_(text.slice(wrapAt - outPos), style);
2476
+ html.push("</span>");
2477
+ wrapAt--;
2478
+ outPos += l;
2479
+ } else {
2480
+ outPos += l;
2481
+ span_(text, style);
2482
+ // Output empty wrapper when at end of line
2483
+ if (outPos == wrapAt && outPos == len) html.push(open + "</span>");
2484
+ // Stop outputting HTML when gone sufficiently far beyond measure
2485
+ else if (outPos > wrapAt + 10 && /\s/.test(text)) span = function(){};
2486
+ }
2487
+ }
2488
+ }
2489
+
2435
2490
  var st = this.styles, allText = this.text, marked = this.marked;
2436
2491
  var len = allText.length;
2437
- if (endAt != null) len = Math.min(endAt, len);
2438
2492
  function styleToClass(style) {
2439
2493
  if (!style) return null;
2440
2494
  return "cm-" + style.replace(/ +/g, " cm-");
2441
2495
  }
2442
2496
 
2443
- if (!allText && endAt == null)
2497
+ if (!allText && wrapAt == null) {
2444
2498
  span(" ");
2445
- else if (!marked || !marked.length)
2499
+ } else if (!marked || !marked.length) {
2446
2500
  for (var i = 0, ch = 0; ch < len; i+=2) {
2447
2501
  var str = st[i], style = st[i+1], l = str.length;
2448
2502
  if (ch + l > len) str = str.slice(0, len - ch);
2449
2503
  ch += l;
2450
2504
  span(str, styleToClass(style));
2451
2505
  }
2452
- else {
2506
+ } else {
2453
2507
  var pos = 0, i = 0, text = "", style, sg = 0;
2454
2508
  var nextChange = marked[0].from || 0, marks = [], markpos = 0;
2455
2509
  function advanceMarks() {
@@ -2535,7 +2589,11 @@ var CodeMirror = (function() {
2535
2589
  },
2536
2590
  insertHeight: function(at, lines, height) {
2537
2591
  this.height += height;
2538
- this.lines.splice.apply(this.lines, [at, 0].concat(lines));
2592
+ // The trick below is apparently too advanced for IE, which
2593
+ // occasionally corrupts this.lines (duplicating elements) when
2594
+ // it is used.
2595
+ if (ie) this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
2596
+ else this.lines.splice.apply(this.lines, [at, 0].concat(lines));
2539
2597
  for (var i = 0, e = lines.length; i < e; ++i) lines[i].parent = this;
2540
2598
  },
2541
2599
  iterN: function(at, n, op) {
@@ -2701,33 +2759,36 @@ var CodeMirror = (function() {
2701
2759
  function History() {
2702
2760
  this.time = 0;
2703
2761
  this.done = []; this.undone = [];
2762
+ this.compound = 0;
2763
+ this.closed = false;
2704
2764
  }
2705
2765
  History.prototype = {
2706
2766
  addChange: function(start, added, old) {
2707
2767
  this.undone.length = 0;
2708
2768
  var time = +new Date, cur = this.done[this.done.length - 1], last = cur && cur[cur.length - 1];
2709
2769
  var dtime = time - this.time;
2710
- if (dtime > 400 || !last) {
2711
- this.done.push([{start: start, added: added, old: old}]);
2712
- } else if (last.start > start + old.length || last.start + last.added < start - last.added + last.old.length) {
2770
+
2771
+ if (this.compound && cur && !this.closed) {
2713
2772
  cur.push({start: start, added: added, old: old});
2773
+ } else if (dtime > 400 || !last || this.closed ||
2774
+ last.start > start + old.length || last.start + last.added < start) {
2775
+ this.done.push([{start: start, added: added, old: old}]);
2776
+ this.closed = false;
2714
2777
  } else {
2715
- var oldoff = 0;
2716
- if (start < last.start) {
2717
- for (var i = last.start - start - 1; i >= 0; --i)
2718
- last.old.unshift(old[i]);
2719
- oldoff = Math.min(0, added - old.length);
2720
- last.added += last.start - start + oldoff;
2721
- last.start = start;
2722
- } else if (last.start < start) {
2723
- oldoff = start - last.start;
2724
- added += oldoff;
2725
- }
2726
- for (var i = last.added - oldoff, e = old.length; i < e; ++i)
2727
- last.old.push(old[i]);
2728
- if (last.added < added) last.added = added;
2778
+ var startBefore = Math.max(0, last.start - start),
2779
+ endAfter = Math.max(0, (start + old.length) - (last.start + last.added));
2780
+ for (var i = startBefore; i > 0; --i) last.old.unshift(old[i - 1]);
2781
+ for (var i = endAfter; i > 0; --i) last.old.push(old[old.length - i]);
2782
+ if (startBefore) last.start = start;
2783
+ last.added += added - (old.length - startBefore - endAfter);
2729
2784
  }
2730
2785
  this.time = time;
2786
+ },
2787
+ startCompound: function() {
2788
+ if (!this.compound++) this.closed = true;
2789
+ },
2790
+ endCompound: function() {
2791
+ if (!--this.compound) this.closed = true;
2731
2792
  }
2732
2793
  };
2733
2794
 
@@ -2789,8 +2850,10 @@ var CodeMirror = (function() {
2789
2850
  var gecko = /gecko\/\d{7}/i.test(navigator.userAgent);
2790
2851
  var ie = /MSIE \d/.test(navigator.userAgent);
2791
2852
  var ie_lt9 = /MSIE [1-8]\b/.test(navigator.userAgent);
2853
+ var quirksMode = ie && document.documentMode == 5;
2792
2854
  var webkit = /WebKit\//.test(navigator.userAgent);
2793
2855
  var chrome = /Chrome\//.test(navigator.userAgent);
2856
+ var safari = /Apple Computer/.test(navigator.vendor);
2794
2857
  var khtml = /KHTML\//.test(navigator.userAgent);
2795
2858
 
2796
2859
  // Detect drag-and-drop
@@ -2802,13 +2865,25 @@ var CodeMirror = (function() {
2802
2865
  return "draggable" in div || "dragDrop" in div;
2803
2866
  }();
2804
2867
 
2805
- var lineSep = "\n";
2806
2868
  // Feature-detect whether newlines in textareas are converted to \r\n
2807
- (function () {
2869
+ var lineSep = function () {
2808
2870
  var te = document.createElement("textarea");
2809
2871
  te.value = "foo\nbar";
2810
- if (te.value.indexOf("\r") > -1) lineSep = "\r\n";
2811
- }());
2872
+ if (te.value.indexOf("\r") > -1) return "\r\n";
2873
+ return "\n";
2874
+ }();
2875
+
2876
+ // For a reason I have yet to figure out, some browsers disallow
2877
+ // word wrapping between certain characters *only* if a new inline
2878
+ // element is started between them. This makes it hard to reliably
2879
+ // measure the position of things, since that requires inserting an
2880
+ // extra span. This terribly fragile set of regexps matches the
2881
+ // character combinations that suffer from this phenomenon on the
2882
+ // various browsers.
2883
+ var spanAffectsWrapping = /^$/; // Won't match any two-character string
2884
+ if (gecko) spanAffectsWrapping = /$'/;
2885
+ else if (safari) spanAffectsWrapping = /\-[^ \-?]|\?[^ !'\"\),.\-\/:;\?\]\}]/;
2886
+ else if (chrome) spanAffectsWrapping = /\-[^ \-\.?]|\?[^ \-\.?\]\}:;!'\"\),\/]|[\.!\"#&%\)*+,:;=>\]|\}~][\(\{\[<]|\$'/;
2812
2887
 
2813
2888
  // Counts the column offset in a string, taking tabs into account.
2814
2889
  // Used mostly to find indentation.