codemirror-rails 2.3 → 2.21

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.
Files changed (71) hide show
  1. data/README.md +0 -16
  2. data/codemirror-rails.gemspec +1 -1
  3. data/lib/codemirror/rails/version.rb +2 -2
  4. data/vendor/assets/javascripts/codemirror.js +323 -687
  5. data/vendor/assets/javascripts/codemirror/modes/clike.js +3 -40
  6. data/vendor/assets/javascripts/codemirror/modes/clojure.js +14 -14
  7. data/vendor/assets/javascripts/codemirror/modes/coffeescript.js +0 -6
  8. data/vendor/assets/javascripts/codemirror/modes/css.js +1 -1
  9. data/vendor/assets/javascripts/codemirror/modes/diff.js +5 -24
  10. data/vendor/assets/javascripts/codemirror/modes/gfm.js +4 -40
  11. data/vendor/assets/javascripts/codemirror/modes/go.js +22 -20
  12. data/vendor/assets/javascripts/codemirror/modes/htmlembedded.js +1 -1
  13. data/vendor/assets/javascripts/codemirror/modes/htmlmixed.js +2 -4
  14. data/vendor/assets/javascripts/codemirror/modes/javascript.js +7 -8
  15. data/vendor/assets/javascripts/codemirror/modes/less.js +54 -100
  16. data/vendor/assets/javascripts/codemirror/modes/markdown.js +49 -52
  17. data/vendor/assets/javascripts/codemirror/modes/pascal.js +46 -2
  18. data/vendor/assets/javascripts/codemirror/modes/perl.js +1 -1
  19. data/vendor/assets/javascripts/codemirror/modes/php.js +25 -54
  20. data/vendor/assets/javascripts/codemirror/modes/python.js +16 -14
  21. data/vendor/assets/javascripts/codemirror/modes/rpm-spec.js +1 -1
  22. data/vendor/assets/javascripts/codemirror/modes/rst.js +1 -1
  23. data/vendor/assets/javascripts/codemirror/modes/ruby.js +9 -4
  24. data/vendor/assets/javascripts/codemirror/modes/scheme.js +46 -74
  25. data/vendor/assets/javascripts/codemirror/modes/smalltalk.js +16 -16
  26. data/vendor/assets/javascripts/codemirror/modes/stex.js +6 -21
  27. data/vendor/assets/javascripts/codemirror/modes/tiddlywiki.js +45 -55
  28. data/vendor/assets/javascripts/codemirror/modes/xml.js +14 -79
  29. data/vendor/assets/javascripts/codemirror/{utils/overlay.js → overlay.js} +2 -3
  30. data/vendor/assets/javascripts/codemirror/runmode.js +27 -0
  31. data/vendor/assets/stylesheets/codemirror.css +2 -63
  32. data/vendor/assets/stylesheets/codemirror/modes/tiddlywiki.css +21 -14
  33. data/vendor/assets/stylesheets/codemirror/themes/eclipse.css +1 -1
  34. data/vendor/assets/stylesheets/codemirror/themes/elegant.css +2 -2
  35. data/vendor/assets/stylesheets/codemirror/themes/neat.css +3 -3
  36. data/vendor/assets/stylesheets/codemirror/themes/night.css +1 -1
  37. data/vendor/assets/stylesheets/codemirror/themes/rubyblue.css +2 -2
  38. metadata +6 -39
  39. data/vendor/assets/javascripts/codemirror/keymaps/emacs.js +0 -29
  40. data/vendor/assets/javascripts/codemirror/keymaps/vim.js +0 -766
  41. data/vendor/assets/javascripts/codemirror/modes/ecl.js +0 -203
  42. data/vendor/assets/javascripts/codemirror/modes/erlang.js +0 -251
  43. data/vendor/assets/javascripts/codemirror/modes/pig.js +0 -172
  44. data/vendor/assets/javascripts/codemirror/modes/properties.js +0 -63
  45. data/vendor/assets/javascripts/codemirror/modes/shell.js +0 -103
  46. data/vendor/assets/javascripts/codemirror/modes/smarty.js +0 -148
  47. data/vendor/assets/javascripts/codemirror/modes/tiki.js +0 -316
  48. data/vendor/assets/javascripts/codemirror/modes/vbscript.js +0 -26
  49. data/vendor/assets/javascripts/codemirror/modes/xquery.js +0 -448
  50. data/vendor/assets/javascripts/codemirror/utils/closetag.js +0 -146
  51. data/vendor/assets/javascripts/codemirror/utils/dialog.js +0 -63
  52. data/vendor/assets/javascripts/codemirror/utils/foldcode.js +0 -196
  53. data/vendor/assets/javascripts/codemirror/utils/formatting.js +0 -297
  54. data/vendor/assets/javascripts/codemirror/utils/javascript-hint.js +0 -134
  55. data/vendor/assets/javascripts/codemirror/utils/loadmode.js +0 -51
  56. data/vendor/assets/javascripts/codemirror/utils/match-highlighter.js +0 -44
  57. data/vendor/assets/javascripts/codemirror/utils/multiplex.js +0 -72
  58. data/vendor/assets/javascripts/codemirror/utils/pig-hint.js +0 -123
  59. data/vendor/assets/javascripts/codemirror/utils/runmode.js +0 -49
  60. data/vendor/assets/javascripts/codemirror/utils/search.js +0 -118
  61. data/vendor/assets/javascripts/codemirror/utils/searchcursor.js +0 -117
  62. data/vendor/assets/javascripts/codemirror/utils/simple-hint.js +0 -72
  63. data/vendor/assets/stylesheets/codemirror/modes/tiki.css +0 -26
  64. data/vendor/assets/stylesheets/codemirror/themes/ambiance.css +0 -81
  65. data/vendor/assets/stylesheets/codemirror/themes/blackboard.css +0 -25
  66. data/vendor/assets/stylesheets/codemirror/themes/erlang-dark.css +0 -21
  67. data/vendor/assets/stylesheets/codemirror/themes/lesser-dark.css +0 -44
  68. data/vendor/assets/stylesheets/codemirror/themes/vibrant-ink.css +0 -27
  69. data/vendor/assets/stylesheets/codemirror/themes/xq-dark.css +0 -46
  70. data/vendor/assets/stylesheets/codemirror/utils/dialog.css +0 -23
  71. data/vendor/assets/stylesheets/codemirror/utils/simple-hint.css +0 -16
data/README.md CHANGED
@@ -35,22 +35,6 @@ 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
-
46
- ### Adding a keymap
47
-
48
- Additional keymap bindings can be added to your application.js:
49
-
50
- ```js
51
- //= require codemirror/keymaps/vim
52
- ```
53
-
54
38
  ### Adding a theme
55
39
 
56
40
  Additional CSS themes can be added to your application.css
@@ -3,7 +3,7 @@ require File.expand_path('../lib/codemirror/rails/version', __FILE__)
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'codemirror-rails'
5
5
  s.version = Codemirror::Rails::VERSION
6
- s.authors = ['Nathan Fixler', 'Robin Bühler']
6
+ s.authors = ['Nathan Fixler']
7
7
  s.email = 'nathan@fixler.org'
8
8
  s.summary = 'Use CodeMirror with Rails 3'
9
9
  s.description = 'This gem provides CodeMirror assets for your Rails 3 application.'
@@ -1,6 +1,6 @@
1
1
  module Codemirror
2
2
  module Rails
3
- VERSION = '2.3'
4
- CODEMIRROR_VERSION = '2.3'
3
+ VERSION = '2.21'
4
+ CODEMIRROR_VERSION = '2.21'
5
5
  end
6
6
  end
@@ -1,4 +1,4 @@
1
- // CodeMirror version 2.3
1
+ // CodeMirror version 2.21
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. Its
9
+ // This is the function that produces an editor instance. It's
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.
@@ -15,27 +15,23 @@ var CodeMirror = (function() {
15
15
  if (defaults.hasOwnProperty(opt))
16
16
  options[opt] = (givenOptions && givenOptions.hasOwnProperty(opt) ? givenOptions : defaults)[opt];
17
17
 
18
+ var targetDocument = options["document"];
18
19
  // The element in which the editor lives.
19
- var wrapper = document.createElement("div");
20
+ var wrapper = targetDocument.createElement("div");
20
21
  wrapper.className = "CodeMirror" + (options.lineWrapping ? " CodeMirror-wrap" : "");
21
22
  // This mess creates the base DOM structure for the editor.
22
23
  wrapper.innerHTML =
23
24
  '<div style="overflow: hidden; position: relative; width: 3px; height: 0px;">' + // Wraps and hides input textarea
24
25
  '<textarea style="position: absolute; padding: 0; width: 1px; height: 1em" wrap="off" ' +
25
26
  'autocorrect="off" autocapitalize="off"></textarea></div>' +
26
- '<div class="CodeMirror-scrollbar">' + // The vertical scrollbar. Horizontal scrolling is handled by the scroller itself.
27
- '<div class="CodeMirror-scrollbar-inner">' + // The empty scrollbar content, used solely for managing the scrollbar thumb.
28
- '</div></div>' + // This must be before the scroll area because it's float-right.
29
27
  '<div class="CodeMirror-scroll" tabindex="-1">' +
30
28
  '<div style="position: relative">' + // Set to the height of the text, causes scrolling
31
29
  '<div style="position: relative">' + // Moved around its parent to cover visible view
32
30
  '<div class="CodeMirror-gutter"><div class="CodeMirror-gutter-text"></div></div>' +
33
31
  // Provides positioning relative to (visible) text origin
34
32
  '<div class="CodeMirror-lines"><div style="position: relative; z-index: 0">' +
35
- // Used to measure text size
36
- '<div style="position: absolute; width: 100%; height: 0; overflow: hidden; visibility: hidden;"></div>' +
33
+ '<div style="position: absolute; width: 100%; height: 0; overflow: hidden; visibility: hidden; outline: 5px auto none"></div>' +
37
34
  '<pre class="CodeMirror-cursor">&#160;</pre>' + // Absolutely positioned blinky cursor
38
- '<pre class="CodeMirror-cursor" style="visibility: hidden">&#160;</pre>' + // Used to force a width
39
35
  '<div style="position: relative; z-index: -1"></div><div></div>' + // DIVs containing the selection and the actual code
40
36
  '</div></div></div></div></div>';
41
37
  if (place.appendChild) place.appendChild(wrapper); else place(wrapper);
@@ -44,30 +40,15 @@ var CodeMirror = (function() {
44
40
  scroller = wrapper.lastChild, code = scroller.firstChild,
45
41
  mover = code.firstChild, gutter = mover.firstChild, gutterText = gutter.firstChild,
46
42
  lineSpace = gutter.nextSibling.firstChild, measure = lineSpace.firstChild,
47
- cursor = measure.nextSibling, widthForcer = cursor.nextSibling,
48
- selectionDiv = widthForcer.nextSibling, lineDiv = selectionDiv.nextSibling,
49
- scrollbar = inputDiv.nextSibling, scrollbarInner = scrollbar.firstChild;
50
- themeChanged(); keyMapChanged();
43
+ cursor = measure.nextSibling, selectionDiv = cursor.nextSibling,
44
+ lineDiv = selectionDiv.nextSibling;
45
+ themeChanged();
51
46
  // Needed to hide big blue blinking cursor on Mobile Safari
52
47
  if (ios) input.style.width = "0px";
53
- if (!webkit) scroller.draggable = true;
48
+ if (!webkit) lineSpace.draggable = true;
54
49
  lineSpace.style.outline = "none";
55
50
  if (options.tabindex != null) input.tabIndex = options.tabindex;
56
- if (options.autofocus) focusInput();
57
51
  if (!options.gutter && !options.lineNumbers) gutter.style.display = "none";
58
- // Needed to handle Tab key in KHTML
59
- if (khtml) inputDiv.style.height = "1px", inputDiv.style.position = "absolute";
60
-
61
- // Check for OS X >= 10.7. If so, we need to force a width on the scrollbar, and
62
- // make it overlap the content. (But we only do this if the scrollbar doesn't already
63
- // have a natural width. If the mouse is plugged in or the user sets the system pref
64
- // to always show scrollbars, the scrollbar shouldn't overlap.)
65
- if (mac_geLion) {
66
- scrollbar.className += (overlapScrollbars() ? " cm-sb-overlap" : " cm-sb-nonoverlap");
67
- } else if (ie_lt8) {
68
- // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
69
- scrollbar.className += " cm-sb-ie7";
70
- }
71
52
 
72
53
  // Check for problem with IE innerHTML not working when we have a
73
54
  // P (or similar) parent node.
@@ -92,7 +73,7 @@ var CodeMirror = (function() {
92
73
  var sel = {from: {line: 0, ch: 0}, to: {line: 0, ch: 0}, inverted: false};
93
74
  // Selection-related flags. shiftSelecting obviously tracks
94
75
  // whether the user is holding shift.
95
- var shiftSelecting, lastClick, lastDoubleClick, lastScrollTop = 0, lastScrollLeft = 0, draggingText,
76
+ var shiftSelecting, lastClick, lastDoubleClick, lastScrollPos = 0, draggingText,
96
77
  overwrite = false, suppressEdits = false;
97
78
  // Variables used by startOperation/endOperation to track what
98
79
  // happened during the operation.
@@ -100,13 +81,12 @@ var CodeMirror = (function() {
100
81
  gutterDirty, callbacks;
101
82
  // Current visible range (may be bigger than the view window).
102
83
  var displayOffset = 0, showingFrom = 0, showingTo = 0, lastSizeC = 0;
103
- // bracketHighlighted is used to remember that a bracket has been
84
+ // bracketHighlighted is used to remember that a backet has been
104
85
  // marked.
105
86
  var bracketHighlighted;
106
87
  // Tracks the maximum line length so that the horizontal scrollbar
107
88
  // can be kept static when scrolling.
108
- var maxLine = "", updateMaxLine = false, maxLineChanged = true;
109
- var tabCache = {};
89
+ var maxLine = "", maxWidth, tabText = computeTabText();
110
90
 
111
91
  // Initialize the content.
112
92
  operation(function(){setValue(options.value || ""); updateInput = false;})();
@@ -115,16 +95,18 @@ var CodeMirror = (function() {
115
95
  // Register our event handlers.
116
96
  connect(scroller, "mousedown", operation(onMouseDown));
117
97
  connect(scroller, "dblclick", operation(onDoubleClick));
98
+ connect(lineSpace, "dragstart", onDragStart);
118
99
  connect(lineSpace, "selectstart", e_preventDefault);
119
100
  // Gecko browsers fire contextmenu *after* opening the menu, at
120
101
  // which point we can't mess with it anymore. Context menu is
121
102
  // handled in onMouseDown for Gecko.
122
103
  if (!gecko) connect(scroller, "contextmenu", onContextMenu);
123
- connect(scroller, "scroll", onScroll);
124
- connect(scrollbar, "scroll", onScroll);
125
- connect(scrollbar, "mousedown", function() {setTimeout(focusInput, 0);});
126
- connect(scroller, "mousewheel", onMouseWheel);
127
- connect(scroller, "DOMMouseScroll", onMouseWheel);
104
+ connect(scroller, "scroll", function() {
105
+ lastScrollPos = scroller.scrollTop;
106
+ updateDisplay([]);
107
+ if (options.fixedGutter) gutter.style.left = scroller.scrollLeft + "px";
108
+ if (options.onScroll) options.onScroll(instance);
109
+ });
128
110
  connect(window, "resize", function() {updateDisplay(true);});
129
111
  connect(input, "keyup", operation(onKeyUp));
130
112
  connect(input, "input", fastPoll);
@@ -133,32 +115,19 @@ var CodeMirror = (function() {
133
115
  connect(input, "focus", onFocus);
134
116
  connect(input, "blur", onBlur);
135
117
 
136
- if (options.dragDrop) {
137
- connect(scroller, "dragstart", onDragStart);
138
- function drag_(e) {
139
- if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return;
140
- e_stop(e);
141
- }
142
- connect(scroller, "dragenter", drag_);
143
- connect(scroller, "dragover", drag_);
144
- connect(scroller, "drop", operation(onDrop));
145
- }
118
+ connect(scroller, "dragenter", e_stop);
119
+ connect(scroller, "dragover", e_stop);
120
+ connect(scroller, "drop", operation(onDrop));
146
121
  connect(scroller, "paste", function(){focusInput(); fastPoll();});
147
122
  connect(input, "paste", fastPoll);
148
123
  connect(input, "cut", operation(function(){
149
124
  if (!options.readOnly) replaceSelection("");
150
125
  }));
151
126
 
152
- // Needed to handle Tab key in KHTML
153
- if (khtml) connect(code, "mouseup", function() {
154
- if (document.activeElement == input) input.blur();
155
- focusInput();
156
- });
157
-
158
127
  // IE throws unspecified error in certain cases, when
159
128
  // trying to access activeElement before onload
160
- var hasFocus; try { hasFocus = (document.activeElement == input); } catch(e) { }
161
- if (hasFocus || options.autofocus) setTimeout(onFocus, 20);
129
+ var hasFocus; try { hasFocus = (targetDocument.activeElement == input); } catch(e) { }
130
+ if (hasFocus) setTimeout(onFocus, 20);
162
131
  else onBlur();
163
132
 
164
133
  function isLine(l) {return l >= 0 && l < doc.size;}
@@ -172,7 +141,7 @@ var CodeMirror = (function() {
172
141
  setValue: operation(setValue),
173
142
  getSelection: getSelection,
174
143
  replaceSelection: operation(replaceSelection),
175
- focus: function(){window.focus(); focusInput(); onFocus(); fastPoll();},
144
+ focus: function(){focusInput(); onFocus(); fastPoll();},
176
145
  setOption: function(option, value) {
177
146
  var oldVal = options[option];
178
147
  options[option] = value;
@@ -181,12 +150,9 @@ var CodeMirror = (function() {
181
150
  else if (option == "readOnly" && !value) {resetInput(true);}
182
151
  else if (option == "theme") themeChanged();
183
152
  else if (option == "lineWrapping" && oldVal != value) operation(wrappingChanged)();
184
- else if (option == "tabSize") updateDisplay(true);
185
- else if (option == "keyMap") keyMapChanged();
186
- if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber" || option == "theme") {
187
- gutterChanged();
153
+ else if (option == "tabSize") operation(tabsChanged)();
154
+ if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber" || option == "theme")
188
155
  updateDisplay(true);
189
- }
190
156
  },
191
157
  getOption: function(option) {return options[option];},
192
158
  undo: operation(undo),
@@ -210,23 +176,17 @@ var CodeMirror = (function() {
210
176
  line = clipLine(line == null ? doc.size - 1: line);
211
177
  return getStateBefore(line + 1);
212
178
  },
213
- cursorCoords: function(start, mode) {
179
+ cursorCoords: function(start){
214
180
  if (start == null) start = sel.inverted;
215
- return this.charCoords(start ? sel.from : sel.to, mode);
216
- },
217
- charCoords: function(pos, mode) {
218
- pos = clipPos(pos);
219
- if (mode == "local") return localCoords(pos, false);
220
- if (mode == "div") return localCoords(pos, true);
221
- return pageCoords(pos);
181
+ return pageCoords(start ? sel.from : sel.to);
222
182
  },
183
+ charCoords: function(pos){return pageCoords(clipPos(pos));},
223
184
  coordsChar: function(coords) {
224
185
  var off = eltOffset(lineSpace);
225
186
  return coordsChar(coords.x - off.left, coords.y - off.top);
226
187
  },
227
188
  markText: operation(markText),
228
189
  setBookmark: setBookmark,
229
- findMarksAt: findMarksAt,
230
190
  setMarker: operation(addGutterMarker),
231
191
  clearMarker: operation(removeGutterMarker),
232
192
  setLineClass: operation(setLineClass),
@@ -294,21 +254,12 @@ var CodeMirror = (function() {
294
254
  replaceRange: operation(replaceRange),
295
255
  getRange: function(from, to) {return getRange(clipPos(from), clipPos(to));},
296
256
 
297
- triggerOnKeyDown: operation(onKeyDown),
298
257
  execCommand: function(cmd) {return commands[cmd](instance);},
299
258
  // Stuff used by commands, probably not much use to outside code.
300
259
  moveH: operation(moveH),
301
260
  deleteH: operation(deleteH),
302
261
  moveV: operation(moveV),
303
- toggleOverwrite: function() {
304
- if(overwrite){
305
- overwrite = false;
306
- cursor.className = cursor.className.replace(" CodeMirror-overwrite", "");
307
- } else {
308
- overwrite = true;
309
- cursor.className += " CodeMirror-overwrite";
310
- }
311
- },
262
+ toggleOverwrite: function() {overwrite = !overwrite;},
312
263
 
313
264
  posFromIndex: function(off) {
314
265
  var lineNo = 0, ch;
@@ -329,21 +280,16 @@ var CodeMirror = (function() {
329
280
  return index;
330
281
  },
331
282
  scrollTo: function(x, y) {
332
- if (x != null) scroller.scrollLeft = x;
333
- if (y != null) scrollbar.scrollTop = y;
283
+ if (x != null) scroller.scrollTop = x;
284
+ if (y != null) scroller.scrollLeft = y;
334
285
  updateDisplay([]);
335
286
  },
336
- getScrollInfo: function() {
337
- return {x: scroller.scrollLeft, y: scrollbar.scrollTop,
338
- height: scrollbar.scrollHeight, width: scroller.scrollWidth};
339
- },
340
287
 
341
288
  operation: function(f){return operation(f)();},
342
- compoundChange: function(f){return compoundChange(f);},
343
289
  refresh: function(){
344
290
  updateDisplay(true);
345
- if (scrollbar.scrollHeight > lastScrollTop)
346
- scrollbar.scrollTop = lastScrollTop;
291
+ if (scroller.scrollHeight > lastScrollPos)
292
+ scroller.scrollTop = lastScrollPos;
347
293
  },
348
294
  getInputField: function(){return input;},
349
295
  getWrapperElement: function(){return wrapper;},
@@ -364,22 +310,12 @@ var CodeMirror = (function() {
364
310
  splitLines(code), top, top);
365
311
  updateInput = true;
366
312
  }
367
- function getValue() {
313
+ function getValue(code) {
368
314
  var text = [];
369
315
  doc.iter(0, doc.size, function(line) { text.push(line.text); });
370
316
  return text.join("\n");
371
317
  }
372
318
 
373
- function onScroll(e) {
374
- if (lastScrollTop != scrollbar.scrollTop || lastScrollLeft != scroller.scrollLeft) {
375
- lastScrollTop = scrollbar.scrollTop;
376
- lastScrollLeft = scroller.scrollLeft;
377
- updateDisplay([]);
378
- if (options.fixedGutter) gutter.style.left = scroller.scrollLeft + "px";
379
- if (options.onScroll) options.onScroll(instance);
380
- }
381
- }
382
-
383
319
  function onMouseDown(e) {
384
320
  setShift(e_prop(e, "shiftKey"));
385
321
  // Check whether this is a click in a widget
@@ -402,8 +338,6 @@ var CodeMirror = (function() {
402
338
  return;
403
339
  case 2:
404
340
  if (start) setCursor(start.line, start.ch, true);
405
- setTimeout(focusInput, 20);
406
- e_preventDefault(e);
407
341
  return;
408
342
  }
409
343
  // For button 1, if it was clicked inside the editor
@@ -425,25 +359,21 @@ var CodeMirror = (function() {
425
359
  } else { lastClick = {time: now, pos: start}; }
426
360
 
427
361
  var last = start, going;
428
- if (options.dragDrop && dragAndDrop && !options.readOnly && !posEq(sel.from, sel.to) &&
362
+ if (dragAndDrop && !options.readOnly && !posEq(sel.from, sel.to) &&
429
363
  !posLess(start, sel.from) && !posLess(sel.to, start)) {
430
364
  // Let the drag handler handle this.
431
- if (webkit) scroller.draggable = true;
432
- function dragEnd(e2) {
433
- if (webkit) scroller.draggable = false;
365
+ if (webkit) lineSpace.draggable = true;
366
+ var up = connect(targetDocument, "mouseup", operation(function(e2) {
367
+ if (webkit) lineSpace.draggable = false;
434
368
  draggingText = false;
435
- up(); drop();
369
+ up();
436
370
  if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
437
371
  e_preventDefault(e2);
438
372
  setCursor(start.line, start.ch, true);
439
373
  focusInput();
440
374
  }
441
- }
442
- var up = connect(document, "mouseup", operation(dragEnd), true);
443
- var drop = connect(scroller, "drop", operation(dragEnd), true);
375
+ }), true);
444
376
  draggingText = true;
445
- // IE's approach to draggable
446
- if (scroller.dragDrop) scroller.dragDrop();
447
377
  return;
448
378
  }
449
379
  e_preventDefault(e);
@@ -462,7 +392,12 @@ var CodeMirror = (function() {
462
392
  }
463
393
  }
464
394
 
465
- function done(e) {
395
+ var move = connect(targetDocument, "mousemove", operation(function(e) {
396
+ clearTimeout(going);
397
+ e_preventDefault(e);
398
+ extend(e);
399
+ }), true);
400
+ var up = connect(targetDocument, "mouseup", operation(function(e) {
466
401
  clearTimeout(going);
467
402
  var cur = posFromMouse(e);
468
403
  if (cur) setSelectionUser(start, cur);
@@ -470,14 +405,7 @@ var CodeMirror = (function() {
470
405
  focusInput();
471
406
  updateInput = true;
472
407
  move(); up();
473
- }
474
- var move = connect(document, "mousemove", operation(function(e) {
475
- clearTimeout(going);
476
- e_preventDefault(e);
477
- if (!ie && !e_button(e)) done(e);
478
- else extend(e);
479
408
  }), true);
480
- var up = connect(document, "mouseup", operation(done), true);
481
409
  }
482
410
  function onDoubleClick(e) {
483
411
  for (var n = e_target(e); n != wrapper; n = n.parentNode)
@@ -489,7 +417,6 @@ var CodeMirror = (function() {
489
417
  selectWordAt(start);
490
418
  }
491
419
  function onDrop(e) {
492
- if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return;
493
420
  e.preventDefault();
494
421
  var pos = posFromMouse(e, true), files = e.dataTransfer.files;
495
422
  if (!pos || options.readOnly) return;
@@ -499,124 +426,86 @@ var CodeMirror = (function() {
499
426
  reader.onload = function() {
500
427
  text[i] = reader.result;
501
428
  if (++read == n) {
502
- pos = clipPos(pos);
503
- operation(function() {
429
+ pos = clipPos(pos);
430
+ operation(function() {
504
431
  var end = replaceRange(text.join(""), pos, pos);
505
432
  setSelectionUser(pos, end);
506
433
  })();
507
- }
434
+ }
508
435
  };
509
436
  reader.readAsText(file);
510
437
  }
511
438
  var n = files.length, text = Array(n), read = 0;
512
439
  for (var i = 0; i < n; ++i) loadFile(files[i], i);
513
- } else {
514
- // Don't do a replace if the drop happened inside of the selected text.
515
- if (draggingText && !(posLess(pos, sel.from) || posLess(sel.to, pos))) return;
440
+ }
441
+ else {
516
442
  try {
517
443
  var text = e.dataTransfer.getData("Text");
518
444
  if (text) {
519
- compoundChange(function() {
520
- var curFrom = sel.from, curTo = sel.to;
521
- setSelectionUser(pos, pos);
522
- if (draggingText) replaceRange("", curFrom, curTo);
523
- replaceSelection(text);
524
- focusInput();
525
- });
526
- }
445
+ var curFrom = sel.from, curTo = sel.to;
446
+ setSelectionUser(pos, pos);
447
+ if (draggingText) replaceRange("", curFrom, curTo);
448
+ replaceSelection(text);
449
+ focusInput();
450
+ }
527
451
  }
528
452
  catch(e){}
529
453
  }
530
454
  }
531
455
  function onDragStart(e) {
532
456
  var txt = getSelection();
457
+ // This will reset escapeElement
458
+ htmlEscape(txt);
459
+ e.dataTransfer.setDragImage(escapeElement, 0, 0);
533
460
  e.dataTransfer.setData("Text", txt);
534
-
535
- // Use dummy image instead of default browsers image.
536
- if (gecko || chrome || opera) {
537
- var img = document.createElement('img');
538
- img.scr = 'data:image/gif;base64,R0lGODdhAgACAIAAAAAAAP///ywAAAAAAgACAAACAoRRADs='; //1x1 image
539
- e.dataTransfer.setDragImage(img, 0, 0);
540
- }
541
461
  }
542
-
543
- function doHandleBinding(bound, dropShift) {
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
+ }
544
480
  if (typeof bound == "string") {
545
- bound = commands[bound];
546
- if (!bound) return false;
481
+ if (commands.propertyIsEnumerable(bound)) bound = commands[bound];
482
+ else bound = null;
547
483
  }
484
+ if (next && (bound || !isModifierKey(e))) options.keyMap = handleNext();
485
+ if (!bound) return false;
548
486
  var prevShift = shiftSelecting;
549
487
  try {
550
488
  if (options.readOnly) suppressEdits = true;
551
489
  if (dropShift) shiftSelecting = null;
552
490
  bound(instance);
553
- } catch(e) {
554
- if (e != Pass) throw e;
555
- return false;
556
491
  } finally {
557
492
  shiftSelecting = prevShift;
558
493
  suppressEdits = false;
559
494
  }
495
+ e_preventDefault(e);
560
496
  return true;
561
497
  }
562
- function handleKeyBinding(e) {
563
- // Handle auto keymap transitions
564
- var startMap = getKeyMap(options.keyMap), next = startMap.auto;
565
- clearTimeout(maybeTransition);
566
- if (next && !isModifierKey(e)) maybeTransition = setTimeout(function() {
567
- if (getKeyMap(options.keyMap) == startMap) {
568
- options.keyMap = (next.call ? next.call(null, instance) : next);
569
- }
570
- }, 50);
571
-
572
- var name = keyNames[e_prop(e, "keyCode")], handled = false;
573
- if (name == null || e.altGraphKey) return false;
574
- if (e_prop(e, "altKey")) name = "Alt-" + name;
575
- if (e_prop(e, "ctrlKey")) name = "Ctrl-" + name;
576
- if (e_prop(e, "metaKey")) name = "Cmd-" + name;
577
-
578
- var stopped = false;
579
- function stop() { stopped = true; }
580
-
581
- if (e_prop(e, "shiftKey")) {
582
- handled = lookupKey("Shift-" + name, options.extraKeys, options.keyMap,
583
- function(b) {return doHandleBinding(b, true);}, stop)
584
- || lookupKey(name, options.extraKeys, options.keyMap, function(b) {
585
- if (typeof b == "string" && /^go[A-Z]/.test(b)) return doHandleBinding(b);
586
- }, stop);
587
- } else {
588
- handled = lookupKey(name, options.extraKeys, options.keyMap, doHandleBinding, stop);
589
- }
590
- if (stopped) handled = false;
591
- if (handled) {
592
- e_preventDefault(e);
593
- restartBlink();
594
- if (ie) { e.oldKeyCode = e.keyCode; e.keyCode = 0; }
595
- }
596
- return handled;
597
- }
598
- function handleCharBinding(e, ch) {
599
- var handled = lookupKey("'" + ch + "'", options.extraKeys,
600
- options.keyMap, function(b) { return doHandleBinding(b, true); });
601
- if (handled) {
602
- e_preventDefault(e);
603
- restartBlink();
604
- }
605
- return handled;
606
- }
607
-
608
- var lastStoppedKey = null, maybeTransition;
498
+ var lastStoppedKey = null;
609
499
  function onKeyDown(e) {
610
500
  if (!focused) onFocus();
611
501
  if (ie && e.keyCode == 27) { e.returnValue = false; }
612
- if (pollingFast) { if (readInput()) pollingFast = false; }
613
502
  if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
614
503
  var code = e_prop(e, "keyCode");
615
504
  // IE does strange things with escape.
616
505
  setShift(code == 16 || e_prop(e, "shiftKey"));
617
506
  // First give onKeyEvent option a chance to handle this.
618
507
  var handled = handleKeyBinding(e);
619
- if (opera) {
508
+ if (window.opera) {
620
509
  lastStoppedKey = handled ? code : null;
621
510
  // Opera has no cut event... we try to at least catch the key combo
622
511
  if (!handled && code == 88 && e_prop(e, mac ? "metaKey" : "ctrlKey"))
@@ -624,17 +513,15 @@ var CodeMirror = (function() {
624
513
  }
625
514
  }
626
515
  function onKeyPress(e) {
627
- if (pollingFast) readInput();
628
- if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
629
516
  var keyCode = e_prop(e, "keyCode"), charCode = e_prop(e, "charCode");
630
- if (opera && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
631
- if (((opera && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(e)) return;
632
- var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
517
+ if (window.opera && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
518
+ if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
519
+ if (window.opera && !e.which && handleKeyBinding(e)) return;
633
520
  if (options.electricChars && mode.electricChars && options.smartIndent && !options.readOnly) {
521
+ var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
634
522
  if (mode.electricChars.indexOf(ch) > -1)
635
523
  setTimeout(operation(function() {indentLine(sel.to.line, "smart");}), 75);
636
524
  }
637
- if (handleCharBinding(e, ch)) return;
638
525
  fastPoll();
639
526
  }
640
527
  function onKeyUp(e) {
@@ -647,8 +534,8 @@ var CodeMirror = (function() {
647
534
  if (!focused) {
648
535
  if (options.onFocus) options.onFocus(instance);
649
536
  focused = true;
650
- if (scroller.className.search(/\bCodeMirror-focused\b/) == -1)
651
- scroller.className += " CodeMirror-focused";
537
+ if (wrapper.className.search(/\bCodeMirror-focused\b/) == -1)
538
+ wrapper.className += " CodeMirror-focused";
652
539
  if (!leaveInputAlone) resetInput(true);
653
540
  }
654
541
  slowPoll();
@@ -662,48 +549,12 @@ var CodeMirror = (function() {
662
549
  operation(function(){
663
550
  if (bracketHighlighted) { bracketHighlighted(); bracketHighlighted = null; }
664
551
  })();
665
- scroller.className = scroller.className.replace(" CodeMirror-focused", "");
552
+ wrapper.className = wrapper.className.replace(" CodeMirror-focused", "");
666
553
  }
667
554
  clearInterval(blinker);
668
555
  setTimeout(function() {if (!focused) shiftSelecting = null;}, 150);
669
556
  }
670
557
 
671
- function chopDelta(delta) {
672
- // Make sure we always scroll a little bit for any nonzero delta.
673
- if (delta > 0.0 && delta < 1.0) return 1;
674
- else if (delta > -1.0 && delta < 0.0) return -1;
675
- else return Math.round(delta);
676
- }
677
-
678
- function onMouseWheel(e) {
679
- var deltaX = 0, deltaY = 0;
680
- if (e.type == "DOMMouseScroll") { // Firefox
681
- var delta = -e.detail * 8.0;
682
- if (e.axis == e.HORIZONTAL_AXIS) deltaX = delta;
683
- else if (e.axis == e.VERTICAL_AXIS) deltaY = delta;
684
- } else if (e.wheelDeltaX !== undefined && e.wheelDeltaY !== undefined) { // WebKit
685
- deltaX = e.wheelDeltaX / 3.0;
686
- deltaY = e.wheelDeltaY / 3.0;
687
- } else if (e.wheelDelta !== undefined) { // IE or Opera
688
- deltaY = e.wheelDelta / 3.0;
689
- }
690
-
691
- var scrolled = false;
692
- deltaX = chopDelta(deltaX);
693
- deltaY = chopDelta(deltaY);
694
- if ((deltaX > 0 && scroller.scrollLeft > 0) ||
695
- (deltaX < 0 && scroller.scrollLeft + scroller.clientWidth < scroller.scrollWidth)) {
696
- scroller.scrollLeft -= deltaX;
697
- scrolled = true;
698
- }
699
- if ((deltaY > 0 && scrollbar.scrollTop > 0) ||
700
- (deltaY < 0 && scrollbar.scrollTop + scrollbar.clientHeight < scrollbar.scrollHeight)) {
701
- scrollbar.scrollTop -= deltaY;
702
- scrolled = true;
703
- }
704
- if (scrolled) e_stop(e);
705
- }
706
-
707
558
  // Replace the range from from to to by the strings in newText.
708
559
  // Afterwards, set the selection to selFrom, selTo.
709
560
  function updateLines(from, to, newText, selFrom, selTo) {
@@ -716,30 +567,29 @@ var CodeMirror = (function() {
716
567
  }
717
568
  updateLinesNoUndo(from, to, newText, selFrom, selTo);
718
569
  }
719
- function unredoHelper(from, to) {
720
- if (!from.length) return;
721
- var set = from.pop(), out = [];
722
- for (var i = set.length - 1; i >= 0; i -= 1) {
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) {
723
573
  var change = set[i];
724
574
  var replaced = [], end = change.start + change.added;
725
575
  doc.iter(change.start, end, function(line) { replaced.push(line.text); });
726
576
  out.push({start: change.start, added: change.old.length, old: replaced});
727
- var pos = {line: change.start + change.old.length - 1,
728
- ch: editEnd(replaced[replaced.length-1], change.old[change.old.length-1])};
577
+ var pos = clipPos({line: change.start + change.old.length - 1,
578
+ ch: editEnd(replaced[replaced.length-1], change.old[change.old.length-1])});
729
579
  updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch: getLine(end-1).text.length}, change.old, pos, pos);
730
580
  }
731
581
  updateInput = true;
732
582
  to.push(out);
733
583
  }
734
- function undo() {unredoHelper(history.done, history.undone);}
735
- function redo() {unredoHelper(history.undone, history.done);}
584
+ function undo() {unredoHelper(history.done, history.undone, -1);}
585
+ function redo() {unredoHelper(history.undone, history.done, 1);}
736
586
 
737
587
  function updateLinesNoUndo(from, to, newText, selFrom, selTo) {
738
588
  if (suppressEdits) return;
739
589
  var recomputeMaxLength = false, maxLineLength = maxLine.length;
740
590
  if (!options.lineWrapping)
741
- doc.iter(from.line, to.line + 1, function(line) {
742
- if (!line.hidden && line.text.length == maxLineLength) {recomputeMaxLength = true; return true;}
591
+ doc.iter(from.line, to.line, function(line) {
592
+ if (line.text.length == maxLineLength) {recomputeMaxLength = true; return true;}
743
593
  });
744
594
  if (from.line != to.line || newText.length > 1) gutterDirty = true;
745
595
 
@@ -786,21 +636,29 @@ var CodeMirror = (function() {
786
636
  doc.insert(from.line + 1, added);
787
637
  }
788
638
  if (options.lineWrapping) {
789
- var perLine = Math.max(5, scroller.clientWidth / charWidth() - 3);
639
+ var perLine = scroller.clientWidth / charWidth() - 3;
790
640
  doc.iter(from.line, from.line + newText.length, function(line) {
791
641
  if (line.hidden) return;
792
642
  var guess = Math.ceil(line.text.length / perLine) || 1;
793
643
  if (guess != line.height) updateLineHeight(line, guess);
794
644
  });
795
645
  } else {
796
- doc.iter(from.line, from.line + newText.length, function(line) {
646
+ doc.iter(from.line, i + newText.length, function(line) {
797
647
  var l = line.text;
798
- if (!line.hidden && l.length > maxLineLength) {
799
- maxLine = l; maxLineLength = l.length; maxLineChanged = true;
648
+ if (l.length > maxLineLength) {
649
+ maxLine = l; maxLineLength = l.length; maxWidth = null;
800
650
  recomputeMaxLength = false;
801
651
  }
802
652
  });
803
- if (recomputeMaxLength) updateMaxLine = true;
653
+ if (recomputeMaxLength) {
654
+ maxLineLength = 0; maxLine = ""; maxWidth = null;
655
+ doc.iter(0, doc.size, function(line) {
656
+ var l = line.text;
657
+ if (l.length > maxLineLength) {
658
+ maxLineLength = l.length; maxLine = l;
659
+ }
660
+ });
661
+ }
804
662
  }
805
663
 
806
664
  // Add these lines to the work array, so that they will be
@@ -826,49 +684,11 @@ var CodeMirror = (function() {
826
684
 
827
685
  // Update the selection
828
686
  function updateLine(n) {return n <= Math.min(to.line, to.line + lendiff) ? n : n + lendiff;}
829
- setSelection(clipPos(selFrom), clipPos(selTo),
830
- updateLine(sel.from.line), updateLine(sel.to.line));
831
- }
687
+ setSelection(selFrom, selTo, updateLine(sel.from.line), updateLine(sel.to.line));
832
688
 
833
- function updateVerticalScroll(scrollTop) {
834
- var th = textHeight(), virtualHeight = Math.floor(doc.height * th + 2 * paddingTop()), scrollbarHeight = scroller.clientHeight;
835
- scrollbar.style.height = scrollbarHeight + "px";
689
+ // Make sure the scroll-size div has the correct height.
836
690
  if (scroller.clientHeight)
837
- scrollbarInner.style.height = virtualHeight + "px";
838
- // Position the mover div to align with the current virtual scroll position
839
- if (scrollTop != null) scrollbar.scrollTop = scrollTop;
840
- mover.style.top = (displayOffset * th - scrollbar.scrollTop) + "px";
841
- scrollbar.style.display = (virtualHeight > scrollbarHeight) ? "block" : "none";
842
- }
843
-
844
- // On Mac OS X Lion and up, detect whether the mouse is plugged in by measuring
845
- // the width of a div with a scrollbar in it. If the width is <= 1, then
846
- // the mouse isn't plugged in and scrollbars should overlap the content.
847
- function overlapScrollbars() {
848
- var tmpSb = document.createElement('div'),
849
- tmpSbInner = document.createElement('div');
850
- tmpSb.className = "CodeMirror-scrollbar";
851
- tmpSb.style.cssText = "position: absolute; left: -9999px; height: 100px;";
852
- tmpSbInner.className = "CodeMirror-scrollbar-inner";
853
- tmpSbInner.style.height = "200px";
854
- tmpSb.appendChild(tmpSbInner);
855
-
856
- document.body.appendChild(tmpSb);
857
- var result = (tmpSb.offsetWidth <= 1);
858
- document.body.removeChild(tmpSb);
859
- return result;
860
- }
861
-
862
- function computeMaxLength() {
863
- var maxLineLength = 0;
864
- maxLine = ""; maxLineChanged = true;
865
- doc.iter(0, doc.size, function(line) {
866
- var l = line.text;
867
- if (!line.hidden && l.length > maxLineLength) {
868
- maxLineLength = l.length; maxLine = l;
869
- }
870
- });
871
- updateMaxLine = false;
691
+ code.style.height = (doc.height * textHeight() + 2 * paddingTop()) + "px";
872
692
  }
873
693
 
874
694
  function replaceRange(code, from, to) {
@@ -957,15 +777,14 @@ var CodeMirror = (function() {
957
777
  else if (overwrite && posEq(sel.from, sel.to))
958
778
  sel.to = {line: sel.to.line, ch: Math.min(getLine(sel.to.line).text.length, sel.to.ch + (text.length - same))};
959
779
  replaceSelection(text.slice(same), "end");
960
- if (text.length > 1000) { input.value = prevInput = ""; }
961
- else prevInput = text;
780
+ prevInput = text;
962
781
  return true;
963
782
  }
964
783
  function resetInput(user) {
965
784
  if (!posEq(sel.from, sel.to)) {
966
785
  prevInput = "";
967
786
  input.value = getSelection();
968
- selectInput(input);
787
+ input.select();
969
788
  } else if (user) prevInput = input.value = "";
970
789
  }
971
790
 
@@ -979,67 +798,55 @@ var CodeMirror = (function() {
979
798
  // IE returns bogus coordinates when the instance sits inside of an iframe and the cursor is hidden
980
799
  if (ie && rect.top == rect.bottom) return;
981
800
  var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
982
- if (rect.top < 0 || rect.bottom > winH) scrollCursorIntoView();
801
+ if (rect.top < 0 || rect.bottom > winH) cursor.scrollIntoView();
983
802
  }
984
803
  function scrollCursorIntoView() {
985
- var coords = calculateCursorCoords();
986
- return scrollIntoView(coords.x, coords.y, coords.x, coords.yBot);
987
- }
988
- function calculateCursorCoords() {
989
804
  var cursor = localCoords(sel.inverted ? sel.from : sel.to);
990
805
  var x = options.lineWrapping ? Math.min(cursor.x, lineSpace.offsetWidth) : cursor.x;
991
- return {x: x, y: cursor.y, yBot: cursor.yBot};
806
+ return scrollIntoView(x, cursor.y, x, cursor.yBot);
992
807
  }
993
808
  function scrollIntoView(x1, y1, x2, y2) {
994
- var scrollPos = calculateScrollPos(x1, y1, x2, y2), scrolled = false;
995
- if (scrollPos.scrollLeft != null) {scroller.scrollLeft = scrollPos.scrollLeft; scrolled = true;}
996
- if (scrollPos.scrollTop != null) {scrollbar.scrollTop = scrollPos.scrollTop; scrolled = true;}
997
- if (scrolled && options.onScroll) options.onScroll(instance);
998
- }
999
- function calculateScrollPos(x1, y1, x2, y2) {
1000
- var pl = paddingLeft(), pt = paddingTop();
809
+ var pl = paddingLeft(), pt = paddingTop(), lh = textHeight();
1001
810
  y1 += pt; y2 += pt; x1 += pl; x2 += pl;
1002
- var screen = scroller.clientHeight, screentop = scrollbar.scrollTop, result = {};
1003
- var atTop = y1 < paddingTop() + 10;
1004
- if (y1 < screentop) result.scrollTop = atTop ? 0 : Math.max(0, y1);
1005
- else if (y2 > screentop + screen) result.scrollTop = y2 - screen;
811
+ var screen = scroller.clientHeight, screentop = scroller.scrollTop, scrolled = false, result = true;
812
+ if (y1 < screentop) {scroller.scrollTop = Math.max(0, y1 - 2*lh); scrolled = true;}
813
+ else if (y2 > screentop + screen) {scroller.scrollTop = y2 + lh - screen; scrolled = true;}
1006
814
 
1007
815
  var screenw = scroller.clientWidth, screenleft = scroller.scrollLeft;
1008
816
  var gutterw = options.fixedGutter ? gutter.clientWidth : 0;
1009
- var atLeft = x1 < gutterw + pl + 10;
1010
- if (x1 < screenleft + gutterw || atLeft) {
1011
- if (atLeft) x1 = 0;
1012
- result.scrollLeft = Math.max(0, x1 - 10 - gutterw);
1013
- } else if (x2 > screenw + screenleft - 3) {
1014
- result.scrollLeft = x2 + 10 - screenw;
817
+ if (x1 < screenleft + gutterw) {
818
+ if (x1 < 50) x1 = 0;
819
+ scroller.scrollLeft = Math.max(0, x1 - 10 - gutterw);
820
+ scrolled = true;
1015
821
  }
822
+ else if (x2 > screenw + screenleft - 3) {
823
+ scroller.scrollLeft = x2 + 10 - screenw;
824
+ scrolled = true;
825
+ if (x2 > code.clientWidth) result = false;
826
+ }
827
+ if (scrolled && options.onScroll) options.onScroll(instance);
1016
828
  return result;
1017
829
  }
1018
830
 
1019
- function visibleLines(scrollTop) {
1020
- var lh = textHeight(), top = (scrollTop != null ? scrollTop : scrollbar.scrollTop) - paddingTop();
1021
- var fromHeight = Math.max(0, Math.floor(top / lh));
1022
- var toHeight = Math.ceil((top + scroller.clientHeight) / lh);
1023
- return {from: lineAtHeight(doc, fromHeight),
1024
- to: lineAtHeight(doc, toHeight)};
831
+ function visibleLines() {
832
+ var lh = textHeight(), top = scroller.scrollTop - paddingTop();
833
+ var from_height = Math.max(0, Math.floor(top / lh));
834
+ var to_height = Math.ceil((top + scroller.clientHeight) / lh);
835
+ return {from: lineAtHeight(doc, from_height),
836
+ to: lineAtHeight(doc, to_height)};
1025
837
  }
1026
838
  // Uses a set of changes plus the current scroll position to
1027
839
  // determine which DOM updates have to be made, and makes the
1028
840
  // updates.
1029
- function updateDisplay(changes, suppressCallback, scrollTop) {
841
+ function updateDisplay(changes, suppressCallback) {
1030
842
  if (!scroller.clientWidth) {
1031
843
  showingFrom = showingTo = displayOffset = 0;
1032
844
  return;
1033
845
  }
1034
846
  // Compute the new visible window
1035
- // If scrollTop is specified, use that to determine which lines
1036
- // to render instead of the current scrollbar position.
1037
- var visible = visibleLines(scrollTop);
847
+ var visible = visibleLines();
1038
848
  // Bail out if the visible area is already rendered and nothing changed.
1039
- if (changes !== true && changes.length == 0 && visible.from > showingFrom && visible.to < showingTo) {
1040
- updateVerticalScroll(scrollTop);
1041
- return;
1042
- }
849
+ if (changes !== true && changes.length == 0 && visible.from > showingFrom && visible.to < showingTo) return;
1043
850
  var from = Math.max(visible.from - 100, 0), to = Math.min(doc.size, visible.to + 100);
1044
851
  if (showingFrom < from && from - showingFrom < 20) from = showingFrom;
1045
852
  if (showingTo > to && showingTo - to < 20) to = Math.min(doc.size, showingTo);
@@ -1057,10 +864,7 @@ var CodeMirror = (function() {
1057
864
  if (range.from >= range.to) intact.splice(i--, 1);
1058
865
  else intactLines += range.to - range.from;
1059
866
  }
1060
- if (intactLines == to - from && from == showingFrom && to == showingTo) {
1061
- updateVerticalScroll(scrollTop);
1062
- return;
1063
- }
867
+ if (intactLines == to - from) return;
1064
868
  intact.sort(function(a, b) {return a.domStart - b.domStart;});
1065
869
 
1066
870
  var th = textHeight(), gutterDisplay = gutter.style.display;
@@ -1068,12 +872,17 @@ var CodeMirror = (function() {
1068
872
  patchDisplay(from, to, intact);
1069
873
  lineDiv.style.display = gutter.style.display = "";
1070
874
 
875
+ // Position the mover div to align with the lines it's supposed
876
+ // to be showing (which will cover the visible display)
1071
877
  var different = from != showingFrom || to != showingTo || lastSizeC != scroller.clientHeight + th;
1072
878
  // This is just a bogus formula that detects when the editor is
1073
879
  // resized or the font size changes.
1074
880
  if (different) lastSizeC = scroller.clientHeight + th;
1075
881
  showingFrom = from; showingTo = to;
1076
882
  displayOffset = heightAtLine(doc, from);
883
+ mover.style.top = (displayOffset * th) + "px";
884
+ if (scroller.clientHeight)
885
+ code.style.height = (doc.height * th + 2 * paddingTop()) + "px";
1077
886
 
1078
887
  // Since this is all rather error prone, it is honoured with the
1079
888
  // only assertion in the whole file.
@@ -1081,7 +890,8 @@ var CodeMirror = (function() {
1081
890
  throw new Error("BAD PATCH! " + JSON.stringify(intact) + " size=" + (showingTo - showingFrom) +
1082
891
  " nodes=" + lineDiv.childNodes.length);
1083
892
 
1084
- function checkHeights() {
893
+ if (options.lineWrapping) {
894
+ maxWidth = scroller.clientWidth;
1085
895
  var curNode = lineDiv.firstChild, heightChanged = false;
1086
896
  doc.iter(showingFrom, showingTo, function(line) {
1087
897
  if (!line.hidden) {
@@ -1093,26 +903,22 @@ var CodeMirror = (function() {
1093
903
  }
1094
904
  curNode = curNode.nextSibling;
1095
905
  });
1096
- return heightChanged;
1097
- }
1098
-
1099
- if (options.lineWrapping) {
1100
- // Guess whether we're going to need the scrollbar, so that we don't end up changing the linewrapping
1101
- // after the scrollbar appears (during updateVerticalScroll()). Only do this if the scrollbar is
1102
- // appearing (if it's disappearing, we don't have to worry about the scroll position, and there are
1103
- // issues on IE7 if we turn it off too early).
1104
- var virtualHeight = Math.floor(doc.height * th + 2 * paddingTop()), scrollbarHeight = scroller.clientHeight;
1105
- if (virtualHeight > scrollbarHeight) scrollbar.style.display = "block";
1106
- checkHeights();
906
+ if (heightChanged)
907
+ code.style.height = (doc.height * th + 2 * paddingTop()) + "px";
908
+ } else {
909
+ if (maxWidth == null) maxWidth = stringWidth(maxLine);
910
+ if (maxWidth > scroller.clientWidth) {
911
+ lineSpace.style.width = maxWidth + "px";
912
+ // Needed to prevent odd wrapping/hiding of widgets placed in here.
913
+ code.style.width = "";
914
+ code.style.width = scroller.scrollWidth + "px";
915
+ } else {
916
+ lineSpace.style.width = code.style.width = "";
917
+ }
1107
918
  }
1108
-
1109
919
  gutter.style.display = gutterDisplay;
1110
- if (different || gutterDirty) {
1111
- // If the gutter grew in size, re-check heights. If those changed, re-draw gutter.
1112
- updateGutter() && options.lineWrapping && checkHeights() && updateGutter();
1113
- }
920
+ if (different || gutterDirty) updateGutter();
1114
921
  updateSelection();
1115
- updateVerticalScroll(scrollTop);
1116
922
  if (!suppressCallback && options.onUpdate) options.onUpdate(instance);
1117
923
  return true;
1118
924
  }
@@ -1159,17 +965,16 @@ var CodeMirror = (function() {
1159
965
  }
1160
966
  // This pass fills in the lines that actually changed.
1161
967
  var nextIntact = intact.shift(), curNode = lineDiv.firstChild, j = from;
1162
- var scratch = document.createElement("div");
968
+ var scratch = targetDocument.createElement("div"), newElt;
1163
969
  doc.iter(from, to, function(line) {
1164
970
  if (nextIntact && nextIntact.to == j) nextIntact = intact.shift();
1165
971
  if (!nextIntact || nextIntact.from > j) {
1166
972
  if (line.hidden) var html = scratch.innerHTML = "<pre></pre>";
1167
973
  else {
1168
- var html = '<pre' + (line.className ? ' class="' + line.className + '"' : '') + '>'
1169
- + line.getHTML(makeTab) + '</pre>';
974
+ var html = '<pre>' + line.getHTML(tabText) + '</pre>';
1170
975
  // Kludge to make sure the styled element lies behind the selection (by z-index)
1171
- if (line.bgClassName)
1172
- html = '<div style="position: relative"><pre class="' + line.bgClassName +
976
+ if (line.className)
977
+ html = '<div style="position: relative"><pre class="' + line.className +
1173
978
  '" style="position: absolute; left: 0; right: 0; top: 0; bottom: 0; z-index: -2">&#160;</pre>' + html + "</div>";
1174
979
  }
1175
980
  scratch.innerHTML = html;
@@ -1185,7 +990,7 @@ var CodeMirror = (function() {
1185
990
  if (!options.gutter && !options.lineNumbers) return;
1186
991
  var hText = mover.offsetHeight, hEditor = scroller.clientHeight;
1187
992
  gutter.style.height = (hText - hEditor < 2 ? hEditor : hText) + "px";
1188
- var html = [], i = showingFrom, normalNode;
993
+ var html = [], i = showingFrom;
1189
994
  doc.iter(showingFrom, Math.max(showingTo, showingFrom + 1), function(line) {
1190
995
  if (line.hidden) {
1191
996
  html.push("<pre></pre>");
@@ -1199,24 +1004,17 @@ var CodeMirror = (function() {
1199
1004
  html.push((marker && marker.style ? '<pre class="' + marker.style + '">' : "<pre>"), text);
1200
1005
  for (var j = 1; j < line.height; ++j) html.push("<br/>&#160;");
1201
1006
  html.push("</pre>");
1202
- if (!marker) normalNode = i;
1203
1007
  }
1204
1008
  ++i;
1205
1009
  });
1206
1010
  gutter.style.display = "none";
1207
1011
  gutterText.innerHTML = html.join("");
1208
- // Make sure scrolling doesn't cause number gutter size to pop
1209
- if (normalNode != null && options.lineNumbers) {
1210
- var node = gutterText.childNodes[normalNode - showingFrom];
1211
- var minwidth = String(doc.size).length, val = eltText(node.firstChild), pad = "";
1212
- while (val.length + pad.length < minwidth) pad += "\u00a0";
1213
- if (pad) node.insertBefore(document.createTextNode(pad), node.firstChild);
1214
- }
1012
+ var minwidth = String(doc.size).length, firstNode = gutterText.firstChild, val = eltText(firstNode), pad = "";
1013
+ while (val.length + pad.length < minwidth) pad += "\u00a0";
1014
+ if (pad) firstNode.insertBefore(targetDocument.createTextNode(pad), firstNode.firstChild);
1215
1015
  gutter.style.display = "";
1216
- var resized = Math.abs((parseInt(lineSpace.style.marginLeft) || 0) - gutter.offsetWidth) > 2;
1217
1016
  lineSpace.style.marginLeft = gutter.offsetWidth + "px";
1218
1017
  gutterDirty = false;
1219
- return resized;
1220
1018
  }
1221
1019
  function updateSelection() {
1222
1020
  var collapsed = posEq(sel.from, sel.to);
@@ -1233,24 +1031,20 @@ var CodeMirror = (function() {
1233
1031
  selectionDiv.style.display = "none";
1234
1032
  } else {
1235
1033
  var sameLine = fromPos.y == toPos.y, html = "";
1236
- var clientWidth = lineSpace.clientWidth || lineSpace.offsetWidth;
1237
- var clientHeight = lineSpace.clientHeight || lineSpace.offsetHeight;
1238
1034
  function add(left, top, right, height) {
1239
- var rstyle = quirksMode ? "width: " + (!right ? clientWidth : clientWidth - right - left) + "px"
1240
- : "right: " + right + "px";
1241
1035
  html += '<div class="CodeMirror-selected" style="position: absolute; left: ' + left +
1242
- 'px; top: ' + top + 'px; ' + rstyle + '; height: ' + height + 'px"></div>';
1036
+ 'px; top: ' + top + 'px; right: ' + right + 'px; height: ' + height + 'px"></div>';
1243
1037
  }
1244
1038
  if (sel.from.ch && fromPos.y >= 0) {
1245
- var right = sameLine ? clientWidth - toPos.x : 0;
1039
+ var right = sameLine ? lineSpace.clientWidth - toPos.x : 0;
1246
1040
  add(fromPos.x, fromPos.y, right, th);
1247
1041
  }
1248
1042
  var middleStart = Math.max(0, fromPos.y + (sel.from.ch ? th : 0));
1249
- var middleHeight = Math.min(toPos.y, clientHeight) - middleStart;
1043
+ var middleHeight = Math.min(toPos.y, lineSpace.clientHeight) - middleStart;
1250
1044
  if (middleHeight > 0.2 * th)
1251
1045
  add(0, middleStart, 0, middleHeight);
1252
- if ((!sameLine || !sel.from.ch) && toPos.y < clientHeight - .5 * th)
1253
- add(0, toPos.y, clientWidth - toPos.x, th);
1046
+ if ((!sameLine || !sel.from.ch) && toPos.y < lineSpace.clientHeight - .5 * th)
1047
+ add(0, toPos.y, lineSpace.clientWidth - toPos.x, th);
1254
1048
  selectionDiv.innerHTML = html;
1255
1049
  cursor.style.display = "none";
1256
1050
  selectionDiv.style.display = "";
@@ -1280,32 +1074,13 @@ var CodeMirror = (function() {
1280
1074
  if (posLess(to, from)) {var tmp = to; to = from; from = tmp;}
1281
1075
 
1282
1076
  // Skip over hidden lines.
1283
- if (from.line != oldFrom) {
1284
- var from1 = skipHidden(from, oldFrom, sel.from.ch);
1285
- // If there is no non-hidden line left, force visibility on current line
1286
- if (!from1) setLineHidden(from.line, false);
1287
- else from = from1;
1288
- }
1077
+ if (from.line != oldFrom) from = skipHidden(from, oldFrom, sel.from.ch);
1289
1078
  if (to.line != oldTo) to = skipHidden(to, oldTo, sel.to.ch);
1290
1079
 
1291
1080
  if (posEq(from, to)) sel.inverted = false;
1292
1081
  else if (posEq(from, sel.to)) sel.inverted = false;
1293
1082
  else if (posEq(to, sel.from)) sel.inverted = true;
1294
1083
 
1295
- if (options.autoClearEmptyLines && posEq(sel.from, sel.to)) {
1296
- var head = sel.inverted ? from : to;
1297
- if (head.line != sel.from.line && sel.from.line < doc.size) {
1298
- var oldLine = getLine(sel.from.line);
1299
- if (/^\s+$/.test(oldLine.text))
1300
- setTimeout(operation(function() {
1301
- if (oldLine.parent && /^\s+$/.test(oldLine.text)) {
1302
- var no = lineNo(oldLine);
1303
- replaceRange("", {line: no, ch: 0}, {line: no, ch: oldLine.text.length});
1304
- }
1305
- }, 10));
1306
- }
1307
- }
1308
-
1309
1084
  sel.from = from; sel.to = to;
1310
1085
  selectionChanged = true;
1311
1086
  }
@@ -1316,14 +1091,13 @@ var CodeMirror = (function() {
1316
1091
  var line = getLine(lNo);
1317
1092
  if (!line.hidden) {
1318
1093
  var ch = pos.ch;
1319
- if (toEnd || ch > oldCh || ch > line.text.length) ch = line.text.length;
1094
+ if (ch > oldCh || ch > line.text.length) ch = line.text.length;
1320
1095
  return {line: lNo, ch: ch};
1321
1096
  }
1322
1097
  lNo += dir;
1323
1098
  }
1324
1099
  }
1325
1100
  var line = getLine(pos.line);
1326
- var toEnd = pos.ch == line.text.length && pos.ch != oldCh;
1327
1101
  if (!line.hidden) return pos;
1328
1102
  if (pos.line >= oldLine) return getNonHidden(1) || getNonHidden(-1);
1329
1103
  else return getNonHidden(-1) || getNonHidden(1);
@@ -1390,7 +1164,6 @@ var CodeMirror = (function() {
1390
1164
  if (unit == "page") dist = Math.min(scroller.clientHeight, window.innerHeight || document.documentElement.clientHeight);
1391
1165
  else if (unit == "line") dist = textHeight();
1392
1166
  var target = coordsChar(pos.x, pos.y + dist * dir + 2);
1393
- if (unit == "page") scrollbar.scrollTop += localCoords(target, true).y - pos.y;
1394
1167
  setCursor(target.line, target.ch, true);
1395
1168
  goalColumn = pos.x;
1396
1169
  }
@@ -1403,7 +1176,7 @@ var CodeMirror = (function() {
1403
1176
  setSelectionUser({line: pos.line, ch: start}, {line: pos.line, ch: end});
1404
1177
  }
1405
1178
  function selectLine(line) {
1406
- setSelectionUser({line: line, ch: 0}, clipPos({line: line + 1, ch: 0}));
1179
+ setSelectionUser({line: line, ch: 0}, {line: line, ch: getLine(line).text.length});
1407
1180
  }
1408
1181
  function indentSelected(mode) {
1409
1182
  if (posEq(sel.from, sel.to)) return indentLine(sel.from.line, mode);
@@ -1420,14 +1193,11 @@ var CodeMirror = (function() {
1420
1193
 
1421
1194
  var line = getLine(n), curSpace = line.indentation(options.tabSize),
1422
1195
  curSpaceString = line.text.match(/^\s*/)[0], indentation;
1423
- if (how == "smart") {
1424
- indentation = mode.indent(state, line.text.slice(curSpaceString.length), line.text);
1425
- if (indentation == Pass) how = "prev";
1426
- }
1427
1196
  if (how == "prev") {
1428
1197
  if (n) indentation = getLine(n-1).indentation(options.tabSize);
1429
1198
  else indentation = 0;
1430
1199
  }
1200
+ else if (how == "smart") indentation = mode.indent(state, line.text.slice(curSpaceString.length), line.text);
1431
1201
  else if (how == "add") indentation = curSpace + options.indentUnit;
1432
1202
  else if (how == "subtract") indentation = curSpace - options.indentUnit;
1433
1203
  indentation = Math.max(0, indentation);
@@ -1436,7 +1206,8 @@ var CodeMirror = (function() {
1436
1206
  if (!diff) {
1437
1207
  if (sel.from.line != n && sel.to.line != n) return;
1438
1208
  var indentString = curSpaceString;
1439
- } else {
1209
+ }
1210
+ else {
1440
1211
  var indentString = "", pos = 0;
1441
1212
  if (options.indentWithTabs)
1442
1213
  for (var i = Math.floor(indentation / options.tabSize); i; --i) {pos += options.tabSize; indentString += "\t";}
@@ -1468,10 +1239,9 @@ var CodeMirror = (function() {
1468
1239
  if (guess != 1) updateLineHeight(line, guess);
1469
1240
  });
1470
1241
  lineSpace.style.width = code.style.width = "";
1471
- widthForcer.style.left = "";
1472
1242
  } else {
1473
1243
  wrapper.className = wrapper.className.replace(" CodeMirror-wrap", "");
1474
- maxLine = ""; maxLineChanged = true;
1244
+ maxWidth = null; maxLine = "";
1475
1245
  doc.iter(0, doc.size, function(line) {
1476
1246
  if (line.height != 1 && !line.hidden) updateLineHeight(line, 1);
1477
1247
  if (line.text.length > maxLine.length) maxLine = line.text;
@@ -1479,21 +1249,18 @@ var CodeMirror = (function() {
1479
1249
  }
1480
1250
  changes.push({from: 0, to: doc.size});
1481
1251
  }
1482
- function makeTab(col) {
1483
- var w = options.tabSize - col % options.tabSize, cached = tabCache[w];
1484
- if (cached) return cached;
1485
- for (var str = '<span class="cm-tab">', i = 0; i < w; ++i) str += " ";
1486
- return (tabCache[w] = {html: str + "</span>", width: w});
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);
1487
1259
  }
1488
1260
  function themeChanged() {
1489
- scroller.className = scroller.className.replace(/\s*cm-s-\S+/g, "") +
1261
+ scroller.className = scroller.className.replace(/\s*cm-s-\w+/g, "") +
1490
1262
  options.theme.replace(/(^|\s)\s*/g, " cm-s-");
1491
1263
  }
1492
- function keyMapChanged() {
1493
- var style = keyMap[options.keyMap].style;
1494
- wrapper.className = wrapper.className.replace(/\s*cm-keymap-\S+/g, "") +
1495
- (style ? " cm-keymap-" + style : "");
1496
- }
1497
1264
 
1498
1265
  function TextMarker() { this.set = []; }
1499
1266
  TextMarker.prototype.clear = operation(function() {
@@ -1504,7 +1271,7 @@ var CodeMirror = (function() {
1504
1271
  var lineN = lineNo(line);
1505
1272
  min = Math.min(min, lineN); max = Math.max(max, lineN);
1506
1273
  for (var j = 0; j < mk.length; ++j)
1507
- if (mk[j].marker == this) mk.splice(j--, 1);
1274
+ if (mk[j].set == this.set) mk.splice(j--, 1);
1508
1275
  }
1509
1276
  if (min != Infinity)
1510
1277
  changes.push({from: min, to: max + 1});
@@ -1515,7 +1282,7 @@ var CodeMirror = (function() {
1515
1282
  var line = this.set[i], mk = line.marked;
1516
1283
  for (var j = 0; j < mk.length; ++j) {
1517
1284
  var mark = mk[j];
1518
- if (mark.marker == this) {
1285
+ if (mark.set == this.set) {
1519
1286
  if (mark.from != null || mark.to != null) {
1520
1287
  var found = lineNo(line);
1521
1288
  if (found != null) {
@@ -1532,9 +1299,8 @@ var CodeMirror = (function() {
1532
1299
  function markText(from, to, className) {
1533
1300
  from = clipPos(from); to = clipPos(to);
1534
1301
  var tm = new TextMarker();
1535
- if (!posLess(from, to)) return tm;
1536
1302
  function add(line, from, to, className) {
1537
- getLine(line).addMark(new MarkedText(from, to, className, tm));
1303
+ getLine(line).addMark(new MarkedText(from, to, className, tm.set));
1538
1304
  }
1539
1305
  if (from.line == to.line) add(from.line, from.ch, to.ch, className);
1540
1306
  else {
@@ -1554,19 +1320,6 @@ var CodeMirror = (function() {
1554
1320
  return bm;
1555
1321
  }
1556
1322
 
1557
- function findMarksAt(pos) {
1558
- pos = clipPos(pos);
1559
- var markers = [], marked = getLine(pos.line).marked;
1560
- if (!marked) return markers;
1561
- for (var i = 0, e = marked.length; i < e; ++i) {
1562
- var m = marked[i];
1563
- if ((m.from == null || m.from <= pos.ch) &&
1564
- (m.to == null || m.to >= pos.ch))
1565
- markers.push(m.marker || m);
1566
- }
1567
- return markers;
1568
- }
1569
-
1570
1323
  function addGutterMarker(line, text, className) {
1571
1324
  if (typeof line == "number") line = getLine(clipLine(line));
1572
1325
  line.gutterMarker = {text: text, style: className};
@@ -1588,11 +1341,10 @@ var CodeMirror = (function() {
1588
1341
  else return null;
1589
1342
  return line;
1590
1343
  }
1591
- function setLineClass(handle, className, bgClassName) {
1344
+ function setLineClass(handle, className) {
1592
1345
  return changeLine(handle, function(line) {
1593
- if (line.className != className || line.bgClassName != bgClassName) {
1346
+ if (line.className != className) {
1594
1347
  line.className = className;
1595
- line.bgClassName = bgClassName;
1596
1348
  return true;
1597
1349
  }
1598
1350
  });
@@ -1601,21 +1353,11 @@ var CodeMirror = (function() {
1601
1353
  return changeLine(handle, function(line, no) {
1602
1354
  if (line.hidden != hidden) {
1603
1355
  line.hidden = hidden;
1604
- if (!options.lineWrapping) {
1605
- var l = line.text;
1606
- if (hidden && l.length == maxLine.length) {
1607
- updateMaxLine = true;
1608
- } else if (!hidden && l.length > maxLine.length) {
1609
- maxLine = l; maxWidth = null; updateMaxLine = false;
1610
- }
1611
- }
1612
1356
  updateLineHeight(line, hidden ? 0 : 1);
1613
1357
  var fline = sel.from.line, tline = sel.to.line;
1614
1358
  if (hidden && (fline == no || tline == no)) {
1615
1359
  var from = fline == no ? skipHidden({line: fline, ch: 0}, fline, 0) : sel.from;
1616
1360
  var to = tline == no ? skipHidden({line: tline, ch: 0}, tline, 0) : sel.to;
1617
- // Can't hide the last visible line, we'd have no place to put the cursor
1618
- if (!to) return;
1619
1361
  setSelection(from, to);
1620
1362
  }
1621
1363
  return (gutterDirty = true);
@@ -1629,13 +1371,14 @@ var CodeMirror = (function() {
1629
1371
  var n = line;
1630
1372
  line = getLine(line);
1631
1373
  if (!line) return null;
1632
- } else {
1374
+ }
1375
+ else {
1633
1376
  var n = lineNo(line);
1634
1377
  if (n == null) return null;
1635
1378
  }
1636
1379
  var marker = line.gutterMarker;
1637
1380
  return {line: n, handle: line, text: line.text, markerText: marker && marker.text,
1638
- markerClass: marker && marker.style, lineClass: line.className, bgClass: line.bgClassName};
1381
+ markerClass: marker && marker.style, lineClass: line.className};
1639
1382
  }
1640
1383
 
1641
1384
  function stringWidth(str) {
@@ -1649,7 +1392,8 @@ var CodeMirror = (function() {
1649
1392
  if (x <= 0) return 0;
1650
1393
  var lineObj = getLine(line), text = lineObj.text;
1651
1394
  function getX(len) {
1652
- return measureLine(lineObj, len).left;
1395
+ measure.innerHTML = "<pre><span>" + lineObj.getHTML(tabText, len) + "</span></pre>";
1396
+ return measure.firstChild.firstChild.offsetWidth;
1653
1397
  }
1654
1398
  var from = 0, fromX = 0, to = text.length, toX;
1655
1399
  // Guess a suitable upper bound for our search.
@@ -1672,13 +1416,19 @@ var CodeMirror = (function() {
1672
1416
  }
1673
1417
  }
1674
1418
 
1675
- var tempId = "CodeMirror-temp-" + Math.floor(Math.random() * 0xffffff).toString(16);
1419
+ var tempId = Math.floor(Math.random() * 0xffffff).toString(16);
1676
1420
  function measureLine(line, ch) {
1677
1421
  if (ch == 0) return {top: 0, left: 0};
1678
- var wbr = options.lineWrapping && ch < line.text.length &&
1679
- spanAffectsWrapping.test(line.text.slice(ch - 1, ch + 1));
1680
- measure.innerHTML = "<pre>" + line.getHTML(makeTab, ch, tempId, wbr) + "</pre>";
1681
- var elt = document.getElementById(tempId);
1422
+ var extra = "";
1423
+ // Include extra text at the end to make sure the measured line is wrapped in the right way.
1424
+ if (options.lineWrapping) {
1425
+ var end = line.text.indexOf(" ", ch + 2);
1426
+ extra = htmlEscape(line.text.slice(ch + 1, end < 0 ? line.text.length : end + (ie ? 5 : 0)));
1427
+ }
1428
+ measure.innerHTML = "<pre>" + line.getHTML(tabText, ch) +
1429
+ '<span id="CodeMirror-temp-' + tempId + '">' + htmlEscape(line.text.charAt(ch) || " ") + "</span>" +
1430
+ extra + "</pre>";
1431
+ var elt = document.getElementById("CodeMirror-temp-" + tempId);
1682
1432
  var top = elt.offsetTop, left = elt.offsetLeft;
1683
1433
  // Older IEs report zero offsets for spans directly after a wrap
1684
1434
  if (ie && top == 0 && left == 0) {
@@ -1778,8 +1528,8 @@ var CodeMirror = (function() {
1778
1528
  return coordsChar(x - offL.left, y - offL.top);
1779
1529
  }
1780
1530
  function onContextMenu(e) {
1781
- var pos = posFromMouse(e), scrollPos = scrollbar.scrollTop;
1782
- if (!pos || opera) return; // Opera is difficult.
1531
+ var pos = posFromMouse(e);
1532
+ if (!pos || window.opera) return; // Opera is difficult.
1783
1533
  if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to))
1784
1534
  operation(setCursor)(pos.line, pos.ch);
1785
1535
 
@@ -1791,13 +1541,12 @@ var CodeMirror = (function() {
1791
1541
  leaveInputAlone = true;
1792
1542
  var val = input.value = getSelection();
1793
1543
  focusInput();
1794
- selectInput(input);
1544
+ input.select();
1795
1545
  function rehide() {
1796
1546
  var newVal = splitLines(input.value).join("\n");
1797
- if (newVal != val && !options.readOnly) operation(replaceSelection)(newVal, "end");
1547
+ if (newVal != val) operation(replaceSelection)(newVal, "end");
1798
1548
  inputDiv.style.position = "relative";
1799
1549
  input.style.cssText = oldCSS;
1800
- if (ie_lt9) scrollbar.scrollTop = scrollPos;
1801
1550
  leaveInputAlone = false;
1802
1551
  resetInput(true);
1803
1552
  slowPoll();
@@ -1809,7 +1558,8 @@ var CodeMirror = (function() {
1809
1558
  mouseup();
1810
1559
  setTimeout(rehide, 20);
1811
1560
  }, true);
1812
- } else {
1561
+ }
1562
+ else {
1813
1563
  setTimeout(rehide, 50);
1814
1564
  }
1815
1565
  }
@@ -1839,7 +1589,7 @@ var CodeMirror = (function() {
1839
1589
  var st = line.styles, pos = forward ? 0 : line.text.length - 1, cur;
1840
1590
  for (var i = forward ? 0 : st.length - 2, e = forward ? st.length : -2; i != e; i += 2*d) {
1841
1591
  var text = st[i];
1842
- if (st[i+1] != style) {pos += d * text.length; continue;}
1592
+ if (st[i+1] != null && st[i+1] != style) {pos += d * text.length; continue;}
1843
1593
  for (var j = forward ? 0 : text.length - 1, te = forward ? text.length : -1; j != te; j += d, pos+=d) {
1844
1594
  if (pos >= from && pos < to && re.test(cur = text.charAt(j))) {
1845
1595
  var match = matching[cur];
@@ -1926,17 +1676,13 @@ var CodeMirror = (function() {
1926
1676
  var changed = line.highlight(mode, state, options.tabSize);
1927
1677
  if (changed) realChange = true;
1928
1678
  line.stateAfter = copyState(mode, state);
1929
- var done = null;
1930
1679
  if (compare) {
1931
- var same = hadState && compare(hadState, state);
1932
- if (same != Pass) done = !!same;
1933
- }
1934
- if (done == null) {
1680
+ if (hadState && compare(hadState, state)) return true;
1681
+ } else {
1935
1682
  if (changed !== false || !hadState) unchanged = 0;
1936
1683
  else if (++unchanged > 3 && (!mode.indent || mode.indent(hadState, "") == mode.indent(state, "")))
1937
- done = true;
1684
+ return true;
1938
1685
  }
1939
- if (done) return true;
1940
1686
  ++i;
1941
1687
  });
1942
1688
  if (bail) return;
@@ -1959,22 +1705,14 @@ var CodeMirror = (function() {
1959
1705
  changes = []; selectionChanged = false; callbacks = [];
1960
1706
  }
1961
1707
  function endOperation() {
1962
- if (updateMaxLine) computeMaxLength();
1963
- if (maxLineChanged && !options.lineWrapping) {
1964
- widthForcer.style.left = stringWidth(maxLine) + "px";
1965
- maxLineChanged = false;
1966
- }
1967
- var newScrollPos, updated;
1968
- if (selectionChanged) {
1969
- var coords = calculateCursorCoords();
1970
- newScrollPos = calculateScrollPos(coords.x, coords.y, coords.x, coords.yBot);
1971
- }
1972
- if (changes.length) updated = updateDisplay(changes, true, (newScrollPos ? newScrollPos.scrollTop : null));
1708
+ var reScroll = false, updated;
1709
+ if (selectionChanged) reScroll = !scrollCursorIntoView();
1710
+ if (changes.length) updated = updateDisplay(changes, true);
1973
1711
  else {
1974
1712
  if (selectionChanged) updateSelection();
1975
1713
  if (gutterDirty) updateGutter();
1976
1714
  }
1977
- if (newScrollPos) scrollCursorIntoView();
1715
+ if (reScroll) scrollCursorIntoView();
1978
1716
  if (selectionChanged) {scrollEditorIntoView(); restartBlink();}
1979
1717
 
1980
1718
  if (focused && !leaveInputAlone &&
@@ -1986,11 +1724,11 @@ var CodeMirror = (function() {
1986
1724
  if (bracketHighlighted) {bracketHighlighted(); bracketHighlighted = null;}
1987
1725
  if (posEq(sel.from, sel.to)) matchBrackets(false);
1988
1726
  }), 20);
1989
- var sc = selectionChanged, cbs = callbacks; // these can be reset by callbacks
1990
- if (textChanged && options.onChange && instance)
1991
- options.onChange(instance, textChanged);
1992
- if (sc && options.onCursorActivity)
1727
+ var tc = textChanged, cbs = callbacks; // these can be reset by callbacks
1728
+ if (selectionChanged && options.onCursorActivity)
1993
1729
  options.onCursorActivity(instance);
1730
+ if (tc && options.onChange && instance)
1731
+ options.onChange(instance, tc);
1994
1732
  for (var i = 0; i < cbs.length; ++i) cbs[i](instance);
1995
1733
  if (updated && options.onUpdate) options.onUpdate(instance);
1996
1734
  }
@@ -2004,11 +1742,6 @@ var CodeMirror = (function() {
2004
1742
  };
2005
1743
  }
2006
1744
 
2007
- function compoundChange(f) {
2008
- history.startCompound();
2009
- try { return f(); } finally { history.endCompound(); }
2010
- }
2011
-
2012
1745
  for (var ext in extensions)
2013
1746
  if (extensions.propertyIsEnumerable(ext) &&
2014
1747
  !instance.propertyIsEnumerable(ext))
@@ -2028,16 +1761,13 @@ var CodeMirror = (function() {
2028
1761
  keyMap: "default",
2029
1762
  extraKeys: null,
2030
1763
  electricChars: true,
2031
- autoClearEmptyLines: false,
2032
1764
  onKeyEvent: null,
2033
- onDragEvent: null,
2034
1765
  lineWrapping: false,
2035
1766
  lineNumbers: false,
2036
1767
  gutter: false,
2037
1768
  fixedGutter: false,
2038
1769
  firstLineNumber: 1,
2039
1770
  readOnly: false,
2040
- dragDrop: true,
2041
1771
  onChange: null,
2042
1772
  onCursorActivity: null,
2043
1773
  onGutterClick: null,
@@ -2050,7 +1780,7 @@ var CodeMirror = (function() {
2050
1780
  pollInterval: 100,
2051
1781
  undoDepth: 40,
2052
1782
  tabindex: null,
2053
- autofocus: null
1783
+ document: window.document
2054
1784
  };
2055
1785
 
2056
1786
  var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
@@ -2058,31 +1788,27 @@ var CodeMirror = (function() {
2058
1788
  var win = /Win/.test(navigator.platform);
2059
1789
 
2060
1790
  // Known modes, by name and by MIME
2061
- var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
1791
+ var modes = {}, mimeModes = {};
2062
1792
  CodeMirror.defineMode = function(name, mode) {
2063
1793
  if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
2064
- if (arguments.length > 2) {
2065
- mode.dependencies = [];
2066
- for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]);
2067
- }
2068
1794
  modes[name] = mode;
2069
1795
  };
2070
1796
  CodeMirror.defineMIME = function(mime, spec) {
2071
1797
  mimeModes[mime] = spec;
2072
1798
  };
2073
- CodeMirror.resolveMode = function(spec) {
1799
+ CodeMirror.getMode = function(options, spec) {
2074
1800
  if (typeof spec == "string" && mimeModes.hasOwnProperty(spec))
2075
1801
  spec = mimeModes[spec];
2076
- else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec))
2077
- return CodeMirror.resolveMode("application/xml");
2078
- if (typeof spec == "string") return {name: spec};
2079
- else return spec || {name: "null"};
2080
- };
2081
- CodeMirror.getMode = function(options, spec) {
2082
- var spec = CodeMirror.resolveMode(spec);
2083
- var mfactory = modes[spec.name];
2084
- if (!mfactory) return CodeMirror.getMode(options, "text/plain");
2085
- return mfactory(options, 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];
1807
+ if (!mfactory) {
1808
+ if (window.console) console.warn("No mode " + mname + " found, falling back to plain text.");
1809
+ return CodeMirror.getMode(options, "text/plain");
1810
+ }
1811
+ return mfactory(options, config || {});
2086
1812
  };
2087
1813
  CodeMirror.listModes = function() {
2088
1814
  var list = [];
@@ -2139,10 +1865,6 @@ var CodeMirror = (function() {
2139
1865
  indentMore: function(cm) {cm.indentSelection("add");},
2140
1866
  indentLess: function(cm) {cm.indentSelection("subtract");},
2141
1867
  insertTab: function(cm) {cm.replaceSelection("\t", "end");},
2142
- defaultTab: function(cm) {
2143
- if (cm.somethingSelected()) cm.indentSelection("add");
2144
- else cm.replaceSelection("\t", "end");
2145
- },
2146
1868
  transposeChars: function(cm) {
2147
1869
  var cur = cm.getCursor(), line = cm.getLine(cur.line);
2148
1870
  if (cur.ch > 0 && cur.ch < line.length - 1)
@@ -2160,7 +1882,7 @@ var CodeMirror = (function() {
2160
1882
  keyMap.basic = {
2161
1883
  "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
2162
1884
  "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
2163
- "Delete": "delCharRight", "Backspace": "delCharLeft", "Tab": "defaultTab", "Shift-Tab": "indentAuto",
1885
+ "Delete": "delCharRight", "Backspace": "delCharLeft", "Tab": "indentMore", "Shift-Tab": "indentLess",
2164
1886
  "Enter": "newlineAndIndent", "Insert": "toggleOverwrite"
2165
1887
  };
2166
1888
  // Note that the save and find-related commands aren't defined by
@@ -2171,7 +1893,6 @@ var CodeMirror = (function() {
2171
1893
  "Ctrl-Left": "goWordLeft", "Ctrl-Right": "goWordRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
2172
1894
  "Ctrl-Backspace": "delWordLeft", "Ctrl-Delete": "delWordRight", "Ctrl-S": "save", "Ctrl-F": "find",
2173
1895
  "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
2174
- "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
2175
1896
  fallthrough: "basic"
2176
1897
  };
2177
1898
  keyMap.macDefault = {
@@ -2180,7 +1901,6 @@ var CodeMirror = (function() {
2180
1901
  "Alt-Right": "goWordRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delWordLeft",
2181
1902
  "Ctrl-Alt-Backspace": "delWordRight", "Alt-Delete": "delWordRight", "Cmd-S": "save", "Cmd-F": "find",
2182
1903
  "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
2183
- "Cmd-[": "indentLess", "Cmd-]": "indentMore",
2184
1904
  fallthrough: ["basic", "emacsy"]
2185
1905
  };
2186
1906
  keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
@@ -2191,30 +1911,20 @@ var CodeMirror = (function() {
2191
1911
  "Alt-D": "delWordRight", "Alt-Backspace": "delWordLeft", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
2192
1912
  };
2193
1913
 
2194
- function getKeyMap(val) {
2195
- if (typeof val == "string") return keyMap[val];
2196
- else return val;
2197
- }
2198
- function lookupKey(name, extraMap, map, handle, stop) {
2199
- function lookup(map) {
2200
- map = getKeyMap(map);
1914
+ function lookupKey(name, extraMap, map) {
1915
+ function lookup(name, map, ft) {
2201
1916
  var found = map[name];
2202
- if (found != null && handle(found)) return true;
2203
- if (map.nofallthrough) {
2204
- if (stop) stop();
2205
- return true;
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;
2206
1924
  }
2207
- var fallthrough = map.fallthrough;
2208
- if (fallthrough == null) return false;
2209
- if (Object.prototype.toString.call(fallthrough) != "[object Array]")
2210
- return lookup(fallthrough);
2211
- for (var i = 0, e = fallthrough.length; i < e; ++i) {
2212
- if (lookup(fallthrough[i])) return true;
2213
- }
2214
- return false;
1925
+ return null;
2215
1926
  }
2216
- if (extraMap && lookup(extraMap)) return true;
2217
- return lookup(map);
1927
+ return extraMap ? lookup(name, extraMap, map) : lookup(name, keyMap[map]);
2218
1928
  }
2219
1929
  function isModifierKey(event) {
2220
1930
  var name = keyNames[e_prop(event, "keyCode")];
@@ -2226,8 +1936,6 @@ var CodeMirror = (function() {
2226
1936
  options.value = textarea.value;
2227
1937
  if (!options.tabindex && textarea.tabindex)
2228
1938
  options.tabindex = textarea.tabindex;
2229
- if (options.autofocus == null && textarea.getAttribute("autofocus") != null)
2230
- options.autofocus = true;
2231
1939
 
2232
1940
  function save() {textarea.value = instance.getValue();}
2233
1941
  if (textarea.form) {
@@ -2328,7 +2036,8 @@ var CodeMirror = (function() {
2328
2036
  if (consume !== false) this.pos += pattern.length;
2329
2037
  return true;
2330
2038
  }
2331
- } else {
2039
+ }
2040
+ else {
2332
2041
  var match = this.string.slice(this.pos).match(pattern);
2333
2042
  if (match && consume !== false) this.pos += match[0].length;
2334
2043
  return match;
@@ -2338,34 +2047,34 @@ var CodeMirror = (function() {
2338
2047
  };
2339
2048
  CodeMirror.StringStream = StringStream;
2340
2049
 
2341
- function MarkedText(from, to, className, marker) {
2342
- this.from = from; this.to = to; this.style = className; this.marker = marker;
2050
+ function MarkedText(from, to, className, set) {
2051
+ this.from = from; this.to = to; this.style = className; this.set = set;
2343
2052
  }
2344
2053
  MarkedText.prototype = {
2345
- attach: function(line) { this.marker.set.push(line); },
2054
+ attach: function(line) { this.set.push(line); },
2346
2055
  detach: function(line) {
2347
- var ix = indexOf(this.marker.set, line);
2348
- if (ix > -1) this.marker.set.splice(ix, 1);
2056
+ var ix = indexOf(this.set, line);
2057
+ if (ix > -1) this.set.splice(ix, 1);
2349
2058
  },
2350
2059
  split: function(pos, lenBefore) {
2351
2060
  if (this.to <= pos && this.to != null) return null;
2352
2061
  var from = this.from < pos || this.from == null ? null : this.from - pos + lenBefore;
2353
2062
  var to = this.to == null ? null : this.to - pos + lenBefore;
2354
- return new MarkedText(from, to, this.style, this.marker);
2063
+ return new MarkedText(from, to, this.style, this.set);
2355
2064
  },
2356
- dup: function() { return new MarkedText(null, null, this.style, this.marker); },
2065
+ dup: function() { return new MarkedText(null, null, this.style, this.set); },
2357
2066
  clipTo: function(fromOpen, from, toOpen, to, diff) {
2067
+ if (this.from != null && this.from >= from)
2068
+ this.from = Math.max(to, this.from) + diff;
2069
+ if (this.to != null && this.to > from)
2070
+ this.to = to < this.to ? this.to + diff : from;
2358
2071
  if (fromOpen && to > this.from && (to < this.to || this.to == null))
2359
2072
  this.from = null;
2360
- else if (this.from != null && this.from >= from)
2361
- this.from = Math.max(to, this.from) + diff;
2362
2073
  if (toOpen && (from < this.to || this.to == null) && (from > this.from || this.from == null))
2363
2074
  this.to = null;
2364
- else if (this.to != null && this.to > from)
2365
- this.to = to < this.to ? this.to + diff : from;
2366
2075
  },
2367
2076
  isDead: function() { return this.from != null && this.to != null && this.from >= this.to; },
2368
- sameSet: function(x) { return this.marker == x.marker; }
2077
+ sameSet: function(x) { return this.set == x.set; }
2369
2078
  };
2370
2079
 
2371
2080
  function Bookmark(pos) {
@@ -2408,7 +2117,7 @@ var CodeMirror = (function() {
2408
2117
  this.styles = styles || [text, null];
2409
2118
  this.text = text;
2410
2119
  this.height = 1;
2411
- this.marked = this.gutterMarker = this.className = this.bgClassName = this.handlers = null;
2120
+ this.marked = this.gutterMarker = this.className = this.handlers = null;
2412
2121
  this.stateAfter = this.parent = this.hidden = null;
2413
2122
  }
2414
2123
  Line.inheritMarks = function(text, orig) {
@@ -2454,7 +2163,6 @@ var CodeMirror = (function() {
2454
2163
  if (newmark) {
2455
2164
  if (!taken.marked) taken.marked = [];
2456
2165
  taken.marked.push(newmark); newmark.attach(taken);
2457
- if (newmark == mark) mk.splice(i--, 1);
2458
2166
  }
2459
2167
  }
2460
2168
  }
@@ -2564,82 +2272,34 @@ var CodeMirror = (function() {
2564
2272
  indentation: function(tabSize) {return countColumn(this.text, null, tabSize);},
2565
2273
  // Produces an HTML fragment for the line, taking selection,
2566
2274
  // marking, and highlighting into account.
2567
- getHTML: function(makeTab, wrapAt, wrapId, wrapWBR) {
2568
- var html = [], first = true, col = 0;
2569
- function span_(text, style) {
2275
+ getHTML: function(tabText, endAt) {
2276
+ var html = [], first = true;
2277
+ function span(text, style) {
2570
2278
  if (!text) return;
2571
2279
  // Work around a bug where, in some compat modes, IE ignores leading spaces
2572
2280
  if (first && ie && text.charAt(0) == " ") text = "\u00a0" + text.slice(1);
2573
2281
  first = false;
2574
- if (text.indexOf("\t") == -1) {
2575
- col += text.length;
2576
- var escaped = htmlEscape(text);
2577
- } else {
2578
- var escaped = "";
2579
- for (var pos = 0;;) {
2580
- var idx = text.indexOf("\t", pos);
2581
- if (idx == -1) {
2582
- escaped += htmlEscape(text.slice(pos));
2583
- col += text.length - pos;
2584
- break;
2585
- } else {
2586
- col += idx - pos;
2587
- var tab = makeTab(col);
2588
- escaped += htmlEscape(text.slice(pos, idx)) + tab.html;
2589
- col += tab.width;
2590
- pos = idx + 1;
2591
- }
2592
- }
2593
- }
2594
- if (style) html.push('<span class="', style, '">', escaped, "</span>");
2595
- else html.push(escaped);
2596
- }
2597
- var span = span_;
2598
- if (wrapAt != null) {
2599
- var outPos = 0, open = "<span id=\"" + wrapId + "\">";
2600
- span = function(text, style) {
2601
- var l = text.length;
2602
- if (wrapAt >= outPos && wrapAt < outPos + l) {
2603
- if (wrapAt > outPos) {
2604
- span_(text.slice(0, wrapAt - outPos), style);
2605
- // See comment at the definition of spanAffectsWrapping
2606
- if (wrapWBR) html.push("<wbr>");
2607
- }
2608
- html.push(open);
2609
- var cut = wrapAt - outPos;
2610
- span_(opera ? text.slice(cut, cut + 1) : text.slice(cut), style);
2611
- html.push("</span>");
2612
- if (opera) span_(text.slice(cut + 1), style);
2613
- wrapAt--;
2614
- outPos += l;
2615
- } else {
2616
- outPos += l;
2617
- span_(text, style);
2618
- // Output empty wrapper when at end of line
2619
- if (outPos == wrapAt && outPos == len) html.push(open + " </span>");
2620
- // Stop outputting HTML when gone sufficiently far beyond measure
2621
- else if (outPos > wrapAt + 10 && /\s/.test(text)) span = function(){};
2622
- }
2623
- }
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));
2624
2284
  }
2625
-
2626
2285
  var st = this.styles, allText = this.text, marked = this.marked;
2627
2286
  var len = allText.length;
2287
+ if (endAt != null) len = Math.min(endAt, len);
2628
2288
  function styleToClass(style) {
2629
2289
  if (!style) return null;
2630
2290
  return "cm-" + style.replace(/ +/g, " cm-");
2631
2291
  }
2632
2292
 
2633
- if (!allText && wrapAt == null) {
2293
+ if (!allText && endAt == null)
2634
2294
  span(" ");
2635
- } else if (!marked || !marked.length) {
2295
+ else if (!marked || !marked.length)
2636
2296
  for (var i = 0, ch = 0; ch < len; i+=2) {
2637
2297
  var str = st[i], style = st[i+1], l = str.length;
2638
2298
  if (ch + l > len) str = str.slice(0, len - ch);
2639
2299
  ch += l;
2640
2300
  span(str, styleToClass(style));
2641
2301
  }
2642
- } else {
2302
+ else {
2643
2303
  var pos = 0, i = 0, text = "", style, sg = 0;
2644
2304
  var nextChange = marked[0].from || 0, marks = [], markpos = 0;
2645
2305
  function advanceMarks() {
@@ -2689,7 +2349,8 @@ var CodeMirror = (function() {
2689
2349
  if (state == 0) {
2690
2350
  if (end > from) dest.push(part.slice(from - pos, Math.min(part.length, to - pos)), source[i+1]);
2691
2351
  if (end >= from) state = 1;
2692
- } else if (state == 1) {
2352
+ }
2353
+ else if (state == 1) {
2693
2354
  if (end > to) dest.push(part.slice(0, to - pos), source[i+1]);
2694
2355
  else dest.push(part, source[i+1]);
2695
2356
  }
@@ -2724,7 +2385,7 @@ var CodeMirror = (function() {
2724
2385
  },
2725
2386
  insertHeight: function(at, lines, height) {
2726
2387
  this.height += height;
2727
- this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
2388
+ this.lines.splice.apply(this.lines, [at, 0].concat(lines));
2728
2389
  for (var i = 0, e = lines.length; i < e; ++i) lines[i].parent = this;
2729
2390
  },
2730
2391
  iterN: function(at, n, op) {
@@ -2890,36 +2551,33 @@ var CodeMirror = (function() {
2890
2551
  function History() {
2891
2552
  this.time = 0;
2892
2553
  this.done = []; this.undone = [];
2893
- this.compound = 0;
2894
- this.closed = false;
2895
2554
  }
2896
2555
  History.prototype = {
2897
2556
  addChange: function(start, added, old) {
2898
2557
  this.undone.length = 0;
2899
2558
  var time = +new Date, cur = this.done[this.done.length - 1], last = cur && cur[cur.length - 1];
2900
2559
  var dtime = time - this.time;
2901
-
2902
- if (this.compound && cur && !this.closed) {
2903
- cur.push({start: start, added: added, old: old});
2904
- } else if (dtime > 400 || !last || this.closed ||
2905
- last.start > start + old.length || last.start + last.added < start) {
2560
+ if (dtime > 400 || !last) {
2906
2561
  this.done.push([{start: start, added: added, old: old}]);
2907
- this.closed = false;
2562
+ } else if (last.start > start + added || last.start + last.added < start - last.added + last.old.length) {
2563
+ cur.push({start: start, added: added, old: old});
2908
2564
  } else {
2909
- var startBefore = Math.max(0, last.start - start),
2910
- endAfter = Math.max(0, (start + old.length) - (last.start + last.added));
2911
- for (var i = startBefore; i > 0; --i) last.old.unshift(old[i - 1]);
2912
- for (var i = endAfter; i > 0; --i) last.old.push(old[old.length - i]);
2913
- if (startBefore) last.start = start;
2914
- last.added += added - (old.length - startBefore - endAfter);
2565
+ var oldoff = 0;
2566
+ if (start < last.start) {
2567
+ for (var i = last.start - start - 1; i >= 0; --i)
2568
+ last.old.unshift(old[i]);
2569
+ last.added += last.start - start;
2570
+ last.start = start;
2571
+ }
2572
+ else if (last.start < start) {
2573
+ oldoff = start - last.start;
2574
+ added += oldoff;
2575
+ }
2576
+ for (var i = last.added - oldoff, e = old.length; i < e; ++i)
2577
+ last.old.push(old[i]);
2578
+ if (last.added < added) last.added = added;
2915
2579
  }
2916
2580
  this.time = time;
2917
- },
2918
- startCompound: function() {
2919
- if (!this.compound++) this.closed = true;
2920
- },
2921
- endCompound: function() {
2922
- if (!--this.compound) this.closed = true;
2923
2581
  }
2924
2582
  };
2925
2583
 
@@ -2964,7 +2622,8 @@ var CodeMirror = (function() {
2964
2622
  if (typeof node.addEventListener == "function") {
2965
2623
  node.addEventListener(type, handler, false);
2966
2624
  if (disconnect) return function() {node.removeEventListener(type, handler, false);};
2967
- } else {
2625
+ }
2626
+ else {
2968
2627
  var wrapHandler = function(event) {handler(event || window.event);};
2969
2628
  node.attachEvent("on" + type, wrapHandler);
2970
2629
  if (disconnect) return function() {node.detachEvent("on" + type, wrapHandler);};
@@ -2975,48 +2634,26 @@ var CodeMirror = (function() {
2975
2634
  function Delayed() {this.id = null;}
2976
2635
  Delayed.prototype = {set: function(ms, f) {clearTimeout(this.id); this.id = setTimeout(f, ms);}};
2977
2636
 
2978
- var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}};
2979
-
2980
- var gecko = /gecko\/\d{7}/i.test(navigator.userAgent);
2981
- var ie = /MSIE \d/.test(navigator.userAgent);
2982
- var ie_lt8 = /MSIE [1-7]\b/.test(navigator.userAgent);
2983
- var ie_lt9 = /MSIE [1-8]\b/.test(navigator.userAgent);
2984
- var quirksMode = ie && document.documentMode == 5;
2985
- var webkit = /WebKit\//.test(navigator.userAgent);
2986
- var chrome = /Chrome\//.test(navigator.userAgent);
2987
- var opera = /Opera\//.test(navigator.userAgent);
2988
- var safari = /Apple Computer/.test(navigator.vendor);
2989
- var khtml = /KHTML\//.test(navigator.userAgent);
2990
- var mac_geLion = /Mac OS X 10\D([7-9]|\d\d)\D/.test(navigator.userAgent);
2991
-
2992
2637
  // Detect drag-and-drop
2993
2638
  var dragAndDrop = function() {
2994
- // There is *some* kind of drag-and-drop support in IE6-8, but I
2995
- // couldn't get it to work yet.
2996
- if (ie_lt9) return false;
2639
+ // IE8 has ondragstart and ondrop properties, but doesn't seem to
2640
+ // actually support ondragstart the way it's supposed to work.
2641
+ if (/MSIE [1-8]\b/.test(navigator.userAgent)) return false;
2997
2642
  var div = document.createElement('div');
2998
- return "draggable" in div || "dragDrop" in div;
2643
+ return "draggable" in div;
2999
2644
  }();
3000
2645
 
2646
+ var gecko = /gecko\/\d{7}/i.test(navigator.userAgent);
2647
+ var ie = /MSIE \d/.test(navigator.userAgent);
2648
+ var webkit = /WebKit\//.test(navigator.userAgent);
2649
+
2650
+ var lineSep = "\n";
3001
2651
  // Feature-detect whether newlines in textareas are converted to \r\n
3002
- var lineSep = function () {
2652
+ (function () {
3003
2653
  var te = document.createElement("textarea");
3004
2654
  te.value = "foo\nbar";
3005
- if (te.value.indexOf("\r") > -1) return "\r\n";
3006
- return "\n";
3007
- }();
3008
-
3009
- // For a reason I have yet to figure out, some browsers disallow
3010
- // word wrapping between certain characters *only* if a new inline
3011
- // element is started between them. This makes it hard to reliably
3012
- // measure the position of things, since that requires inserting an
3013
- // extra span. This terribly fragile set of regexps matches the
3014
- // character combinations that suffer from this phenomenon on the
3015
- // various browsers.
3016
- var spanAffectsWrapping = /^$/; // Won't match any two-character string
3017
- if (gecko) spanAffectsWrapping = /$'/;
3018
- else if (safari) spanAffectsWrapping = /\-[^ \-?]|\?[^ !'\"\),.\-\/:;\?\]\}]/;
3019
- else if (chrome) spanAffectsWrapping = /\-[^ \-\.?]|\?[^ \-\.?\]\}:;!'\"\),\/]|[\.!\"#&%\)*+,:;=>\]|\}~][\(\{\[<]|\$'/;
2655
+ if (te.value.indexOf("\r") > -1) lineSep = "\r\n";
2656
+ }());
3020
2657
 
3021
2658
  // Counts the column offset in a string, taking tabs into account.
3022
2659
  // Used mostly to find indentation.
@@ -3097,19 +2734,18 @@ var CodeMirror = (function() {
3097
2734
  }
3098
2735
  // Recent (late 2011) Opera betas insert bogus newlines at the start
3099
2736
  // of the textContent, so we strip those.
3100
- if (htmlEscape("a") == "\na") {
2737
+ if (htmlEscape("a") == "\na")
3101
2738
  htmlEscape = function(str) {
3102
2739
  escapeElement.textContent = str;
3103
2740
  return escapeElement.innerHTML.slice(1);
3104
2741
  };
3105
2742
  // Some IEs don't preserve tabs through innerHTML
3106
- } else if (htmlEscape("\t") != "\t") {
2743
+ else if (htmlEscape("\t") != "\t")
3107
2744
  htmlEscape = function(str) {
3108
2745
  escapeElement.innerHTML = "";
3109
2746
  escapeElement.appendChild(document.createTextNode(str));
3110
2747
  return escapeElement.innerHTML;
3111
2748
  };
3112
- }
3113
2749
  CodeMirror.htmlEscape = htmlEscape;
3114
2750
 
3115
2751
  // Used to position the cursor after an undo/redo by finding the
@@ -3163,10 +2799,10 @@ var CodeMirror = (function() {
3163
2799
  var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
3164
2800
  19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
3165
2801
  36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
3166
- 46: "Delete", 59: ";", 91: "Mod", 92: "Mod", 93: "Mod", 109: "-", 107: "=", 127: "Delete",
3167
- 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
3168
- 221: "]", 222: "'", 63276: "PageUp", 63277: "PageDown", 63275: "End", 63273: "Home",
3169
- 63234: "Left", 63232: "Up", 63235: "Right", 63233: "Down", 63302: "Insert", 63272: "Delete"};
2802
+ 46: "Delete", 59: ";", 91: "Mod", 92: "Mod", 93: "Mod", 186: ";", 187: "=", 188: ",",
2803
+ 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", 221: "]", 222: "'", 63276: "PageUp",
2804
+ 63277: "PageDown", 63275: "End", 63273: "Home", 63234: "Left", 63232: "Up", 63235: "Right",
2805
+ 63233: "Down", 63302: "Insert", 63272: "Delete"};
3170
2806
  CodeMirror.keyNames = keyNames;
3171
2807
  (function() {
3172
2808
  // Number keys