codemirror-rails 2.21.1 → 2.22

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/README.md +8 -0
  2. data/lib/codemirror/rails/version.rb +2 -2
  3. data/vendor/assets/javascripts/codemirror.js +160 -86
  4. data/vendor/assets/javascripts/codemirror/modes/clike.js +2 -2
  5. data/vendor/assets/javascripts/codemirror/modes/clojure.js +1 -1
  6. data/vendor/assets/javascripts/codemirror/modes/ecl.js +203 -0
  7. data/vendor/assets/javascripts/codemirror/modes/gfm.js +1 -1
  8. data/vendor/assets/javascripts/codemirror/modes/go.js +20 -22
  9. data/vendor/assets/javascripts/codemirror/modes/less.js +5 -2
  10. data/vendor/assets/javascripts/codemirror/modes/markdown.js +58 -24
  11. data/vendor/assets/javascripts/codemirror/modes/pascal.js +2 -46
  12. data/vendor/assets/javascripts/codemirror/modes/perl.js +1 -1
  13. data/vendor/assets/javascripts/codemirror/modes/php.js +53 -24
  14. data/vendor/assets/javascripts/codemirror/modes/properties.js +57 -0
  15. data/vendor/assets/javascripts/codemirror/modes/rpm-spec.css +5 -0
  16. data/vendor/assets/javascripts/codemirror/modes/rpm-spec.js +1 -1
  17. data/vendor/assets/javascripts/codemirror/modes/ruby.js +1 -1
  18. data/vendor/assets/javascripts/codemirror/modes/smalltalk.js +16 -16
  19. data/vendor/assets/javascripts/codemirror/modes/verilog.js +194 -194
  20. data/vendor/assets/javascripts/codemirror/modes/xml.js +15 -8
  21. data/vendor/assets/javascripts/codemirror/utils/dialog.js +63 -0
  22. data/vendor/assets/javascripts/codemirror/utils/foldcode.js +186 -0
  23. data/vendor/assets/javascripts/codemirror/utils/formatting.js +294 -0
  24. data/vendor/assets/javascripts/codemirror/utils/javascript-hint.js +132 -0
  25. data/vendor/assets/javascripts/codemirror/utils/match-highlighter.js +44 -0
  26. data/vendor/assets/javascripts/codemirror/{overlay.js → utils/overlay.js} +0 -0
  27. data/vendor/assets/javascripts/codemirror/utils/runmode.js +49 -0
  28. data/vendor/assets/javascripts/codemirror/utils/search.js +114 -0
  29. data/vendor/assets/javascripts/codemirror/utils/searchcursor.js +117 -0
  30. data/vendor/assets/javascripts/codemirror/utils/simple-hint.js +66 -0
  31. data/vendor/assets/stylesheets/codemirror.css +3 -0
  32. data/vendor/assets/stylesheets/codemirror/modes/properties.css +3 -0
  33. data/vendor/assets/stylesheets/codemirror/themes/rubyblue.css +1 -1
  34. data/vendor/assets/stylesheets/codemirror/utils/dialog.css +23 -0
  35. data/vendor/assets/stylesheets/codemirror/utils/simple-hint.css +16 -0
  36. metadata +20 -6
  37. data/vendor/assets/javascripts/codemirror/runmode.js +0 -27
data/README.md CHANGED
@@ -35,6 +35,14 @@ Additional syntax modes can be added to your application.js:
35
35
  //= require codemirror/modes/ruby
36
36
  ```
37
37
 
38
+ ### Adding a util
39
+
40
+ Additional reusable util components can be added in your application.js:
41
+
42
+ ```js
43
+ //= require codemirror/utils/dialog
44
+ ```
45
+
38
46
  ### Adding a keymap
39
47
 
40
48
  Additional keymap bindings can be added to your application.js:
@@ -1,6 +1,6 @@
1
1
  module Codemirror
2
2
  module Rails
3
- VERSION = '2.21.1'
4
- CODEMIRROR_VERSION = '2.21'
3
+ VERSION = '2.22'
4
+ CODEMIRROR_VERSION = '2.22'
5
5
  end
6
6
  end
@@ -1,4 +1,4 @@
1
- // CodeMirror version 2.21
1
+ // CodeMirror version 2.22
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,
@@ -6,7 +6,7 @@
6
6
 
7
7
  // CodeMirror is the only global var we claim
8
8
  var CodeMirror = (function() {
9
- // This is the function that produces an editor instance. It's
9
+ // This is the function that produces an editor instance. Its
10
10
  // closure is used to store the editor state.
11
11
  function CodeMirror(place, givenOptions) {
12
12
  // Determine effective options based on given values and defaults.
@@ -30,7 +30,7 @@ var CodeMirror = (function() {
30
30
  '<div class="CodeMirror-gutter"><div class="CodeMirror-gutter-text"></div></div>' +
31
31
  // Provides positioning relative to (visible) text origin
32
32
  '<div class="CodeMirror-lines"><div style="position: relative; z-index: 0">' +
33
- '<div style="position: absolute; width: 100%; height: 0; overflow: hidden; visibility: hidden; outline: 5px auto none"></div>' +
33
+ '<div style="position: absolute; width: 100%; height: 0; overflow: hidden; visibility: hidden;"></div>' +
34
34
  '<pre class="CodeMirror-cursor">&#160;</pre>' + // Absolutely positioned blinky cursor
35
35
  '<div style="position: relative; z-index: -1"></div><div></div>' + // DIVs containing the selection and the actual code
36
36
  '</div></div></div></div></div>';
@@ -86,7 +86,7 @@ var CodeMirror = (function() {
86
86
  var bracketHighlighted;
87
87
  // Tracks the maximum line length so that the horizontal scrollbar
88
88
  // can be kept static when scrolling.
89
- var maxLine = "", maxWidth, tabText = computeTabText();
89
+ var maxLine = "", maxWidth;
90
90
 
91
91
  // Initialize the content.
92
92
  operation(function(){setValue(options.value || ""); updateInput = false;})();
@@ -141,7 +141,7 @@ var CodeMirror = (function() {
141
141
  setValue: operation(setValue),
142
142
  getSelection: getSelection,
143
143
  replaceSelection: operation(replaceSelection),
144
- focus: function(){focusInput(); onFocus(); fastPoll();},
144
+ focus: function(){window.focus(); focusInput(); onFocus(); fastPoll();},
145
145
  setOption: function(option, value) {
146
146
  var oldVal = options[option];
147
147
  options[option] = value;
@@ -150,9 +150,11 @@ var CodeMirror = (function() {
150
150
  else if (option == "readOnly" && !value) {resetInput(true);}
151
151
  else if (option == "theme") themeChanged();
152
152
  else if (option == "lineWrapping" && oldVal != value) operation(wrappingChanged)();
153
- else if (option == "tabSize") operation(tabsChanged)();
154
- if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber" || option == "theme")
153
+ else if (option == "tabSize") updateDisplay(true);
154
+ if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber" || option == "theme") {
155
+ gutterChanged();
155
156
  updateDisplay(true);
157
+ }
156
158
  },
157
159
  getOption: function(option) {return options[option];},
158
160
  undo: operation(undo),
@@ -259,7 +261,15 @@ var CodeMirror = (function() {
259
261
  moveH: operation(moveH),
260
262
  deleteH: operation(deleteH),
261
263
  moveV: operation(moveV),
262
- toggleOverwrite: function() {overwrite = !overwrite;},
264
+ toggleOverwrite: function() {
265
+ if(overwrite){
266
+ overwrite = false;
267
+ cursor.className = cursor.className.replace(" CodeMirror-overwrite", "");
268
+ } else {
269
+ overwrite = true;
270
+ cursor.className += " CodeMirror-overwrite";
271
+ }
272
+ },
263
273
 
264
274
  posFromIndex: function(off) {
265
275
  var lineNo = 0, ch;
@@ -280,8 +290,8 @@ var CodeMirror = (function() {
280
290
  return index;
281
291
  },
282
292
  scrollTo: function(x, y) {
283
- if (x != null) scroller.scrollTop = x;
284
- if (y != null) scroller.scrollLeft = y;
293
+ if (x != null) scroller.scrollLeft = x;
294
+ if (y != null) scroller.scrollTop = y;
285
295
  updateDisplay([]);
286
296
  },
287
297
 
@@ -454,51 +464,69 @@ var CodeMirror = (function() {
454
464
  }
455
465
  function onDragStart(e) {
456
466
  var txt = getSelection();
457
- // This will reset escapeElement
458
- htmlEscape(txt);
459
- e.dataTransfer.setDragImage(escapeElement, 0, 0);
467
+ // Disabled until further notice. Doesn't work on most browsers,
468
+ // and crashes Safari (issue #332).
469
+ //htmlEscape(txt);
470
+ //e.dataTransfer.setDragImage(escapeElement, 0, 0);
460
471
  e.dataTransfer.setData("Text", txt);
461
472
  }
462
- function handleKeyBinding(e) {
463
- var name = keyNames[e_prop(e, "keyCode")], next = keyMap[options.keyMap].auto, bound, dropShift;
464
- function handleNext() {
465
- return next.call ? next.call(null, instance) : next;
466
- }
467
- if (name == null || e.altGraphKey) {
468
- if (next) options.keyMap = handleNext();
469
- return null;
470
- }
471
- if (e_prop(e, "altKey")) name = "Alt-" + name;
472
- if (e_prop(e, "ctrlKey")) name = "Ctrl-" + name;
473
- if (e_prop(e, "metaKey")) name = "Cmd-" + name;
474
- if (e_prop(e, "shiftKey") &&
475
- (bound = lookupKey("Shift-" + name, options.extraKeys, options.keyMap))) {
476
- dropShift = true;
477
- } else {
478
- bound = lookupKey(name, options.extraKeys, options.keyMap);
479
- }
473
+
474
+ function doHandleBinding(bound, dropShift) {
480
475
  if (typeof bound == "string") {
481
- if (commands.propertyIsEnumerable(bound)) bound = commands[bound];
482
- else bound = null;
476
+ bound = commands[bound];
477
+ if (!bound) return false;
483
478
  }
484
- if (next && (bound || !isModifierKey(e))) options.keyMap = handleNext();
485
- if (!bound) return false;
486
479
  var prevShift = shiftSelecting;
487
480
  try {
488
481
  if (options.readOnly) suppressEdits = true;
489
482
  if (dropShift) shiftSelecting = null;
490
483
  bound(instance);
484
+ } catch(e) {
485
+ if (e != Pass) throw e;
486
+ return false;
491
487
  } finally {
492
488
  shiftSelecting = prevShift;
493
489
  suppressEdits = false;
494
490
  }
495
- e_preventDefault(e);
496
491
  return true;
497
492
  }
498
- var lastStoppedKey = null;
493
+ function handleKeyBinding(e) {
494
+ // Handle auto keymap transitions
495
+ var startMap = getKeyMap(options.keyMap), next = startMap.auto;
496
+ clearTimeout(maybeTransition);
497
+ if (next && !isModifierKey(e)) maybeTransition = setTimeout(function() {
498
+ if (getKeyMap(options.keyMap) == startMap) {
499
+ options.keyMap = (next.call ? next.call(null, instance) : next);
500
+ }
501
+ }, 50);
502
+
503
+ var name = keyNames[e_prop(e, "keyCode")], handled = false;
504
+ if (name == null || e.altGraphKey) return false;
505
+ if (e_prop(e, "altKey")) name = "Alt-" + name;
506
+ if (e_prop(e, "ctrlKey")) name = "Ctrl-" + name;
507
+ if (e_prop(e, "metaKey")) name = "Cmd-" + name;
508
+
509
+ if (e_prop(e, "shiftKey"))
510
+ handled = lookupKey("Shift-" + name, options.extraKeys, options.keyMap,
511
+ function(b) {return doHandleBinding(b, true);});
512
+ if (!handled)
513
+ handled = lookupKey(name, options.extraKeys, options.keyMap, doHandleBinding);
514
+
515
+ if (handled) e_preventDefault(e);
516
+ return handled;
517
+ }
518
+ function handleCharBinding(e, ch) {
519
+ var handled = lookupKey("'" + ch + "'", options.extraKeys,
520
+ options.keyMap, doHandleBinding);
521
+ if (handled) e_preventDefault(e);
522
+ return handled;
523
+ }
524
+
525
+ var lastStoppedKey = null, maybeTransition;
499
526
  function onKeyDown(e) {
500
527
  if (!focused) onFocus();
501
528
  if (ie && e.keyCode == 27) { e.returnValue = false; }
529
+ if (pollingFast) { if (readInput()) pollingFast = false; }
502
530
  if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
503
531
  var code = e_prop(e, "keyCode");
504
532
  // IE does strange things with escape.
@@ -513,15 +541,17 @@ var CodeMirror = (function() {
513
541
  }
514
542
  }
515
543
  function onKeyPress(e) {
544
+ if (pollingFast) readInput();
545
+ if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
516
546
  var keyCode = e_prop(e, "keyCode"), charCode = e_prop(e, "charCode");
517
547
  if (window.opera && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
518
- if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
519
548
  if (window.opera && !e.which && handleKeyBinding(e)) return;
549
+ var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
520
550
  if (options.electricChars && mode.electricChars && options.smartIndent && !options.readOnly) {
521
- var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
522
551
  if (mode.electricChars.indexOf(ch) > -1)
523
552
  setTimeout(operation(function() {indentLine(sel.to.line, "smart");}), 75);
524
553
  }
554
+ if (handleCharBinding(e, ch)) return;
525
555
  fastPoll();
526
556
  }
527
557
  function onKeyUp(e) {
@@ -567,9 +597,10 @@ var CodeMirror = (function() {
567
597
  }
568
598
  updateLinesNoUndo(from, to, newText, selFrom, selTo);
569
599
  }
570
- function unredoHelper(from, to, dir) {
571
- var set = from.pop(), len = set ? set.length : 0, out = [];
572
- for (var i = dir > 0 ? 0 : len - 1, e = dir > 0 ? len : -1; i != e; i += dir) {
600
+ function unredoHelper(from, to) {
601
+ if (!from.length) return;
602
+ var set = from.pop(), out = [];
603
+ for (var i = set.length - 1; i >= 0; i -= 1) {
573
604
  var change = set[i];
574
605
  var replaced = [], end = change.start + change.added;
575
606
  doc.iter(change.start, end, function(line) { replaced.push(line.text); });
@@ -581,8 +612,8 @@ var CodeMirror = (function() {
581
612
  updateInput = true;
582
613
  to.push(out);
583
614
  }
584
- function undo() {unredoHelper(history.done, history.undone, -1);}
585
- function redo() {unredoHelper(history.undone, history.done, 1);}
615
+ function undo() {unredoHelper(history.done, history.undone);}
616
+ function redo() {unredoHelper(history.undone, history.done);}
586
617
 
587
618
  function updateLinesNoUndo(from, to, newText, selFrom, selTo) {
588
619
  if (suppressEdits) return;
@@ -784,7 +815,7 @@ var CodeMirror = (function() {
784
815
  if (!posEq(sel.from, sel.to)) {
785
816
  prevInput = "";
786
817
  input.value = getSelection();
787
- input.select();
818
+ selectInput(input);
788
819
  } else if (user) prevInput = input.value = "";
789
820
  }
790
821
 
@@ -971,7 +1002,7 @@ var CodeMirror = (function() {
971
1002
  if (!nextIntact || nextIntact.from > j) {
972
1003
  if (line.hidden) var html = scratch.innerHTML = "<pre></pre>";
973
1004
  else {
974
- var html = '<pre>' + line.getHTML(tabText) + '</pre>';
1005
+ var html = '<pre>' + line.getHTML(makeTab) + '</pre>';
975
1006
  // Kludge to make sure the styled element lies behind the selection (by z-index)
976
1007
  if (line.className)
977
1008
  html = '<div style="position: relative"><pre class="' + line.className +
@@ -1081,6 +1112,20 @@ var CodeMirror = (function() {
1081
1112
  else if (posEq(from, sel.to)) sel.inverted = false;
1082
1113
  else if (posEq(to, sel.from)) sel.inverted = true;
1083
1114
 
1115
+ if (options.autoClearEmptyLines && posEq(sel.from, sel.to)) {
1116
+ var head = sel.inverted ? from : to;
1117
+ if (head.line != sel.from.line) {
1118
+ var oldLine = getLine(sel.from.line);
1119
+ if (/^\s+$/.test(oldLine.text))
1120
+ setTimeout(operation(function() {
1121
+ if (oldLine.parent && /^\s+$/.test(oldLine.text)) {
1122
+ var no = lineNo(oldLine);
1123
+ replaceRange("", {line: no, ch: 0}, {line: no, ch: oldLine.text.length});
1124
+ }
1125
+ }, 10));
1126
+ }
1127
+ }
1128
+
1084
1129
  sel.from = from; sel.to = to;
1085
1130
  selectionChanged = true;
1086
1131
  }
@@ -1176,7 +1221,7 @@ var CodeMirror = (function() {
1176
1221
  setSelectionUser({line: pos.line, ch: start}, {line: pos.line, ch: end});
1177
1222
  }
1178
1223
  function selectLine(line) {
1179
- setSelectionUser({line: line, ch: 0}, {line: line, ch: getLine(line).text.length});
1224
+ setSelectionUser({line: line, ch: 0}, clipPos({line: line + 1, ch: 0}));
1180
1225
  }
1181
1226
  function indentSelected(mode) {
1182
1227
  if (posEq(sel.from, sel.to)) return indentLine(sel.from.line, mode);
@@ -1249,13 +1294,10 @@ var CodeMirror = (function() {
1249
1294
  }
1250
1295
  changes.push({from: 0, to: doc.size});
1251
1296
  }
1252
- function computeTabText() {
1253
- for (var str = '<span class="cm-tab">', i = 0; i < options.tabSize; ++i) str += " ";
1254
- return str + "</span>";
1255
- }
1256
- function tabsChanged() {
1257
- tabText = computeTabText();
1258
- updateDisplay(true);
1297
+ function makeTab(col) {
1298
+ var w = options.tabSize - col % options.tabSize;
1299
+ for (var str = '<span class="cm-tab">', i = 0; i < w; ++i) str += " ";
1300
+ return {html: str + "</span>", width: w};
1259
1301
  }
1260
1302
  function themeChanged() {
1261
1303
  scroller.className = scroller.className.replace(/\s*cm-s-\w+/g, "") +
@@ -1392,7 +1434,7 @@ var CodeMirror = (function() {
1392
1434
  if (x <= 0) return 0;
1393
1435
  var lineObj = getLine(line), text = lineObj.text;
1394
1436
  function getX(len) {
1395
- measure.innerHTML = "<pre><span>" + lineObj.getHTML(tabText, len) + "</span></pre>";
1437
+ measure.innerHTML = "<pre><span>" + lineObj.getHTML(makeTab, len) + "</span></pre>";
1396
1438
  return measure.firstChild.firstChild.offsetWidth;
1397
1439
  }
1398
1440
  var from = 0, fromX = 0, to = text.length, toX;
@@ -1425,7 +1467,7 @@ var CodeMirror = (function() {
1425
1467
  var end = line.text.indexOf(" ", ch + 2);
1426
1468
  extra = htmlEscape(line.text.slice(ch + 1, end < 0 ? line.text.length : end + (ie ? 5 : 0)));
1427
1469
  }
1428
- measure.innerHTML = "<pre>" + line.getHTML(tabText, ch) +
1470
+ measure.innerHTML = "<pre>" + line.getHTML(makeTab, ch) +
1429
1471
  '<span id="CodeMirror-temp-' + tempId + '">' + htmlEscape(line.text.charAt(ch) || " ") + "</span>" +
1430
1472
  extra + "</pre>";
1431
1473
  var elt = document.getElementById("CodeMirror-temp-" + tempId);
@@ -1528,7 +1570,7 @@ var CodeMirror = (function() {
1528
1570
  return coordsChar(x - offL.left, y - offL.top);
1529
1571
  }
1530
1572
  function onContextMenu(e) {
1531
- var pos = posFromMouse(e);
1573
+ var pos = posFromMouse(e), scrollPos = scroller.scrollTop;
1532
1574
  if (!pos || window.opera) return; // Opera is difficult.
1533
1575
  if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to))
1534
1576
  operation(setCursor)(pos.line, pos.ch);
@@ -1541,12 +1583,13 @@ var CodeMirror = (function() {
1541
1583
  leaveInputAlone = true;
1542
1584
  var val = input.value = getSelection();
1543
1585
  focusInput();
1544
- input.select();
1586
+ selectInput(input);
1545
1587
  function rehide() {
1546
1588
  var newVal = splitLines(input.value).join("\n");
1547
1589
  if (newVal != val) operation(replaceSelection)(newVal, "end");
1548
1590
  inputDiv.style.position = "relative";
1549
1591
  input.style.cssText = oldCSS;
1592
+ if (ie_lt9) scroller.scrollTop = scrollPos;
1550
1593
  leaveInputAlone = false;
1551
1594
  resetInput(true);
1552
1595
  slowPoll();
@@ -1558,8 +1601,7 @@ var CodeMirror = (function() {
1558
1601
  mouseup();
1559
1602
  setTimeout(rehide, 20);
1560
1603
  }, true);
1561
- }
1562
- else {
1604
+ } else {
1563
1605
  setTimeout(rehide, 50);
1564
1606
  }
1565
1607
  }
@@ -1761,6 +1803,7 @@ var CodeMirror = (function() {
1761
1803
  keyMap: "default",
1762
1804
  extraKeys: null,
1763
1805
  electricChars: true,
1806
+ autoClearEmptyLines: false,
1764
1807
  onKeyEvent: null,
1765
1808
  lineWrapping: false,
1766
1809
  lineNumbers: false,
@@ -1796,19 +1839,20 @@ var CodeMirror = (function() {
1796
1839
  CodeMirror.defineMIME = function(mime, spec) {
1797
1840
  mimeModes[mime] = spec;
1798
1841
  };
1799
- CodeMirror.getMode = function(options, spec) {
1842
+ CodeMirror.resolveMode = function(spec) {
1800
1843
  if (typeof spec == "string" && mimeModes.hasOwnProperty(spec))
1801
1844
  spec = mimeModes[spec];
1802
- if (typeof spec == "string")
1803
- var mname = spec, config = {};
1804
- else if (spec != null)
1805
- var mname = spec.name, config = spec;
1806
- var mfactory = modes[mname];
1845
+ if (typeof spec == "string") return {name: spec};
1846
+ else return spec || {name: "null"};
1847
+ };
1848
+ CodeMirror.getMode = function(options, spec) {
1849
+ var spec = CodeMirror.resolveMode(spec);
1850
+ var mfactory = modes[spec.name];
1807
1851
  if (!mfactory) {
1808
- if (window.console) console.warn("No mode " + mname + " found, falling back to plain text.");
1852
+ if (window.console) console.warn("No mode " + spec.name + " found, falling back to plain text.");
1809
1853
  return CodeMirror.getMode(options, "text/plain");
1810
1854
  }
1811
- return mfactory(options, config || {});
1855
+ return mfactory(options, spec);
1812
1856
  };
1813
1857
  CodeMirror.listModes = function() {
1814
1858
  var list = [];
@@ -1911,20 +1955,27 @@ var CodeMirror = (function() {
1911
1955
  "Alt-D": "delWordRight", "Alt-Backspace": "delWordLeft", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
1912
1956
  };
1913
1957
 
1914
- function lookupKey(name, extraMap, map) {
1915
- function lookup(name, map, ft) {
1958
+ function getKeyMap(val) {
1959
+ if (typeof val == "string") return keyMap[val];
1960
+ else return val;
1961
+ }
1962
+ function lookupKey(name, extraMap, map, handle) {
1963
+ function lookup(map) {
1964
+ map = getKeyMap(map);
1916
1965
  var found = map[name];
1917
- if (found != null) return found;
1918
- if (ft == null) ft = map.fallthrough;
1919
- if (ft == null) return map.catchall;
1920
- if (typeof ft == "string") return lookup(name, keyMap[ft]);
1921
- for (var i = 0, e = ft.length; i < e; ++i) {
1922
- found = lookup(name, keyMap[ft[i]]);
1923
- if (found != null) return found;
1924
- }
1925
- return null;
1926
- }
1927
- return extraMap ? lookup(name, extraMap, map) : lookup(name, keyMap[map]);
1966
+ if (found != null && handle(found)) return true;
1967
+ if (map.catchall) return handle(map.catchall);
1968
+ var fallthrough = map.fallthrough;
1969
+ if (fallthrough == null) return false;
1970
+ if (Object.prototype.toString.call(fallthrough) != "[object Array]")
1971
+ return lookup(fallthrough);
1972
+ for (var i = 0, e = fallthrough.length; i < e; ++i) {
1973
+ if (lookup(fallthrough[i])) return true;
1974
+ }
1975
+ return false;
1976
+ }
1977
+ if (extraMap && lookup(extraMap)) return true;
1978
+ return lookup(map);
1928
1979
  }
1929
1980
  function isModifierKey(event) {
1930
1981
  var name = keyNames[e_prop(event, "keyCode")];
@@ -2272,15 +2323,35 @@ var CodeMirror = (function() {
2272
2323
  indentation: function(tabSize) {return countColumn(this.text, null, tabSize);},
2273
2324
  // Produces an HTML fragment for the line, taking selection,
2274
2325
  // marking, and highlighting into account.
2275
- getHTML: function(tabText, endAt) {
2276
- var html = [], first = true;
2326
+ getHTML: function(makeTab, endAt) {
2327
+ var html = [], first = true, col = 0;
2277
2328
  function span(text, style) {
2278
2329
  if (!text) return;
2279
2330
  // Work around a bug where, in some compat modes, IE ignores leading spaces
2280
2331
  if (first && ie && text.charAt(0) == " ") text = "\u00a0" + text.slice(1);
2281
2332
  first = false;
2282
- if (style) html.push('<span class="', style, '">', htmlEscape(text).replace(/\t/g, tabText), "</span>");
2283
- else html.push(htmlEscape(text).replace(/\t/g, tabText));
2333
+ if (text.indexOf("\t") == -1) {
2334
+ col += text.length;
2335
+ var escaped = htmlEscape(text);
2336
+ } else {
2337
+ var escaped = "";
2338
+ for (var pos = 0;;) {
2339
+ var idx = text.indexOf("\t", pos);
2340
+ if (idx == -1) {
2341
+ escaped += htmlEscape(text.slice(pos));
2342
+ col += text.length - pos;
2343
+ break;
2344
+ } else {
2345
+ col += idx - pos;
2346
+ var tab = makeTab(col);
2347
+ escaped += htmlEscape(text.slice(pos, idx)) + tab.html;
2348
+ col += tab.width;
2349
+ pos = idx + 1;
2350
+ }
2351
+ }
2352
+ }
2353
+ if (style) html.push('<span class="', style, '">', escaped, "</span>");
2354
+ else html.push(escaped);
2284
2355
  }
2285
2356
  var st = this.styles, allText = this.text, marked = this.marked;
2286
2357
  var len = allText.length;
@@ -2559,7 +2630,7 @@ var CodeMirror = (function() {
2559
2630
  var dtime = time - this.time;
2560
2631
  if (dtime > 400 || !last) {
2561
2632
  this.done.push([{start: start, added: added, old: old}]);
2562
- } else if (last.start > start + added || last.start + last.added < start - last.added + last.old.length) {
2633
+ } else if (last.start > start + old.length || last.start + last.added < start - last.added + last.old.length) {
2563
2634
  cur.push({start: start, added: added, old: old});
2564
2635
  } else {
2565
2636
  var oldoff = 0;
@@ -2634,6 +2705,8 @@ var CodeMirror = (function() {
2634
2705
  function Delayed() {this.id = null;}
2635
2706
  Delayed.prototype = {set: function(ms, f) {clearTimeout(this.id); this.id = setTimeout(f, ms);}};
2636
2707
 
2708
+ var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}};
2709
+
2637
2710
  // Detect drag-and-drop
2638
2711
  var dragAndDrop = function() {
2639
2712
  // IE8 has ondragstart and ondrop properties, but doesn't seem to
@@ -2645,6 +2718,7 @@ var CodeMirror = (function() {
2645
2718
 
2646
2719
  var gecko = /gecko\/\d{7}/i.test(navigator.userAgent);
2647
2720
  var ie = /MSIE \d/.test(navigator.userAgent);
2721
+ var ie_lt9 = /MSIE [1-8]\b/.test(navigator.userAgent);
2648
2722
  var webkit = /WebKit\//.test(navigator.userAgent);
2649
2723
 
2650
2724
  var lineSep = "\n";