OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 }); |
OLD | NEW |