Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(165)

Side by Side Diff: Source/devtools/front_end/cm/codemirror.js

Issue 354833004: DevTools: [CodeMirror] roll CodeMirror to version @e20d175 (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: address comments Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others 1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE 2 // Distributed under an MIT license: http://codemirror.net/LICENSE
3 3
4 // This is CodeMirror (http://codemirror.net), a code editor 4 // This is CodeMirror (http://codemirror.net), a code editor
5 // implemented in JavaScript on top of the browser's DOM. 5 // implemented in JavaScript on top of the browser's DOM.
6 // 6 //
7 // You can find some technical background for some of the code below 7 // You can find some technical background for some of the code below
8 // at http://marijnhaverbeke.nl/blog/#cm-internals . 8 // at http://marijnhaverbeke.nl/blog/#cm-internals .
9 9
10 (function(mod) { 10 (function(mod) {
11 if (typeof exports == "object" && typeof module == "object") // CommonJS 11 if (typeof exports == "object" && typeof module == "object") // CommonJS
12 module.exports = mod(); 12 module.exports = mod();
13 else if (typeof define == "function" && define.amd) // AMD 13 else if (typeof define == "function" && define.amd) // AMD
14 return define([], mod); 14 return define([], mod);
15 else // Plain browser env 15 else // Plain browser env
16 this.CodeMirror = mod(); 16 this.CodeMirror = mod();
17 })(function() { 17 })(function() {
18 "use strict"; 18 "use strict";
19 19
20 // BROWSER SNIFFING 20 // BROWSER SNIFFING
21 21
22 // Kludges for bugs and behavior differences that can't be feature 22 // Kludges for bugs and behavior differences that can't be feature
23 // detected are enabled based on userAgent etc sniffing. 23 // detected are enabled based on userAgent etc sniffing.
24 24
25 var gecko = /gecko\/\d/i.test(navigator.userAgent); 25 var gecko = /gecko\/\d/i.test(navigator.userAgent);
26 // ie_uptoN means Internet Explorer version N or lower 26 // ie_uptoN means Internet Explorer version N or lower
27 var ie_upto10 = /MSIE \d/.test(navigator.userAgent); 27 var ie_upto10 = /MSIE \d/.test(navigator.userAgent);
28 var ie_upto7 = ie_upto10 && (document.documentMode == null || document.documen tMode < 8); 28 var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent );
29 var ie_upto8 = ie_upto10 && (document.documentMode == null || document.documen tMode < 9);
30 var ie_upto9 = ie_upto10 && (document.documentMode == null || document.documen tMode < 10);
31 var ie_11up = /Trident\/([7-9]|\d{2,})\./.test(navigator.userAgent);
32 var ie = ie_upto10 || ie_11up; 29 var ie = ie_upto10 || ie_11up;
30 var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]);
33 var webkit = /WebKit\//.test(navigator.userAgent); 31 var webkit = /WebKit\//.test(navigator.userAgent);
34 var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent); 32 var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
35 var chrome = /Chrome\//.test(navigator.userAgent); 33 var chrome = /Chrome\//.test(navigator.userAgent);
36 var presto = /Opera\//.test(navigator.userAgent); 34 var presto = /Opera\//.test(navigator.userAgent);
37 var safari = /Apple Computer/.test(navigator.vendor); 35 var safari = /Apple Computer/.test(navigator.vendor);
38 var khtml = /KHTML\//.test(navigator.userAgent); 36 var khtml = /KHTML\//.test(navigator.userAgent);
39 var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAge nt); 37 var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAge nt);
40 var phantom = /PhantomJS/.test(navigator.userAgent); 38 var phantom = /PhantomJS/.test(navigator.userAgent);
41 39
42 var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(naviga tor.userAgent); 40 var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(naviga tor.userAgent);
43 // This is woefully incomplete. Suggestions for alternative methods welcome. 41 // This is woefully incomplete. Suggestions for alternative methods welcome.
44 var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i .test(navigator.userAgent); 42 var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i .test(navigator.userAgent);
45 var mac = ios || /Mac/.test(navigator.platform); 43 var mac = ios || /Mac/.test(navigator.platform);
46 var windows = /win/i.test(navigator.platform); 44 var windows = /win/i.test(navigator.platform);
47 45
48 var presto_version = presto && navigator.userAgent.match(/Version\/(\d*\.\d*)/ ); 46 var presto_version = presto && navigator.userAgent.match(/Version\/(\d*\.\d*)/ );
49 if (presto_version) presto_version = Number(presto_version[1]); 47 if (presto_version) presto_version = Number(presto_version[1]);
50 if (presto_version && presto_version >= 15) { presto = false; webkit = true; } 48 if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
51 // Some browsers use the wrong event properties to signal cmd/ctrl on OS X 49 // Some browsers use the wrong event properties to signal cmd/ctrl on OS X
52 var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || pre sto_version < 12.11)); 50 var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || pre sto_version < 12.11));
53 var captureRightClick = gecko || (ie && !ie_upto8); 51 var captureRightClick = gecko || (ie && ie_version >= 9);
54 52
55 // Optimize some code when these features are not used. 53 // Optimize some code when these features are not used.
56 var sawReadOnlySpans = false, sawCollapsedSpans = false; 54 var sawReadOnlySpans = false, sawCollapsedSpans = false;
57 55
58 // EDITOR CONSTRUCTOR 56 // EDITOR CONSTRUCTOR
59 57
60 // A CodeMirror instance represents an editor. This is the object 58 // A CodeMirror instance represents an editor. This is the object
61 // that user code is usually dealing with. 59 // that user code is usually dealing with.
62 60
63 function CodeMirror(place, options) { 61 function CodeMirror(place, options) {
(...skipping 22 matching lines...) Expand all
86 modeGen: 0, // bumped when mode/overlay changes, used to invalidate high lighting info 84 modeGen: 0, // bumped when mode/overlay changes, used to invalidate high lighting info
87 overwrite: false, focused: false, 85 overwrite: false, focused: false,
88 suppressEdits: false, // used to disable editing during key handlers when in readOnly mode 86 suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
89 pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edit s in readInput 87 pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edit s in readInput
90 draggingText: false, 88 draggingText: false,
91 highlight: new Delayed() // stores highlight worker timeout 89 highlight: new Delayed() // stores highlight worker timeout
92 }; 90 };
93 91
94 // Override magic textarea content restore that IE sometimes does 92 // Override magic textarea content restore that IE sometimes does
95 // on our hidden textarea on reload 93 // on our hidden textarea on reload
96 if (ie_upto10) setTimeout(bind(resetInput, this, true), 20); 94 if (ie && ie_version < 11) setTimeout(bind(resetInput, this, true), 20);
97 95
98 registerEventHandlers(this); 96 registerEventHandlers(this);
99 ensureGlobalHandlers(); 97 ensureGlobalHandlers();
100 98
101 var cm = this; 99 var cm = this;
102 runInOp(this, function() { 100 runInOp(this, function() {
103 cm.curOp.forceUpdate = true; 101 cm.curOp.forceUpdate = true;
104 attachDoc(cm, doc); 102 attachDoc(cm, doc);
105 103
106 if ((options.autofocus && !mobile) || activeElt() == display.input) 104 if ((options.autofocus && !mobile) || activeElt() == display.input)
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
170 d.gutters = elt("div", null, "CodeMirror-gutters"); 168 d.gutters = elt("div", null, "CodeMirror-gutters");
171 d.lineGutter = null; 169 d.lineGutter = null;
172 // Actual scrollable element. 170 // Actual scrollable element.
173 d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-sc roll"); 171 d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-sc roll");
174 d.scroller.setAttribute("tabIndex", "-1"); 172 d.scroller.setAttribute("tabIndex", "-1");
175 // The element in which the editor lives. 173 // The element in which the editor lives.
176 d.wrapper = elt("div", [d.inputDiv, d.scrollbarH, d.scrollbarV, 174 d.wrapper = elt("div", [d.inputDiv, d.scrollbarH, d.scrollbarV,
177 d.scrollbarFiller, d.gutterFiller, d.scroller], "Cod eMirror"); 175 d.scrollbarFiller, d.gutterFiller, d.scroller], "Cod eMirror");
178 176
179 // Work around IE7 z-index bug (not perfect, hence IE7 not really being supp orted) 177 // Work around IE7 z-index bug (not perfect, hence IE7 not really being supp orted)
180 if (ie_upto7) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; } 178 if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.pa ddingRight = 0; }
181 // Needed to hide big blue blinking cursor on Mobile Safari 179 // Needed to hide big blue blinking cursor on Mobile Safari
182 if (ios) input.style.width = "0px"; 180 if (ios) input.style.width = "0px";
183 if (!webkit) d.scroller.draggable = true; 181 if (!webkit) d.scroller.draggable = true;
184 // Needed to handle Tab key in KHTML 182 // Needed to handle Tab key in KHTML
185 if (khtml) { d.inputDiv.style.height = "1px"; d.inputDiv.style.position = "a bsolute"; } 183 if (khtml) { d.inputDiv.style.height = "1px"; d.inputDiv.style.position = "a bsolute"; }
186 // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8). 184 // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
187 if (ie_upto7) d.scrollbarH.style.minHeight = d.scrollbarV.style.minWidth = " 18px"; 185 if (ie && ie_version < 8) d.scrollbarH.style.minHeight = d.scrollbarV.style. minWidth = "18px";
188 186
189 if (place.appendChild) place.appendChild(d.wrapper); 187 if (place.appendChild) place.appendChild(d.wrapper);
190 else place(d.wrapper); 188 else place(d.wrapper);
191 189
192 // Current rendered range (may be bigger than the view window). 190 // Current rendered range (may be bigger than the view window).
193 d.viewFrom = d.viewTo = doc.first; 191 d.viewFrom = d.viewTo = doc.first;
194 // Information about the rendered lines. 192 // Information about the rendered lines.
195 d.view = []; 193 d.view = [];
196 // Holds info about a single rendered line when it was rendered 194 // Holds info about a single rendered line when it was rendered
197 // for measurement, while not in view. 195 // for measurement, while not in view.
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
387 if (found == -1 && options.lineNumbers) { 385 if (found == -1 && options.lineNumbers) {
388 options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]); 386 options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]);
389 } else if (found > -1 && !options.lineNumbers) { 387 } else if (found > -1 && !options.lineNumbers) {
390 options.gutters = options.gutters.slice(0); 388 options.gutters = options.gutters.slice(0);
391 options.gutters.splice(found, 1); 389 options.gutters.splice(found, 1);
392 } 390 }
393 } 391 }
394 392
395 // SCROLLBARS 393 // SCROLLBARS
396 394
395 function hScrollbarTakesSpace(cm) {
396 return cm.display.scroller.clientHeight - cm.display.wrapper.clientHeight < scrollerCutOff - 3;
397 }
398
397 // Prepare DOM reads needed to update the scrollbars. Done in one 399 // Prepare DOM reads needed to update the scrollbars. Done in one
398 // shot to minimize update/measure roundtrips. 400 // shot to minimize update/measure roundtrips.
399 function measureForScrollbars(cm) { 401 function measureForScrollbars(cm) {
400 var scroll = cm.display.scroller; 402 var scroll = cm.display.scroller;
401 return { 403 return {
402 clientHeight: scroll.clientHeight, 404 clientHeight: scroll.clientHeight,
403 barHeight: cm.display.scrollbarV.clientHeight, 405 barHeight: cm.display.scrollbarV.clientHeight,
404 scrollWidth: scroll.scrollWidth, clientWidth: scroll.clientWidth, 406 scrollWidth: scroll.scrollWidth, clientWidth: scroll.clientWidth,
407 hScrollbarTakesSpace: hScrollbarTakesSpace(cm),
405 barWidth: cm.display.scrollbarH.clientWidth, 408 barWidth: cm.display.scrollbarH.clientWidth,
406 docHeight: Math.round(cm.doc.height + paddingVert(cm.display)) 409 docHeight: Math.round(cm.doc.height + paddingVert(cm.display))
407 }; 410 };
408 } 411 }
409 412
410 // Re-synchronize the fake scrollbars with the actual size of the 413 // Re-synchronize the fake scrollbars with the actual size of the
411 // content. 414 // content.
412 function updateScrollbars(cm, measure) { 415 function updateScrollbars(cm, measure) {
413 if (!measure) measure = measureForScrollbars(cm); 416 if (!measure) measure = measureForScrollbars(cm);
414 var d = cm.display; 417 var d = cm.display, sWidth = scrollbarWidth(d.measure);
415 var scrollHeight = measure.docHeight + scrollerCutOff; 418 var scrollHeight = measure.docHeight + scrollerCutOff;
416 var needsH = measure.scrollWidth > measure.clientWidth; 419 var needsH = measure.scrollWidth > measure.clientWidth;
420 if (needsH && measure.scrollWidth <= measure.clientWidth + 1 &&
421 sWidth > 0 && !measure.hScrollbarTakesSpace)
422 needsH = false; // (Issue #2562)
417 var needsV = scrollHeight > measure.clientHeight; 423 var needsV = scrollHeight > measure.clientHeight;
424
418 if (needsV) { 425 if (needsV) {
419 d.scrollbarV.style.display = "block"; 426 d.scrollbarV.style.display = "block";
420 d.scrollbarV.style.bottom = needsH ? scrollbarWidth(d.measure) + "px" : "0 "; 427 d.scrollbarV.style.bottom = needsH ? sWidth + "px" : "0";
421 // A bug in IE8 can cause this value to be negative, so guard it. 428 // A bug in IE8 can cause this value to be negative, so guard it.
422 d.scrollbarV.firstChild.style.height = 429 d.scrollbarV.firstChild.style.height =
423 Math.max(0, scrollHeight - measure.clientHeight + (measure.barHeight || d.scrollbarV.clientHeight)) + "px"; 430 Math.max(0, scrollHeight - measure.clientHeight + (measure.barHeight || d.scrollbarV.clientHeight)) + "px";
424 } else { 431 } else {
425 d.scrollbarV.style.display = ""; 432 d.scrollbarV.style.display = "";
426 d.scrollbarV.firstChild.style.height = "0"; 433 d.scrollbarV.firstChild.style.height = "0";
427 } 434 }
428 if (needsH) { 435 if (needsH) {
429 d.scrollbarH.style.display = "block"; 436 d.scrollbarH.style.display = "block";
430 d.scrollbarH.style.right = needsV ? scrollbarWidth(d.measure) + "px" : "0" ; 437 d.scrollbarH.style.right = needsV ? sWidth + "px" : "0";
431 d.scrollbarH.firstChild.style.width = 438 d.scrollbarH.firstChild.style.width =
432 (measure.scrollWidth - measure.clientWidth + (measure.barWidth || d.scro llbarH.clientWidth)) + "px"; 439 (measure.scrollWidth - measure.clientWidth + (measure.barWidth || d.scro llbarH.clientWidth)) + "px";
433 } else { 440 } else {
434 d.scrollbarH.style.display = ""; 441 d.scrollbarH.style.display = "";
435 d.scrollbarH.firstChild.style.width = "0"; 442 d.scrollbarH.firstChild.style.width = "0";
436 } 443 }
437 if (needsH && needsV) { 444 if (needsH && needsV) {
438 d.scrollbarFiller.style.display = "block"; 445 d.scrollbarFiller.style.display = "block";
439 d.scrollbarFiller.style.height = d.scrollbarFiller.style.width = scrollbar Width(d.measure) + "px"; 446 d.scrollbarFiller.style.height = d.scrollbarFiller.style.width = sWidth + "px";
440 } else d.scrollbarFiller.style.display = ""; 447 } else d.scrollbarFiller.style.display = "";
441 if (needsH && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutte r) { 448 if (needsH && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutte r) {
442 d.gutterFiller.style.display = "block"; 449 d.gutterFiller.style.display = "block";
443 d.gutterFiller.style.height = scrollbarWidth(d.measure) + "px"; 450 d.gutterFiller.style.height = sWidth + "px";
444 d.gutterFiller.style.width = d.gutters.offsetWidth + "px"; 451 d.gutterFiller.style.width = d.gutters.offsetWidth + "px";
445 } else d.gutterFiller.style.display = ""; 452 } else d.gutterFiller.style.display = "";
446 453
447 if (!cm.state.checkedOverlayScrollbar && measure.clientHeight > 0) { 454 if (!cm.state.checkedOverlayScrollbar && measure.clientHeight > 0) {
448 if (scrollbarWidth(d.measure) === 0) { 455 if (sWidth === 0) {
449 var w = mac && !mac_geMountainLion ? "12px" : "18px"; 456 var w = mac && !mac_geMountainLion ? "12px" : "18px";
450 d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = w; 457 d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = w;
451 var barMouseDown = function(e) { 458 var barMouseDown = function(e) {
452 if (e_target(e) != d.scrollbarV && e_target(e) != d.scrollbarH) 459 if (e_target(e) != d.scrollbarV && e_target(e) != d.scrollbarH)
453 operation(cm, onMouseDown)(e); 460 operation(cm, onMouseDown)(e);
454 }; 461 };
455 on(d.scrollbarV, "mousedown", barMouseDown); 462 on(d.scrollbarV, "mousedown", barMouseDown);
456 on(d.scrollbarH, "mousedown", barMouseDown); 463 on(d.scrollbarH, "mousedown", barMouseDown);
457 } 464 }
458 cm.state.checkedOverlayScrollbar = true; 465 cm.state.checkedOverlayScrollbar = true;
(...skipping 13 matching lines...) Expand all
472 // forces those lines into the viewport (if possible). 479 // forces those lines into the viewport (if possible).
473 if (viewPort && viewPort.ensure) { 480 if (viewPort && viewPort.ensure) {
474 var ensureFrom = viewPort.ensure.from.line, ensureTo = viewPort.ensure.to. line; 481 var ensureFrom = viewPort.ensure.from.line, ensureTo = viewPort.ensure.to. line;
475 if (ensureFrom < from) 482 if (ensureFrom < from)
476 return {from: ensureFrom, 483 return {from: ensureFrom,
477 to: lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + d isplay.wrapper.clientHeight)}; 484 to: lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + d isplay.wrapper.clientHeight)};
478 if (Math.min(ensureTo, doc.lastLine()) >= to) 485 if (Math.min(ensureTo, doc.lastLine()) >= to)
479 return {from: lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - d isplay.wrapper.clientHeight), 486 return {from: lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - d isplay.wrapper.clientHeight),
480 to: ensureTo}; 487 to: ensureTo};
481 } 488 }
482 return {from: from, to: to}; 489 return {from: from, to: Math.max(to, from + 1)};
483 } 490 }
484 491
485 // LINE NUMBERS 492 // LINE NUMBERS
486 493
487 // Re-align line numbers and gutter marks to compensate for 494 // Re-align line numbers and gutter marks to compensate for
488 // horizontal scrolling. 495 // horizontal scrolling.
489 function alignHorizontally(cm) { 496 function alignHorizontally(cm) {
490 var display = cm.display, view = display.view; 497 var display = cm.display, view = display.view;
491 if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fix edGutter)) return; 498 if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fix edGutter)) return;
492 var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm. doc.scrollLeft; 499 var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm. doc.scrollLeft;
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
553 // and ensure the document's width matches it. 560 // and ensure the document's width matches it.
554 if (cm.display.maxLineChanged && !cm.options.lineWrapping) 561 if (cm.display.maxLineChanged && !cm.options.lineWrapping)
555 adjustContentWidth(cm); 562 adjustContentWidth(cm);
556 563
557 var barMeasure = measureForScrollbars(cm); 564 var barMeasure = measureForScrollbars(cm);
558 updateSelection(cm); 565 updateSelection(cm);
559 setDocumentHeight(cm, barMeasure); 566 setDocumentHeight(cm, barMeasure);
560 updateScrollbars(cm, barMeasure); 567 updateScrollbars(cm, barMeasure);
561 if (webkit && cm.options.lineWrapping) 568 if (webkit && cm.options.lineWrapping)
562 checkForWebkitWidthBug(cm, barMeasure); // (Issue #2420) 569 checkForWebkitWidthBug(cm, barMeasure); // (Issue #2420)
570 if (webkit && barMeasure.scrollWidth > barMeasure.clientWidth &&
571 barMeasure.scrollWidth < barMeasure.clientWidth + 1 &&
572 !hScrollbarTakesSpace(cm))
573 updateScrollbars(cm); // (Issue #2562)
563 if (first && cm.options.lineWrapping && oldWidth != cm.display.scroller.cl ientWidth) { 574 if (first && cm.options.lineWrapping && oldWidth != cm.display.scroller.cl ientWidth) {
564 forced = true; 575 forced = true;
565 continue; 576 continue;
566 } 577 }
567 forced = false; 578 forced = false;
568 579
569 // Clip forced viewport to actual scrollable area. 580 // Clip forced viewport to actual scrollable area.
570 if (viewPort && viewPort.top != null) 581 if (viewPort && viewPort.top != null)
571 viewPort = {top: Math.min(barMeasure.docHeight - scrollerCutOff - barMea sure.clientHeight, viewPort.top)}; 582 viewPort = {top: Math.min(barMeasure.docHeight - scrollerCutOff - barMea sure.clientHeight, viewPort.top)};
572 // Updated line heights might result in the drawn area not 583 // Updated line heights might result in the drawn area not
(...skipping 17 matching lines...) Expand all
590 // false. 601 // false.
591 function updateDisplayInner(cm, visible, forced) { 602 function updateDisplayInner(cm, visible, forced) {
592 var display = cm.display, doc = cm.doc; 603 var display = cm.display, doc = cm.doc;
593 if (!display.wrapper.offsetWidth) { 604 if (!display.wrapper.offsetWidth) {
594 resetView(cm); 605 resetView(cm);
595 return; 606 return;
596 } 607 }
597 608
598 // Bail out if the visible area is already rendered and nothing changed. 609 // Bail out if the visible area is already rendered and nothing changed.
599 if (!forced && visible.from >= display.viewFrom && visible.to <= display.vie wTo && 610 if (!forced && visible.from >= display.viewFrom && visible.to <= display.vie wTo &&
611 (display.updateLineNumbers == null || display.updateLineNumbers >= displ ay.viewTo) &&
600 countDirtyView(cm) == 0) 612 countDirtyView(cm) == 0)
601 return; 613 return;
602 614
603 if (maybeUpdateLineNumberWidth(cm)) 615 if (maybeUpdateLineNumberWidth(cm))
604 resetView(cm); 616 resetView(cm);
605 var dims = getDimensions(cm); 617 var dims = getDimensions(cm);
606 618
607 // Compute a suitable new viewport (from & to) 619 // Compute a suitable new viewport (from & to)
608 var end = doc.first + doc.size; 620 var end = doc.first + doc.size;
609 var from = Math.max(visible.from - cm.options.viewportMargin, doc.first); 621 var from = Math.max(visible.from - cm.options.viewportMargin, doc.first);
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
677 } 689 }
678 690
679 // Read the actual heights of the rendered lines, and update their 691 // Read the actual heights of the rendered lines, and update their
680 // stored heights to match. 692 // stored heights to match.
681 function updateHeightsInViewport(cm) { 693 function updateHeightsInViewport(cm) {
682 var display = cm.display; 694 var display = cm.display;
683 var prevBottom = display.lineDiv.offsetTop; 695 var prevBottom = display.lineDiv.offsetTop;
684 for (var i = 0; i < display.view.length; i++) { 696 for (var i = 0; i < display.view.length; i++) {
685 var cur = display.view[i], height; 697 var cur = display.view[i], height;
686 if (cur.hidden) continue; 698 if (cur.hidden) continue;
687 if (ie_upto7) { 699 if (ie && ie_version < 8) {
688 var bot = cur.node.offsetTop + cur.node.offsetHeight; 700 var bot = cur.node.offsetTop + cur.node.offsetHeight;
689 height = bot - prevBottom; 701 height = bot - prevBottom;
690 prevBottom = bot; 702 prevBottom = bot;
691 } else { 703 } else {
692 var box = cur.node.getBoundingClientRect(); 704 var box = cur.node.getBoundingClientRect();
693 height = box.bottom - box.top; 705 height = box.bottom - box.top;
694 } 706 }
695 var diff = cur.line.height - height; 707 var diff = cur.line.height - height;
696 if (height < 2) height = textHeight(display); 708 if (height < 2) height = textHeight(display);
697 if (diff > .001 || diff < -.001) { 709 if (diff > .001 || diff < -.001) {
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
786 } 798 }
787 799
788 // Lines with gutter elements, widgets or a background class need to 800 // Lines with gutter elements, widgets or a background class need to
789 // be wrapped, and have the extra elements added to the wrapper div 801 // be wrapped, and have the extra elements added to the wrapper div
790 function ensureLineWrapped(lineView) { 802 function ensureLineWrapped(lineView) {
791 if (lineView.node == lineView.text) { 803 if (lineView.node == lineView.text) {
792 lineView.node = elt("div", null, null, "position: relative"); 804 lineView.node = elt("div", null, null, "position: relative");
793 if (lineView.text.parentNode) 805 if (lineView.text.parentNode)
794 lineView.text.parentNode.replaceChild(lineView.node, lineView.text); 806 lineView.text.parentNode.replaceChild(lineView.node, lineView.text);
795 lineView.node.appendChild(lineView.text); 807 lineView.node.appendChild(lineView.text);
796 if (ie_upto7) lineView.node.style.zIndex = 2; 808 if (ie && ie_version < 8) lineView.node.style.zIndex = 2;
797 } 809 }
798 return lineView.node; 810 return lineView.node;
799 } 811 }
800 812
801 function updateLineBackground(lineView) { 813 function updateLineBackground(lineView) {
802 var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass; 814 var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass;
803 if (cls) cls += " CodeMirror-linebackground"; 815 if (cls) cls += " CodeMirror-linebackground";
804 if (lineView.background) { 816 if (lineView.background) {
805 if (cls) lineView.background.className = cls; 817 if (cls) lineView.background.className = cls;
806 else { lineView.background.parentNode.removeChild(lineView.background); li neView.background = null; } 818 else { lineView.background.parentNode.removeChild(lineView.background); li neView.background = null; }
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after
1142 // Set a new selection. 1154 // Set a new selection.
1143 function setSelection(doc, sel, options) { 1155 function setSelection(doc, sel, options) {
1144 setSelectionNoUndo(doc, sel, options); 1156 setSelectionNoUndo(doc, sel, options);
1145 addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options) ; 1157 addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options) ;
1146 } 1158 }
1147 1159
1148 function setSelectionNoUndo(doc, sel, options) { 1160 function setSelectionNoUndo(doc, sel, options) {
1149 if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange")) 1161 if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
1150 sel = filterSelectionChange(doc, sel); 1162 sel = filterSelectionChange(doc, sel);
1151 1163
1152 var bias = cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1; 1164 var bias = options && options.bias ||
1165 (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
1153 setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true)); 1166 setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));
1154 1167
1155 if (!(options && options.scroll === false) && doc.cm) 1168 if (!(options && options.scroll === false) && doc.cm)
1156 ensureCursorVisible(doc.cm); 1169 ensureCursorVisible(doc.cm);
1157 } 1170 }
1158 1171
1159 function setSelectionInner(doc, sel) { 1172 function setSelectionInner(doc, sel) {
1160 if (sel.equals(doc.sel)) return; 1173 if (sel.equals(doc.sel)) return;
1161 1174
1162 doc.sel = sel; 1175 doc.sel = sel;
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
1269 display.inputDiv.style.top = top + "px"; 1282 display.inputDiv.style.top = top + "px";
1270 display.inputDiv.style.left = left + "px"; 1283 display.inputDiv.style.left = left + "px";
1271 } 1284 }
1272 1285
1273 removeChildrenAndAdd(display.cursorDiv, curFragment); 1286 removeChildrenAndAdd(display.cursorDiv, curFragment);
1274 removeChildrenAndAdd(display.selectionDiv, selFragment); 1287 removeChildrenAndAdd(display.selectionDiv, selFragment);
1275 } 1288 }
1276 1289
1277 // Draws a cursor for the given range 1290 // Draws a cursor for the given range
1278 function drawSelectionCursor(cm, range, output) { 1291 function drawSelectionCursor(cm, range, output) {
1279 var pos = cursorCoords(cm, range.head, "div"); 1292 var pos = cursorCoords(cm, range.head, "div", null, null, !cm.options.single CursorHeightPerLine);
1280 1293
1281 var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor")); 1294 var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
1282 cursor.style.left = pos.left + "px"; 1295 cursor.style.left = pos.left + "px";
1283 cursor.style.top = pos.top + "px"; 1296 cursor.style.top = pos.top + "px";
1284 cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorH eight + "px"; 1297 cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorH eight + "px";
1285 1298
1286 if (pos.other) { 1299 if (pos.other) {
1287 // Secondary cursor, shown when on a 'jump' in bi-directional text 1300 // Secondary cursor, shown when on a 'jump' in bi-directional text
1288 var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-curs or CodeMirror-secondarycursor")); 1301 var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-curs or CodeMirror-secondarycursor"));
1289 otherCursor.style.display = ""; 1302 otherCursor.style.display = "";
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
1371 function restartBlink(cm) { 1384 function restartBlink(cm) {
1372 if (!cm.state.focused) return; 1385 if (!cm.state.focused) return;
1373 var display = cm.display; 1386 var display = cm.display;
1374 clearInterval(display.blinker); 1387 clearInterval(display.blinker);
1375 var on = true; 1388 var on = true;
1376 display.cursorDiv.style.visibility = ""; 1389 display.cursorDiv.style.visibility = "";
1377 if (cm.options.cursorBlinkRate > 0) 1390 if (cm.options.cursorBlinkRate > 0)
1378 display.blinker = setInterval(function() { 1391 display.blinker = setInterval(function() {
1379 display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; 1392 display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden";
1380 }, cm.options.cursorBlinkRate); 1393 }, cm.options.cursorBlinkRate);
1394 else if (cm.options.cursorBlinkRate < 0)
1395 display.cursorDiv.style.visibility = "hidden";
1381 } 1396 }
1382 1397
1383 // HIGHLIGHT WORKER 1398 // HIGHLIGHT WORKER
1384 1399
1385 function startWorker(cm, time) { 1400 function startWorker(cm, time) {
1386 if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo) 1401 if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo)
1387 cm.state.highlight.set(time, bind(highlightWorker, cm)); 1402 cm.state.highlight.set(time, bind(highlightWorker, cm));
1388 } 1403 }
1389 1404
1390 function highlightWorker(cm) { 1405 function highlightWorker(cm) {
1391 var doc = cm.doc; 1406 var doc = cm.doc;
1392 if (doc.frontier < doc.first) doc.frontier = doc.first; 1407 if (doc.frontier < doc.first) doc.frontier = doc.first;
1393 if (doc.frontier >= cm.display.viewTo) return; 1408 if (doc.frontier >= cm.display.viewTo) return;
1394 var end = +new Date + cm.options.workTime; 1409 var end = +new Date + cm.options.workTime;
1395 var state = copyState(doc.mode, getStateBefore(cm, doc.frontier)); 1410 var state = copyState(doc.mode, getStateBefore(cm, doc.frontier));
1396 1411
1397 runInOp(cm, function() { 1412 runInOp(cm, function() {
1398 doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 50 0), function(line) { 1413 doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 50 0), function(line) {
1399 if (doc.frontier >= cm.display.viewFrom) { // Visible 1414 if (doc.frontier >= cm.display.viewFrom) { // Visible
1400 var oldStyles = line.styles; 1415 var oldStyles = line.styles;
1401 var highlighted = highlightLine(cm, line, state, true); 1416 var highlighted = highlightLine(cm, line, state, true);
1402 line.styles = highlighted.styles; 1417 line.styles = highlighted.styles;
1403 if (highlighted.classes) line.styleClasses = highlighted.classes; 1418 var oldCls = line.styleClasses, newCls = highlighted.classes;
1404 else if (line.styleClasses) line.styleClasses = null; 1419 if (newCls) line.styleClasses = newCls;
1405 var ischange = !oldStyles || oldStyles.length != line.styles.length; 1420 else if (oldCls) line.styleClasses = null;
1421 var ischange = !oldStyles || oldStyles.length != line.styles.length ||
1422 oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bg Class || oldCls.textClass != newCls.textClass);
1406 for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldSt yles[i] != line.styles[i]; 1423 for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldSt yles[i] != line.styles[i];
1407 if (ischange) regLineChange(cm, doc.frontier, "text"); 1424 if (ischange) regLineChange(cm, doc.frontier, "text");
1408 line.stateAfter = copyState(doc.mode, state); 1425 line.stateAfter = copyState(doc.mode, state);
1409 } else { 1426 } else {
1410 processLine(cm, line.text, state); 1427 processLine(cm, line.text, state);
1411 line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : n ull; 1428 line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : n ull;
1412 } 1429 }
1413 ++doc.frontier; 1430 ++doc.frontier;
1414 if (+new Date > end) { 1431 if (+new Date > end) {
1415 startWorker(cm, cm.options.workDelay); 1432 startWorker(cm, cm.options.workDelay);
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
1551 var info = mapFromLineView(view, line, lineN); 1568 var info = mapFromLineView(view, line, lineN);
1552 return { 1569 return {
1553 line: line, view: view, rect: null, 1570 line: line, view: view, rect: null,
1554 map: info.map, cache: info.cache, before: info.before, 1571 map: info.map, cache: info.cache, before: info.before,
1555 hasHeights: false 1572 hasHeights: false
1556 }; 1573 };
1557 } 1574 }
1558 1575
1559 // Given a prepared measurement object, measures the position of an 1576 // Given a prepared measurement object, measures the position of an
1560 // actual character (or fetches it from the cache). 1577 // actual character (or fetches it from the cache).
1561 function measureCharPrepared(cm, prepared, ch, bias) { 1578 function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
1562 if (prepared.before) ch = -1; 1579 if (prepared.before) ch = -1;
1563 var key = ch + (bias || ""), found; 1580 var key = ch + (bias || ""), found;
1564 if (prepared.cache.hasOwnProperty(key)) { 1581 if (prepared.cache.hasOwnProperty(key)) {
1565 found = prepared.cache[key]; 1582 found = prepared.cache[key];
1566 } else { 1583 } else {
1567 if (!prepared.rect) 1584 if (!prepared.rect)
1568 prepared.rect = prepared.view.text.getBoundingClientRect(); 1585 prepared.rect = prepared.view.text.getBoundingClientRect();
1569 if (!prepared.hasHeights) { 1586 if (!prepared.hasHeights) {
1570 ensureLineHeights(cm, prepared.view, prepared.rect); 1587 ensureLineHeights(cm, prepared.view, prepared.rect);
1571 prepared.hasHeights = true; 1588 prepared.hasHeights = true;
1572 } 1589 }
1573 found = measureCharInner(cm, prepared, ch, bias); 1590 found = measureCharInner(cm, prepared, ch, bias);
1574 if (!found.bogus) prepared.cache[key] = found; 1591 if (!found.bogus) prepared.cache[key] = found;
1575 } 1592 }
1576 return {left: found.left, right: found.right, top: found.top, bottom: found. bottom}; 1593 return {left: found.left, right: found.right,
1594 top: varHeight ? found.rtop : found.top,
1595 bottom: varHeight ? found.rbottom : found.bottom};
1577 } 1596 }
1578 1597
1579 var nullRect = {left: 0, right: 0, top: 0, bottom: 0}; 1598 var nullRect = {left: 0, right: 0, top: 0, bottom: 0};
1580 1599
1581 function measureCharInner(cm, prepared, ch, bias) { 1600 function measureCharInner(cm, prepared, ch, bias) {
1582 var map = prepared.map; 1601 var map = prepared.map;
1583 1602
1584 var node, start, end, collapse; 1603 var node, start, end, collapse;
1585 // First, search the line map for the text node corresponding to, 1604 // First, search the line map for the text node corresponding to,
1586 // or closest to, the target character. 1605 // or closest to, the target character.
(...skipping 25 matching lines...) Expand all
1612 collapse = "right"; 1631 collapse = "right";
1613 } 1632 }
1614 break; 1633 break;
1615 } 1634 }
1616 } 1635 }
1617 1636
1618 var rect; 1637 var rect;
1619 if (node.nodeType == 3) { // If it is a text node, use a range to retrieve t he coordinates. 1638 if (node.nodeType == 3) { // If it is a text node, use a range to retrieve t he coordinates.
1620 while (start && isExtendingChar(prepared.line.text.charAt(mStart + start)) ) --start; 1639 while (start && isExtendingChar(prepared.line.text.charAt(mStart + start)) ) --start;
1621 while (mStart + end < mEnd && isExtendingChar(prepared.line.text.charAt(mS tart + end))) ++end; 1640 while (mStart + end < mEnd && isExtendingChar(prepared.line.text.charAt(mS tart + end))) ++end;
1622 if (ie_upto8 && start == 0 && end == mEnd - mStart) { 1641 if (ie && ie_version < 9 && start == 0 && end == mEnd - mStart) {
1623 rect = node.parentNode.getBoundingClientRect(); 1642 rect = node.parentNode.getBoundingClientRect();
1624 } else if (ie && cm.options.lineWrapping) { 1643 } else if (ie && cm.options.lineWrapping) {
1625 var rects = range(node, start, end).getClientRects(); 1644 var rects = range(node, start, end).getClientRects();
1626 if (rects.length) 1645 if (rects.length)
1627 rect = rects[bias == "right" ? rects.length - 1 : 0]; 1646 rect = rects[bias == "right" ? rects.length - 1 : 0];
1628 else 1647 else
1629 rect = nullRect; 1648 rect = nullRect;
1630 } else { 1649 } else {
1631 rect = range(node, start, end).getBoundingClientRect() || nullRect; 1650 rect = range(node, start, end).getBoundingClientRect() || nullRect;
1632 } 1651 }
1633 } else { // If it is a widget, simply get the box for the whole widget. 1652 } else { // If it is a widget, simply get the box for the whole widget.
1634 if (start > 0) collapse = bias = "right"; 1653 if (start > 0) collapse = bias = "right";
1635 var rects; 1654 var rects;
1636 if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1) 1655 if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)
1637 rect = rects[bias == "right" ? rects.length - 1 : 0]; 1656 rect = rects[bias == "right" ? rects.length - 1 : 0];
1638 else 1657 else
1639 rect = node.getBoundingClientRect(); 1658 rect = node.getBoundingClientRect();
1640 } 1659 }
1641 if (ie_upto8 && !start && (!rect || !rect.left && !rect.right)) { 1660 if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {
1642 var rSpan = node.parentNode.getClientRects()[0]; 1661 var rSpan = node.parentNode.getClientRects()[0];
1643 if (rSpan) 1662 if (rSpan)
1644 rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top : rSpan.top, bottom: rSpan.bottom}; 1663 rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top : rSpan.top, bottom: rSpan.bottom};
1645 else 1664 else
1646 rect = nullRect; 1665 rect = nullRect;
1647 } 1666 }
1648 1667
1649 var top, bot = (rect.bottom + rect.top) / 2 - prepared.rect.top; 1668 var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect. top;
1669 var mid = (rtop + rbot) / 2;
1650 var heights = prepared.view.measure.heights; 1670 var heights = prepared.view.measure.heights;
1651 for (var i = 0; i < heights.length - 1; i++) 1671 for (var i = 0; i < heights.length - 1; i++)
1652 if (bot < heights[i]) break; 1672 if (mid < heights[i]) break;
1653 top = i ? heights[i - 1] : 0; bot = heights[i]; 1673 var top = i ? heights[i - 1] : 0, bot = heights[i];
1654 var result = {left: (collapse == "right" ? rect.right : rect.left) - prepare d.rect.left, 1674 var result = {left: (collapse == "right" ? rect.right : rect.left) - prepare d.rect.left,
1655 right: (collapse == "left" ? rect.left : rect.right) - prepare d.rect.left, 1675 right: (collapse == "left" ? rect.left : rect.right) - prepare d.rect.left,
1656 top: top, bottom: bot}; 1676 top: top, bottom: bot};
1657 if (!rect.left && !rect.right) result.bogus = true; 1677 if (!rect.left && !rect.right) result.bogus = true;
1678 if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbot tom = rbot; }
1658 return result; 1679 return result;
1659 } 1680 }
1660 1681
1661 function clearLineMeasurementCacheFor(lineView) { 1682 function clearLineMeasurementCacheFor(lineView) {
1662 if (lineView.measure) { 1683 if (lineView.measure) {
1663 lineView.measure.cache = {}; 1684 lineView.measure.cache = {};
1664 lineView.measure.heights = null; 1685 lineView.measure.heights = null;
1665 if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) 1686 if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)
1666 lineView.measure.caches[i] = {}; 1687 lineView.measure.caches[i] = {};
1667 } 1688 }
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
1727 } 1748 }
1728 1749
1729 function charCoords(cm, pos, context, lineObj, bias) { 1750 function charCoords(cm, pos, context, lineObj, bias) {
1730 if (!lineObj) lineObj = getLine(cm.doc, pos.line); 1751 if (!lineObj) lineObj = getLine(cm.doc, pos.line);
1731 return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context); 1752 return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context);
1732 } 1753 }
1733 1754
1734 // Returns a box for a given cursor position, which may have an 1755 // Returns a box for a given cursor position, which may have an
1735 // 'other' property containing the position of the secondary cursor 1756 // 'other' property containing the position of the secondary cursor
1736 // on a bidi boundary. 1757 // on a bidi boundary.
1737 function cursorCoords(cm, pos, context, lineObj, preparedMeasure) { 1758 function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
1738 lineObj = lineObj || getLine(cm.doc, pos.line); 1759 lineObj = lineObj || getLine(cm.doc, pos.line);
1739 if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj); 1760 if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj);
1740 function get(ch, right) { 1761 function get(ch, right) {
1741 var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "le ft"); 1762 var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "le ft", varHeight);
1742 if (right) m.left = m.right; else m.right = m.left; 1763 if (right) m.left = m.right; else m.right = m.left;
1743 return intoCoordSystem(cm, lineObj, m, context); 1764 return intoCoordSystem(cm, lineObj, m, context);
1744 } 1765 }
1745 function getBidi(ch, partPos) { 1766 function getBidi(ch, partPos) {
1746 var part = order[partPos], right = part.level % 2; 1767 var part = order[partPos], right = part.level % 2;
1747 if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].lev el) { 1768 if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].lev el) {
1748 part = order[--partPos]; 1769 part = order[--partPos];
1749 ch = bidiRight(part) - (part.level % 2 ? 0 : 1); 1770 ch = bidiRight(part) - (part.level % 2 ? 0 : 1);
1750 right = true; 1771 right = true;
1751 } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.lev el < order[partPos + 1].level) { 1772 } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.lev el < order[partPos + 1].level) {
(...skipping 490 matching lines...) Expand 10 before | Expand all | Expand 10 after
2242 return false; 2263 return false;
2243 // See paste handler for more on the fakedLastChar kludge 2264 // See paste handler for more on the fakedLastChar kludge
2244 if (cm.state.pasteIncoming && cm.state.fakedLastChar) { 2265 if (cm.state.pasteIncoming && cm.state.fakedLastChar) {
2245 input.value = input.value.substring(0, input.value.length - 1); 2266 input.value = input.value.substring(0, input.value.length - 1);
2246 cm.state.fakedLastChar = false; 2267 cm.state.fakedLastChar = false;
2247 } 2268 }
2248 var text = input.value; 2269 var text = input.value;
2249 // If nothing changed, bail. 2270 // If nothing changed, bail.
2250 if (text == prevInput && !cm.somethingSelected()) return false; 2271 if (text == prevInput && !cm.somethingSelected()) return false;
2251 // Work around nonsensical selection resetting in IE9/10 2272 // Work around nonsensical selection resetting in IE9/10
2252 if (ie && !ie_upto8 && cm.display.inputHasSelection === text) { 2273 if (ie && ie_version >= 9 && cm.display.inputHasSelection === text) {
2253 resetInput(cm); 2274 resetInput(cm);
2254 return false; 2275 return false;
2255 } 2276 }
2256 2277
2257 var withOp = !cm.curOp; 2278 var withOp = !cm.curOp;
2258 if (withOp) startOperation(cm); 2279 if (withOp) startOperation(cm);
2259 cm.display.shift = false; 2280 cm.display.shift = false;
2260 2281
2261 if (text.charCodeAt(0) == 0x200b && doc.sel == cm.display.selForContextMenu && !prevInput) 2282 if (text.charCodeAt(0) == 0x200b && doc.sel == cm.display.selForContextMenu && !prevInput)
2262 prevInput = "\u200b"; 2283 prevInput = "\u200b";
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
2318 function resetInput(cm, typing) { 2339 function resetInput(cm, typing) {
2319 var minimal, selected, doc = cm.doc; 2340 var minimal, selected, doc = cm.doc;
2320 if (cm.somethingSelected()) { 2341 if (cm.somethingSelected()) {
2321 cm.display.prevInput = ""; 2342 cm.display.prevInput = "";
2322 var range = doc.sel.primary(); 2343 var range = doc.sel.primary();
2323 minimal = hasCopyEvent && 2344 minimal = hasCopyEvent &&
2324 (range.to().line - range.from().line > 100 || (selected = cm.getSelectio n()).length > 1000); 2345 (range.to().line - range.from().line > 100 || (selected = cm.getSelectio n()).length > 1000);
2325 var content = minimal ? "-" : selected || cm.getSelection(); 2346 var content = minimal ? "-" : selected || cm.getSelection();
2326 cm.display.input.value = content; 2347 cm.display.input.value = content;
2327 if (cm.state.focused) selectInput(cm.display.input); 2348 if (cm.state.focused) selectInput(cm.display.input);
2328 if (ie && !ie_upto8) cm.display.inputHasSelection = content; 2349 if (ie && ie_version >= 9) cm.display.inputHasSelection = content;
2329 } else if (!typing) { 2350 } else if (!typing) {
2330 cm.display.prevInput = cm.display.input.value = ""; 2351 cm.display.prevInput = cm.display.input.value = "";
2331 if (ie && !ie_upto8) cm.display.inputHasSelection = null; 2352 if (ie && ie_version >= 9) cm.display.inputHasSelection = null;
2332 } 2353 }
2333 cm.display.inaccurateSelection = minimal; 2354 cm.display.inaccurateSelection = minimal;
2334 } 2355 }
2335 2356
2336 function focusInput(cm) { 2357 function focusInput(cm) {
2337 if (cm.options.readOnly != "nocursor" && (!mobile || activeElt() != cm.displ ay.input)) 2358 if (cm.options.readOnly != "nocursor" && (!mobile || activeElt() != cm.displ ay.input))
2338 cm.display.input.focus(); 2359 cm.display.input.focus();
2339 } 2360 }
2340 2361
2341 function ensureFocus(cm) { 2362 function ensureFocus(cm) {
2342 if (!cm.state.focused) { focusInput(cm); onFocus(cm); } 2363 if (!cm.state.focused) { focusInput(cm); onFocus(cm); }
2343 } 2364 }
2344 2365
2345 function isReadOnly(cm) { 2366 function isReadOnly(cm) {
2346 return cm.options.readOnly || cm.doc.cantEdit; 2367 return cm.options.readOnly || cm.doc.cantEdit;
2347 } 2368 }
2348 2369
2349 // EVENT HANDLERS 2370 // EVENT HANDLERS
2350 2371
2351 // Attach the necessary event handlers when initializing the editor 2372 // Attach the necessary event handlers when initializing the editor
2352 function registerEventHandlers(cm) { 2373 function registerEventHandlers(cm) {
2353 var d = cm.display; 2374 var d = cm.display;
2354 on(d.scroller, "mousedown", operation(cm, onMouseDown)); 2375 on(d.scroller, "mousedown", operation(cm, onMouseDown));
2355 // Older IE's will not fire a second mousedown for a double click 2376 // Older IE's will not fire a second mousedown for a double click
2356 if (ie_upto10) 2377 if (ie && ie_version < 11)
2357 on(d.scroller, "dblclick", operation(cm, function(e) { 2378 on(d.scroller, "dblclick", operation(cm, function(e) {
2358 if (signalDOMEvent(cm, e)) return; 2379 if (signalDOMEvent(cm, e)) return;
2359 var pos = posFromMouse(cm, e); 2380 var pos = posFromMouse(cm, e);
2360 if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return ; 2381 if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return ;
2361 e_preventDefault(e); 2382 e_preventDefault(e);
2362 var word = findWordAt(cm, pos); 2383 var word = findWordAt(cm, pos);
2363 extendSelection(cm.doc, word.anchor, word.head); 2384 extendSelection(cm.doc, word.anchor, word.head);
2364 })); 2385 }));
2365 else 2386 else
2366 on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preven tDefault(e); }); 2387 on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preven tDefault(e); });
(...skipping 28 matching lines...) Expand all
2395 2416
2396 // Prevent clicks in the scrollbars from killing focus 2417 // Prevent clicks in the scrollbars from killing focus
2397 function reFocus() { if (cm.state.focused) setTimeout(bind(focusInput, cm), 0); } 2418 function reFocus() { if (cm.state.focused) setTimeout(bind(focusInput, cm), 0); }
2398 on(d.scrollbarH, "mousedown", reFocus); 2419 on(d.scrollbarH, "mousedown", reFocus);
2399 on(d.scrollbarV, "mousedown", reFocus); 2420 on(d.scrollbarV, "mousedown", reFocus);
2400 // Prevent wrapper from ever scrolling 2421 // Prevent wrapper from ever scrolling
2401 on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollL eft = 0; }); 2422 on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollL eft = 0; });
2402 2423
2403 on(d.input, "keyup", operation(cm, onKeyUp)); 2424 on(d.input, "keyup", operation(cm, onKeyUp));
2404 on(d.input, "input", function() { 2425 on(d.input, "input", function() {
2405 if (ie && !ie_upto8 && cm.display.inputHasSelection) cm.display.inputHasSe lection = null; 2426 if (ie && ie_version >= 9 && cm.display.inputHasSelection) cm.display.inpu tHasSelection = null;
2406 fastPoll(cm); 2427 fastPoll(cm);
2407 }); 2428 });
2408 on(d.input, "keydown", operation(cm, onKeyDown)); 2429 on(d.input, "keydown", operation(cm, onKeyDown));
2409 on(d.input, "keypress", operation(cm, onKeyPress)); 2430 on(d.input, "keypress", operation(cm, onKeyPress));
2410 on(d.input, "focus", bind(onFocus, cm)); 2431 on(d.input, "focus", bind(onFocus, cm));
2411 on(d.input, "blur", bind(onBlur, cm)); 2432 on(d.input, "blur", bind(onBlur, cm));
2412 2433
2413 function drag_(e) { 2434 function drag_(e) {
2414 if (!signalDOMEvent(cm, e)) e_stop(e); 2435 if (!signalDOMEvent(cm, e)) e_stop(e);
2415 } 2436 }
2416 if (cm.options.dragDrop) { 2437 if (cm.options.dragDrop) {
2417 on(d.scroller, "dragstart", function(e){onDragStart(cm, e);}); 2438 on(d.scroller, "dragstart", function(e){onDragStart(cm, e);});
2418 on(d.scroller, "dragenter", drag_); 2439 on(d.scroller, "dragenter", drag_);
2419 on(d.scroller, "dragover", drag_); 2440 on(d.scroller, "dragover", drag_);
2420 on(d.scroller, "drop", operation(cm, onDrop)); 2441 on(d.scroller, "drop", operation(cm, onDrop));
2421 } 2442 }
2422 on(d.scroller, "paste", function(e) { 2443 on(d.scroller, "paste", function(e) {
2423 if (eventInWidget(d, e)) return; 2444 if (eventInWidget(d, e)) return;
2424 cm.state.pasteIncoming = true; 2445 cm.state.pasteIncoming = true;
2425 focusInput(cm); 2446 focusInput(cm);
2426 fastPoll(cm); 2447 fastPoll(cm);
2427 }); 2448 });
2428 on(d.input, "paste", function() { 2449 on(d.input, "paste", function() {
2429 // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206 2450 // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206
2430 // Add a char to the end of textarea before paste occur so that 2451 // Add a char to the end of textarea before paste occur so that
2431 // selection doesn't span to the end of textarea. 2452 // selection doesn't span to the end of textarea.
2432 if (webkit && !cm.state.fakedLastChar && !(new Date - cm.state.lastMiddleD own < 200)) { 2453 if (webkit && !cm.state.fakedLastChar && !(new Date - cm.state.lastMiddleD own < 200)) {
2433 var start = d.input.selectionStart, end = d.input.selectionEnd; 2454 var start = d.input.selectionStart, end = d.input.selectionEnd;
2434 d.input.value += "$"; 2455 d.input.value += "$";
2456 // The selection end needs to be set before the start, otherwise there
2457 // can be an intermediate non-empty selection between the two, which
2458 // can override the middle-click paste buffer on linux and cause the
2459 // wrong thing to get pasted.
2460 d.input.selectionEnd = end;
2435 d.input.selectionStart = start; 2461 d.input.selectionStart = start;
2436 d.input.selectionEnd = end;
2437 cm.state.fakedLastChar = true; 2462 cm.state.fakedLastChar = true;
2438 } 2463 }
2439 cm.state.pasteIncoming = true; 2464 cm.state.pasteIncoming = true;
2440 fastPoll(cm); 2465 fastPoll(cm);
2441 }); 2466 });
2442 2467
2443 function prepareCopyCut(e) { 2468 function prepareCopyCut(e) {
2444 if (cm.somethingSelected()) { 2469 if (cm.somethingSelected()) {
2445 if (d.inaccurateSelection) { 2470 if (d.inaccurateSelection) {
2446 d.prevInput = ""; 2471 d.prevInput = "";
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
2567 if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleCli ck.pos, start) == 0) { 2592 if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleCli ck.pos, start) == 0) {
2568 type = "triple"; 2593 type = "triple";
2569 } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, sta rt) == 0) { 2594 } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, sta rt) == 0) {
2570 type = "double"; 2595 type = "double";
2571 lastDoubleClick = {time: now, pos: start}; 2596 lastDoubleClick = {time: now, pos: start};
2572 } else { 2597 } else {
2573 type = "single"; 2598 type = "single";
2574 lastClick = {time: now, pos: start}; 2599 lastClick = {time: now, pos: start};
2575 } 2600 }
2576 2601
2577 var sel = cm.doc.sel, addNew = mac ? e.metaKey : e.ctrlKey; 2602 var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey;
2578 if (cm.options.dragDrop && dragAndDrop && !addNew && !isReadOnly(cm) && 2603 if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) &&
2579 type == "single" && sel.contains(start) > -1 && sel.somethingSelected()) 2604 type == "single" && sel.contains(start) > -1 && sel.somethingSelected())
2580 leftButtonStartDrag(cm, e, start); 2605 leftButtonStartDrag(cm, e, start, modifier);
2581 else 2606 else
2582 leftButtonSelect(cm, e, start, type, addNew); 2607 leftButtonSelect(cm, e, start, type, modifier);
2583 } 2608 }
2584 2609
2585 // Start a text drag. When it ends, see if any dragging actually 2610 // Start a text drag. When it ends, see if any dragging actually
2586 // happen, and treat as a click if it didn't. 2611 // happen, and treat as a click if it didn't.
2587 function leftButtonStartDrag(cm, e, start) { 2612 function leftButtonStartDrag(cm, e, start, modifier) {
2588 var display = cm.display; 2613 var display = cm.display;
2589 var dragEnd = operation(cm, function(e2) { 2614 var dragEnd = operation(cm, function(e2) {
2590 if (webkit) display.scroller.draggable = false; 2615 if (webkit) display.scroller.draggable = false;
2591 cm.state.draggingText = false; 2616 cm.state.draggingText = false;
2592 off(document, "mouseup", dragEnd); 2617 off(document, "mouseup", dragEnd);
2593 off(display.scroller, "drop", dragEnd); 2618 off(display.scroller, "drop", dragEnd);
2594 if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) { 2619 if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
2595 e_preventDefault(e2); 2620 e_preventDefault(e2);
2596 extendSelection(cm.doc, start); 2621 if (!modifier)
2622 extendSelection(cm.doc, start);
2597 focusInput(cm); 2623 focusInput(cm);
2598 // Work around unexplainable focus problem in IE9 (#2127) 2624 // Work around unexplainable focus problem in IE9 (#2127)
2599 if (ie_upto10 && !ie_upto8) 2625 if (ie && ie_version == 9)
2600 setTimeout(function() {document.body.focus(); focusInput(cm);}, 20); 2626 setTimeout(function() {document.body.focus(); focusInput(cm);}, 20);
2601 } 2627 }
2602 }); 2628 });
2603 // Let the drag handler handle this. 2629 // Let the drag handler handle this.
2604 if (webkit) display.scroller.draggable = true; 2630 if (webkit) display.scroller.draggable = true;
2605 cm.state.draggingText = dragEnd; 2631 cm.state.draggingText = dragEnd;
2606 // IE's approach to draggable 2632 // IE's approach to draggable
2607 if (display.scroller.dragDrop) display.scroller.dragDrop(); 2633 if (display.scroller.dragDrop) display.scroller.dragDrop();
2608 on(document, "mouseup", dragEnd); 2634 on(document, "mouseup", dragEnd);
2609 on(display.scroller, "drop", dragEnd); 2635 on(display.scroller, "drop", dragEnd);
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
2732 function done(e) { 2758 function done(e) {
2733 counter = Infinity; 2759 counter = Infinity;
2734 e_preventDefault(e); 2760 e_preventDefault(e);
2735 focusInput(cm); 2761 focusInput(cm);
2736 off(document, "mousemove", move); 2762 off(document, "mousemove", move);
2737 off(document, "mouseup", up); 2763 off(document, "mouseup", up);
2738 doc.history.lastSelOrigin = null; 2764 doc.history.lastSelOrigin = null;
2739 } 2765 }
2740 2766
2741 var move = operation(cm, function(e) { 2767 var move = operation(cm, function(e) {
2742 if ((ie && !ie_upto9) ? !e.buttons : !e_button(e)) done(e); 2768 if (!e_button(e)) done(e);
2743 else extend(e); 2769 else extend(e);
2744 }); 2770 });
2745 var up = operation(cm, done); 2771 var up = operation(cm, done);
2746 on(document, "mousemove", move); 2772 on(document, "mousemove", move);
2747 on(document, "mouseup", up); 2773 on(document, "mouseup", up);
2748 } 2774 }
2749 2775
2750 // Determines whether an event happened in the gutter, and fires the 2776 // Determines whether an event happened in the gutter, and fires the
2751 // handlers for the corresponding event. 2777 // handlers for the corresponding event.
2752 function gutterEvent(cm, e, type, prevent, signalfn) { 2778 function gutterEvent(cm, e, type, prevent, signalfn) {
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
2810 // Don't do a replace if the drop happened inside of the selected text. 2836 // Don't do a replace if the drop happened inside of the selected text.
2811 if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) { 2837 if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
2812 cm.state.draggingText(e); 2838 cm.state.draggingText(e);
2813 // Ensure the editor is re-focused 2839 // Ensure the editor is re-focused
2814 setTimeout(bind(focusInput, cm), 20); 2840 setTimeout(bind(focusInput, cm), 20);
2815 return; 2841 return;
2816 } 2842 }
2817 try { 2843 try {
2818 var text = e.dataTransfer.getData("Text"); 2844 var text = e.dataTransfer.getData("Text");
2819 if (text) { 2845 if (text) {
2820 var selected = cm.state.draggingText && cm.listSelections(); 2846 if (cm.state.draggingText && !(mac ? e.metaKey : e.ctrlKey))
2847 var selected = cm.listSelections();
2821 setSelectionNoUndo(cm.doc, simpleSelection(pos, pos)); 2848 setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));
2822 if (selected) for (var i = 0; i < selected.length; ++i) 2849 if (selected) for (var i = 0; i < selected.length; ++i)
2823 replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag "); 2850 replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag ");
2824 cm.replaceSelection(text, "around", "paste"); 2851 cm.replaceSelection(text, "around", "paste");
2825 focusInput(cm); 2852 focusInput(cm);
2826 } 2853 }
2827 } 2854 }
2828 catch(e){} 2855 catch(e){}
2829 } 2856 }
2830 } 2857 }
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after
3048 } 3075 }
3049 return handled; 3076 return handled;
3050 } 3077 }
3051 3078
3052 var lastStoppedKey = null; 3079 var lastStoppedKey = null;
3053 function onKeyDown(e) { 3080 function onKeyDown(e) {
3054 var cm = this; 3081 var cm = this;
3055 ensureFocus(cm); 3082 ensureFocus(cm);
3056 if (signalDOMEvent(cm, e)) return; 3083 if (signalDOMEvent(cm, e)) return;
3057 // IE does strange things with escape. 3084 // IE does strange things with escape.
3058 if (ie_upto10 && e.keyCode == 27) e.returnValue = false; 3085 if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false;
3059 var code = e.keyCode; 3086 var code = e.keyCode;
3060 cm.display.shift = code == 16 || e.shiftKey; 3087 cm.display.shift = code == 16 || e.shiftKey;
3061 var handled = handleKeyBinding(cm, e); 3088 var handled = handleKeyBinding(cm, e);
3062 if (presto) { 3089 if (presto) {
3063 lastStoppedKey = handled ? code : null; 3090 lastStoppedKey = handled ? code : null;
3064 // Opera has no cut event... we try to at least catch the key combo 3091 // Opera has no cut event... we try to at least catch the key combo
3065 if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKe y)) 3092 if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKe y))
3066 cm.replaceSelection("", null, "cut"); 3093 cm.replaceSelection("", null, "cut");
3067 } 3094 }
3068 3095
(...skipping 17 matching lines...) Expand all
3086 on(document, "mouseover", up); 3113 on(document, "mouseover", up);
3087 } 3114 }
3088 3115
3089 function onKeyUp(e) { 3116 function onKeyUp(e) {
3090 if (signalDOMEvent(this, e)) return; 3117 if (signalDOMEvent(this, e)) return;
3091 if (e.keyCode == 16) this.doc.sel.shift = false; 3118 if (e.keyCode == 16) this.doc.sel.shift = false;
3092 } 3119 }
3093 3120
3094 function onKeyPress(e) { 3121 function onKeyPress(e) {
3095 var cm = this; 3122 var cm = this;
3096 if (signalDOMEvent(cm, e)) return; 3123 if (signalDOMEvent(cm, e) || e.ctrlKey || mac && e.metaKey) return;
3097 var keyCode = e.keyCode, charCode = e.charCode; 3124 var keyCode = e.keyCode, charCode = e.charCode;
3098 if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDe fault(e); return;} 3125 if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDe fault(e); return;}
3099 if (((presto && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(cm , e)) return; 3126 if (((presto && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(cm , e)) return;
3100 var ch = String.fromCharCode(charCode == null ? keyCode : charCode); 3127 var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
3101 if (handleCharBinding(cm, e, ch)) return; 3128 if (handleCharBinding(cm, e, ch)) return;
3102 if (ie && !ie_upto8) cm.display.inputHasSelection = null; 3129 if (ie && ie_version >= 9) cm.display.inputHasSelection = null;
3103 fastPoll(cm); 3130 fastPoll(cm);
3104 } 3131 }
3105 3132
3106 // FOCUS/BLUR EVENTS 3133 // FOCUS/BLUR EVENTS
3107 3134
3108 function onFocus(cm) { 3135 function onFocus(cm) {
3109 if (cm.options.readOnly == "nocursor") return; 3136 if (cm.options.readOnly == "nocursor") return;
3110 if (!cm.state.focused) { 3137 if (!cm.state.focused) {
3111 signal(cm, "focus", cm); 3138 signal(cm, "focus", cm);
3112 cm.state.focused = true; 3139 cm.state.focused = true;
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
3166 3193
3167 // Select-all will be greyed out if there's nothing to select, so 3194 // Select-all will be greyed out if there's nothing to select, so
3168 // this adds a zero-width space so that we can later check whether 3195 // this adds a zero-width space so that we can later check whether
3169 // it got selected. 3196 // it got selected.
3170 function prepareSelectAllHack() { 3197 function prepareSelectAllHack() {
3171 if (display.input.selectionStart != null) { 3198 if (display.input.selectionStart != null) {
3172 var selected = cm.somethingSelected(); 3199 var selected = cm.somethingSelected();
3173 var extval = display.input.value = "\u200b" + (selected ? display.input. value : ""); 3200 var extval = display.input.value = "\u200b" + (selected ? display.input. value : "");
3174 display.prevInput = selected ? "" : "\u200b"; 3201 display.prevInput = selected ? "" : "\u200b";
3175 display.input.selectionStart = 1; display.input.selectionEnd = extval.le ngth; 3202 display.input.selectionStart = 1; display.input.selectionEnd = extval.le ngth;
3203 // Re-set this, in case some other handler touched the
3204 // selection in the meantime.
3205 display.selForContextMenu = cm.doc.sel;
3176 } 3206 }
3177 } 3207 }
3178 function rehide() { 3208 function rehide() {
3179 display.inputDiv.style.position = "relative"; 3209 display.inputDiv.style.position = "relative";
3180 display.input.style.cssText = oldCSS; 3210 display.input.style.cssText = oldCSS;
3181 if (ie_upto8) display.scrollbarV.scrollTop = display.scroller.scrollTop = scrollPos; 3211 if (ie && ie_version < 9) display.scrollbarV.scrollTop = display.scroller. scrollTop = scrollPos;
3182 slowPoll(cm); 3212 slowPoll(cm);
3183 3213
3184 // Try to detect the user choosing select-all 3214 // Try to detect the user choosing select-all
3185 if (display.input.selectionStart != null) { 3215 if (display.input.selectionStart != null) {
3186 if (!ie || ie_upto8) prepareSelectAllHack(); 3216 if (!ie || (ie && ie_version < 9)) prepareSelectAllHack();
3187 var i = 0, poll = function() { 3217 var i = 0, poll = function() {
3188 if (display.selForContextMenu == cm.doc.sel && display.input.selection Start == 0) 3218 if (display.selForContextMenu == cm.doc.sel && display.input.selection Start == 0)
3189 operation(cm, commands.selectAll)(cm); 3219 operation(cm, commands.selectAll)(cm);
3190 else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500); 3220 else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500);
3191 else resetInput(cm); 3221 else resetInput(cm);
3192 }; 3222 };
3193 display.detectingSelectAll = setTimeout(poll, 200); 3223 display.detectingSelectAll = setTimeout(poll, 200);
3194 } 3224 }
3195 } 3225 }
3196 3226
3197 if (ie && !ie_upto8) prepareSelectAllHack(); 3227 if (ie && ie_version >= 9) prepareSelectAllHack();
3198 if (captureRightClick) { 3228 if (captureRightClick) {
3199 e_stop(e); 3229 e_stop(e);
3200 var mouseup = function() { 3230 var mouseup = function() {
3201 off(window, "mouseup", mouseup); 3231 off(window, "mouseup", mouseup);
3202 setTimeout(rehide, 20); 3232 setTimeout(rehide, 20);
3203 }; 3233 };
3204 on(window, "mouseup", mouseup); 3234 on(window, "mouseup", mouseup);
3205 } else { 3235 } else {
3206 setTimeout(rehide, 50); 3236 setTimeout(rehide, 50);
3207 } 3237 }
(...skipping 490 matching lines...) Expand 10 before | Expand all | Expand 10 after
3698 break; 3728 break;
3699 } 3729 }
3700 } 3730 }
3701 } 3731 }
3702 line.stateAfter = null; 3732 line.stateAfter = null;
3703 } 3733 }
3704 3734
3705 // Utility for applying a change to a line by handle or number, 3735 // Utility for applying a change to a line by handle or number,
3706 // returning the number and optionally registering the line as 3736 // returning the number and optionally registering the line as
3707 // changed. 3737 // changed.
3708 function changeLine(cm, handle, changeType, op) { 3738 function changeLine(doc, handle, changeType, op) {
3709 var no = handle, line = handle, doc = cm.doc; 3739 var no = handle, line = handle;
3710 if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle)); 3740 if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle));
3711 else no = lineNo(handle); 3741 else no = lineNo(handle);
3712 if (no == null) return null; 3742 if (no == null) return null;
3713 if (op(line, no)) regLineChange(cm, no, changeType); 3743 if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType);
3714 return line; 3744 return line;
3715 } 3745 }
3716 3746
3717 // Helper for deleting text near the selection(s), used to implement 3747 // Helper for deleting text near the selection(s), used to implement
3718 // backspace, delete, and similar functionality. 3748 // backspace, delete, and similar functionality.
3719 function deleteNearSelection(cm, compute) { 3749 function deleteNearSelection(cm, compute) {
3720 var ranges = cm.doc.sel.ranges, kill = []; 3750 var ranges = cm.doc.sel.ranges, kill = [];
3721 // Build up a set of ranges to kill first, merging overlapping 3751 // Build up a set of ranges to kill first, merging overlapping
3722 // ranges. 3752 // ranges.
3723 for (var i = 0; i < ranges.length; i++) { 3753 for (var i = 0; i < ranges.length; i++) {
(...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after
4018 else if (line > last) { line = last; end = true; } 4048 else if (line > last) { line = last; end = true; }
4019 var lineObj = getLine(this.doc, line); 4049 var lineObj = getLine(this.doc, line);
4020 return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page").t op + 4050 return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page").t op +
4021 (end ? this.doc.height - heightAtLine(lineObj) : 0); 4051 (end ? this.doc.height - heightAtLine(lineObj) : 0);
4022 }, 4052 },
4023 4053
4024 defaultTextHeight: function() { return textHeight(this.display); }, 4054 defaultTextHeight: function() { return textHeight(this.display); },
4025 defaultCharWidth: function() { return charWidth(this.display); }, 4055 defaultCharWidth: function() { return charWidth(this.display); },
4026 4056
4027 setGutterMarker: methodOp(function(line, gutterID, value) { 4057 setGutterMarker: methodOp(function(line, gutterID, value) {
4028 return changeLine(this, line, "gutter", function(line) { 4058 return changeLine(this.doc, line, "gutter", function(line) {
4029 var markers = line.gutterMarkers || (line.gutterMarkers = {}); 4059 var markers = line.gutterMarkers || (line.gutterMarkers = {});
4030 markers[gutterID] = value; 4060 markers[gutterID] = value;
4031 if (!value && isEmpty(markers)) line.gutterMarkers = null; 4061 if (!value && isEmpty(markers)) line.gutterMarkers = null;
4032 return true; 4062 return true;
4033 }); 4063 });
4034 }), 4064 }),
4035 4065
4036 clearGutter: methodOp(function(gutterID) { 4066 clearGutter: methodOp(function(gutterID) {
4037 var cm = this, doc = cm.doc, i = doc.first; 4067 var cm = this, doc = cm.doc, i = doc.first;
4038 doc.iter(function(line) { 4068 doc.iter(function(line) {
4039 if (line.gutterMarkers && line.gutterMarkers[gutterID]) { 4069 if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
4040 line.gutterMarkers[gutterID] = null; 4070 line.gutterMarkers[gutterID] = null;
4041 regLineChange(cm, i, "gutter"); 4071 regLineChange(cm, i, "gutter");
4042 if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null; 4072 if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null;
4043 } 4073 }
4044 ++i; 4074 ++i;
4045 }); 4075 });
4046 }), 4076 }),
4047 4077
4048 addLineClass: methodOp(function(handle, where, cls) {
4049 return changeLine(this, handle, "class", function(line) {
4050 var prop = where == "text" ? "textClass" : where == "background" ? "bgCl ass" : "wrapClass";
4051 if (!line[prop]) line[prop] = cls;
4052 else if (new RegExp("(?:^|\\s)" + cls + "(?:$|\\s)").test(line[prop])) r eturn false;
4053 else line[prop] += " " + cls;
4054 return true;
4055 });
4056 }),
4057
4058 removeLineClass: methodOp(function(handle, where, cls) {
4059 return changeLine(this, handle, "class", function(line) {
4060 var prop = where == "text" ? "textClass" : where == "background" ? "bgCl ass" : "wrapClass";
4061 var cur = line[prop];
4062 if (!cur) return false;
4063 else if (cls == null) line[prop] = null;
4064 else {
4065 var found = cur.match(new RegExp("(?:^|\\s+)" + cls + "(?:$|\\s+)"));
4066 if (!found) return false;
4067 var end = found.index + found[0].length;
4068 line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.l ength ? "" : " ") + cur.slice(end) || null;
4069 }
4070 return true;
4071 });
4072 }),
4073
4074 addLineWidget: methodOp(function(handle, node, options) { 4078 addLineWidget: methodOp(function(handle, node, options) {
4075 return addLineWidget(this, handle, node, options); 4079 return addLineWidget(this, handle, node, options);
4076 }), 4080 }),
4077 4081
4078 removeLineWidget: function(widget) { widget.clear(); }, 4082 removeLineWidget: function(widget) { widget.clear(); },
4079 4083
4080 lineInfo: function(line) { 4084 lineInfo: function(line) {
4081 if (typeof line == "number") { 4085 if (typeof line == "number") {
4082 if (!isLine(this.doc, line)) return null; 4086 if (!isLine(this.doc, line)) return null;
4083 var n = line; 4087 var n = line;
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
4239 } else { 4243 } else {
4240 var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.l eft), 4244 var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.l eft),
4241 Math.min(range.from.top, range.to.top) - r ange.margin, 4245 Math.min(range.from.top, range.to.top) - r ange.margin,
4242 Math.max(range.from.right, range.to.right) , 4246 Math.max(range.from.right, range.to.right) ,
4243 Math.max(range.from.bottom, range.to.botto m) + range.margin); 4247 Math.max(range.from.bottom, range.to.botto m) + range.margin);
4244 this.scrollTo(sPos.scrollLeft, sPos.scrollTop); 4248 this.scrollTo(sPos.scrollLeft, sPos.scrollTop);
4245 } 4249 }
4246 }), 4250 }),
4247 4251
4248 setSize: methodOp(function(width, height) { 4252 setSize: methodOp(function(width, height) {
4253 var cm = this;
4249 function interpret(val) { 4254 function interpret(val) {
4250 return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; 4255 return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val;
4251 } 4256 }
4252 if (width != null) this.display.wrapper.style.width = interpret(width); 4257 if (width != null) cm.display.wrapper.style.width = interpret(width);
4253 if (height != null) this.display.wrapper.style.height = interpret(height); 4258 if (height != null) cm.display.wrapper.style.height = interpret(height);
4254 if (this.options.lineWrapping) clearLineMeasurementCache(this); 4259 if (cm.options.lineWrapping) clearLineMeasurementCache(this);
4255 this.curOp.forceUpdate = true; 4260 var lineNo = cm.display.viewFrom;
4256 signal(this, "refresh", this); 4261 cm.doc.iter(lineNo, cm.display.viewTo, function(line) {
4262 if (line.widgets) for (var i = 0; i < line.widgets.length; i++)
4263 if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break; }
4264 ++lineNo;
4265 });
4266 cm.curOp.forceUpdate = true;
4267 signal(cm, "refresh", this);
4257 }), 4268 }),
4258 4269
4259 operation: function(f){return runInOp(this, f);}, 4270 operation: function(f){return runInOp(this, f);},
4260 4271
4261 refresh: methodOp(function() { 4272 refresh: methodOp(function() {
4262 var oldHeight = this.display.cachedTextHeight; 4273 var oldHeight = this.display.cachedTextHeight;
4263 regChange(this); 4274 regChange(this);
4264 this.curOp.forceUpdate = true; 4275 this.curOp.forceUpdate = true;
4265 clearCaches(this); 4276 clearCaches(this);
4266 this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop); 4277 this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop);
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
4366 } else { 4377 } else {
4367 cm.display.disabled = false; 4378 cm.display.disabled = false;
4368 if (!val) resetInput(cm); 4379 if (!val) resetInput(cm);
4369 } 4380 }
4370 }); 4381 });
4371 option("disableInput", false, function(cm, val) {if (!val) resetInput(cm);}, t rue); 4382 option("disableInput", false, function(cm, val) {if (!val) resetInput(cm);}, t rue);
4372 option("dragDrop", true); 4383 option("dragDrop", true);
4373 4384
4374 option("cursorBlinkRate", 530); 4385 option("cursorBlinkRate", 530);
4375 option("cursorScrollMargin", 0); 4386 option("cursorScrollMargin", 0);
4376 option("cursorHeight", 1); 4387 option("cursorHeight", 1, updateSelection, true);
4388 option("singleCursorHeightPerLine", true, updateSelection, true);
4377 option("workTime", 100); 4389 option("workTime", 100);
4378 option("workDelay", 100); 4390 option("workDelay", 100);
4379 option("flattenSpans", true, resetModeState, true); 4391 option("flattenSpans", true, resetModeState, true);
4380 option("addModeClass", false, resetModeState, true); 4392 option("addModeClass", false, resetModeState, true);
4381 option("pollInterval", 100); 4393 option("pollInterval", 100);
4382 option("undoDepth", 200, function(cm, val){cm.doc.history.undoDepth = val;}); 4394 option("undoDepth", 200, function(cm, val){cm.doc.history.undoDepth = val;});
4383 option("historyEventDelay", 1250); 4395 option("historyEventDelay", 1250);
4384 option("viewportMargin", 10, function(cm){cm.refresh();}, true); 4396 option("viewportMargin", 10, function(cm){cm.refresh();}, true);
4385 option("maxHighlightLength", 10000, resetModeState, true); 4397 option("maxHighlightLength", 10000, resetModeState, true);
4386 option("moveInputWithCursor", true, function(cm, val) { 4398 option("moveInputWithCursor", true, function(cm, val) {
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
4556 return {from: Pos(range.from().line, 0), to: range.from()}; 4568 return {from: Pos(range.from().line, 0), to: range.from()};
4557 }); 4569 });
4558 }, 4570 },
4559 undo: function(cm) {cm.undo();}, 4571 undo: function(cm) {cm.undo();},
4560 redo: function(cm) {cm.redo();}, 4572 redo: function(cm) {cm.redo();},
4561 undoSelection: function(cm) {cm.undoSelection();}, 4573 undoSelection: function(cm) {cm.undoSelection();},
4562 redoSelection: function(cm) {cm.redoSelection();}, 4574 redoSelection: function(cm) {cm.redoSelection();},
4563 goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));}, 4575 goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));},
4564 goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));}, 4576 goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));},
4565 goLineStart: function(cm) { 4577 goLineStart: function(cm) {
4566 cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.li ne); }, sel_move); 4578 cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.li ne); },
4579 {origin: "+move", bias: 1});
4567 }, 4580 },
4568 goLineStartSmart: function(cm) { 4581 goLineStartSmart: function(cm) {
4569 cm.extendSelectionsBy(function(range) { 4582 cm.extendSelectionsBy(function(range) {
4570 var start = lineStart(cm, range.head.line); 4583 var start = lineStart(cm, range.head.line);
4571 var line = cm.getLineHandle(start.line); 4584 var line = cm.getLineHandle(start.line);
4572 var order = getOrder(line); 4585 var order = getOrder(line);
4573 if (!order || order[0].level == 0) { 4586 if (!order || order[0].level == 0) {
4574 var firstNonWS = Math.max(0, line.text.search(/\S/)); 4587 var firstNonWS = Math.max(0, line.text.search(/\S/));
4575 var inWS = range.head.line == start.line && range.head.ch <= firstNonW S && range.head.ch; 4588 var inWS = range.head.line == start.line && range.head.ch <= firstNonW S && range.head.ch;
4576 return Pos(start.line, inWS ? 0 : firstNonWS); 4589 return Pos(start.line, inWS ? 0 : firstNonWS);
4577 } 4590 }
4578 return start; 4591 return start;
4579 }, sel_move); 4592 }, {origin: "+move", bias: 1});
4580 }, 4593 },
4581 goLineEnd: function(cm) { 4594 goLineEnd: function(cm) {
4582 cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line ); }, sel_move); 4595 cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line ); },
4596 {origin: "+move", bias: -1});
4583 }, 4597 },
4584 goLineRight: function(cm) { 4598 goLineRight: function(cm) {
4585 cm.extendSelectionsBy(function(range) { 4599 cm.extendSelectionsBy(function(range) {
4586 var top = cm.charCoords(range.head, "div").top + 5; 4600 var top = cm.charCoords(range.head, "div").top + 5;
4587 return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: t op}, "div"); 4601 return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: t op}, "div");
4588 }, sel_move); 4602 }, sel_move);
4589 }, 4603 },
4590 goLineLeft: function(cm) { 4604 goLineLeft: function(cm) {
4591 cm.extendSelectionsBy(function(range) { 4605 cm.extendSelectionsBy(function(range) {
4592 var top = cm.charCoords(range.head, "div").top + 5; 4606 var top = cm.charCoords(range.head, "div").top + 5;
(...skipping 811 matching lines...) Expand 10 before | Expand all | Expand 10 after
5404 function conflictingCollapsedRange(doc, lineNo, from, to, marker) { 5418 function conflictingCollapsedRange(doc, lineNo, from, to, marker) {
5405 var line = getLine(doc, lineNo); 5419 var line = getLine(doc, lineNo);
5406 var sps = sawCollapsedSpans && line.markedSpans; 5420 var sps = sawCollapsedSpans && line.markedSpans;
5407 if (sps) for (var i = 0; i < sps.length; ++i) { 5421 if (sps) for (var i = 0; i < sps.length; ++i) {
5408 var sp = sps[i]; 5422 var sp = sps[i];
5409 if (!sp.marker.collapsed) continue; 5423 if (!sp.marker.collapsed) continue;
5410 var found = sp.marker.find(0); 5424 var found = sp.marker.find(0);
5411 var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(ma rker); 5425 var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(ma rker);
5412 var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker ); 5426 var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker );
5413 if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue; 5427 if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue;
5414 if (fromCmp <= 0 && (cmp(found.to, from) || extraRight(sp.marker) - extraL eft(marker)) > 0 || 5428 if (fromCmp <= 0 && (cmp(found.to, from) > 0 || (sp.marker.inclusiveRight && marker.inclusiveLeft)) ||
5415 fromCmp >= 0 && (cmp(found.from, to) || extraLeft(sp.marker) - extraRi ght(marker)) < 0) 5429 fromCmp >= 0 && (cmp(found.from, to) < 0 || (sp.marker.inclusiveLeft & & marker.inclusiveRight)))
5416 return true; 5430 return true;
5417 } 5431 }
5418 } 5432 }
5419 5433
5420 // A visual line is a line as drawn on the screen. Folding, for 5434 // A visual line is a line as drawn on the screen. Folding, for
5421 // example, can cause multiple logical lines to appear on the same 5435 // example, can cause multiple logical lines to appear on the same
5422 // visual line. This finds the start of the visual line that the 5436 // visual line. This finds the start of the visual line that the
5423 // given line is part of (usually that is the line itself). 5437 // given line is part of (usually that is the line itself).
5424 function visualLine(line) { 5438 function visualLine(line) {
5425 var merged; 5439 var merged;
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
5523 if (!diff) return; 5537 if (!diff) return;
5524 runInOp(cm, function() { 5538 runInOp(cm, function() {
5525 cm.curOp.forceUpdate = true; 5539 cm.curOp.forceUpdate = true;
5526 adjustScrollWhenAboveVisible(cm, line, diff); 5540 adjustScrollWhenAboveVisible(cm, line, diff);
5527 updateLineHeight(line, line.height + diff); 5541 updateLineHeight(line, line.height + diff);
5528 }); 5542 });
5529 }; 5543 };
5530 5544
5531 function widgetHeight(widget) { 5545 function widgetHeight(widget) {
5532 if (widget.height != null) return widget.height; 5546 if (widget.height != null) return widget.height;
5533 if (!contains(document.body, widget.node)) 5547 if (!contains(document.body, widget.node)) {
5534 removeChildrenAndAdd(widget.cm.display.measure, elt("div", [widget.node], null, "position: relative")); 5548 var parentStyle = "position: relative;";
5549 if (widget.coverGutter)
5550 parentStyle += "margin-left: -" + widget.cm.getGutterElement().offsetWid th + "px;";
5551 removeChildrenAndAdd(widget.cm.display.measure, elt("div", [widget.node], null, parentStyle));
5552 }
5535 return widget.height = widget.node.offsetHeight; 5553 return widget.height = widget.node.offsetHeight;
5536 } 5554 }
5537 5555
5538 function addLineWidget(cm, handle, node, options) { 5556 function addLineWidget(cm, handle, node, options) {
5539 var widget = new LineWidget(cm, node, options); 5557 var widget = new LineWidget(cm, node, options);
5540 if (widget.noHScroll) cm.display.alignWidgets = true; 5558 if (widget.noHScroll) cm.display.alignWidgets = true;
5541 changeLine(cm, handle, "widget", function(line) { 5559 changeLine(cm.doc, handle, "widget", function(line) {
5542 var widgets = line.widgets || (line.widgets = []); 5560 var widgets = line.widgets || (line.widgets = []);
5543 if (widget.insertAt == null) widgets.push(widget); 5561 if (widget.insertAt == null) widgets.push(widget);
5544 else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insert At)), 0, widget); 5562 else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insert At)), 0, widget);
5545 widget.line = line; 5563 widget.line = line;
5546 if (!lineIsHidden(cm.doc, line)) { 5564 if (!lineIsHidden(cm.doc, line)) {
5547 var aboveVisible = heightAtLine(line) < cm.doc.scrollTop; 5565 var aboveVisible = heightAtLine(line) < cm.doc.scrollTop;
5548 updateLineHeight(line, line.height + widgetHeight(widget)); 5566 updateLineHeight(line, line.height + widgetHeight(widget));
5549 if (aboveVisible) addToScrollPos(cm, null, widget.height); 5567 if (aboveVisible) addToScrollPos(cm, null, widget.height);
5550 cm.curOp.forceUpdate = true; 5568 cm.curOp.forceUpdate = true;
5551 } 5569 }
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after
5767 if (i == 0) { 5785 if (i == 0) {
5768 lineView.measure.map = builder.map; 5786 lineView.measure.map = builder.map;
5769 lineView.measure.cache = {}; 5787 lineView.measure.cache = {};
5770 } else { 5788 } else {
5771 (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map ); 5789 (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map );
5772 (lineView.measure.caches || (lineView.measure.caches = [])).push({}); 5790 (lineView.measure.caches || (lineView.measure.caches = [])).push({});
5773 } 5791 }
5774 } 5792 }
5775 5793
5776 signal(cm, "renderLine", cm, lineView.line, builder.pre); 5794 signal(cm, "renderLine", cm, lineView.line, builder.pre);
5795 if (builder.pre.className)
5796 builder.textClass = joinClasses(builder.pre.className, builder.textClass | | "");
5777 return builder; 5797 return builder;
5778 } 5798 }
5779 5799
5780 function defaultSpecialCharPlaceholder(ch) { 5800 function defaultSpecialCharPlaceholder(ch) {
5781 var token = elt("span", "\u2022", "cm-invalidchar"); 5801 var token = elt("span", "\u2022", "cm-invalidchar");
5782 token.title = "\\u" + ch.charCodeAt(0).toString(16); 5802 token.title = "\\u" + ch.charCodeAt(0).toString(16);
5783 return token; 5803 return token;
5784 } 5804 }
5785 5805
5786 // Build up the DOM representation for a single token, and add it to 5806 // Build up the DOM representation for a single token, and add it to
5787 // the line map. Takes care to render special characters separately. 5807 // the line map. Takes care to render special characters separately.
5788 function buildToken(builder, text, style, startStyle, endStyle, title) { 5808 function buildToken(builder, text, style, startStyle, endStyle, title) {
5789 if (!text) return; 5809 if (!text) return;
5790 var special = builder.cm.options.specialChars, mustWrap = false; 5810 var special = builder.cm.options.specialChars, mustWrap = false;
5791 if (!special.test(text)) { 5811 if (!special.test(text)) {
5792 builder.col += text.length; 5812 builder.col += text.length;
5793 var content = document.createTextNode(text); 5813 var content = document.createTextNode(text);
5794 builder.map.push(builder.pos, builder.pos + text.length, content); 5814 builder.map.push(builder.pos, builder.pos + text.length, content);
5795 if (ie_upto8) mustWrap = true; 5815 if (ie && ie_version < 9) mustWrap = true;
5796 builder.pos += text.length; 5816 builder.pos += text.length;
5797 } else { 5817 } else {
5798 var content = document.createDocumentFragment(), pos = 0; 5818 var content = document.createDocumentFragment(), pos = 0;
5799 while (true) { 5819 while (true) {
5800 special.lastIndex = pos; 5820 special.lastIndex = pos;
5801 var m = special.exec(text); 5821 var m = special.exec(text);
5802 var skipped = m ? m.index - pos : text.length - pos; 5822 var skipped = m ? m.index - pos : text.length - pos;
5803 if (skipped) { 5823 if (skipped) {
5804 var txt = document.createTextNode(text.slice(pos, pos + skipped)); 5824 var txt = document.createTextNode(text.slice(pos, pos + skipped));
5805 if (ie_upto8) content.appendChild(elt("span", [txt])); 5825 if (ie && ie_version < 9) content.appendChild(elt("span", [txt]));
5806 else content.appendChild(txt); 5826 else content.appendChild(txt);
5807 builder.map.push(builder.pos, builder.pos + skipped, txt); 5827 builder.map.push(builder.pos, builder.pos + skipped, txt);
5808 builder.col += skipped; 5828 builder.col += skipped;
5809 builder.pos += skipped; 5829 builder.pos += skipped;
5810 } 5830 }
5811 if (!m) break; 5831 if (!m) break;
5812 pos += skipped + 1; 5832 pos += skipped + 1;
5813 if (m[0] == "\t") { 5833 if (m[0] == "\t") {
5814 var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder .col % tabSize; 5834 var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder .col % tabSize;
5815 var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab" )); 5835 var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab" ));
5816 builder.col += tabWidth; 5836 builder.col += tabWidth;
5817 } else { 5837 } else {
5818 var txt = builder.cm.options.specialCharPlaceholder(m[0]); 5838 var txt = builder.cm.options.specialCharPlaceholder(m[0]);
5819 if (ie_upto8) content.appendChild(elt("span", [txt])); 5839 if (ie && ie_version < 9) content.appendChild(elt("span", [txt]));
5820 else content.appendChild(txt); 5840 else content.appendChild(txt);
5821 builder.col += 1; 5841 builder.col += 1;
5822 } 5842 }
5823 builder.map.push(builder.pos, builder.pos + 1, txt); 5843 builder.map.push(builder.pos, builder.pos + 1, txt);
5824 builder.pos++; 5844 builder.pos++;
5825 } 5845 }
5826 } 5846 }
5827 if (style || startStyle || endStyle || mustWrap) { 5847 if (style || startStyle || endStyle || mustWrap) {
5828 var fullStyle = style || ""; 5848 var fullStyle = style || "";
5829 if (startStyle) fullStyle += startStyle; 5849 if (startStyle) fullStyle += startStyle;
(...skipping 504 matching lines...) Expand 10 before | Expand all | Expand 10 after
6334 getHistory: function() { 6354 getHistory: function() {
6335 return {done: copyHistoryArray(this.history.done), 6355 return {done: copyHistoryArray(this.history.done),
6336 undone: copyHistoryArray(this.history.undone)}; 6356 undone: copyHistoryArray(this.history.undone)};
6337 }, 6357 },
6338 setHistory: function(histData) { 6358 setHistory: function(histData) {
6339 var hist = this.history = new History(this.history.maxGeneration); 6359 var hist = this.history = new History(this.history.maxGeneration);
6340 hist.done = copyHistoryArray(histData.done.slice(0), null, true); 6360 hist.done = copyHistoryArray(histData.done.slice(0), null, true);
6341 hist.undone = copyHistoryArray(histData.undone.slice(0), null, true); 6361 hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);
6342 }, 6362 },
6343 6363
6364 addLineClass: docMethodOp(function(handle, where, cls) {
6365 return changeLine(this, handle, "class", function(line) {
6366 var prop = where == "text" ? "textClass" : where == "background" ? "bgCl ass" : "wrapClass";
6367 if (!line[prop]) line[prop] = cls;
6368 else if (new RegExp("(?:^|\\s)" + cls + "(?:$|\\s)").test(line[prop])) r eturn false;
6369 else line[prop] += " " + cls;
6370 return true;
6371 });
6372 }),
6373 removeLineClass: docMethodOp(function(handle, where, cls) {
6374 return changeLine(this, handle, "class", function(line) {
6375 var prop = where == "text" ? "textClass" : where == "background" ? "bgCl ass" : "wrapClass";
6376 var cur = line[prop];
6377 if (!cur) return false;
6378 else if (cls == null) line[prop] = null;
6379 else {
6380 var found = cur.match(new RegExp("(?:^|\\s+)" + cls + "(?:$|\\s+)"));
6381 if (!found) return false;
6382 var end = found.index + found[0].length;
6383 line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.l ength ? "" : " ") + cur.slice(end) || null;
6384 }
6385 return true;
6386 });
6387 }),
6388
6344 markText: function(from, to, options) { 6389 markText: function(from, to, options) {
6345 return markText(this, clipPos(this, from), clipPos(this, to), options, "ra nge"); 6390 return markText(this, clipPos(this, from), clipPos(this, to), options, "ra nge");
6346 }, 6391 },
6347 setBookmark: function(pos, options) { 6392 setBookmark: function(pos, options) {
6348 var realOpts = {replacedWith: options && (options.nodeType == null ? optio ns.widget : options), 6393 var realOpts = {replacedWith: options && (options.nodeType == null ? optio ns.widget : options),
6349 insertLeft: options && options.insertLeft, 6394 insertLeft: options && options.insertLeft,
6350 clearWhenEmpty: false, shared: options && options.shared}; 6395 clearWhenEmpty: false, shared: options && options.shared};
6351 pos = clipPos(this, pos); 6396 pos = clipPos(this, pos);
6352 return markText(this, pos, pos, realOpts, "bookmark"); 6397 return markText(this, pos, pos, realOpts, "bookmark");
6353 }, 6398 },
(...skipping 787 matching lines...) Expand 10 before | Expand all | Expand 10 after
7141 function contains(parent, child) { 7186 function contains(parent, child) {
7142 if (parent.contains) 7187 if (parent.contains)
7143 return parent.contains(child); 7188 return parent.contains(child);
7144 while (child = child.parentNode) 7189 while (child = child.parentNode)
7145 if (child == parent) return true; 7190 if (child == parent) return true;
7146 } 7191 }
7147 7192
7148 function activeElt() { return document.activeElement; } 7193 function activeElt() { return document.activeElement; }
7149 // Older versions of IE throws unspecified error when touching 7194 // Older versions of IE throws unspecified error when touching
7150 // document.activeElement in some cases (during loading, in iframe) 7195 // document.activeElement in some cases (during loading, in iframe)
7151 if (ie_upto10) activeElt = function() { 7196 if (ie && ie_version < 11) activeElt = function() {
7152 try { return document.activeElement; } 7197 try { return document.activeElement; }
7153 catch(e) { return document.body; } 7198 catch(e) { return document.body; }
7154 }; 7199 };
7155 7200
7156 function classTest(cls) { return new RegExp("\\b" + cls + "\\b\\s*"); } 7201 function classTest(cls) { return new RegExp("\\b" + cls + "\\b\\s*"); }
7157 function rmClass(node, cls) { 7202 function rmClass(node, cls) {
7158 var test = classTest(cls); 7203 var test = classTest(cls);
7159 if (test.test(node.className)) node.className = node.className.replace(test, ""); 7204 if (test.test(node.className)) node.className = node.className.replace(test, "");
7160 } 7205 }
7161 function addClass(node, cls) { 7206 function addClass(node, cls) {
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
7204 forEachCodeMirror(onBlur); 7249 forEachCodeMirror(onBlur);
7205 }); 7250 });
7206 } 7251 }
7207 7252
7208 // FEATURE DETECTION 7253 // FEATURE DETECTION
7209 7254
7210 // Detect drag-and-drop 7255 // Detect drag-and-drop
7211 var dragAndDrop = function() { 7256 var dragAndDrop = function() {
7212 // There is *some* kind of drag-and-drop support in IE6-8, but I 7257 // There is *some* kind of drag-and-drop support in IE6-8, but I
7213 // couldn't get it to work yet. 7258 // couldn't get it to work yet.
7214 if (ie_upto8) return false; 7259 if (ie && ie_version < 9) return false;
7215 var div = elt('div'); 7260 var div = elt('div');
7216 return "draggable" in div || "dragDrop" in div; 7261 return "draggable" in div || "dragDrop" in div;
7217 }(); 7262 }();
7218 7263
7219 var knownScrollbarWidth; 7264 var knownScrollbarWidth;
7220 function scrollbarWidth(measure) { 7265 function scrollbarWidth(measure) {
7221 if (knownScrollbarWidth != null) return knownScrollbarWidth; 7266 if (knownScrollbarWidth != null) return knownScrollbarWidth;
7222 var test = elt("div", null, null, "width: 50px; height: 50px; overflow-x: sc roll"); 7267 var test = elt("div", null, null, "width: 50px; height: 50px; overflow-x: sc roll");
7223 removeChildrenAndAdd(measure, test); 7268 removeChildrenAndAdd(measure, test);
7224 if (test.offsetWidth) 7269 if (test.offsetWidth)
7225 knownScrollbarWidth = test.offsetHeight - test.clientHeight; 7270 knownScrollbarWidth = test.offsetHeight - test.clientHeight;
7226 return knownScrollbarWidth || 0; 7271 return knownScrollbarWidth || 0;
7227 } 7272 }
7228 7273
7229 var zwspSupported; 7274 var zwspSupported;
7230 function zeroWidthElement(measure) { 7275 function zeroWidthElement(measure) {
7231 if (zwspSupported == null) { 7276 if (zwspSupported == null) {
7232 var test = elt("span", "\u200b"); 7277 var test = elt("span", "\u200b");
7233 removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode(" x")])); 7278 removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode(" x")]));
7234 if (measure.firstChild.offsetHeight != 0) 7279 if (measure.firstChild.offsetHeight != 0)
7235 zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !ie_up to7; 7280 zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie & & ie_version < 8);
7236 } 7281 }
7237 if (zwspSupported) return elt("span", "\u200b"); 7282 if (zwspSupported) return elt("span", "\u200b");
7238 else return elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px"); 7283 else return elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
7239 } 7284 }
7240 7285
7241 // Feature-detect IE's crummy client rect reporting for bidi text 7286 // Feature-detect IE's crummy client rect reporting for bidi text
7242 var badBidiRects; 7287 var badBidiRects;
7243 function hasBadBidiRects(measure) { 7288 function hasBadBidiRects(measure) {
7244 if (badBidiRects != null) return badBidiRects; 7289 if (badBidiRects != null) return badBidiRects;
7245 var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA")) ; 7290 var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA")) ;
(...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after
7580 } 7625 }
7581 if (order[0].level != lst(order).level) 7626 if (order[0].level != lst(order).level)
7582 order.push(new BidiSpan(order[0].level, len, len)); 7627 order.push(new BidiSpan(order[0].level, len, len));
7583 7628
7584 return order; 7629 return order;
7585 }; 7630 };
7586 })(); 7631 })();
7587 7632
7588 // THE END 7633 // THE END
7589 7634
7590 CodeMirror.version = "4.1.1"; 7635 CodeMirror.version = "4.3.1";
7591 7636
7592 return CodeMirror; 7637 return CodeMirror;
7593 }); 7638 });
OLDNEW
« no previous file with comments | « Source/devtools/front_end/cm/codemirror.css ('k') | Source/devtools/front_end/cm/coffeescript.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698