OLD | NEW |
1 // CodeMirror is the only global var we claim | 1 // CodeMirror is the only global var we claim |
2 window.CodeMirror = (function() { | 2 window.CodeMirror = (function() { |
3 "use strict"; | 3 "use strict"; |
4 | 4 |
5 // BROWSER SNIFFING | 5 // BROWSER SNIFFING |
6 | 6 |
7 // Crude, but necessary to handle a number of hard-to-feature-detect | 7 // Crude, but necessary to handle a number of hard-to-feature-detect |
8 // bugs and behavior differences. | 8 // bugs and behavior differences. |
9 var gecko = /gecko\/\d/i.test(navigator.userAgent); | 9 var gecko = /gecko\/\d/i.test(navigator.userAgent); |
10 var ie = /MSIE \d/.test(navigator.userAgent); | 10 var ie = /MSIE \d/.test(navigator.userAgent); |
11 var ie_lt8 = ie && (document.documentMode == null || document.documentMode < 8
); | 11 var ie_lt8 = ie && (document.documentMode == null || document.documentMode < 8
); |
12 var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9
); | 12 var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9
); |
13 var webkit = /WebKit\//.test(navigator.userAgent); | 13 var webkit = /WebKit\//.test(navigator.userAgent); |
14 var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent); | 14 var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent); |
15 var chrome = /Chrome\//.test(navigator.userAgent); | 15 var chrome = /Chrome\//.test(navigator.userAgent); |
16 var opera = /Opera\//.test(navigator.userAgent); | 16 var opera = /Opera\//.test(navigator.userAgent); |
17 var safari = /Apple Computer/.test(navigator.vendor); | 17 var safari = /Apple Computer/.test(navigator.vendor); |
18 var khtml = /KHTML\//.test(navigator.userAgent); | 18 var khtml = /KHTML\//.test(navigator.userAgent); |
19 var mac_geLion = /Mac OS X 1\d\D([7-9]|\d\d)\D/.test(navigator.userAgent); | 19 var mac_geLion = /Mac OS X 1\d\D([7-9]|\d\d)\D/.test(navigator.userAgent); |
20 var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAge
nt); | 20 var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAge
nt); |
21 var phantom = /PhantomJS/.test(navigator.userAgent); | 21 var phantom = /PhantomJS/.test(navigator.userAgent); |
22 | 22 |
23 var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(naviga
tor.userAgent); | 23 var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(naviga
tor.userAgent); |
24 // This is woefully incomplete. Suggestions for alternative methods welcome. | 24 // This is woefully incomplete. Suggestions for alternative methods welcome. |
25 var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i
.test(navigator.userAgent); | 25 var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i
.test(navigator.userAgent); |
26 var mac = ios || /Mac/.test(navigator.platform); | 26 var mac = ios || /Mac/.test(navigator.platform); |
27 var windows = /windows/i.test(navigator.platform); | 27 var windows = /win/i.test(navigator.platform); |
28 | 28 |
29 var opera_version = opera && navigator.userAgent.match(/Version\/(\d*\.\d*)/); | 29 var opera_version = opera && navigator.userAgent.match(/Version\/(\d*\.\d*)/); |
30 if (opera_version) opera_version = Number(opera_version[1]); | 30 if (opera_version) opera_version = Number(opera_version[1]); |
31 if (opera_version && opera_version >= 15) { opera = false; webkit = true; } | 31 if (opera_version && opera_version >= 15) { opera = false; webkit = true; } |
32 // Some browsers use the wrong event properties to signal cmd/ctrl on OS X | 32 // Some browsers use the wrong event properties to signal cmd/ctrl on OS X |
33 var flipCtrlCmd = mac && (qtwebkit || opera && (opera_version == null || opera
_version < 12.11)); | 33 var flipCtrlCmd = mac && (qtwebkit || opera && (opera_version == null || opera
_version < 12.11)); |
34 var captureMiddleClick = gecko || (ie && !ie_lt9); | 34 var captureMiddleClick = gecko || (ie && !ie_lt9); |
35 | 35 |
36 // Optimize some code when these features are not used | 36 // Optimize some code when these features are not used |
37 var sawReadOnlySpans = false, sawCollapsedSpans = false; | 37 var sawReadOnlySpans = false, sawCollapsedSpans = false; |
(...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 if (len > d.maxLineLength) { | 297 if (len > d.maxLineLength) { |
298 d.maxLineLength = len; | 298 d.maxLineLength = len; |
299 d.maxLine = line; | 299 d.maxLine = line; |
300 } | 300 } |
301 }); | 301 }); |
302 } | 302 } |
303 | 303 |
304 // Make sure the gutters options contains the element | 304 // Make sure the gutters options contains the element |
305 // "CodeMirror-linenumbers" when the lineNumbers option is true. | 305 // "CodeMirror-linenumbers" when the lineNumbers option is true. |
306 function setGuttersForLineNumbers(options) { | 306 function setGuttersForLineNumbers(options) { |
307 var found = false; | 307 var found = indexOf(options.gutters, "CodeMirror-linenumbers"); |
308 for (var i = 0; i < options.gutters.length; ++i) { | 308 if (found == -1 && options.lineNumbers) { |
309 if (options.gutters[i] == "CodeMirror-linenumbers") { | 309 options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]); |
310 if (options.lineNumbers) found = true; | 310 } else if (found > -1 && !options.lineNumbers) { |
311 else options.gutters.splice(i--, 1); | 311 options.gutters = options.gutters.slice(0); |
312 } | 312 options.gutters.splice(i, 1); |
313 } | 313 } |
314 if (!found && options.lineNumbers) | |
315 options.gutters.push("CodeMirror-linenumbers"); | |
316 } | 314 } |
317 | 315 |
318 // SCROLLBARS | 316 // SCROLLBARS |
319 | 317 |
320 // Re-synchronize the fake scrollbars with the actual size of the | 318 // Re-synchronize the fake scrollbars with the actual size of the |
321 // content. Optionally force a scrollTop. | 319 // content. Optionally force a scrollTop. |
322 function updateScrollbars(cm) { | 320 function updateScrollbars(cm) { |
323 var d = cm.display, docHeight = cm.doc.height; | 321 var d = cm.display, docHeight = cm.doc.height; |
324 var totalHeight = docHeight + paddingVert(d); | 322 var totalHeight = docHeight + paddingVert(d); |
325 d.sizer.style.minHeight = d.heightForcer.style.top = totalHeight + "px"; | 323 d.sizer.style.minHeight = d.heightForcer.style.top = totalHeight + "px"; |
326 d.gutters.style.height = Math.max(totalHeight, d.scroller.clientHeight - scr
ollerCutOff) + "px"; | 324 d.gutters.style.height = Math.max(totalHeight, d.scroller.clientHeight - scr
ollerCutOff) + "px"; |
327 var scrollHeight = Math.max(totalHeight, d.scroller.scrollHeight); | 325 var scrollHeight = Math.max(totalHeight, d.scroller.scrollHeight); |
328 var needsH = d.scroller.scrollWidth > (d.scroller.clientWidth + 1); | 326 var needsH = d.scroller.scrollWidth > (d.scroller.clientWidth + 1); |
329 var needsV = scrollHeight > (d.scroller.clientHeight + 1); | 327 var needsV = scrollHeight > (d.scroller.clientHeight + 1); |
330 if (needsV) { | 328 if (needsV) { |
331 d.scrollbarV.style.display = "block"; | 329 d.scrollbarV.style.display = "block"; |
332 d.scrollbarV.style.bottom = needsH ? scrollbarWidth(d.measure) + "px" : "0
"; | 330 d.scrollbarV.style.bottom = needsH ? scrollbarWidth(d.measure) + "px" : "0
"; |
333 d.scrollbarV.firstChild.style.height = | 331 d.scrollbarV.firstChild.style.height = |
334 (scrollHeight - d.scroller.clientHeight + d.scrollbarV.clientHeight) + "
px"; | 332 (scrollHeight - d.scroller.clientHeight + d.scrollbarV.clientHeight) + "
px"; |
335 } else d.scrollbarV.style.display = ""; | 333 } else { |
| 334 d.scrollbarV.style.display = ""; |
| 335 d.scrollbarV.firstChild.style.height = "0"; |
| 336 } |
336 if (needsH) { | 337 if (needsH) { |
337 d.scrollbarH.style.display = "block"; | 338 d.scrollbarH.style.display = "block"; |
338 d.scrollbarH.style.right = needsV ? scrollbarWidth(d.measure) + "px" : "0"
; | 339 d.scrollbarH.style.right = needsV ? scrollbarWidth(d.measure) + "px" : "0"
; |
339 d.scrollbarH.firstChild.style.width = | 340 d.scrollbarH.firstChild.style.width = |
340 (d.scroller.scrollWidth - d.scroller.clientWidth + d.scrollbarH.clientWi
dth) + "px"; | 341 (d.scroller.scrollWidth - d.scroller.clientWidth + d.scrollbarH.clientWi
dth) + "px"; |
341 } else d.scrollbarH.style.display = ""; | 342 } else { |
| 343 d.scrollbarH.style.display = ""; |
| 344 d.scrollbarH.firstChild.style.width = "0"; |
| 345 } |
342 if (needsH && needsV) { | 346 if (needsH && needsV) { |
343 d.scrollbarFiller.style.display = "block"; | 347 d.scrollbarFiller.style.display = "block"; |
344 d.scrollbarFiller.style.height = d.scrollbarFiller.style.width = scrollbar
Width(d.measure) + "px"; | 348 d.scrollbarFiller.style.height = d.scrollbarFiller.style.width = scrollbar
Width(d.measure) + "px"; |
345 } else d.scrollbarFiller.style.display = ""; | 349 } else d.scrollbarFiller.style.display = ""; |
346 if (needsH && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutte
r) { | 350 if (needsH && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutte
r) { |
347 d.gutterFiller.style.display = "block"; | 351 d.gutterFiller.style.display = "block"; |
348 d.gutterFiller.style.height = scrollbarWidth(d.measure) + "px"; | 352 d.gutterFiller.style.height = scrollbarWidth(d.measure) + "px"; |
349 d.gutterFiller.style.width = d.gutters.offsetWidth + "px"; | 353 d.gutterFiller.style.width = d.gutters.offsetWidth + "px"; |
350 } else d.gutterFiller.style.display = ""; | 354 } else d.gutterFiller.style.display = ""; |
351 | 355 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
399 function compensateForHScroll(display) { | 403 function compensateForHScroll(display) { |
400 return getRect(display.scroller).left - getRect(display.sizer).left; | 404 return getRect(display.scroller).left - getRect(display.sizer).left; |
401 } | 405 } |
402 | 406 |
403 // DISPLAY DRAWING | 407 // DISPLAY DRAWING |
404 | 408 |
405 function updateDisplay(cm, changes, viewPort, forced) { | 409 function updateDisplay(cm, changes, viewPort, forced) { |
406 var oldFrom = cm.display.showingFrom, oldTo = cm.display.showingTo, updated; | 410 var oldFrom = cm.display.showingFrom, oldTo = cm.display.showingTo, updated; |
407 var visible = visibleLines(cm.display, cm.doc, viewPort); | 411 var visible = visibleLines(cm.display, cm.doc, viewPort); |
408 for (;;) { | 412 for (;;) { |
| 413 var oldWidth = cm.display.scroller.clientWidth; |
409 if (!updateDisplayInner(cm, changes, visible, forced)) break; | 414 if (!updateDisplayInner(cm, changes, visible, forced)) break; |
410 forced = false; | |
411 updated = true; | 415 updated = true; |
| 416 changes = []; |
412 updateSelection(cm); | 417 updateSelection(cm); |
413 updateScrollbars(cm); | 418 updateScrollbars(cm); |
| 419 if (cm.options.lineWrapping && oldWidth != cm.display.scroller.clientWidth
) { |
| 420 forced = true; |
| 421 continue; |
| 422 } |
| 423 forced = false; |
414 | 424 |
415 // Clip forced viewport to actual scrollable area | 425 // Clip forced viewport to actual scrollable area |
416 if (viewPort) | 426 if (viewPort) |
417 viewPort = Math.min(cm.display.scroller.scrollHeight - cm.display.scroll
er.clientHeight, | 427 viewPort = Math.min(cm.display.scroller.scrollHeight - cm.display.scroll
er.clientHeight, |
418 typeof viewPort == "number" ? viewPort : viewPort.to
p); | 428 typeof viewPort == "number" ? viewPort : viewPort.to
p); |
419 visible = visibleLines(cm.display, cm.doc, viewPort); | 429 visible = visibleLines(cm.display, cm.doc, viewPort); |
420 if (visible.from >= cm.display.showingFrom && visible.to <= cm.display.sho
wingTo) | 430 if (visible.from >= cm.display.showingFrom && visible.to <= cm.display.sho
wingTo) |
421 break; | 431 break; |
422 changes = []; | |
423 } | 432 } |
424 | 433 |
425 if (updated) { | 434 if (updated) { |
426 signalLater(cm, "update", cm); | 435 signalLater(cm, "update", cm); |
427 if (cm.display.showingFrom != oldFrom || cm.display.showingTo != oldTo) | 436 if (cm.display.showingFrom != oldFrom || cm.display.showingTo != oldTo) |
428 signalLater(cm, "viewportChange", cm, cm.display.showingFrom, cm.display
.showingTo); | 437 signalLater(cm, "viewportChange", cm, cm.display.showingFrom, cm.display
.showingTo); |
429 } | 438 } |
430 return updated; | 439 return updated; |
431 } | 440 } |
432 | 441 |
(...skipping 15 matching lines...) Expand all Loading... |
448 | 457 |
449 if (maybeUpdateLineNumberWidth(cm)) | 458 if (maybeUpdateLineNumberWidth(cm)) |
450 changes = [{from: doc.first, to: doc.first + doc.size}]; | 459 changes = [{from: doc.first, to: doc.first + doc.size}]; |
451 var gutterW = display.sizer.style.marginLeft = display.gutters.offsetWidth +
"px"; | 460 var gutterW = display.sizer.style.marginLeft = display.gutters.offsetWidth +
"px"; |
452 display.scrollbarH.style.left = cm.options.fixedGutter ? gutterW : "0"; | 461 display.scrollbarH.style.left = cm.options.fixedGutter ? gutterW : "0"; |
453 | 462 |
454 // Used to determine which lines need their line numbers updated | 463 // Used to determine which lines need their line numbers updated |
455 var positionsChangedFrom = Infinity; | 464 var positionsChangedFrom = Infinity; |
456 if (cm.options.lineNumbers) | 465 if (cm.options.lineNumbers) |
457 for (var i = 0; i < changes.length; ++i) | 466 for (var i = 0; i < changes.length; ++i) |
458 if (changes[i].diff) { positionsChangedFrom = changes[i].from; break; } | 467 if (changes[i].diff && changes[i].from < positionsChangedFrom) { positio
nsChangedFrom = changes[i].from; } |
459 | 468 |
460 var end = doc.first + doc.size; | 469 var end = doc.first + doc.size; |
461 var from = Math.max(visible.from - cm.options.viewportMargin, doc.first); | 470 var from = Math.max(visible.from - cm.options.viewportMargin, doc.first); |
462 var to = Math.min(end, visible.to + cm.options.viewportMargin); | 471 var to = Math.min(end, visible.to + cm.options.viewportMargin); |
463 if (display.showingFrom < from && from - display.showingFrom < 20) from = Ma
th.max(doc.first, display.showingFrom); | 472 if (display.showingFrom < from && from - display.showingFrom < 20) from = Ma
th.max(doc.first, display.showingFrom); |
464 if (display.showingTo > to && display.showingTo - to < 20) to = Math.min(end
, display.showingTo); | 473 if (display.showingTo > to && display.showingTo - to < 20) to = Math.min(end
, display.showingTo); |
465 if (sawCollapsedSpans) { | 474 if (sawCollapsedSpans) { |
466 from = lineNo(visualLine(doc, getLine(doc, from))); | 475 from = lineNo(visualLine(doc, getLine(doc, from))); |
467 while (to < end && lineIsHidden(doc, getLine(doc, to))) ++to; | 476 while (to < end && lineIsHidden(doc, getLine(doc, to))) ++to; |
468 } | 477 } |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
605 node.parentNode.removeChild(node); | 614 node.parentNode.removeChild(node); |
606 } | 615 } |
607 return next; | 616 return next; |
608 } | 617 } |
609 | 618 |
610 var nextIntact = intact.shift(), lineN = from; | 619 var nextIntact = intact.shift(), lineN = from; |
611 cm.doc.iter(from, to, function(line) { | 620 cm.doc.iter(from, to, function(line) { |
612 if (nextIntact && nextIntact.to == lineN) nextIntact = intact.shift(); | 621 if (nextIntact && nextIntact.to == lineN) nextIntact = intact.shift(); |
613 if (lineIsHidden(cm.doc, line)) { | 622 if (lineIsHidden(cm.doc, line)) { |
614 if (line.height != 0) updateLineHeight(line, 0); | 623 if (line.height != 0) updateLineHeight(line, 0); |
615 if (line.widgets && cur.previousSibling) for (var i = 0; i < line.widget
s.length; ++i) { | 624 if (line.widgets && cur && cur.previousSibling) for (var i = 0; i < line
.widgets.length; ++i) { |
616 var w = line.widgets[i]; | 625 var w = line.widgets[i]; |
617 if (w.showIfHidden) { | 626 if (w.showIfHidden) { |
618 var prev = cur.previousSibling; | 627 var prev = cur.previousSibling; |
619 if (/pre/i.test(prev.nodeName)) { | 628 if (/pre/i.test(prev.nodeName)) { |
620 var wrap = elt("div", null, null, "position: relative"); | 629 var wrap = elt("div", null, null, "position: relative"); |
621 prev.parentNode.replaceChild(wrap, prev); | 630 prev.parentNode.replaceChild(wrap, prev); |
622 wrap.appendChild(prev); | 631 wrap.appendChild(prev); |
623 prev = wrap; | 632 prev = wrap; |
624 } | 633 } |
625 var wnode = prev.appendChild(elt("div", [w.node], "CodeMirror-linewi
dget")); | 634 var wnode = prev.appendChild(elt("div", [w.node], "CodeMirror-linewi
dget")); |
(...skipping 24 matching lines...) Expand all Loading... |
650 } | 659 } |
651 | 660 |
652 lineNode.lineObj = line; | 661 lineNode.lineObj = line; |
653 } | 662 } |
654 ++lineN; | 663 ++lineN; |
655 }); | 664 }); |
656 while (cur) cur = rm(cur); | 665 while (cur) cur = rm(cur); |
657 } | 666 } |
658 | 667 |
659 function buildLineElement(cm, line, lineNo, dims, reuse) { | 668 function buildLineElement(cm, line, lineNo, dims, reuse) { |
660 var lineElement = lineContent(cm, line); | 669 var built = buildLineContent(cm, line), lineElement = built.pre; |
661 var markers = line.gutterMarkers, display = cm.display, wrap; | 670 var markers = line.gutterMarkers, display = cm.display, wrap; |
662 | 671 |
663 if (!cm.options.lineNumbers && !markers && !line.bgClass && !line.wrapClass
&& !line.widgets) | 672 var bgClass = built.bgClass ? built.bgClass + " " + (line.bgClass || "") : l
ine.bgClass; |
| 673 if (!cm.options.lineNumbers && !markers && !bgClass && !line.wrapClass && !l
ine.widgets) |
664 return lineElement; | 674 return lineElement; |
665 | 675 |
666 // Lines with gutter elements, widgets or a background class need | 676 // Lines with gutter elements, widgets or a background class need |
667 // to be wrapped again, and have the extra elements added to the | 677 // to be wrapped again, and have the extra elements added to the |
668 // wrapper div | 678 // wrapper div |
669 | 679 |
670 if (reuse) { | 680 if (reuse) { |
671 reuse.alignable = null; | 681 reuse.alignable = null; |
672 var isOk = true, widgetsSeen = 0, insertBefore = null; | 682 var isOk = true, widgetsSeen = 0, insertBefore = null; |
673 for (var n = reuse.firstChild, next; n; n = next) { | 683 for (var n = reuse.firstChild, next; n; n = next) { |
(...skipping 17 matching lines...) Expand all Loading... |
691 if (isOk && widgetsSeen == line.widgets.length) { | 701 if (isOk && widgetsSeen == line.widgets.length) { |
692 wrap = reuse; | 702 wrap = reuse; |
693 reuse.className = line.wrapClass || ""; | 703 reuse.className = line.wrapClass || ""; |
694 } | 704 } |
695 } | 705 } |
696 if (!wrap) { | 706 if (!wrap) { |
697 wrap = elt("div", null, line.wrapClass, "position: relative"); | 707 wrap = elt("div", null, line.wrapClass, "position: relative"); |
698 wrap.appendChild(lineElement); | 708 wrap.appendChild(lineElement); |
699 } | 709 } |
700 // Kludge to make sure the styled element lies behind the selection (by z-in
dex) | 710 // Kludge to make sure the styled element lies behind the selection (by z-in
dex) |
701 if (line.bgClass) | 711 if (bgClass) |
702 wrap.insertBefore(elt("div", null, line.bgClass + " CodeMirror-linebackgro
und"), wrap.firstChild); | 712 wrap.insertBefore(elt("div", null, bgClass + " CodeMirror-linebackground")
, wrap.firstChild); |
703 if (cm.options.lineNumbers || markers) { | 713 if (cm.options.lineNumbers || markers) { |
704 var gutterWrap = wrap.insertBefore(elt("div", null, null, "position: absol
ute; left: " + | 714 var gutterWrap = wrap.insertBefore(elt("div", null, null, "position: absol
ute; left: " + |
705 (cm.options.fixedGutter ? dims.fixe
dPos : -dims.gutterTotalWidth) + "px"), | 715 (cm.options.fixedGutter ? dims.fixe
dPos : -dims.gutterTotalWidth) + "px"), |
706 wrap.firstChild); | 716 wrap.firstChild); |
707 if (cm.options.fixedGutter) (wrap.alignable || (wrap.alignable = [])).push
(gutterWrap); | 717 if (cm.options.fixedGutter) (wrap.alignable || (wrap.alignable = [])).push
(gutterWrap); |
708 if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumber
s"])) | 718 if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumber
s"])) |
709 wrap.lineNumber = gutterWrap.appendChild( | 719 wrap.lineNumber = gutterWrap.appendChild( |
710 elt("div", lineNumberFor(cm.options, lineNo), | 720 elt("div", lineNumberFor(cm.options, lineNo), |
711 "CodeMirror-linenumber CodeMirror-gutter-elt", | 721 "CodeMirror-linenumber CodeMirror-gutter-elt", |
712 "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width:
" | 722 "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width:
" |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
864 display.selectionDiv.style.display = ""; | 874 display.selectionDiv.style.display = ""; |
865 } | 875 } |
866 | 876 |
867 // Cursor-blinking | 877 // Cursor-blinking |
868 function restartBlink(cm) { | 878 function restartBlink(cm) { |
869 if (!cm.state.focused) return; | 879 if (!cm.state.focused) return; |
870 var display = cm.display; | 880 var display = cm.display; |
871 clearInterval(display.blinker); | 881 clearInterval(display.blinker); |
872 var on = true; | 882 var on = true; |
873 display.cursor.style.visibility = display.otherCursor.style.visibility = ""; | 883 display.cursor.style.visibility = display.otherCursor.style.visibility = ""; |
874 display.blinker = setInterval(function() { | 884 if (cm.options.cursorBlinkRate > 0) |
875 display.cursor.style.visibility = display.otherCursor.style.visibility = (
on = !on) ? "" : "hidden"; | 885 display.blinker = setInterval(function() { |
876 }, cm.options.cursorBlinkRate); | 886 display.cursor.style.visibility = display.otherCursor.style.visibility =
(on = !on) ? "" : "hidden"; |
| 887 }, cm.options.cursorBlinkRate); |
877 } | 888 } |
878 | 889 |
879 // HIGHLIGHT WORKER | 890 // HIGHLIGHT WORKER |
880 | 891 |
881 function startWorker(cm, time) { | 892 function startWorker(cm, time) { |
882 if (cm.doc.mode.startState && cm.doc.frontier < cm.display.showingTo) | 893 if (cm.doc.mode.startState && cm.doc.frontier < cm.display.showingTo) |
883 cm.state.highlight.set(time, bind(highlightWorker, cm)); | 894 cm.state.highlight.set(time, bind(highlightWorker, cm)); |
884 } | 895 } |
885 | 896 |
886 function highlightWorker(cm) { | 897 function highlightWorker(cm) { |
(...skipping 30 matching lines...) Expand all Loading... |
917 regChange(this, changed[i].start, changed[i].end); | 928 regChange(this, changed[i].start, changed[i].end); |
918 })(); | 929 })(); |
919 } | 930 } |
920 | 931 |
921 // Finds the line to start with when starting a parse. Tries to | 932 // Finds the line to start with when starting a parse. Tries to |
922 // find a line with a stateAfter, so that it can start with a | 933 // find a line with a stateAfter, so that it can start with a |
923 // valid state. If that fails, it returns the line with the | 934 // valid state. If that fails, it returns the line with the |
924 // smallest indentation, which tends to need the least context to | 935 // smallest indentation, which tends to need the least context to |
925 // parse correctly. | 936 // parse correctly. |
926 function findStartLine(cm, n, precise) { | 937 function findStartLine(cm, n, precise) { |
927 var minindent, minline, doc = cm.doc; | 938 var minindent, minline, doc = cm.doc, maxScan = cm.doc.mode.innerMode ? 1000
: 100; |
928 for (var search = n, lim = n - 100; search > lim; --search) { | 939 for (var search = n, lim = n - maxScan; search > lim; --search) { |
929 if (search <= doc.first) return doc.first; | 940 if (search <= doc.first) return doc.first; |
930 var line = getLine(doc, search - 1); | 941 var line = getLine(doc, search - 1); |
931 if (line.stateAfter && (!precise || search <= doc.frontier)) return search
; | 942 if (line.stateAfter && (!precise || search <= doc.frontier)) return search
; |
932 var indented = countColumn(line.text, null, cm.options.tabSize); | 943 var indented = countColumn(line.text, null, cm.options.tabSize); |
933 if (minline == null || minindent > indented) { | 944 if (minline == null || minindent > indented) { |
934 minline = search - 1; | 945 minline = search - 1; |
935 minindent = indented; | 946 minindent = indented; |
936 } | 947 } |
937 } | 948 } |
938 return minline; | 949 return minline; |
939 } | 950 } |
940 | 951 |
941 function getStateBefore(cm, n, precise) { | 952 function getStateBefore(cm, n, precise) { |
942 var doc = cm.doc, display = cm.display; | 953 var doc = cm.doc, display = cm.display; |
943 if (!doc.mode.startState) return true; | 954 if (!doc.mode.startState) return true; |
944 var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(
doc, pos-1).stateAfter; | 955 var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(
doc, pos-1).stateAfter; |
945 if (!state) state = startState(doc.mode); | 956 if (!state) state = startState(doc.mode); |
946 else state = copyState(doc.mode, state); | 957 else state = copyState(doc.mode, state); |
947 doc.iter(pos, n, function(line) { | 958 doc.iter(pos, n, function(line) { |
948 processLine(cm, line, state); | 959 processLine(cm, line, state); |
949 var save = pos == n - 1 || pos % 5 == 0 || pos >= display.showingFrom && p
os < display.showingTo; | 960 var save = pos == n - 1 || pos % 5 == 0 || pos >= display.showingFrom && p
os < display.showingTo; |
950 line.stateAfter = save ? copyState(doc.mode, state) : null; | 961 line.stateAfter = save ? copyState(doc.mode, state) : null; |
951 ++pos; | 962 ++pos; |
952 }); | 963 }); |
953 return state; | 964 return state; |
954 } | 965 } |
955 | 966 |
956 // POSITION MEASUREMENT | 967 // POSITION MEASUREMENT |
957 | 968 |
958 function paddingTop(display) {return display.lineSpace.offsetTop;} | 969 function paddingTop(display) {return display.lineSpace.offsetTop;} |
959 function paddingVert(display) {return display.mover.offsetHeight - display.lin
eSpace.offsetHeight;} | 970 function paddingVert(display) {return display.mover.offsetHeight - display.lin
eSpace.offsetHeight;} |
960 function paddingLeft(display) { | 971 function paddingLeft(display) { |
961 var e = removeChildrenAndAdd(display.measure, elt("pre", null, null, "text-a
lign: left")).appendChild(elt("span", "x")); | 972 var e = removeChildrenAndAdd(display.measure, elt("pre", null, null, "text-a
lign: left")).appendChild(elt("span", "x")); |
962 return e.offsetLeft; | 973 return e.offsetLeft; |
963 } | 974 } |
964 | 975 |
965 function measureChar(cm, line, ch, data, bias) { | 976 function measureChar(cm, line, ch, data, bias) { |
966 var dir = -1; | 977 var dir = -1; |
967 data = data || measureLine(cm, line); | 978 data = data || measureLine(cm, line); |
| 979 if (data.crude) { |
| 980 var left = data.left + ch * data.width; |
| 981 return {left: left, right: left + data.width, top: data.top, bottom: data.
bottom}; |
| 982 } |
968 | 983 |
969 for (var pos = ch;; pos += dir) { | 984 for (var pos = ch;; pos += dir) { |
970 var r = data.get(pos); | 985 var r = data[pos]; |
971 if (r) break; | 986 if (r) break; |
972 if (dir < 0 && pos == 0) dir = 1; | 987 if (dir < 0 && pos == 0) dir = 1; |
973 } | 988 } |
974 bias = pos > ch ? "left" : pos < ch ? "right" : bias; | 989 bias = pos > ch ? "left" : pos < ch ? "right" : bias; |
975 if (bias == "left" && r.leftSide) r = r.leftSide; | 990 if (bias == "left" && r.leftSide) r = r.leftSide; |
976 else if (bias == "right" && r.rightSide) r = r.rightSide; | 991 else if (bias == "right" && r.rightSide) r = r.rightSide; |
977 return {left: pos < ch ? r.right : r.left, | 992 return {left: pos < ch ? r.right : r.left, |
978 right: pos > ch ? r.left : r.right, | 993 right: pos > ch ? r.left : r.right, |
979 top: r.top, | 994 top: r.top, |
980 bottom: r.bottom}; | 995 bottom: r.bottom}; |
(...skipping 14 matching lines...) Expand all Loading... |
995 var exists = findCachedMeasurement(cm, line); | 1010 var exists = findCachedMeasurement(cm, line); |
996 if (exists) exists.text = exists.measure = exists.markedSpans = null; | 1011 if (exists) exists.text = exists.measure = exists.markedSpans = null; |
997 } | 1012 } |
998 | 1013 |
999 function measureLine(cm, line) { | 1014 function measureLine(cm, line) { |
1000 // First look in the cache | 1015 // First look in the cache |
1001 var cached = findCachedMeasurement(cm, line); | 1016 var cached = findCachedMeasurement(cm, line); |
1002 if (cached) return cached.measure; | 1017 if (cached) return cached.measure; |
1003 | 1018 |
1004 // Failing that, recompute and store result in cache | 1019 // Failing that, recompute and store result in cache |
1005 var measure = measureLineInner(cm, line, 0, 10); | 1020 var measure = measureLineInner(cm, line); |
1006 measure.get = function(num) { | |
1007 if (this[num]) return this[num]; | |
1008 if (num < 0 || num >= line.text.length) return null; | |
1009 measureLineInner(cm, line, Math.max(num - 50, 0), Math.min(num + 50, line.
text.length), this); | |
1010 return this[num]; | |
1011 }; | |
1012 var cache = cm.display.measureLineCache; | 1021 var cache = cm.display.measureLineCache; |
1013 var memo = {text: line.text, width: cm.display.scroller.clientWidth, | 1022 var memo = {text: line.text, width: cm.display.scroller.clientWidth, |
1014 markedSpans: line.markedSpans, measure: measure, | 1023 markedSpans: line.markedSpans, measure: measure, |
1015 classes: line.textClass + "|" + line.bgClass + "|" + line.wrapCl
ass}; | 1024 classes: line.textClass + "|" + line.bgClass + "|" + line.wrapCl
ass}; |
1016 if (cache.length == 16) cache[++cm.display.measureLineCachePos % 16] = memo; | 1025 if (cache.length == 16) cache[++cm.display.measureLineCachePos % 16] = memo; |
1017 else cache.push(memo); | 1026 else cache.push(memo); |
1018 return measure; | 1027 return measure; |
1019 } | 1028 } |
1020 | 1029 |
1021 function measureLineInner(cm, line, from, to, oldMeasure) { | 1030 function measureLineInner(cm, line) { |
| 1031 if (!cm.options.lineWrapping && line.text.length >= cm.options.crudeMeasurin
gFrom) |
| 1032 return crudelyMeasureLine(cm, line); |
| 1033 |
1022 var display = cm.display, measure = emptyArray(line.text.length); | 1034 var display = cm.display, measure = emptyArray(line.text.length); |
1023 var pre = lineContent(cm, line, measure, true, from, to); | 1035 var pre = buildLineContent(cm, line, measure, true).pre; |
1024 | 1036 |
1025 // IE does not cache element positions of inline elements between | 1037 // IE does not cache element positions of inline elements between |
1026 // calls to getBoundingClientRect. This makes the loop below, | 1038 // calls to getBoundingClientRect. This makes the loop below, |
1027 // which gathers the positions of all the characters on the line, | 1039 // which gathers the positions of all the characters on the line, |
1028 // do an amount of layout work quadratic to the number of | 1040 // do an amount of layout work quadratic to the number of |
1029 // characters. When line wrapping is off, we try to improve things | 1041 // characters. When line wrapping is off, we try to improve things |
1030 // by first subdividing the line into a bunch of inline blocks, so | 1042 // by first subdividing the line into a bunch of inline blocks, so |
1031 // that IE can reuse most of the layout information from caches | 1043 // that IE can reuse most of the layout information from caches |
1032 // for those blocks. This does interfere with line wrapping, so it | 1044 // for those blocks. This does interfere with line wrapping, so it |
1033 // doesn't work when wrapping is on, but in that case the | 1045 // doesn't work when wrapping is on, but in that case the |
1034 // situation is slightly better, since IE does cache line-wrapping | 1046 // situation is slightly better, since IE does cache line-wrapping |
1035 // information and only recomputes per-line. | 1047 // information and only recomputes per-line. |
1036 if (ie && !ie_lt8 && !cm.options.lineWrapping && pre.childNodes.length > 100
) { | 1048 if (ie && !ie_lt8 && !cm.options.lineWrapping && pre.childNodes.length > 100
) { |
1037 var fragment = document.createDocumentFragment(); | 1049 var fragment = document.createDocumentFragment(); |
1038 var chunk = 10, n = pre.childNodes.length; | 1050 var chunk = 10, n = pre.childNodes.length; |
1039 for (var i = 0, chunks = Math.ceil(n / chunk); i < chunks; ++i) { | 1051 for (var i = 0, chunks = Math.ceil(n / chunk); i < chunks; ++i) { |
1040 var wrap = elt("div", null, null, "display: inline-block"); | 1052 var wrap = elt("div", null, null, "display: inline-block"); |
1041 for (var j = 0; j < chunk && n; ++j) { | 1053 for (var j = 0; j < chunk && n; ++j) { |
1042 wrap.appendChild(pre.firstChild); | 1054 wrap.appendChild(pre.firstChild); |
1043 --n; | 1055 --n; |
1044 } | 1056 } |
1045 fragment.appendChild(wrap); | 1057 fragment.appendChild(wrap); |
1046 } | 1058 } |
1047 pre.appendChild(fragment); | 1059 pre.appendChild(fragment); |
1048 } | 1060 } |
1049 | 1061 |
1050 removeChildrenAndAdd(display.measure, pre); | 1062 removeChildrenAndAdd(display.measure, pre); |
1051 | 1063 |
1052 var outer = getRect(display.lineDiv); | 1064 var outer = getRect(display.lineDiv); |
1053 var vranges = [], data = oldMeasure || emptyArray(line.text.length), maxBot
= pre.offsetHeight; | 1065 var vranges = [], data = emptyArray(line.text.length), maxBot = pre.offsetHe
ight; |
1054 // Work around an IE7/8 bug where it will sometimes have randomly | 1066 // Work around an IE7/8 bug where it will sometimes have randomly |
1055 // replaced our pre with a clone at this point. | 1067 // replaced our pre with a clone at this point. |
1056 if (ie_lt9 && display.measure.first != pre) | 1068 if (ie_lt9 && display.measure.first != pre) |
1057 removeChildrenAndAdd(display.measure, pre); | 1069 removeChildrenAndAdd(display.measure, pre); |
1058 | 1070 |
1059 function measureRect(rect) { | 1071 function measureRect(rect) { |
1060 var top = rect.top - outer.top, bot = rect.bottom - outer.top; | 1072 var top = rect.top - outer.top, bot = rect.bottom - outer.top; |
1061 if (bot > maxBot) bot = maxBot; | 1073 if (bot > maxBot) bot = maxBot; |
1062 if (top < 0) top = 0; | 1074 if (top < 0) top = 0; |
1063 for (var i = vranges.length - 2; i >= 0; i -= 2) { | 1075 for (var i = vranges.length - 2; i >= 0; i -= 2) { |
(...skipping 25 matching lines...) Expand all Loading... |
1089 var rects = node.getClientRects(); | 1101 var rects = node.getClientRects(); |
1090 if (rects.length > 1) { | 1102 if (rects.length > 1) { |
1091 rect = data[i] = measureRect(rects[0]); | 1103 rect = data[i] = measureRect(rects[0]); |
1092 rect.rightSide = measureRect(rects[rects.length - 1]); | 1104 rect.rightSide = measureRect(rects[rects.length - 1]); |
1093 } | 1105 } |
1094 } | 1106 } |
1095 if (!rect) rect = data[i] = measureRect(getRect(node)); | 1107 if (!rect) rect = data[i] = measureRect(getRect(node)); |
1096 if (cur.measureRight) rect.right = getRect(cur.measureRight).left; | 1108 if (cur.measureRight) rect.right = getRect(cur.measureRight).left; |
1097 if (cur.leftSide) rect.leftSide = measureRect(getRect(cur.leftSide)); | 1109 if (cur.leftSide) rect.leftSide = measureRect(getRect(cur.leftSide)); |
1098 } | 1110 } |
1099 for (var i = 0, cur; i < data.length; ++i) if (measure[i] && (cur = data[i])
) { | 1111 removeChildren(cm.display.measure); |
| 1112 for (var i = 0, cur; i < data.length; ++i) if (cur = data[i]) { |
1100 finishRect(cur); | 1113 finishRect(cur); |
1101 if (cur.leftSide) finishRect(cur.leftSide); | 1114 if (cur.leftSide) finishRect(cur.leftSide); |
1102 if (cur.rightSide) finishRect(cur.rightSide); | 1115 if (cur.rightSide) finishRect(cur.rightSide); |
1103 } | 1116 } |
1104 return data; | 1117 return data; |
1105 } | 1118 } |
1106 | 1119 |
| 1120 function crudelyMeasureLine(cm, line) { |
| 1121 var copy = new Line(line.text.slice(0, 100), null); |
| 1122 if (line.textClass) copy.textClass = line.textClass; |
| 1123 var measure = measureLineInner(cm, copy); |
| 1124 var left = measureChar(cm, copy, 0, measure, "left"); |
| 1125 var right = measureChar(cm, copy, 99, measure, "right"); |
| 1126 return {crude: true, top: left.top, left: left.left, bottom: left.bottom, wi
dth: (right.right - left.left) / 100}; |
| 1127 } |
| 1128 |
1107 function measureLineWidth(cm, line) { | 1129 function measureLineWidth(cm, line) { |
1108 var hasBadSpan = false; | 1130 var hasBadSpan = false; |
1109 if (line.markedSpans) for (var i = 0; i < line.markedSpans; ++i) { | 1131 if (line.markedSpans) for (var i = 0; i < line.markedSpans; ++i) { |
1110 var sp = line.markedSpans[i]; | 1132 var sp = line.markedSpans[i]; |
1111 if (sp.collapsed && (sp.to == null || sp.to == line.text.length)) hasBadSp
an = true; | 1133 if (sp.collapsed && (sp.to == null || sp.to == line.text.length)) hasBadSp
an = true; |
1112 } | 1134 } |
1113 var cached = !hasBadSpan && findCachedMeasurement(cm, line); | 1135 var cached = !hasBadSpan && findCachedMeasurement(cm, line); |
1114 if (cached) return measureChar(cm, line, line.text.length, cached.measure, "
right").right; | 1136 if (cached || line.text.length >= cm.options.crudeMeasuringFrom) |
| 1137 return measureChar(cm, line, line.text.length, cached && cached.measure, "
right").right; |
1115 | 1138 |
1116 var pre = lineContent(cm, line, null, true); | 1139 var pre = buildLineContent(cm, line, null, true).pre; |
1117 var end = pre.appendChild(zeroWidthElement(cm.display.measure)); | 1140 var end = pre.appendChild(zeroWidthElement(cm.display.measure)); |
1118 removeChildrenAndAdd(cm.display.measure, pre); | 1141 removeChildrenAndAdd(cm.display.measure, pre); |
1119 return getRect(end).right - getRect(cm.display.lineDiv).left; | 1142 return getRect(end).right - getRect(cm.display.lineDiv).left; |
1120 } | 1143 } |
1121 | 1144 |
1122 function clearCaches(cm) { | 1145 function clearCaches(cm) { |
1123 cm.display.measureLineCache.length = cm.display.measureLineCachePos = 0; | 1146 cm.display.measureLineCache.length = cm.display.measureLineCachePos = 0; |
1124 cm.display.cachedCharWidth = cm.display.cachedTextHeight = null; | 1147 cm.display.cachedCharWidth = cm.display.cachedTextHeight = null; |
1125 if (!cm.options.lineWrapping) cm.display.maxLineChanged = true; | 1148 if (!cm.options.lineWrapping) cm.display.maxLineChanged = true; |
1126 cm.display.lineNumChars = null; | 1149 cm.display.lineNumChars = null; |
(...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1591 function drag_(e) { | 1614 function drag_(e) { |
1592 if (signalDOMEvent(cm, e) || cm.options.onDragEvent && cm.options.onDragEv
ent(cm, addStop(e))) return; | 1615 if (signalDOMEvent(cm, e) || cm.options.onDragEvent && cm.options.onDragEv
ent(cm, addStop(e))) return; |
1593 e_stop(e); | 1616 e_stop(e); |
1594 } | 1617 } |
1595 if (cm.options.dragDrop) { | 1618 if (cm.options.dragDrop) { |
1596 on(d.scroller, "dragstart", function(e){onDragStart(cm, e);}); | 1619 on(d.scroller, "dragstart", function(e){onDragStart(cm, e);}); |
1597 on(d.scroller, "dragenter", drag_); | 1620 on(d.scroller, "dragenter", drag_); |
1598 on(d.scroller, "dragover", drag_); | 1621 on(d.scroller, "dragover", drag_); |
1599 on(d.scroller, "drop", operation(cm, onDrop)); | 1622 on(d.scroller, "drop", operation(cm, onDrop)); |
1600 } | 1623 } |
1601 on(d.scroller, "paste", function(e){ | 1624 on(d.scroller, "paste", function(e) { |
1602 if (eventInWidget(d, e)) return; | 1625 if (eventInWidget(d, e)) return; |
1603 focusInput(cm); | 1626 focusInput(cm); |
1604 fastPoll(cm); | 1627 fastPoll(cm); |
1605 }); | 1628 }); |
1606 on(d.input, "paste", function() { | 1629 on(d.input, "paste", function() { |
1607 // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206 | 1630 // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206 |
1608 // Add a char to the end of textarea before paste occur so that | 1631 // Add a char to the end of textarea before paste occur so that |
1609 // selection doesn't span to the end of textarea. | 1632 // selection doesn't span to the end of textarea. |
1610 if (webkit && !cm.state.fakedLastChar) { | 1633 if (webkit && !cm.state.fakedLastChar && !(new Date - cm.state.lastMiddleD
own < 200)) { |
1611 var start = d.input.selectionStart, end = d.input.selectionEnd; | 1634 var start = d.input.selectionStart, end = d.input.selectionEnd; |
1612 d.input.value += "$"; | 1635 d.input.value += "$"; |
1613 d.input.selectionStart = start; | 1636 d.input.selectionStart = start; |
1614 d.input.selectionEnd = end; | 1637 d.input.selectionEnd = end; |
1615 cm.state.fakedLastChar = true; | 1638 cm.state.fakedLastChar = true; |
1616 } | 1639 } |
1617 cm.state.pasteIncoming = true; | 1640 cm.state.pasteIncoming = true; |
1618 fastPoll(cm); | 1641 fastPoll(cm); |
1619 }); | 1642 }); |
1620 | 1643 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1670 return; | 1693 return; |
1671 } | 1694 } |
1672 if (clickInGutter(cm, e)) return; | 1695 if (clickInGutter(cm, e)) return; |
1673 var start = posFromMouse(cm, e); | 1696 var start = posFromMouse(cm, e); |
1674 | 1697 |
1675 switch (e_button(e)) { | 1698 switch (e_button(e)) { |
1676 case 3: | 1699 case 3: |
1677 if (captureMiddleClick) onContextMenu.call(cm, cm, e); | 1700 if (captureMiddleClick) onContextMenu.call(cm, cm, e); |
1678 return; | 1701 return; |
1679 case 2: | 1702 case 2: |
| 1703 if (webkit) cm.state.lastMiddleDown = +new Date; |
1680 if (start) extendSelection(cm.doc, start); | 1704 if (start) extendSelection(cm.doc, start); |
1681 setTimeout(bind(focusInput, cm), 20); | 1705 setTimeout(bind(focusInput, cm), 20); |
1682 e_preventDefault(e); | 1706 e_preventDefault(e); |
1683 return; | 1707 return; |
1684 } | 1708 } |
1685 // For button 1, if it was clicked inside the editor | 1709 // For button 1, if it was clicked inside the editor |
1686 // (posFromMouse returning non-null), we have to adjust the | 1710 // (posFromMouse returning non-null), we have to adjust the |
1687 // selection. | 1711 // selection. |
1688 if (!start) {if (e_target(e) == display.scroller) e_preventDefault(e); retur
n;} | 1712 if (!start) {if (e_target(e) == display.scroller) e_preventDefault(e); retur
n;} |
1689 | 1713 |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1790 | 1814 |
1791 var move = operation(cm, function(e) { | 1815 var move = operation(cm, function(e) { |
1792 if (!ie && !e_button(e)) done(e); | 1816 if (!ie && !e_button(e)) done(e); |
1793 else extend(e); | 1817 else extend(e); |
1794 }); | 1818 }); |
1795 var up = operation(cm, done); | 1819 var up = operation(cm, done); |
1796 on(document, "mousemove", move); | 1820 on(document, "mousemove", move); |
1797 on(document, "mouseup", up); | 1821 on(document, "mouseup", up); |
1798 } | 1822 } |
1799 | 1823 |
1800 function clickInGutter(cm, e) { | 1824 function gutterEvent(cm, e, type, prevent, signalfn) { |
1801 var display = cm.display; | |
1802 try { var mX = e.clientX, mY = e.clientY; } | 1825 try { var mX = e.clientX, mY = e.clientY; } |
1803 catch(e) { return false; } | 1826 catch(e) { return false; } |
| 1827 if (mX >= Math.floor(getRect(cm.display.gutters).right)) return false; |
| 1828 if (prevent) e_preventDefault(e); |
1804 | 1829 |
1805 if (mX >= Math.floor(getRect(display.gutters).right)) return false; | 1830 var display = cm.display; |
1806 e_preventDefault(e); | 1831 var lineBox = getRect(display.lineDiv); |
1807 if (!hasHandler(cm, "gutterClick")) return true; | |
1808 | 1832 |
1809 var lineBox = getRect(display.lineDiv); | 1833 if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(
e); |
1810 if (mY > lineBox.bottom) return true; | |
1811 mY -= lineBox.top - display.viewOffset; | 1834 mY -= lineBox.top - display.viewOffset; |
1812 | 1835 |
1813 for (var i = 0; i < cm.options.gutters.length; ++i) { | 1836 for (var i = 0; i < cm.options.gutters.length; ++i) { |
1814 var g = display.gutters.childNodes[i]; | 1837 var g = display.gutters.childNodes[i]; |
1815 if (g && getRect(g).right >= mX) { | 1838 if (g && getRect(g).right >= mX) { |
1816 var line = lineAtHeight(cm.doc, mY); | 1839 var line = lineAtHeight(cm.doc, mY); |
1817 var gutter = cm.options.gutters[i]; | 1840 var gutter = cm.options.gutters[i]; |
1818 signalLater(cm, "gutterClick", cm, line, gutter, e); | 1841 signalfn(cm, type, cm, line, gutter, e); |
1819 break; | 1842 return e_defaultPrevented(e); |
1820 } | 1843 } |
1821 } | 1844 } |
1822 return true; | 1845 } |
| 1846 |
| 1847 function contextMenuInGutter(cm, e) { |
| 1848 if (!hasHandler(cm, "gutterContextMenu")) return false; |
| 1849 return gutterEvent(cm, e, "gutterContextMenu", false, signal); |
| 1850 } |
| 1851 |
| 1852 function clickInGutter(cm, e) { |
| 1853 return gutterEvent(cm, e, "gutterClick", true, signalLater); |
1823 } | 1854 } |
1824 | 1855 |
1825 // Kludge to work around strange IE behavior where it'll sometimes | 1856 // Kludge to work around strange IE behavior where it'll sometimes |
1826 // re-fire a series of drag-related events right after the drop (#1551) | 1857 // re-fire a series of drag-related events right after the drop (#1551) |
1827 var lastDrop = 0; | 1858 var lastDrop = 0; |
1828 | 1859 |
1829 function onDrop(e) { | 1860 function onDrop(e) { |
1830 var cm = this; | 1861 var cm = this; |
1831 if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e) || (cm.options.onD
ragEvent && cm.options.onDragEvent(cm, addStop(e)))) | 1862 if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e) || (cm.options.onD
ragEvent && cm.options.onDragEvent(cm, addStop(e)))) |
1832 return; | 1863 return; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1875 if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e
); return; } | 1906 if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e
); return; } |
1876 if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return; | 1907 if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return; |
1877 | 1908 |
1878 var txt = cm.getSelection(); | 1909 var txt = cm.getSelection(); |
1879 e.dataTransfer.setData("Text", txt); | 1910 e.dataTransfer.setData("Text", txt); |
1880 | 1911 |
1881 // Use dummy image instead of default browsers image. | 1912 // Use dummy image instead of default browsers image. |
1882 // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so
we don't do it there. | 1913 // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so
we don't do it there. |
1883 if (e.dataTransfer.setDragImage && !safari) { | 1914 if (e.dataTransfer.setDragImage && !safari) { |
1884 var img = elt("img", null, null, "position: fixed; left: 0; top: 0;"); | 1915 var img = elt("img", null, null, "position: fixed; left: 0; top: 0;"); |
| 1916 img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAA
AICTAEAOw=="; |
1885 if (opera) { | 1917 if (opera) { |
1886 img.width = img.height = 1; | 1918 img.width = img.height = 1; |
1887 cm.display.wrapper.appendChild(img); | 1919 cm.display.wrapper.appendChild(img); |
1888 // Force a relayout, or Opera won't use our image for some obscure reaso
n | 1920 // Force a relayout, or Opera won't use our image for some obscure reaso
n |
1889 img._top = img.offsetTop; | 1921 img._top = img.offsetTop; |
1890 } | 1922 } |
1891 e.dataTransfer.setDragImage(img, 0, 0); | 1923 e.dataTransfer.setDragImage(img, 0, 0); |
1892 if (opera) img.parentNode.removeChild(img); | 1924 if (opera) img.parentNode.removeChild(img); |
1893 } | 1925 } |
1894 } | 1926 } |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2073 restartBlink(cm); | 2105 restartBlink(cm); |
2074 signalLater(cm, "keyHandled", cm, "'" + ch + "'", e); | 2106 signalLater(cm, "keyHandled", cm, "'" + ch + "'", e); |
2075 } | 2107 } |
2076 return handled; | 2108 return handled; |
2077 } | 2109 } |
2078 | 2110 |
2079 var lastStoppedKey = null; | 2111 var lastStoppedKey = null; |
2080 function onKeyDown(e) { | 2112 function onKeyDown(e) { |
2081 var cm = this; | 2113 var cm = this; |
2082 if (!cm.state.focused) onFocus(cm); | 2114 if (!cm.state.focused) onFocus(cm); |
2083 if (ie && e.keyCode == 27) { e.returnValue = false; } | |
2084 if (signalDOMEvent(cm, e) || cm.options.onKeyEvent && cm.options.onKeyEvent(
cm, addStop(e))) return; | 2115 if (signalDOMEvent(cm, e) || cm.options.onKeyEvent && cm.options.onKeyEvent(
cm, addStop(e))) return; |
| 2116 if (ie && e.keyCode == 27) e.returnValue = false; |
2085 var code = e.keyCode; | 2117 var code = e.keyCode; |
2086 // IE does strange things with escape. | 2118 // IE does strange things with escape. |
2087 cm.doc.sel.shift = code == 16 || e.shiftKey; | 2119 cm.doc.sel.shift = code == 16 || e.shiftKey; |
2088 // First give onKeyEvent option a chance to handle this. | 2120 // First give onKeyEvent option a chance to handle this. |
2089 var handled = handleKeyBinding(cm, e); | 2121 var handled = handleKeyBinding(cm, e); |
2090 if (opera) { | 2122 if (opera) { |
2091 lastStoppedKey = handled ? code : null; | 2123 lastStoppedKey = handled ? code : null; |
2092 // Opera has no cut event... we try to at least catch the key combo | 2124 // Opera has no cut event... we try to at least catch the key combo |
2093 if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKe
y)) | 2125 if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKe
y)) |
2094 cm.replaceSelection(""); | 2126 cm.replaceSelection(""); |
(...skipping 16 matching lines...) Expand all Loading... |
2111 fastPoll(cm); | 2143 fastPoll(cm); |
2112 } | 2144 } |
2113 | 2145 |
2114 function onFocus(cm) { | 2146 function onFocus(cm) { |
2115 if (cm.options.readOnly == "nocursor") return; | 2147 if (cm.options.readOnly == "nocursor") return; |
2116 if (!cm.state.focused) { | 2148 if (!cm.state.focused) { |
2117 signal(cm, "focus", cm); | 2149 signal(cm, "focus", cm); |
2118 cm.state.focused = true; | 2150 cm.state.focused = true; |
2119 if (cm.display.wrapper.className.search(/\bCodeMirror-focused\b/) == -1) | 2151 if (cm.display.wrapper.className.search(/\bCodeMirror-focused\b/) == -1) |
2120 cm.display.wrapper.className += " CodeMirror-focused"; | 2152 cm.display.wrapper.className += " CodeMirror-focused"; |
2121 resetInput(cm, true); | 2153 if (!cm.curOp) { |
| 2154 resetInput(cm, true); |
| 2155 if (webkit) setTimeout(bind(resetInput, cm, true), 0); // Issue #1730 |
| 2156 } |
2122 } | 2157 } |
2123 slowPoll(cm); | 2158 slowPoll(cm); |
2124 restartBlink(cm); | 2159 restartBlink(cm); |
2125 } | 2160 } |
2126 function onBlur(cm) { | 2161 function onBlur(cm) { |
2127 if (cm.state.focused) { | 2162 if (cm.state.focused) { |
2128 signal(cm, "blur", cm); | 2163 signal(cm, "blur", cm); |
2129 cm.state.focused = false; | 2164 cm.state.focused = false; |
2130 cm.display.wrapper.className = cm.display.wrapper.className.replace(" Code
Mirror-focused", ""); | 2165 cm.display.wrapper.className = cm.display.wrapper.className.replace(" Code
Mirror-focused", ""); |
2131 } | 2166 } |
2132 clearInterval(cm.display.blinker); | 2167 clearInterval(cm.display.blinker); |
2133 setTimeout(function() {if (!cm.state.focused) cm.doc.sel.shift = false;}, 15
0); | 2168 setTimeout(function() {if (!cm.state.focused) cm.doc.sel.shift = false;}, 15
0); |
2134 } | 2169 } |
2135 | 2170 |
2136 var detectingSelectAll; | 2171 var detectingSelectAll; |
2137 function onContextMenu(cm, e) { | 2172 function onContextMenu(cm, e) { |
2138 if (signalDOMEvent(cm, e, "contextmenu")) return; | 2173 if (signalDOMEvent(cm, e, "contextmenu")) return; |
2139 var display = cm.display, sel = cm.doc.sel; | 2174 var display = cm.display, sel = cm.doc.sel; |
2140 if (eventInWidget(display, e)) return; | 2175 if (eventInWidget(display, e) || contextMenuInGutter(cm, e)) return; |
2141 | 2176 |
2142 var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop; | 2177 var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop; |
2143 if (!pos || opera) return; // Opera is difficult. | 2178 if (!pos || opera) return; // Opera is difficult. |
2144 if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.t
o)) | 2179 if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.t
o)) |
2145 operation(cm, setSelection)(cm.doc, pos, pos); | 2180 operation(cm, setSelection)(cm.doc, pos, pos); |
2146 | 2181 |
2147 var oldCSS = display.input.style.cssText; | 2182 var oldCSS = display.input.style.cssText; |
2148 display.inputDiv.style.position = "absolute"; | 2183 display.inputDiv.style.position = "absolute"; |
2149 display.input.style.cssText = "position: fixed; width: 30px; height: 30px; t
op: " + (e.clientY - 5) + | 2184 display.input.style.cssText = "position: fixed; width: 30px; height: 30px; t
op: " + (e.clientY - 5) + |
2150 "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: white; ou
tline: none;" + | 2185 "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: white; ou
tline: none;" + |
2151 "border-width: 0; outline: none; overflow: hidden; opacity: .05; -ms-opaci
ty: .05; filter: alpha(opacity=5);"; | 2186 "border-width: 0; outline: none; overflow: hidden; opacity: .05; -ms-opaci
ty: .05; filter: alpha(opacity=5);"; |
2152 focusInput(cm); | 2187 focusInput(cm); |
2153 resetInput(cm, true); | 2188 resetInput(cm, true); |
2154 // Adds "Select all" to context menu in FF | 2189 // Adds "Select all" to context menu in FF |
2155 if (posEq(sel.from, sel.to)) display.input.value = display.prevInput = " "; | 2190 if (posEq(sel.from, sel.to)) display.input.value = display.prevInput = " "; |
2156 | 2191 |
2157 function prepareSelectAllHack() { | 2192 function prepareSelectAllHack() { |
2158 if (display.input.selectionStart != null) { | 2193 if (display.input.selectionStart != null) { |
2159 var extval = display.input.value = " " + (posEq(sel.from, sel.to) ? "" :
display.input.value); | 2194 var extval = display.input.value = "\u200b" + (posEq(sel.from, sel.to) ?
"" : display.input.value); |
2160 display.prevInput = " "; | 2195 display.prevInput = "\u200b"; |
2161 display.input.selectionStart = 1; display.input.selectionEnd = extval.le
ngth; | 2196 display.input.selectionStart = 1; display.input.selectionEnd = extval.le
ngth; |
2162 } | 2197 } |
2163 } | 2198 } |
2164 function rehide() { | 2199 function rehide() { |
2165 display.inputDiv.style.position = "relative"; | 2200 display.inputDiv.style.position = "relative"; |
2166 display.input.style.cssText = oldCSS; | 2201 display.input.style.cssText = oldCSS; |
2167 if (ie_lt9) display.scrollbarV.scrollTop = display.scroller.scrollTop = sc
rollPos; | 2202 if (ie_lt9) display.scrollbarV.scrollTop = display.scroller.scrollTop = sc
rollPos; |
2168 slowPoll(cm); | 2203 slowPoll(cm); |
2169 | 2204 |
2170 // Try to detect the user choosing select-all | 2205 // Try to detect the user choosing select-all |
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2506 // numbers before the update. | 2541 // numbers before the update. |
2507 function setSelection(doc, anchor, head, bias, checkAtomic) { | 2542 function setSelection(doc, anchor, head, bias, checkAtomic) { |
2508 if (!checkAtomic && hasHandler(doc, "beforeSelectionChange") || doc.cm && ha
sHandler(doc.cm, "beforeSelectionChange")) { | 2543 if (!checkAtomic && hasHandler(doc, "beforeSelectionChange") || doc.cm && ha
sHandler(doc.cm, "beforeSelectionChange")) { |
2509 var filtered = filterSelectionChange(doc, anchor, head); | 2544 var filtered = filterSelectionChange(doc, anchor, head); |
2510 head = filtered.head; | 2545 head = filtered.head; |
2511 anchor = filtered.anchor; | 2546 anchor = filtered.anchor; |
2512 } | 2547 } |
2513 | 2548 |
2514 var sel = doc.sel; | 2549 var sel = doc.sel; |
2515 sel.goalColumn = null; | 2550 sel.goalColumn = null; |
| 2551 if (bias == null) bias = posLess(head, sel.head) ? -1 : 1; |
2516 // Skip over atomic spans. | 2552 // Skip over atomic spans. |
2517 if (checkAtomic || !posEq(anchor, sel.anchor)) | 2553 if (checkAtomic || !posEq(anchor, sel.anchor)) |
2518 anchor = skipAtomic(doc, anchor, bias, checkAtomic != "push"); | 2554 anchor = skipAtomic(doc, anchor, bias, checkAtomic != "push"); |
2519 if (checkAtomic || !posEq(head, sel.head)) | 2555 if (checkAtomic || !posEq(head, sel.head)) |
2520 head = skipAtomic(doc, head, bias, checkAtomic != "push"); | 2556 head = skipAtomic(doc, head, bias, checkAtomic != "push"); |
2521 | 2557 |
2522 if (posEq(sel.anchor, anchor) && posEq(sel.head, head)) return; | 2558 if (posEq(sel.anchor, anchor) && posEq(sel.head, head)) return; |
2523 | 2559 |
2524 sel.anchor = anchor; sel.head = head; | 2560 sel.anchor = anchor; sel.head = head; |
2525 var inv = posLess(head, anchor); | 2561 var inv = posLess(head, anchor); |
(...skipping 624 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3150 if (width != null) this.display.wrapper.style.width = interpret(width); | 3186 if (width != null) this.display.wrapper.style.width = interpret(width); |
3151 if (height != null) this.display.wrapper.style.height = interpret(height); | 3187 if (height != null) this.display.wrapper.style.height = interpret(height); |
3152 if (this.options.lineWrapping) | 3188 if (this.options.lineWrapping) |
3153 this.display.measureLineCache.length = this.display.measureLineCachePos
= 0; | 3189 this.display.measureLineCache.length = this.display.measureLineCachePos
= 0; |
3154 this.curOp.forceUpdate = true; | 3190 this.curOp.forceUpdate = true; |
3155 }), | 3191 }), |
3156 | 3192 |
3157 operation: function(f){return runInOp(this, f);}, | 3193 operation: function(f){return runInOp(this, f);}, |
3158 | 3194 |
3159 refresh: operation(null, function() { | 3195 refresh: operation(null, function() { |
| 3196 var badHeight = this.display.cachedTextHeight == null; |
3160 clearCaches(this); | 3197 clearCaches(this); |
3161 updateScrollPos(this, this.doc.scrollLeft, this.doc.scrollTop); | 3198 updateScrollPos(this, this.doc.scrollLeft, this.doc.scrollTop); |
3162 regChange(this); | 3199 regChange(this); |
| 3200 if (badHeight) estimateLineHeights(this); |
3163 }), | 3201 }), |
3164 | 3202 |
3165 swapDoc: operation(null, function(doc) { | 3203 swapDoc: operation(null, function(doc) { |
3166 var old = this.doc; | 3204 var old = this.doc; |
3167 old.cm = null; | 3205 old.cm = null; |
3168 attachDoc(this, doc); | 3206 attachDoc(this, doc); |
3169 clearCaches(this); | 3207 clearCaches(this); |
3170 resetInput(this, true); | 3208 resetInput(this, true); |
3171 updateScrollPos(this, doc.scrollLeft, doc.scrollTop); | 3209 updateScrollPos(this, doc.scrollLeft, doc.scrollTop); |
3172 return old; | 3210 return old; |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3253 option("cursorScrollMargin", 0); | 3291 option("cursorScrollMargin", 0); |
3254 option("cursorHeight", 1); | 3292 option("cursorHeight", 1); |
3255 option("workTime", 100); | 3293 option("workTime", 100); |
3256 option("workDelay", 100); | 3294 option("workDelay", 100); |
3257 option("flattenSpans", true); | 3295 option("flattenSpans", true); |
3258 option("pollInterval", 100); | 3296 option("pollInterval", 100); |
3259 option("undoDepth", 40, function(cm, val){cm.doc.history.undoDepth = val;}); | 3297 option("undoDepth", 40, function(cm, val){cm.doc.history.undoDepth = val;}); |
3260 option("historyEventDelay", 500); | 3298 option("historyEventDelay", 500); |
3261 option("viewportMargin", 10, function(cm){cm.refresh();}, true); | 3299 option("viewportMargin", 10, function(cm){cm.refresh();}, true); |
3262 option("maxHighlightLength", 10000, function(cm){loadMode(cm); cm.refresh();},
true); | 3300 option("maxHighlightLength", 10000, function(cm){loadMode(cm); cm.refresh();},
true); |
| 3301 option("crudeMeasuringFrom", 10000); |
3263 option("moveInputWithCursor", true, function(cm, val) { | 3302 option("moveInputWithCursor", true, function(cm, val) { |
3264 if (!val) cm.display.inputDiv.style.top = cm.display.inputDiv.style.left = 0
; | 3303 if (!val) cm.display.inputDiv.style.top = cm.display.inputDiv.style.left = 0
; |
3265 }); | 3304 }); |
3266 | 3305 |
3267 option("tabindex", null, function(cm, val) { | 3306 option("tabindex", null, function(cm, val) { |
3268 cm.display.input.tabIndex = val || ""; | 3307 cm.display.input.tabIndex = val || ""; |
3269 }); | 3308 }); |
3270 option("autofocus", null); | 3309 option("autofocus", null); |
3271 | 3310 |
3272 // MODE DEFINITION AND QUERYING | 3311 // MODE DEFINITION AND QUERYING |
(...skipping 922 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4195 // classes. | 4234 // classes. |
4196 function runMode(cm, text, mode, state, f) { | 4235 function runMode(cm, text, mode, state, f) { |
4197 var flattenSpans = mode.flattenSpans; | 4236 var flattenSpans = mode.flattenSpans; |
4198 if (flattenSpans == null) flattenSpans = cm.options.flattenSpans; | 4237 if (flattenSpans == null) flattenSpans = cm.options.flattenSpans; |
4199 var curStart = 0, curStyle = null; | 4238 var curStart = 0, curStyle = null; |
4200 var stream = new StringStream(text, cm.options.tabSize), style; | 4239 var stream = new StringStream(text, cm.options.tabSize), style; |
4201 if (text == "" && mode.blankLine) mode.blankLine(state); | 4240 if (text == "" && mode.blankLine) mode.blankLine(state); |
4202 while (!stream.eol()) { | 4241 while (!stream.eol()) { |
4203 if (stream.pos > cm.options.maxHighlightLength) { | 4242 if (stream.pos > cm.options.maxHighlightLength) { |
4204 flattenSpans = false; | 4243 flattenSpans = false; |
4205 // Webkit seems to refuse to render text nodes longer than 57444 charact
ers | 4244 stream.pos = text.length; |
4206 stream.pos = Math.min(text.length, stream.start + 50000); | |
4207 style = null; | 4245 style = null; |
4208 } else { | 4246 } else { |
4209 style = mode.token(stream, state); | 4247 style = mode.token(stream, state); |
4210 } | 4248 } |
4211 if (!flattenSpans || curStyle != style) { | 4249 if (!flattenSpans || curStyle != style) { |
4212 if (curStart < stream.start) f(stream.start, curStyle); | 4250 if (curStart < stream.start) f(stream.start, curStyle); |
4213 curStart = stream.start; curStyle = style; | 4251 curStart = stream.start; curStyle = style; |
4214 } | 4252 } |
4215 stream.start = stream.pos; | 4253 stream.start = stream.pos; |
4216 } | 4254 } |
4217 if (curStart < stream.pos) f(stream.pos, curStyle); | 4255 while (curStart < stream.pos) { |
| 4256 // Webkit seems to refuse to render text nodes longer than 57444 character
s |
| 4257 var pos = Math.min(stream.pos, curStart + 50000); |
| 4258 f(pos, curStyle); |
| 4259 curStart = pos; |
| 4260 } |
4218 } | 4261 } |
4219 | 4262 |
4220 function highlightLine(cm, line, state) { | 4263 function highlightLine(cm, line, state) { |
4221 // A styles array always starts with a number identifying the | 4264 // A styles array always starts with a number identifying the |
4222 // mode/overlays that it is based on (for easy invalidation). | 4265 // mode/overlays that it is based on (for easy invalidation). |
4223 var st = [cm.state.modeGen]; | 4266 var st = [cm.state.modeGen]; |
4224 // Compute the base array of styles | 4267 // Compute the base array of styles |
4225 runMode(cm, line.text, cm.doc.mode, state, function(end, style) {st.push(end
, style);}); | 4268 runMode(cm, line.text, cm.doc.mode, state, function(end, style) {st.push(end
, style);}); |
4226 | 4269 |
4227 // Run overlays, adjust style array. | 4270 // Run overlays, adjust style array. |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4265 var mode = cm.doc.mode; | 4308 var mode = cm.doc.mode; |
4266 var stream = new StringStream(line.text, cm.options.tabSize); | 4309 var stream = new StringStream(line.text, cm.options.tabSize); |
4267 if (line.text == "" && mode.blankLine) mode.blankLine(state); | 4310 if (line.text == "" && mode.blankLine) mode.blankLine(state); |
4268 while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) { | 4311 while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) { |
4269 mode.token(stream, state); | 4312 mode.token(stream, state); |
4270 stream.start = stream.pos; | 4313 stream.start = stream.pos; |
4271 } | 4314 } |
4272 } | 4315 } |
4273 | 4316 |
4274 var styleToClassCache = {}; | 4317 var styleToClassCache = {}; |
4275 function styleToClass(style) { | 4318 function interpretTokenStyle(style, builder) { |
4276 if (!style) return null; | 4319 if (!style) return null; |
| 4320 for (;;) { |
| 4321 var lineClass = style.match(/(?:^|\s)line-(background-)?(\S+)/); |
| 4322 if (!lineClass) break; |
| 4323 style = style.slice(0, lineClass.index) + style.slice(lineClass.index + li
neClass[0].length); |
| 4324 var prop = lineClass[1] ? "bgClass" : "textClass"; |
| 4325 if (builder[prop] == null) |
| 4326 builder[prop] = lineClass[2]; |
| 4327 else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(builde
r[prop])) |
| 4328 builder[prop] += " " + lineClass[2]; |
| 4329 } |
4277 return styleToClassCache[style] || | 4330 return styleToClassCache[style] || |
4278 (styleToClassCache[style] = "cm-" + style.replace(/ +/g, " cm-")); | 4331 (styleToClassCache[style] = "cm-" + style.replace(/ +/g, " cm-")); |
4279 } | 4332 } |
4280 | 4333 |
4281 function lineContent(cm, realLine, measure, copyWidgets, from, to) { | 4334 function buildLineContent(cm, realLine, measure, copyWidgets) { |
4282 var merged, line = realLine, empty = true; | 4335 var merged, line = realLine, empty = true; |
4283 while (merged = collapsedSpanAtStart(line)) | 4336 while (merged = collapsedSpanAtStart(line)) |
4284 line = getLine(cm.doc, merged.find().from.line); | 4337 line = getLine(cm.doc, merged.find().from.line); |
4285 | 4338 |
4286 var builder = {pre: elt("pre"), col: 0, pos: 0, | 4339 var builder = {pre: elt("pre"), col: 0, pos: 0, |
4287 measure: null, measuredSomething: false, cm: cm, from: from,
to: to, | 4340 measure: null, measuredSomething: false, cm: cm, |
4288 copyWidgets: copyWidgets}; | 4341 copyWidgets: copyWidgets}; |
4289 if (line.textClass) builder.pre.className = line.textClass; | |
4290 | 4342 |
4291 do { | 4343 do { |
4292 if (line.text) empty = false; | 4344 if (line.text) empty = false; |
4293 builder.measure = line == realLine && measure; | 4345 builder.measure = line == realLine && measure; |
4294 builder.pos = 0; | 4346 builder.pos = 0; |
4295 builder.addToken = builder.measure ? buildTokenMeasure : buildToken; | 4347 builder.addToken = builder.measure ? buildTokenMeasure : buildToken; |
4296 if ((ie || webkit) && cm.getOption("lineWrapping")) | 4348 if ((ie || webkit) && cm.getOption("lineWrapping")) |
4297 builder.addToken = buildTokenSplitSpaces(builder.addToken); | 4349 builder.addToken = buildTokenSplitSpaces(builder.addToken); |
4298 var next = insertLineContent(line, builder, getLineStyles(cm, line)); | 4350 var next = insertLineContent(line, builder, getLineStyles(cm, line)); |
4299 if (measure && line == realLine && !builder.measuredSomething) { | 4351 if (measure && line == realLine && !builder.measuredSomething) { |
(...skipping 16 matching lines...) Expand all Loading... |
4316 var l = order.length - 1; | 4368 var l = order.length - 1; |
4317 if (order[l].from == order[l].to) --l; | 4369 if (order[l].from == order[l].to) --l; |
4318 var last = order[l], prev = order[l - 1]; | 4370 var last = order[l], prev = order[l - 1]; |
4319 if (last.from + 1 == last.to && prev && last.level < prev.level) { | 4371 if (last.from + 1 == last.to && prev && last.level < prev.level) { |
4320 var span = measure[builder.pos - 1]; | 4372 var span = measure[builder.pos - 1]; |
4321 if (span) span.parentNode.insertBefore(span.measureRight = zeroWidthElem
ent(cm.display.measure), | 4373 if (span) span.parentNode.insertBefore(span.measureRight = zeroWidthElem
ent(cm.display.measure), |
4322 span.nextSibling); | 4374 span.nextSibling); |
4323 } | 4375 } |
4324 } | 4376 } |
4325 | 4377 |
| 4378 var textClass = builder.textClass ? builder.textClass + " " + (realLine.text
Class || "") : realLine.textClass; |
| 4379 if (textClass) builder.pre.className = textClass; |
| 4380 |
4326 signal(cm, "renderLine", cm, realLine, builder.pre); | 4381 signal(cm, "renderLine", cm, realLine, builder.pre); |
4327 return builder.pre; | 4382 return builder; |
4328 } | 4383 } |
4329 | 4384 |
4330 var tokenSpecialChars = /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\uFEFF]/g; | 4385 var tokenSpecialChars = /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\uFEFF]/g; |
4331 function buildToken(builder, text, style, startStyle, endStyle, title) { | 4386 function buildToken(builder, text, style, startStyle, endStyle, title) { |
4332 if (!text) return; | 4387 if (!text) return; |
4333 if (!tokenSpecialChars.test(text)) { | 4388 if (!tokenSpecialChars.test(text)) { |
4334 builder.col += text.length; | 4389 builder.col += text.length; |
4335 var content = document.createTextNode(text); | 4390 var content = document.createTextNode(text); |
4336 } else { | 4391 } else { |
4337 var content = document.createDocumentFragment(), pos = 0; | 4392 var content = document.createDocumentFragment(), pos = 0; |
(...skipping 24 matching lines...) Expand all Loading... |
4362 if (startStyle) fullStyle += startStyle; | 4417 if (startStyle) fullStyle += startStyle; |
4363 if (endStyle) fullStyle += endStyle; | 4418 if (endStyle) fullStyle += endStyle; |
4364 var token = elt("span", [content], fullStyle); | 4419 var token = elt("span", [content], fullStyle); |
4365 if (title) token.title = title; | 4420 if (title) token.title = title; |
4366 return builder.pre.appendChild(token); | 4421 return builder.pre.appendChild(token); |
4367 } | 4422 } |
4368 builder.pre.appendChild(content); | 4423 builder.pre.appendChild(content); |
4369 } | 4424 } |
4370 | 4425 |
4371 function buildTokenMeasure(builder, text, style, startStyle, endStyle) { | 4426 function buildTokenMeasure(builder, text, style, startStyle, endStyle) { |
4372 //FIXME consider 2-byte chars | |
4373 if (builder.from || builder.to) { | |
4374 if (builder.from >= builder.pos + text.length) { | |
4375 buildToken(builder, text, style, startStyle, endStyle); | |
4376 builder.pos += text.length; | |
4377 return; | |
4378 } | |
4379 } | |
4380 var wrapping = builder.cm.options.lineWrapping; | 4427 var wrapping = builder.cm.options.lineWrapping; |
4381 for (var i = 0; i < text.length; ++i) { | 4428 for (var i = 0; i < text.length; ++i) { |
4382 var ch = text.charAt(i), start = i == 0; | 4429 var ch = text.charAt(i), start = i == 0; |
4383 if (ch >= "\ud800" && ch < "\udbff" && i < text.length - 1) { | 4430 if (ch >= "\ud800" && ch < "\udbff" && i < text.length - 1) { |
4384 ch = text.slice(i, i + 2); | 4431 ch = text.slice(i, i + 2); |
4385 ++i; | 4432 ++i; |
4386 } else if (i && wrapping && spanAffectsWrapping(text, i)) { | 4433 } else if (i && wrapping && spanAffectsWrapping(text, i)) { |
4387 builder.pre.appendChild(elt("wbr")); | 4434 builder.pre.appendChild(elt("wbr")); |
4388 } | 4435 } |
4389 var old = builder.measure[builder.pos]; | 4436 var old = builder.measure[builder.pos]; |
(...skipping 26 matching lines...) Expand all Loading... |
4416 | 4463 |
4417 function buildCollapsedSpan(builder, size, marker, ignoreWidget) { | 4464 function buildCollapsedSpan(builder, size, marker, ignoreWidget) { |
4418 var widget = !ignoreWidget && marker.replacedWith; | 4465 var widget = !ignoreWidget && marker.replacedWith; |
4419 if (widget) { | 4466 if (widget) { |
4420 if (builder.copyWidgets) widget = widget.cloneNode(true); | 4467 if (builder.copyWidgets) widget = widget.cloneNode(true); |
4421 builder.pre.appendChild(widget); | 4468 builder.pre.appendChild(widget); |
4422 if (builder.measure) { | 4469 if (builder.measure) { |
4423 if (size) { | 4470 if (size) { |
4424 builder.measure[builder.pos] = widget; | 4471 builder.measure[builder.pos] = widget; |
4425 } else { | 4472 } else { |
4426 var elt = builder.measure[builder.pos] = zeroWidthElement(builder.cm.d
isplay.measure); | 4473 var elt = zeroWidthElement(builder.cm.display.measure); |
4427 if (marker.type != "bookmark" || marker.insertLeft) | 4474 if (marker.type == "bookmark" && !marker.insertLeft) |
4428 builder.pre.insertBefore(elt, widget); | 4475 builder.measure[builder.pos] = builder.pre.appendChild(elt); |
| 4476 else if (builder.measure[builder.pos]) |
| 4477 return; |
4429 else | 4478 else |
4430 builder.pre.appendChild(elt); | 4479 builder.measure[builder.pos] = builder.pre.insertBefore(elt, widget)
; |
4431 } | 4480 } |
4432 builder.measuredSomething = true; | 4481 builder.measuredSomething = true; |
4433 } | 4482 } |
4434 } | 4483 } |
4435 builder.pos += size; | 4484 builder.pos += size; |
4436 } | 4485 } |
4437 | 4486 |
4438 // Outputs a number of spans to make up a line, taking highlighting | 4487 // Outputs a number of spans to make up a line, taking highlighting |
4439 // and marked text into account. | 4488 // and marked text into account. |
4440 function insertLineContent(line, builder, styles) { | 4489 function insertLineContent(line, builder, styles) { |
4441 var spans = line.markedSpans, allText = line.text, at = 0; | 4490 var spans = line.markedSpans, allText = line.text, at = 0; |
4442 if (!spans) { | 4491 if (!spans) { |
4443 if (builder.to || builder.from) { | 4492 for (var i = 1; i < styles.length; i+=2) |
4444 for (var i = 1; i < styles.length && (!builder.to || builder.pos < build
er.to); i+=2) { | 4493 builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTo
kenStyle(styles[i+1], builder)); |
4445 var text = allText.slice(at, at = styles[i]); | |
4446 var textLength = text.length; | |
4447 var resolvedStyles = styleToClass(styles[i+1]); | |
4448 if (builder.pos + textLength <= builder.from) { | |
4449 builder.addToken(builder, text, resolvedStyles); | |
4450 continue; | |
4451 } | |
4452 // if we are not inside, but will get over it | |
4453 if (builder.pos < builder.from && builder.pos + textLength > builder.f
rom) { | |
4454 var overlap = builder.from - builder.pos; | |
4455 builder.addToken(builder, text.substring(0, overlap), resolvedStyles
); | |
4456 text = text.substring(overlap); | |
4457 } | |
4458 builder.addToken(builder, text.substr(0, Math.min(builder.to - builder
.from, text.length)), resolvedStyles); | |
4459 } | |
4460 } else { | |
4461 for (var i = 1; i < styles.length; i+=2) | |
4462 builder.addToken(builder, allText.slice(at, at = styles[i]), styleToCl
ass(styles[i+1])); | |
4463 } | |
4464 return; | 4494 return; |
4465 } | 4495 } |
4466 | 4496 |
4467 var len = allText.length, pos = 0, i = 1, text = "", style; | 4497 var len = allText.length, pos = 0, i = 1, text = "", style; |
4468 var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapse
d; | 4498 var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapse
d; |
4469 for (;;) { | 4499 for (;;) { |
4470 if (nextChange == pos) { // Update current marker set | 4500 if (nextChange == pos) { // Update current marker set |
4471 spanStyle = spanEndStyle = spanStartStyle = title = ""; | 4501 spanStyle = spanEndStyle = spanStartStyle = title = ""; |
4472 collapsed = null; nextChange = Infinity; | 4502 collapsed = null; nextChange = Infinity; |
4473 var foundBookmarks = []; | 4503 var foundBookmarks = []; |
(...skipping 23 matching lines...) Expand all Loading... |
4497 if (pos >= len) break; | 4527 if (pos >= len) break; |
4498 | 4528 |
4499 var upto = Math.min(len, nextChange); | 4529 var upto = Math.min(len, nextChange); |
4500 while (true) { | 4530 while (true) { |
4501 if (text) { | 4531 if (text) { |
4502 var end = pos + text.length; | 4532 var end = pos + text.length; |
4503 if (!collapsed) { | 4533 if (!collapsed) { |
4504 var tokenText = end > upto ? text.slice(0, upto - pos) : text; | 4534 var tokenText = end > upto ? text.slice(0, upto - pos) : text; |
4505 builder.addToken(builder, tokenText, style ? style + spanStyle : spa
nStyle, | 4535 builder.addToken(builder, tokenText, style ? style + spanStyle : spa
nStyle, |
4506 spanStartStyle, pos + tokenText.length == nextChang
e ? spanEndStyle : "", title); | 4536 spanStartStyle, pos + tokenText.length == nextChang
e ? spanEndStyle : "", title); |
4507 if (builder.to && builder.pos >= builder.to) | |
4508 return; | |
4509 } | 4537 } |
4510 if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;} | 4538 if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;} |
4511 pos = end; | 4539 pos = end; |
4512 spanStartStyle = ""; | 4540 spanStartStyle = ""; |
4513 } | 4541 } |
4514 text = allText.slice(at, at = styles[i++]); | 4542 text = allText.slice(at, at = styles[i++]); |
4515 style = styleToClass(styles[i++]); | 4543 style = interpretTokenStyle(styles[i++], builder); |
4516 } | 4544 } |
4517 } | 4545 } |
4518 } | 4546 } |
4519 | 4547 |
4520 // DOCUMENT DATA STRUCTURE | 4548 // DOCUMENT DATA STRUCTURE |
4521 | 4549 |
4522 function updateDoc(doc, change, markedSpans, selAfter, estimateHeight) { | 4550 function updateDoc(doc, change, markedSpans, selAfter, estimateHeight) { |
4523 function spansFor(n) {return markedSpans ? markedSpans[n] : null;} | 4551 function spansFor(n) {return markedSpans ? markedSpans[n] : null;} |
4524 function update(line, text, spans) { | 4552 function update(line, text, spans) { |
4525 updateLine(line, text, spans, estimateHeight); | 4553 updateLine(line, text, spans, estimateHeight); |
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4783 else pos = sel.from; | 4811 else pos = sel.from; |
4784 return copyPos(pos); | 4812 return copyPos(pos); |
4785 }, | 4813 }, |
4786 somethingSelected: function() {return !posEq(this.sel.head, this.sel.anchor)
;}, | 4814 somethingSelected: function() {return !posEq(this.sel.head, this.sel.anchor)
;}, |
4787 | 4815 |
4788 setCursor: docOperation(function(line, ch, extend) { | 4816 setCursor: docOperation(function(line, ch, extend) { |
4789 var pos = clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : lin
e); | 4817 var pos = clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : lin
e); |
4790 if (extend) extendSelection(this, pos); | 4818 if (extend) extendSelection(this, pos); |
4791 else setSelection(this, pos, pos); | 4819 else setSelection(this, pos, pos); |
4792 }), | 4820 }), |
4793 setSelection: docOperation(function(anchor, head) { | 4821 setSelection: docOperation(function(anchor, head, bias) { |
4794 setSelection(this, clipPos(this, anchor), clipPos(this, head || anchor)); | 4822 setSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), b
ias); |
4795 }), | 4823 }), |
4796 extendSelection: docOperation(function(from, to) { | 4824 extendSelection: docOperation(function(from, to, bias) { |
4797 extendSelection(this, clipPos(this, from), to && clipPos(this, to)); | 4825 extendSelection(this, clipPos(this, from), to && clipPos(this, to), bias); |
4798 }), | 4826 }), |
4799 | 4827 |
4800 getSelection: function(lineSep) {return this.getRange(this.sel.from, this.se
l.to, lineSep);}, | 4828 getSelection: function(lineSep) {return this.getRange(this.sel.from, this.se
l.to, lineSep);}, |
4801 replaceSelection: function(code, collapse, origin) { | 4829 replaceSelection: function(code, collapse, origin) { |
4802 makeChange(this, {from: this.sel.from, to: this.sel.to, text: splitLines(c
ode), origin: origin}, collapse || "around"); | 4830 makeChange(this, {from: this.sel.from, to: this.sel.to, text: splitLines(c
ode), origin: origin}, collapse || "around"); |
4803 }, | 4831 }, |
4804 undo: docOperation(function() {makeChangeFromHistory(this, "undo");}), | 4832 undo: docOperation(function() {makeChangeFromHistory(this, "undo");}), |
4805 redo: docOperation(function() {makeChangeFromHistory(this, "redo");}), | 4833 redo: docOperation(function() {makeChangeFromHistory(this, "redo");}), |
4806 | 4834 |
4807 setExtending: function(val) {this.sel.extend = val;}, | 4835 setExtending: function(val) {this.sel.extend = val;}, |
(...skipping 665 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5473 // various browsers. | 5501 // various browsers. |
5474 function spanAffectsWrapping() { return false; } | 5502 function spanAffectsWrapping() { return false; } |
5475 if (gecko) // Only for "$'" | 5503 if (gecko) // Only for "$'" |
5476 spanAffectsWrapping = function(str, i) { | 5504 spanAffectsWrapping = function(str, i) { |
5477 return str.charCodeAt(i - 1) == 36 && str.charCodeAt(i) == 39; | 5505 return str.charCodeAt(i - 1) == 36 && str.charCodeAt(i) == 39; |
5478 }; | 5506 }; |
5479 else if (safari && !/Version\/([6-9]|\d\d)\b/.test(navigator.userAgent)) | 5507 else if (safari && !/Version\/([6-9]|\d\d)\b/.test(navigator.userAgent)) |
5480 spanAffectsWrapping = function(str, i) { | 5508 spanAffectsWrapping = function(str, i) { |
5481 return /\-[^ \-?]|\?[^ !\'\"\),.\-\/:;\?\]\}]/.test(str.slice(i - 1, i + 1
)); | 5509 return /\-[^ \-?]|\?[^ !\'\"\),.\-\/:;\?\]\}]/.test(str.slice(i - 1, i + 1
)); |
5482 }; | 5510 }; |
5483 else if (webkit && !/Chrome\/(?:29|[3-9]\d|\d\d\d)\./.test(navigator.userAgent
)) | 5511 else if (webkit && /Chrome\/(?:29|[3-9]\d|\d\d\d)\./.test(navigator.userAgent)
) |
| 5512 spanAffectsWrapping = function(str, i) { |
| 5513 var code = str.charCodeAt(i - 1); |
| 5514 return code >= 8208 && code <= 8212; |
| 5515 }; |
| 5516 else if (webkit) |
5484 spanAffectsWrapping = function(str, i) { | 5517 spanAffectsWrapping = function(str, i) { |
5485 if (i > 1 && str.charCodeAt(i - 1) == 45) { | 5518 if (i > 1 && str.charCodeAt(i - 1) == 45) { |
5486 if (/\w/.test(str.charAt(i - 2)) && /[^\-?\.]/.test(str.charAt(i))) retu
rn true; | 5519 if (/\w/.test(str.charAt(i - 2)) && /[^\-?\.]/.test(str.charAt(i))) retu
rn true; |
5487 if (i > 2 && /[\d\.,]/.test(str.charAt(i - 2)) && /[\d\.,]/.test(str.cha
rAt(i))) return false; | 5520 if (i > 2 && /[\d\.,]/.test(str.charAt(i - 2)) && /[\d\.,]/.test(str.cha
rAt(i))) return false; |
5488 } | 5521 } |
5489 return /[~!#%&*)=+}\]|\"\.>,:;][({[<]|-[^\-?\.\u2010-\u201f\u2026]|\?[\w~`
@#$%\^&*(_=+{[|><]|…[\w~`@#$%\^&*(_=+{[><]/.test(str.slice(i - 1, i + 1)); | 5522 return /[~!#%&*)=+}\]|\"\.>,:;][({[<]|-[^\-?\.\u2010-\u201f\u2026]|\?[\w~`
@#$%\^&*(_=+{[|><]|…[\w~`@#$%\^&*(_=+{[><]/.test(str.slice(i - 1, i + 1)); |
5490 }; | 5523 }; |
5491 | 5524 |
5492 var knownScrollbarWidth; | 5525 var knownScrollbarWidth; |
5493 function scrollbarWidth(measure) { | 5526 function scrollbarWidth(measure) { |
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5835 } | 5868 } |
5836 if (order[0].level != lst(order).level) | 5869 if (order[0].level != lst(order).level) |
5837 order.push({from: len, to: len, level: order[0].level}); | 5870 order.push({from: len, to: len, level: order[0].level}); |
5838 | 5871 |
5839 return order; | 5872 return order; |
5840 }; | 5873 }; |
5841 })(); | 5874 })(); |
5842 | 5875 |
5843 // THE END | 5876 // THE END |
5844 | 5877 |
5845 CodeMirror.version = "3.15.1"; | 5878 CodeMirror.version = "3.16.1"; |
5846 | 5879 |
5847 return CodeMirror; | 5880 return CodeMirror; |
5848 })(); | 5881 })(); |
OLD | NEW |