codemirror-rails 4.8 → 4.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +24 -6
  3. data/lib/codemirror/rails/version.rb +2 -2
  4. data/vendor/assets/javascripts/codemirror.js +289 -184
  5. data/vendor/assets/javascripts/codemirror/addons/dialog/dialog.js +1 -1
  6. data/vendor/assets/javascripts/codemirror/addons/display/panel.js +94 -0
  7. data/vendor/assets/javascripts/codemirror/addons/edit/continuelist.js +4 -4
  8. data/vendor/assets/javascripts/codemirror/addons/hint/anyword-hint.js +1 -2
  9. data/vendor/assets/javascripts/codemirror/addons/hint/css-hint.js +1 -1
  10. data/vendor/assets/javascripts/codemirror/addons/hint/html-hint.js +1 -1
  11. data/vendor/assets/javascripts/codemirror/addons/hint/javascript-hint.js +8 -3
  12. data/vendor/assets/javascripts/codemirror/addons/hint/show-hint.js +1 -1
  13. data/vendor/assets/javascripts/codemirror/addons/hint/sql-hint.js +7 -4
  14. data/vendor/assets/javascripts/codemirror/addons/hint/xml-hint.js +3 -4
  15. data/vendor/assets/javascripts/codemirror/addons/merge/merge.js +170 -63
  16. data/vendor/assets/javascripts/codemirror/addons/mode/simple.js +11 -8
  17. data/vendor/assets/javascripts/codemirror/addons/scroll/annotatescrollbar.js +76 -0
  18. data/vendor/assets/javascripts/codemirror/addons/scroll/simplescrollbars.js +139 -0
  19. data/vendor/assets/javascripts/codemirror/addons/search/matchesonscrollbar.js +90 -0
  20. data/vendor/assets/javascripts/codemirror/addons/search/search.js +9 -4
  21. data/vendor/assets/javascripts/codemirror/addons/tern/tern.js +5 -3
  22. data/vendor/assets/javascripts/codemirror/keymaps/emacs.js +25 -7
  23. data/vendor/assets/javascripts/codemirror/keymaps/vim.js +181 -109
  24. data/vendor/assets/javascripts/codemirror/modes/coffeescript.js +2 -2
  25. data/vendor/assets/javascripts/codemirror/modes/commonlisp.js +5 -3
  26. data/vendor/assets/javascripts/codemirror/modes/cypher.js +1 -1
  27. data/vendor/assets/javascripts/codemirror/modes/dart.js +50 -0
  28. data/vendor/assets/javascripts/codemirror/modes/dockerfile.js +5 -9
  29. data/vendor/assets/javascripts/codemirror/modes/ebnf.js +195 -0
  30. data/vendor/assets/javascripts/codemirror/modes/javascript.js +2 -0
  31. data/vendor/assets/javascripts/codemirror/modes/markdown.js +3 -3
  32. data/vendor/assets/javascripts/codemirror/modes/puppet.js +2 -2
  33. data/vendor/assets/javascripts/codemirror/modes/shell.js +2 -1
  34. data/vendor/assets/javascripts/codemirror/modes/soy.js +198 -0
  35. data/vendor/assets/javascripts/codemirror/modes/spreadsheet.js +109 -0
  36. data/vendor/assets/javascripts/codemirror/modes/stex.js +4 -6
  37. data/vendor/assets/javascripts/codemirror/modes/textile.js +392 -476
  38. data/vendor/assets/javascripts/codemirror/modes/turtle.js +3 -1
  39. data/vendor/assets/stylesheets/codemirror.css +2 -11
  40. data/vendor/assets/stylesheets/codemirror/addons/merge/merge.css +14 -0
  41. data/vendor/assets/stylesheets/codemirror/addons/scroll/simplescrollbars.css +66 -0
  42. data/vendor/assets/stylesheets/codemirror/addons/search/matchesonscrollbar.css +8 -0
  43. data/vendor/assets/stylesheets/codemirror/themes/tomorrow-night-bright.css +35 -0
  44. data/vendor/assets/stylesheets/codemirror/themes/zenburn.css +37 -0
  45. metadata +14 -3
  46. data/vendor/assets/javascripts/codemirror/addons/hint/python-hint.js +0 -102
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0d7ed536cdd6c54bf26a2267fc6cf13ed09e4624
4
- data.tar.gz: 62813e43c76250a3ff56dc69e5d4123a1d42217f
3
+ metadata.gz: 284033712dc0b2bfb8a7dfacbf9978310a1a9da2
4
+ data.tar.gz: 9e39f05137ce738d972d9d52f557671d0449d9a7
5
5
  SHA512:
6
- metadata.gz: 3317a5d5a1f262e96ee51ce496be3108871e07f081140d3c35636beba654d2dc665a10004384f6cb49a7d6feca12a5aea7c634675cb905819226d32ed8798b79
7
- data.tar.gz: f48c7e94303a13be7f6ef197dc5346ed5c113c829fcf9b8be8e858511b989c641bf7957082514f86df44e32140d8ee5c296118ff2e29f6703b6ce886f8ca608c
6
+ metadata.gz: b786c5741f9fa9638104a273b5b5b1c3c7791add1ff0b0f9720e5d9e50a05e733d06bbb2e9d1addcbf2f609240c7b2ccdc96cdcc28a854b2edaa15a631ce080e
7
+ data.tar.gz: 54801430f624d1651b225da319fcd972d7cf699f9954521ec735ad71690cc00f0b0fc5eb3578d090abb5d8799988f988bd2558c5157e2e3ea3ecaf1ddd03b9a2
data/README.md CHANGED
@@ -21,12 +21,20 @@ gem install codemirror-rails
21
21
 
22
22
  All of the assets from the most latest stable CodeMirror release are vendored
23
23
  so that you can use them with the asset pipeline. At a minimum, you will
24
- probably want the following in your application.js and application.css:
24
+ probably want the following in your application.js:
25
25
 
26
26
  ```js
27
27
  //= require codemirror
28
28
  ```
29
29
 
30
+ And in your application.css:
31
+
32
+ ```css
33
+ /*
34
+ *= require codemirror
35
+ */
36
+ ```
37
+
30
38
  ### Adding a mode
31
39
 
32
40
  Additional syntax modes can be added to your application.js:
@@ -35,12 +43,20 @@ Additional syntax modes can be added to your application.js:
35
43
  //= require codemirror/modes/ruby
36
44
  ```
37
45
 
38
- ### Adding a util
46
+ ### Adding an addon
39
47
 
40
- Additional reusable util components can be added in your application.js:
48
+ Additional addons can be added in your application.js:
41
49
 
42
50
  ```js
43
- //= require codemirror/utils/dialog
51
+ //= require_tree codemirror/addons/dialog
52
+ ```
53
+
54
+ And your application.css:
55
+
56
+ ```css
57
+ /*
58
+ *= require_tree codemirror/addons/dialog
59
+ */
44
60
  ```
45
61
 
46
62
  ### Adding a keymap
@@ -55,8 +71,10 @@ Additional keymap bindings can be added to your application.js:
55
71
 
56
72
  Additional CSS themes can be added to your application.css
57
73
 
58
- ```js
59
- //= require codemirror/themes/night
74
+ ```css
75
+ /*
76
+ *= require codemirror/themes/night
77
+ */
60
78
  ```
61
79
 
62
80
  ### Precompiling Codemirror
@@ -1,6 +1,6 @@
1
1
  module Codemirror
2
2
  module Rails
3
- VERSION = '4.8'
4
- CODEMIRROR_VERSION = '4.8'
3
+ VERSION = '4.9'
4
+ CODEMIRROR_VERSION = '4.9'
5
5
  end
6
6
  end
@@ -77,6 +77,7 @@
77
77
  if (options.lineWrapping)
78
78
  this.display.wrapper.className += " CodeMirror-wrap";
79
79
  if (options.autofocus && !mobile) focusInput(this);
80
+ initScrollbars(this);
80
81
 
81
82
  this.state = {
82
83
  keyMaps: [], // stores maps added by addKeyMap
@@ -137,14 +138,13 @@
137
138
 
138
139
  // Wraps and hides input textarea
139
140
  d.inputDiv = elt("div", [input], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
140
- // The fake scrollbar elements.
141
- d.scrollbarH = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
142
- d.scrollbarV = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar");
143
141
  // Covers bottom-right square when both scrollbars are present.
144
142
  d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
143
+ d.scrollbarFiller.setAttribute("not-content", "true");
145
144
  // Covers bottom of gutter when coverGutterNextToScrollbar is on
146
145
  // and h scrollbar is present.
147
146
  d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
147
+ d.gutterFiller.setAttribute("not-content", "true");
148
148
  // Will contain the actual code, positioned to cover the viewport.
149
149
  d.lineDiv = elt("div", null, "CodeMirror-code");
150
150
  // Elements are added to these to represent selection and cursors.
@@ -161,10 +161,11 @@
161
161
  d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative");
162
162
  // Set to the height of the document, allowing scrolling.
163
163
  d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
164
+ d.sizerWidth = null;
164
165
  // Behavior of elts with overflow: auto and padding is
165
166
  // inconsistent across browsers. This is used to ensure the
166
167
  // scrollable area is big enough.
167
- d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerCutOff + "px; width: 1px;");
168
+ d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;");
168
169
  // Will contain the gutters, if any.
169
170
  d.gutters = elt("div", null, "CodeMirror-gutters");
170
171
  d.lineGutter = null;
@@ -172,8 +173,7 @@
172
173
  d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
173
174
  d.scroller.setAttribute("tabIndex", "-1");
174
175
  // The element in which the editor lives.
175
- d.wrapper = elt("div", [d.inputDiv, d.scrollbarH, d.scrollbarV,
176
- d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
176
+ d.wrapper = elt("div", [d.inputDiv, d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
177
177
 
178
178
  // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
179
179
  if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
@@ -182,8 +182,6 @@
182
182
  if (!webkit) d.scroller.draggable = true;
183
183
  // Needed to handle Tab key in KHTML
184
184
  if (khtml) { d.inputDiv.style.height = "1px"; d.inputDiv.style.position = "absolute"; }
185
- // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
186
- if (ie && ie_version < 8) d.scrollbarH.style.minHeight = d.scrollbarV.style.minWidth = "18px";
187
185
 
188
186
  if (place) {
189
187
  if (place.appendChild) place.appendChild(d.wrapper);
@@ -192,8 +190,10 @@
192
190
 
193
191
  // Current rendered range (may be bigger than the view window).
194
192
  d.viewFrom = d.viewTo = doc.first;
193
+ d.reportedViewFrom = d.reportedViewTo = doc.first;
195
194
  // Information about the rendered lines.
196
195
  d.view = [];
196
+ d.renderedView = null;
197
197
  // Holds info about a single rendered line when it was rendered
198
198
  // for measurement, while not in view.
199
199
  d.externalMeasured = null;
@@ -202,6 +202,9 @@
202
202
  d.lastWrapHeight = d.lastWrapWidth = 0;
203
203
  d.updateLineNumbers = null;
204
204
 
205
+ d.nativeBarWidth = d.barHeight = d.barWidth = 0;
206
+ d.scrollbarsClipped = false;
207
+
205
208
  // Used to only resize the line number gutter when necessary (when
206
209
  // the amount of lines crosses a boundary that makes its width change)
207
210
  d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
@@ -265,6 +268,7 @@
265
268
  if (cm.options.lineWrapping) {
266
269
  addClass(cm.display.wrapper, "CodeMirror-wrap");
267
270
  cm.display.sizer.style.minWidth = "";
271
+ cm.display.sizerWidth = null;
268
272
  } else {
269
273
  rmClass(cm.display.wrapper, "CodeMirror-wrap");
270
274
  findMaxLine(cm);
@@ -336,7 +340,6 @@
336
340
  function updateGutterSpace(cm) {
337
341
  var width = cm.display.gutters.offsetWidth;
338
342
  cm.display.sizer.style.marginLeft = width + "px";
339
- cm.display.scrollbarH.style.left = cm.options.fixedGutter ? width + "px" : 0;
340
343
  }
341
344
 
342
345
  // Compute the character length of a line, taking into account
@@ -389,78 +392,166 @@
389
392
 
390
393
  // SCROLLBARS
391
394
 
392
- function hScrollbarTakesSpace(cm) {
393
- return cm.display.scroller.clientHeight - cm.display.wrapper.clientHeight < scrollerCutOff - 3;
394
- }
395
-
396
395
  // Prepare DOM reads needed to update the scrollbars. Done in one
397
396
  // shot to minimize update/measure roundtrips.
398
397
  function measureForScrollbars(cm) {
399
- var scroll = cm.display.scroller;
398
+ var d = cm.display, gutterW = d.gutters.offsetWidth;
399
+ var docH = Math.round(cm.doc.height + paddingVert(cm.display));
400
400
  return {
401
- clientHeight: scroll.clientHeight,
402
- barHeight: cm.display.scrollbarV.clientHeight,
403
- scrollWidth: scroll.scrollWidth, clientWidth: scroll.clientWidth,
404
- hScrollbarTakesSpace: hScrollbarTakesSpace(cm),
405
- barWidth: cm.display.scrollbarH.clientWidth,
406
- docHeight: Math.round(cm.doc.height + paddingVert(cm.display))
401
+ clientHeight: d.scroller.clientHeight,
402
+ viewHeight: d.wrapper.clientHeight,
403
+ scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
404
+ viewWidth: d.wrapper.clientWidth,
405
+ barLeft: cm.options.fixedGutter ? gutterW : 0,
406
+ docHeight: docH,
407
+ scrollHeight: docH + scrollGap(cm) + d.barHeight,
408
+ nativeBarWidth: d.nativeBarWidth,
409
+ gutterWidth: gutterW
407
410
  };
408
411
  }
409
412
 
410
- // Re-synchronize the fake scrollbars with the actual size of the
411
- // content.
413
+ function NativeScrollbars(place, scroll, cm) {
414
+ this.cm = cm;
415
+ var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar");
416
+ var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
417
+ place(vert); place(horiz);
418
+
419
+ on(vert, "scroll", function() {
420
+ if (vert.clientHeight) scroll(vert.scrollTop, "vertical");
421
+ });
422
+ on(horiz, "scroll", function() {
423
+ if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal");
424
+ });
425
+
426
+ this.checkedOverlay = false;
427
+ // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
428
+ if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px";
429
+ }
430
+
431
+ NativeScrollbars.prototype = copyObj({
432
+ update: function(measure) {
433
+ var needsH = measure.scrollWidth > measure.clientWidth + 1;
434
+ var needsV = measure.scrollHeight > measure.clientHeight + 1;
435
+ var sWidth = measure.nativeBarWidth;
436
+
437
+ if (needsV) {
438
+ this.vert.style.display = "block";
439
+ this.vert.style.bottom = needsH ? sWidth + "px" : "0";
440
+ var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);
441
+ // A bug in IE8 can cause this value to be negative, so guard it.
442
+ this.vert.firstChild.style.height =
443
+ Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px";
444
+ } else {
445
+ this.vert.style.display = "";
446
+ this.vert.firstChild.style.height = "0";
447
+ }
448
+
449
+ if (needsH) {
450
+ this.horiz.style.display = "block";
451
+ this.horiz.style.right = needsV ? sWidth + "px" : "0";
452
+ this.horiz.style.left = measure.barLeft + "px";
453
+ var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0);
454
+ this.horiz.firstChild.style.width =
455
+ (measure.scrollWidth - measure.clientWidth + totalWidth) + "px";
456
+ } else {
457
+ this.horiz.style.display = "";
458
+ this.horiz.firstChild.style.width = "0";
459
+ }
460
+
461
+ if (!this.checkedOverlay && measure.clientHeight > 0) {
462
+ if (sWidth == 0) this.overlayHack();
463
+ this.checkedOverlay = true;
464
+ }
465
+
466
+ return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0};
467
+ },
468
+ setScrollLeft: function(pos) {
469
+ if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos;
470
+ },
471
+ setScrollTop: function(pos) {
472
+ if (this.vert.scrollTop != pos) this.vert.scrollTop = pos;
473
+ },
474
+ overlayHack: function() {
475
+ var w = mac && !mac_geMountainLion ? "12px" : "18px";
476
+ this.horiz.style.minHeight = this.vert.style.minWidth = w;
477
+ var self = this;
478
+ var barMouseDown = function(e) {
479
+ if (e_target(e) != self.vert && e_target(e) != self.horiz)
480
+ operation(self.cm, onMouseDown)(e);
481
+ };
482
+ on(this.vert, "mousedown", barMouseDown);
483
+ on(this.horiz, "mousedown", barMouseDown);
484
+ },
485
+ clear: function() {
486
+ var parent = this.horiz.parentNode;
487
+ parent.removeChild(this.horiz);
488
+ parent.removeChild(this.vert);
489
+ }
490
+ }, NativeScrollbars.prototype);
491
+
492
+ function NullScrollbars() {}
493
+
494
+ NullScrollbars.prototype = copyObj({
495
+ update: function() { return {bottom: 0, right: 0}; },
496
+ setScrollLeft: function() {},
497
+ setScrollTop: function() {},
498
+ clear: function() {}
499
+ }, NullScrollbars.prototype);
500
+
501
+ CodeMirror.scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars};
502
+
503
+ function initScrollbars(cm) {
504
+ if (cm.display.scrollbars) {
505
+ cm.display.scrollbars.clear();
506
+ if (cm.display.scrollbars.addClass)
507
+ rmClass(cm.display.wrapper, cm.display.scrollbars.addClass);
508
+ }
509
+
510
+ cm.display.scrollbars = new CodeMirror.scrollbarModel[cm.options.scrollbarStyle](function(node) {
511
+ cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);
512
+ on(node, "mousedown", function() {
513
+ if (cm.state.focused) setTimeout(bind(focusInput, cm), 0);
514
+ });
515
+ node.setAttribute("not-content", "true");
516
+ }, function(pos, axis) {
517
+ if (axis == "horizontal") setScrollLeft(cm, pos);
518
+ else setScrollTop(cm, pos);
519
+ }, cm);
520
+ if (cm.display.scrollbars.addClass)
521
+ addClass(cm.display.wrapper, cm.display.scrollbars.addClass);
522
+ }
523
+
412
524
  function updateScrollbars(cm, measure) {
413
525
  if (!measure) measure = measureForScrollbars(cm);
414
- var d = cm.display, sWidth = scrollbarWidth(d.measure);
415
- var scrollHeight = measure.docHeight + scrollerCutOff;
416
- var needsH = measure.scrollWidth > measure.clientWidth;
417
- if (needsH && measure.scrollWidth <= measure.clientWidth + 1 &&
418
- sWidth > 0 && !measure.hScrollbarTakesSpace)
419
- needsH = false; // (Issue #2562)
420
- var needsV = scrollHeight > measure.clientHeight;
421
-
422
- if (needsV) {
423
- d.scrollbarV.style.display = "block";
424
- d.scrollbarV.style.bottom = needsH ? sWidth + "px" : "0";
425
- // A bug in IE8 can cause this value to be negative, so guard it.
426
- d.scrollbarV.firstChild.style.height =
427
- Math.max(0, scrollHeight - measure.clientHeight + (measure.barHeight || d.scrollbarV.clientHeight)) + "px";
428
- } else {
429
- d.scrollbarV.style.display = "";
430
- d.scrollbarV.firstChild.style.height = "0";
431
- }
432
- if (needsH) {
433
- d.scrollbarH.style.display = "block";
434
- d.scrollbarH.style.right = needsV ? sWidth + "px" : "0";
435
- d.scrollbarH.firstChild.style.width =
436
- (measure.scrollWidth - measure.clientWidth + (measure.barWidth || d.scrollbarH.clientWidth)) + "px";
437
- } else {
438
- d.scrollbarH.style.display = "";
439
- d.scrollbarH.firstChild.style.width = "0";
526
+ var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;
527
+ updateScrollbarsInner(cm, measure);
528
+ for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
529
+ if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
530
+ updateHeightsInViewport(cm);
531
+ updateScrollbarsInner(cm, measureForScrollbars(cm));
532
+ startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;
440
533
  }
441
- if (needsH && needsV) {
534
+ }
535
+
536
+ // Re-synchronize the fake scrollbars with the actual size of the
537
+ // content.
538
+ function updateScrollbarsInner(cm, measure) {
539
+ var d = cm.display;
540
+ var sizes = d.scrollbars.update(measure);
541
+
542
+ d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px";
543
+ d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px";
544
+
545
+ if (sizes.right && sizes.bottom) {
442
546
  d.scrollbarFiller.style.display = "block";
443
- d.scrollbarFiller.style.height = d.scrollbarFiller.style.width = sWidth + "px";
547
+ d.scrollbarFiller.style.height = sizes.bottom + "px";
548
+ d.scrollbarFiller.style.width = sizes.right + "px";
444
549
  } else d.scrollbarFiller.style.display = "";
445
- if (needsH && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
550
+ if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
446
551
  d.gutterFiller.style.display = "block";
447
- d.gutterFiller.style.height = sWidth + "px";
448
- d.gutterFiller.style.width = d.gutters.offsetWidth + "px";
552
+ d.gutterFiller.style.height = sizes.bottom + "px";
553
+ d.gutterFiller.style.width = measure.gutterWidth + "px";
449
554
  } else d.gutterFiller.style.display = "";
450
-
451
- if (!cm.state.checkedOverlayScrollbar && measure.clientHeight > 0) {
452
- if (sWidth === 0) {
453
- var w = mac && !mac_geMountainLion ? "12px" : "18px";
454
- d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = w;
455
- var barMouseDown = function(e) {
456
- if (e_target(e) != d.scrollbarV && e_target(e) != d.scrollbarH)
457
- operation(cm, onMouseDown)(e);
458
- };
459
- on(d.scrollbarV, "mousedown", barMouseDown);
460
- on(d.scrollbarH, "mousedown", barMouseDown);
461
- }
462
- cm.state.checkedOverlayScrollbar = true;
463
- }
464
555
  }
465
556
 
466
557
  // Compute the lines that are visible in a given viewport (defaults
@@ -476,12 +567,13 @@
476
567
  // forces those lines into the viewport (if possible).
477
568
  if (viewport && viewport.ensure) {
478
569
  var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;
479
- if (ensureFrom < from)
480
- return {from: ensureFrom,
481
- to: lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight)};
482
- if (Math.min(ensureTo, doc.lastLine()) >= to)
483
- return {from: lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight),
484
- to: ensureTo};
570
+ if (ensureFrom < from) {
571
+ from = ensureFrom;
572
+ to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);
573
+ } else if (Math.min(ensureTo, doc.lastLine()) >= to) {
574
+ from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);
575
+ to = ensureTo;
576
+ }
485
577
  }
486
578
  return {from: from, to: Math.max(to, from + 1)};
487
579
  }
@@ -549,17 +641,28 @@
549
641
  this.editorIsHidden = !display.wrapper.offsetWidth;
550
642
  this.wrapperHeight = display.wrapper.clientHeight;
551
643
  this.wrapperWidth = display.wrapper.clientWidth;
552
- this.oldViewFrom = display.viewFrom; this.oldViewTo = display.viewTo;
553
- this.oldScrollerWidth = display.scroller.clientWidth;
644
+ this.oldDisplayWidth = displayWidth(cm);
554
645
  this.force = force;
555
646
  this.dims = getDimensions(cm);
556
647
  }
557
648
 
649
+ function maybeClipScrollbars(cm) {
650
+ var display = cm.display;
651
+ if (!display.scrollbarsClipped && display.scroller.offsetWidth) {
652
+ display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;
653
+ display.heightForcer.style.height = scrollGap(cm) + "px";
654
+ display.sizer.style.marginBottom = -display.nativeBarWidth + "px";
655
+ display.sizer.style.borderRightWidth = scrollGap(cm) + "px";
656
+ display.scrollbarsClipped = true;
657
+ }
658
+ }
659
+
558
660
  // Does the actual updating of the line display. Bails out
559
661
  // (returning false) when there is nothing to be done and forced is
560
662
  // false.
561
663
  function updateDisplayIfNeeded(cm, update) {
562
664
  var display = cm.display, doc = cm.doc;
665
+
563
666
  if (update.editorIsHidden) {
564
667
  resetView(cm);
565
668
  return false;
@@ -569,7 +672,7 @@
569
672
  if (!update.force &&
570
673
  update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
571
674
  (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
572
- countDirtyView(cm) == 0)
675
+ display.renderedView == display.view && countDirtyView(cm) == 0)
573
676
  return false;
574
677
 
575
678
  if (maybeUpdateLineNumberWidth(cm)) {
@@ -597,7 +700,7 @@
597
700
  cm.display.mover.style.top = display.viewOffset + "px";
598
701
 
599
702
  var toUpdate = countDirtyView(cm);
600
- if (!different && toUpdate == 0 && !update.force &&
703
+ if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&
601
704
  (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))
602
705
  return false;
603
706
 
@@ -607,14 +710,16 @@
607
710
  if (toUpdate > 4) display.lineDiv.style.display = "none";
608
711
  patchDisplay(cm, display.updateLineNumbers, update.dims);
609
712
  if (toUpdate > 4) display.lineDiv.style.display = "";
713
+ display.renderedView = display.view;
610
714
  // There might have been a widget with a focused element that got
611
715
  // hidden or updated, if so re-focus it.
612
716
  if (focused && activeElt() != focused && focused.offsetHeight) focused.focus();
613
717
 
614
718
  // Prevent selection and cursors from interfering with the scroll
615
- // width.
719
+ // width and height.
616
720
  removeChildren(display.cursorDiv);
617
721
  removeChildren(display.selectionDiv);
722
+ display.heightForcer.style.top = display.gutters.style.height = 0;
618
723
 
619
724
  if (different) {
620
725
  display.lastWrapHeight = update.wrapperHeight;
@@ -630,14 +735,13 @@
630
735
  function postUpdateDisplay(cm, update) {
631
736
  var force = update.force, viewport = update.viewport;
632
737
  for (var first = true;; first = false) {
633
- if (first && cm.options.lineWrapping && update.oldScrollerWidth != cm.display.scroller.clientWidth) {
738
+ if (first && cm.options.lineWrapping && update.oldDisplayWidth != displayWidth(cm)) {
634
739
  force = true;
635
740
  } else {
636
741
  force = false;
637
742
  // Clip forced viewport to actual scrollable area.
638
743
  if (viewport && viewport.top != null)
639
- viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - scrollerCutOff -
640
- cm.display.scroller.clientHeight, viewport.top)};
744
+ viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)};
641
745
  // Updated line heights might result in the drawn area not
642
746
  // actually covering the viewport. Keep looping until it does.
643
747
  update.visible = visibleLines(cm.display, cm.doc, viewport);
@@ -653,8 +757,10 @@
653
757
  }
654
758
 
655
759
  signalLater(cm, "update", cm);
656
- if (cm.display.viewFrom != update.oldViewFrom || cm.display.viewTo != update.oldViewTo)
760
+ if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {
657
761
  signalLater(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo);
762
+ cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;
763
+ }
658
764
  }
659
765
 
660
766
  function updateDisplaySimple(cm, viewport) {
@@ -671,16 +777,7 @@
671
777
 
672
778
  function setDocumentHeight(cm, measure) {
673
779
  cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = measure.docHeight + "px";
674
- cm.display.gutters.style.height = Math.max(measure.docHeight, measure.clientHeight - scrollerCutOff) + "px";
675
- }
676
-
677
- function checkForWebkitWidthBug(cm, measure) {
678
- // Work around Webkit bug where it sometimes reserves space for a
679
- // non-existing phantom scrollbar in the scroller (Issue #2420)
680
- if (cm.display.sizer.offsetWidth + cm.display.gutters.offsetWidth < cm.display.scroller.clientWidth - 1) {
681
- cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = "0px";
682
- cm.display.gutters.style.height = measure.docHeight + "px";
683
- }
780
+ cm.display.gutters.style.height = Math.max(measure.docHeight + scrollGap(cm), measure.clientHeight) + "px";
684
781
  }
685
782
 
686
783
  // Read the actual heights of the rendered lines, and update their
@@ -924,7 +1021,7 @@
924
1021
  var wrap = ensureLineWrapped(lineView);
925
1022
  for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
926
1023
  var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
927
- if (!widget.handleMouseEvents) node.ignoreEvents = true;
1024
+ if (!widget.handleMouseEvents) node.setAttribute("cm-ignore-events", "true");
928
1025
  positionLineWidget(widget, node, lineView, dims);
929
1026
  if (allowAbove && widget.above)
930
1027
  wrap.insertBefore(node, lineView.gutter || lineView.text);
@@ -1319,7 +1416,8 @@
1319
1416
  function drawSelectionRange(cm, range, output) {
1320
1417
  var display = cm.display, doc = cm.doc;
1321
1418
  var fragment = document.createDocumentFragment();
1322
- var padding = paddingH(cm.display), leftSide = padding.left, rightSide = display.lineSpace.offsetWidth - padding.right;
1419
+ var padding = paddingH(cm.display), leftSide = padding.left;
1420
+ var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right;
1323
1421
 
1324
1422
  function add(left, top, width, bottom) {
1325
1423
  if (top < 0) top = 0;
@@ -1498,13 +1596,21 @@
1498
1596
  return data;
1499
1597
  }
1500
1598
 
1599
+ function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth; }
1600
+ function displayWidth(cm) {
1601
+ return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth;
1602
+ }
1603
+ function displayHeight(cm) {
1604
+ return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight;
1605
+ }
1606
+
1501
1607
  // Ensure the lineView.wrapping.heights array is populated. This is
1502
1608
  // an array of bottom offsets for the lines that make up a drawn
1503
1609
  // line. When lineWrapping is on, there might be more than one
1504
1610
  // height.
1505
1611
  function ensureLineHeights(cm, lineView, rect) {
1506
1612
  var wrapping = cm.options.lineWrapping;
1507
- var curWidth = wrapping && cm.display.scroller.clientWidth;
1613
+ var curWidth = wrapping && displayWidth(cm);
1508
1614
  if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
1509
1615
  var heights = lineView.measure.heights = [];
1510
1616
  if (wrapping) {
@@ -2022,6 +2128,7 @@
2022
2128
 
2023
2129
  function endOperation_R1(op) {
2024
2130
  var cm = op.cm, display = cm.display;
2131
+ maybeClipScrollbars(cm);
2025
2132
  if (op.updateMaxLine) findMaxLine(cm);
2026
2133
 
2027
2134
  op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
@@ -2047,8 +2154,10 @@
2047
2154
  // updateDisplay_W2 will use these properties to do the actual resizing
2048
2155
  if (display.maxLineChanged && !cm.options.lineWrapping) {
2049
2156
  op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;
2050
- op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo +
2051
- scrollerCutOff - display.scroller.clientWidth);
2157
+ cm.display.sizerWidth = op.adjustWidthTo;
2158
+ op.barMeasure.scrollWidth =
2159
+ Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth);
2160
+ op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm));
2052
2161
  }
2053
2162
 
2054
2163
  if (op.updatedDisplay || op.selectionChanged)
@@ -2081,9 +2190,6 @@
2081
2190
  function endOperation_finish(op) {
2082
2191
  var cm = op.cm, display = cm.display, doc = cm.doc;
2083
2192
 
2084
- if (op.adjustWidthTo != null && Math.abs(op.barMeasure.scrollWidth - cm.display.scroller.scrollWidth) > 1)
2085
- updateScrollbars(cm);
2086
-
2087
2193
  if (op.updatedDisplay) postUpdateDisplay(cm, op.update);
2088
2194
 
2089
2195
  // Abort mouse wheel delta measurement, when scrolling explicitly
@@ -2092,12 +2198,14 @@
2092
2198
 
2093
2199
  // Propagate the scroll position to the actual DOM scroller
2094
2200
  if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) {
2095
- var top = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop));
2096
- display.scroller.scrollTop = display.scrollbarV.scrollTop = doc.scrollTop = top;
2201
+ doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop));
2202
+ display.scrollbars.setScrollTop(doc.scrollTop);
2203
+ display.scroller.scrollTop = doc.scrollTop;
2097
2204
  }
2098
2205
  if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) {
2099
- var left = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, op.scrollLeft));
2100
- display.scroller.scrollLeft = display.scrollbarH.scrollLeft = doc.scrollLeft = left;
2206
+ doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - displayWidth(cm), op.scrollLeft));
2207
+ display.scrollbars.setScrollLeft(doc.scrollLeft);
2208
+ display.scroller.scrollLeft = doc.scrollLeft;
2101
2209
  alignHorizontally(cm);
2102
2210
  }
2103
2211
  // If we need to scroll a specific position into view, do so.
@@ -2118,16 +2226,6 @@
2118
2226
  if (display.wrapper.offsetHeight)
2119
2227
  doc.scrollTop = cm.display.scroller.scrollTop;
2120
2228
 
2121
- // Apply workaround for two webkit bugs
2122
- if (op.updatedDisplay && webkit) {
2123
- if (cm.options.lineWrapping)
2124
- checkForWebkitWidthBug(cm, op.barMeasure); // (Issue #2420)
2125
- if (op.barMeasure.scrollWidth > op.barMeasure.clientWidth &&
2126
- op.barMeasure.scrollWidth < op.barMeasure.clientWidth + 1 &&
2127
- !hScrollbarTakesSpace(cm))
2128
- updateScrollbars(cm); // (Issue #2562)
2129
- }
2130
-
2131
2229
  // Fire change events, and delayed event handlers
2132
2230
  if (op.changeObjs)
2133
2231
  signal(cm, "changes", cm, op.changeObjs);
@@ -2486,6 +2584,7 @@
2486
2584
  // Reset the input to correspond to the selection (or to be empty,
2487
2585
  // when not typing and nothing is selected)
2488
2586
  function resetInput(cm, typing) {
2587
+ if (cm.display.contextMenuPending) return;
2489
2588
  var minimal, selected, doc = cm.doc;
2490
2589
  if (cm.somethingSelected()) {
2491
2590
  cm.display.prevInput = "";
@@ -2552,28 +2651,18 @@
2552
2651
  signal(cm, "scroll", cm);
2553
2652
  }
2554
2653
  });
2555
- on(d.scrollbarV, "scroll", function() {
2556
- if (d.scroller.clientHeight) setScrollTop(cm, d.scrollbarV.scrollTop);
2557
- });
2558
- on(d.scrollbarH, "scroll", function() {
2559
- if (d.scroller.clientHeight) setScrollLeft(cm, d.scrollbarH.scrollLeft);
2560
- });
2561
2654
 
2562
2655
  // Listen to wheel events in order to try and update the viewport on time.
2563
2656
  on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);});
2564
2657
  on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);});
2565
2658
 
2566
- // Prevent clicks in the scrollbars from killing focus
2567
- function reFocus() { if (cm.state.focused) setTimeout(bind(focusInput, cm), 0); }
2568
- on(d.scrollbarH, "mousedown", reFocus);
2569
- on(d.scrollbarV, "mousedown", reFocus);
2570
2659
  // Prevent wrapper from ever scrolling
2571
2660
  on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
2572
2661
 
2573
2662
  on(d.input, "keyup", function(e) { onKeyUp.call(cm, e); });
2574
2663
  on(d.input, "input", function() {
2575
2664
  if (ie && ie_version >= 9 && cm.display.inputHasSelection) cm.display.inputHasSelection = null;
2576
- fastPoll(cm);
2665
+ readInput(cm);
2577
2666
  });
2578
2667
  on(d.input, "keydown", operation(cm, onKeyDown));
2579
2668
  on(d.input, "keypress", operation(cm, onKeyPress));
@@ -2659,6 +2748,7 @@
2659
2748
  return;
2660
2749
  // Might be a text scaling operation, clear size caches.
2661
2750
  d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
2751
+ d.scrollbarsClipped = false;
2662
2752
  cm.setSize();
2663
2753
  }
2664
2754
 
@@ -2667,7 +2757,7 @@
2667
2757
  // Return true when the given mouse event happened in a widget
2668
2758
  function eventInWidget(display, e) {
2669
2759
  for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
2670
- if (!n || n.ignoreEvents || n.parentNode == display.sizer && n != display.mover) return true;
2760
+ if (!n || n.getAttribute("cm-ignore-events") == "true" || n.parentNode == display.sizer && n != display.mover) return true;
2671
2761
  }
2672
2762
  }
2673
2763
 
@@ -2678,11 +2768,8 @@
2678
2768
  // coordinates beyond the right of the text.
2679
2769
  function posFromMouse(cm, e, liberal, forRect) {
2680
2770
  var display = cm.display;
2681
- if (!liberal) {
2682
- var target = e_target(e);
2683
- if (target == display.scrollbarH || target == display.scrollbarV ||
2684
- target == display.scrollbarFiller || target == display.gutterFiller) return null;
2685
- }
2771
+ if (!liberal && e_target(e).getAttribute("not-content") == "true") return null;
2772
+
2686
2773
  var x, y, space = display.lineSpace.getBoundingClientRect();
2687
2774
  // Fails unpredictably on IE[67] when mouse is dragged around quickly.
2688
2775
  try { x = e.clientX - space.left; y = e.clientY - space.top; }
@@ -2752,9 +2839,10 @@
2752
2839
  lastClick = {time: now, pos: start};
2753
2840
  }
2754
2841
 
2755
- var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey;
2842
+ var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained;
2756
2843
  if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) &&
2757
- type == "single" && sel.contains(start) > -1 && sel.somethingSelected())
2844
+ type == "single" && (contained = sel.contains(start)) > -1 &&
2845
+ !sel.ranges[contained].empty())
2758
2846
  leftButtonStartDrag(cm, e, start, modifier);
2759
2847
  else
2760
2848
  leftButtonSelect(cm, e, start, type, modifier);
@@ -2793,11 +2881,11 @@
2793
2881
  var display = cm.display, doc = cm.doc;
2794
2882
  e_preventDefault(e);
2795
2883
 
2796
- var ourRange, ourIndex, startSel = doc.sel;
2884
+ var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;
2797
2885
  if (addNew && !e.shiftKey) {
2798
2886
  ourIndex = doc.sel.contains(start);
2799
2887
  if (ourIndex > -1)
2800
- ourRange = doc.sel.ranges[ourIndex];
2888
+ ourRange = ranges[ourIndex];
2801
2889
  else
2802
2890
  ourRange = new Range(start, start);
2803
2891
  } else {
@@ -2829,12 +2917,15 @@
2829
2917
  ourIndex = 0;
2830
2918
  setSelection(doc, new Selection([ourRange], 0), sel_mouse);
2831
2919
  startSel = doc.sel;
2832
- } else if (ourIndex > -1) {
2833
- replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
2834
- } else {
2835
- ourIndex = doc.sel.ranges.length;
2836
- setSelection(doc, normalizeSelection(doc.sel.ranges.concat([ourRange]), ourIndex),
2920
+ } else if (ourIndex == -1) {
2921
+ ourIndex = ranges.length;
2922
+ setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex),
2837
2923
  {scroll: false, origin: "*mouse"});
2924
+ } else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single") {
2925
+ setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0));
2926
+ startSel = doc.sel;
2927
+ } else {
2928
+ replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
2838
2929
  }
2839
2930
 
2840
2931
  var lastPos = start;
@@ -3040,7 +3131,7 @@
3040
3131
  cm.doc.scrollTop = val;
3041
3132
  if (!gecko) updateDisplaySimple(cm, {top: val});
3042
3133
  if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val;
3043
- if (cm.display.scrollbarV.scrollTop != val) cm.display.scrollbarV.scrollTop = val;
3134
+ cm.display.scrollbars.setScrollTop(val);
3044
3135
  if (gecko) updateDisplaySimple(cm);
3045
3136
  startWorker(cm, 100);
3046
3137
  }
@@ -3052,7 +3143,7 @@
3052
3143
  cm.doc.scrollLeft = val;
3053
3144
  alignHorizontally(cm);
3054
3145
  if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val;
3055
- if (cm.display.scrollbarH.scrollLeft != val) cm.display.scrollbarH.scrollLeft = val;
3146
+ cm.display.scrollbars.setScrollLeft(val);
3056
3147
  }
3057
3148
 
3058
3149
  // Since the delta values reported on mouse wheel events are
@@ -3076,11 +3167,22 @@
3076
3167
  else if (chrome) wheelPixelsPerUnit = -.7;
3077
3168
  else if (safari) wheelPixelsPerUnit = -1/3;
3078
3169
 
3079
- function onScrollWheel(cm, e) {
3170
+ var wheelEventDelta = function(e) {
3080
3171
  var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
3081
3172
  if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail;
3082
3173
  if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail;
3083
3174
  else if (dy == null) dy = e.wheelDelta;
3175
+ return {x: dx, y: dy};
3176
+ };
3177
+ CodeMirror.wheelEventPixels = function(e) {
3178
+ var delta = wheelEventDelta(e);
3179
+ delta.x *= wheelPixelsPerUnit;
3180
+ delta.y *= wheelPixelsPerUnit;
3181
+ return delta;
3182
+ };
3183
+
3184
+ function onScrollWheel(cm, e) {
3185
+ var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;
3084
3186
 
3085
3187
  var display = cm.display, scroll = display.scroller;
3086
3188
  // Quit if there's nothing to scroll here
@@ -3173,11 +3275,11 @@
3173
3275
 
3174
3276
  function lookupKeyForEditor(cm, name, handle) {
3175
3277
  for (var i = 0; i < cm.state.keyMaps.length; i++) {
3176
- var result = lookupKey(name, cm.state.keyMaps[i], handle);
3278
+ var result = lookupKey(name, cm.state.keyMaps[i], handle, cm);
3177
3279
  if (result) return result;
3178
3280
  }
3179
- return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle))
3180
- || lookupKey(name, cm.options.keyMap, handle);
3281
+ return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))
3282
+ || lookupKey(name, cm.options.keyMap, handle, cm);
3181
3283
  }
3182
3284
 
3183
3285
  var stopSeq = new Delayed;
@@ -3351,6 +3453,7 @@
3351
3453
  resetInput(cm);
3352
3454
  // Adds "Select all" to context menu in FF
3353
3455
  if (!cm.somethingSelected()) display.input.value = display.prevInput = " ";
3456
+ display.contextMenuPending = true;
3354
3457
  display.selForContextMenu = cm.doc.sel;
3355
3458
  clearTimeout(display.detectingSelectAll);
3356
3459
 
@@ -3369,9 +3472,10 @@
3369
3472
  }
3370
3473
  }
3371
3474
  function rehide() {
3475
+ display.contextMenuPending = false;
3372
3476
  display.inputDiv.style.position = "relative";
3373
3477
  display.input.style.cssText = oldCSS;
3374
- if (ie && ie_version < 9) display.scrollbarV.scrollTop = display.scroller.scrollTop = scrollPos;
3478
+ if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos);
3375
3479
  slowPoll(cm);
3376
3480
 
3377
3481
  // Try to detect the user choosing select-all
@@ -3721,7 +3825,7 @@
3721
3825
  if (doScroll != null && !phantom) {
3722
3826
  var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " +
3723
3827
  (coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " +
3724
- (coords.bottom - coords.top + scrollerCutOff) + "px; left: " +
3828
+ (coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + "px; left: " +
3725
3829
  coords.left + "px; width: 2px;");
3726
3830
  cm.display.lineSpace.appendChild(scrollNode);
3727
3831
  scrollNode.scrollIntoView(doScroll);
@@ -3750,8 +3854,9 @@
3750
3854
  setScrollLeft(cm, scrollPos.scrollLeft);
3751
3855
  if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true;
3752
3856
  }
3753
- if (!changed) return coords;
3857
+ if (!changed) break;
3754
3858
  }
3859
+ return coords;
3755
3860
  }
3756
3861
 
3757
3862
  // Scroll a given set of coordinates into view (immediately).
@@ -3769,7 +3874,7 @@
3769
3874
  var display = cm.display, snapMargin = textHeight(cm.display);
3770
3875
  if (y1 < 0) y1 = 0;
3771
3876
  var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
3772
- var screen = display.scroller.clientHeight - scrollerCutOff, result = {};
3877
+ var screen = displayHeight(cm), result = {};
3773
3878
  if (y2 - y1 > screen) y2 = y1 + screen;
3774
3879
  var docBottom = cm.doc.height + paddingVert(display);
3775
3880
  var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin;
@@ -3781,7 +3886,7 @@
3781
3886
  }
3782
3887
 
3783
3888
  var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
3784
- var screenw = display.scroller.clientWidth - scrollerCutOff - display.gutters.offsetWidth;
3889
+ var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0);
3785
3890
  var tooWide = x2 - x1 > screenw;
3786
3891
  if (tooWide) x2 = x1 + screenw;
3787
3892
  if (x1 < 10)
@@ -3790,7 +3895,6 @@
3790
3895
  result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10));
3791
3896
  else if (x2 > screenw + screenleft - 3)
3792
3897
  result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw;
3793
-
3794
3898
  return result;
3795
3899
  }
3796
3900
 
@@ -4245,6 +4349,7 @@
4245
4349
  pos = cursorCoords(this, clipPos(this.doc, pos));
4246
4350
  var top = pos.bottom, left = pos.left;
4247
4351
  node.style.position = "absolute";
4352
+ node.setAttribute("cm-ignore-events", "true");
4248
4353
  display.sizer.appendChild(node);
4249
4354
  if (vert == "over") {
4250
4355
  top = pos.top;
@@ -4379,10 +4484,11 @@
4379
4484
  if (y != null) this.curOp.scrollTop = y;
4380
4485
  }),
4381
4486
  getScrollInfo: function() {
4382
- var scroller = this.display.scroller, co = scrollerCutOff;
4487
+ var scroller = this.display.scroller;
4383
4488
  return {left: scroller.scrollLeft, top: scroller.scrollTop,
4384
- height: scroller.scrollHeight - co, width: scroller.scrollWidth - co,
4385
- clientHeight: scroller.clientHeight - co, clientWidth: scroller.clientWidth - co};
4489
+ height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,
4490
+ width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,
4491
+ clientHeight: displayHeight(this), clientWidth: displayWidth(this)};
4386
4492
  },
4387
4493
 
4388
4494
  scrollIntoView: methodOp(function(range, margin) {
@@ -4524,7 +4630,13 @@
4524
4630
  cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
4525
4631
  cm.refresh();
4526
4632
  }, true);
4527
- option("coverGutterNextToScrollbar", false, updateScrollbars, true);
4633
+ option("coverGutterNextToScrollbar", false, function(cm) {updateScrollbars(cm);}, true);
4634
+ option("scrollbarStyle", "native", function(cm) {
4635
+ initScrollbars(cm);
4636
+ updateScrollbars(cm);
4637
+ cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);
4638
+ cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);
4639
+ }, true);
4528
4640
  option("lineNumbers", false, function(cm) {
4529
4641
  setGuttersForLineNumbers(cm.options);
4530
4642
  guttersChanged(cm);
@@ -4954,18 +5066,18 @@
4954
5066
  return keymap;
4955
5067
  };
4956
5068
 
4957
- var lookupKey = CodeMirror.lookupKey = function(key, map, handle) {
5069
+ var lookupKey = CodeMirror.lookupKey = function(key, map, handle, context) {
4958
5070
  map = getKeyMap(map);
4959
- var found = map.call ? map.call(key) : map[key];
5071
+ var found = map.call ? map.call(key, context) : map[key];
4960
5072
  if (found === false) return "nothing";
4961
5073
  if (found === "...") return "multi";
4962
5074
  if (found != null && handle(found)) return "handled";
4963
5075
 
4964
5076
  if (map.fallthrough) {
4965
5077
  if (Object.prototype.toString.call(map.fallthrough) != "[object Array]")
4966
- return lookupKey(key, map.fallthrough, handle);
5078
+ return lookupKey(key, map.fallthrough, handle, context);
4967
5079
  for (var i = 0; i < map.fallthrough.length; i++) {
4968
- var result = lookupKey(key, map.fallthrough[i], handle);
5080
+ var result = lookupKey(key, map.fallthrough[i], handle, context);
4969
5081
  if (result) return result;
4970
5082
  }
4971
5083
  }
@@ -5272,7 +5384,7 @@
5272
5384
  // Showing up as a widget implies collapsed (widget replaces text)
5273
5385
  marker.collapsed = true;
5274
5386
  marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget");
5275
- if (!options.handleMouseEvents) marker.widgetNode.ignoreEvents = true;
5387
+ if (!options.handleMouseEvents) marker.widgetNode.setAttribute("cm-ignore-events", "true");
5276
5388
  if (options.insertLeft) marker.widgetNode.insertLeft = true;
5277
5389
  }
5278
5390
  if (marker.collapsed) {
@@ -5316,7 +5428,7 @@
5316
5428
  if (updateMaxLine) cm.curOp.updateMaxLine = true;
5317
5429
  if (marker.collapsed)
5318
5430
  regChange(cm, from.line, to.line + 1);
5319
- else if (marker.className || marker.title || marker.startStyle || marker.endStyle)
5431
+ else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css)
5320
5432
  for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text");
5321
5433
  if (marker.atomic) reCheckSelection(cm.doc);
5322
5434
  signalLater(cm, "markerAdded", cm, marker);
@@ -5896,8 +6008,11 @@
5896
6008
  if (mName) style = "m-" + (style ? mName + " " + style : mName);
5897
6009
  }
5898
6010
  if (!flattenSpans || curStyle != style) {
5899
- if (curStart < stream.start) f(stream.start, curStyle);
5900
- curStart = stream.start; curStyle = style;
6011
+ while (curStart < stream.start) {
6012
+ curStart = Math.min(stream.start, curStart + 50000);
6013
+ f(curStart, curStyle);
6014
+ }
6015
+ curStyle = style;
5901
6016
  }
5902
6017
  stream.start = stream.pos;
5903
6018
  }
@@ -6054,7 +6169,7 @@
6054
6169
 
6055
6170
  // Build up the DOM representation for a single token, and add it to
6056
6171
  // the line map. Takes care to render special characters separately.
6057
- function buildToken(builder, text, style, startStyle, endStyle, title) {
6172
+ function buildToken(builder, text, style, startStyle, endStyle, title, css) {
6058
6173
  if (!text) return;
6059
6174
  var special = builder.cm.options.specialChars, mustWrap = false;
6060
6175
  if (!special.test(text)) {
@@ -6093,11 +6208,11 @@
6093
6208
  builder.pos++;
6094
6209
  }
6095
6210
  }
6096
- if (style || startStyle || endStyle || mustWrap) {
6211
+ if (style || startStyle || endStyle || mustWrap || css) {
6097
6212
  var fullStyle = style || "";
6098
6213
  if (startStyle) fullStyle += startStyle;
6099
6214
  if (endStyle) fullStyle += endStyle;
6100
- var token = elt("span", [content], fullStyle);
6215
+ var token = elt("span", [content], fullStyle, css);
6101
6216
  if (title) token.title = title;
6102
6217
  return builder.content.appendChild(token);
6103
6218
  }
@@ -6156,11 +6271,11 @@
6156
6271
  return;
6157
6272
  }
6158
6273
 
6159
- var len = allText.length, pos = 0, i = 1, text = "", style;
6274
+ var len = allText.length, pos = 0, i = 1, text = "", style, css;
6160
6275
  var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;
6161
6276
  for (;;) {
6162
6277
  if (nextChange == pos) { // Update current marker set
6163
- spanStyle = spanEndStyle = spanStartStyle = title = "";
6278
+ spanStyle = spanEndStyle = spanStartStyle = title = css = "";
6164
6279
  collapsed = null; nextChange = Infinity;
6165
6280
  var foundBookmarks = [];
6166
6281
  for (var j = 0; j < spans.length; ++j) {
@@ -6168,6 +6283,7 @@
6168
6283
  if (sp.from <= pos && (sp.to == null || sp.to > pos)) {
6169
6284
  if (sp.to != null && nextChange > sp.to) { nextChange = sp.to; spanEndStyle = ""; }
6170
6285
  if (m.className) spanStyle += " " + m.className;
6286
+ if (m.css) css = m.css;
6171
6287
  if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
6172
6288
  if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
6173
6289
  if (m.title && !title) title = m.title;
@@ -6195,7 +6311,7 @@
6195
6311
  if (!collapsed) {
6196
6312
  var tokenText = end > upto ? text.slice(0, upto - pos) : text;
6197
6313
  builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
6198
- spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title);
6314
+ spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css);
6199
6315
  }
6200
6316
  if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
6201
6317
  pos = end;
@@ -6622,7 +6738,7 @@
6622
6738
  });
6623
6739
  }),
6624
6740
  removeLineClass: docMethodOp(function(handle, where, cls) {
6625
- return changeLine(this, handle, "class", function(line) {
6741
+ return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) {
6626
6742
  var prop = where == "text" ? "textClass"
6627
6743
  : where == "background" ? "bgClass"
6628
6744
  : where == "gutter" ? "gutterClass" : "wrapClass";
@@ -7278,7 +7394,7 @@
7278
7394
  // MISC UTILITIES
7279
7395
 
7280
7396
  // Number of pixels added to scroller and sizer to hide scrollbar
7281
- var scrollerCutOff = 30;
7397
+ var scrollerGap = 30;
7282
7398
 
7283
7399
  // Returned or thrown by various protocols to signal 'I'm not
7284
7400
  // handling this'.
@@ -7504,7 +7620,6 @@
7504
7620
  on(window, "resize", function() {
7505
7621
  if (resizeTimer == null) resizeTimer = setTimeout(function() {
7506
7622
  resizeTimer = null;
7507
- knownScrollbarWidth = null;
7508
7623
  forEachCodeMirror(onResize);
7509
7624
  }, 100);
7510
7625
  });
@@ -7525,16 +7640,6 @@
7525
7640
  return "draggable" in div || "dragDrop" in div;
7526
7641
  }();
7527
7642
 
7528
- var knownScrollbarWidth;
7529
- function scrollbarWidth(measure) {
7530
- if (knownScrollbarWidth != null) return knownScrollbarWidth;
7531
- var test = elt("div", null, null, "width: 50px; height: 50px; overflow-x: scroll");
7532
- removeChildrenAndAdd(measure, test);
7533
- if (test.offsetWidth)
7534
- knownScrollbarWidth = test.offsetHeight - test.clientHeight;
7535
- return knownScrollbarWidth || 0;
7536
- }
7537
-
7538
7643
  var zwspSupported;
7539
7644
  function zeroWidthElement(measure) {
7540
7645
  if (zwspSupported == null) {
@@ -7916,7 +8021,7 @@
7916
8021
 
7917
8022
  // THE END
7918
8023
 
7919
- CodeMirror.version = "4.8.0";
8024
+ CodeMirror.version = "4.9.0";
7920
8025
 
7921
8026
  return CodeMirror;
7922
8027
  });