| OLD | NEW |
| 1 // CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others |
| 2 // Distributed under an MIT license: http://codemirror.net/LICENSE |
| 3 |
| 1 // This is CodeMirror (http://codemirror.net), a code editor | 4 // This is CodeMirror (http://codemirror.net), a code editor |
| 2 // implemented in JavaScript on top of the browser's DOM. | 5 // implemented in JavaScript on top of the browser's DOM. |
| 3 // | 6 // |
| 4 // 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 |
| 5 // at http://marijnhaverbeke.nl/blog/#cm-internals . | 8 // at http://marijnhaverbeke.nl/blog/#cm-internals . |
| 6 | 9 |
| 7 (function(mod) { | 10 (function(mod) { |
| 8 if (typeof exports == "object" && typeof module == "object") // CommonJS | 11 if (typeof exports == "object" && typeof module == "object") // CommonJS |
| 9 module.exports = mod(); | 12 module.exports = mod(); |
| 10 else if (typeof define == "function" && define.amd) // AMD | 13 else if (typeof define == "function" && define.amd) // AMD |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edit
s in readInput | 89 pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edit
s in readInput |
| 87 draggingText: false, | 90 draggingText: false, |
| 88 highlight: new Delayed() // stores highlight worker timeout | 91 highlight: new Delayed() // stores highlight worker timeout |
| 89 }; | 92 }; |
| 90 | 93 |
| 91 // Override magic textarea content restore that IE sometimes does | 94 // Override magic textarea content restore that IE sometimes does |
| 92 // on our hidden textarea on reload | 95 // on our hidden textarea on reload |
| 93 if (ie_upto10) setTimeout(bind(resetInput, this, true), 20); | 96 if (ie_upto10) setTimeout(bind(resetInput, this, true), 20); |
| 94 | 97 |
| 95 registerEventHandlers(this); | 98 registerEventHandlers(this); |
| 99 ensureGlobalHandlers(); |
| 96 | 100 |
| 97 var cm = this; | 101 var cm = this; |
| 98 runInOp(this, function() { | 102 runInOp(this, function() { |
| 99 cm.curOp.forceUpdate = true; | 103 cm.curOp.forceUpdate = true; |
| 100 attachDoc(cm, doc); | 104 attachDoc(cm, doc); |
| 101 | 105 |
| 102 if ((options.autofocus && !mobile) || activeElt() == display.input) | 106 if ((options.autofocus && !mobile) || activeElt() == display.input) |
| 103 setTimeout(bind(onFocus, cm), 20); | 107 setTimeout(bind(onFocus, cm), 20); |
| 104 else | 108 else |
| 105 onBlur(cm); | 109 onBlur(cm); |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 223 // can be kept static when scrolling. | 227 // can be kept static when scrolling. |
| 224 d.maxLine = null; | 228 d.maxLine = null; |
| 225 d.maxLineLength = 0; | 229 d.maxLineLength = 0; |
| 226 d.maxLineChanged = false; | 230 d.maxLineChanged = false; |
| 227 | 231 |
| 228 // Used for measuring wheel scrolling granularity | 232 // Used for measuring wheel scrolling granularity |
| 229 d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null; | 233 d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null; |
| 230 | 234 |
| 231 // True when shift is held down. | 235 // True when shift is held down. |
| 232 d.shift = false; | 236 d.shift = false; |
| 237 |
| 238 // Used to track whether anything happened since the context menu |
| 239 // was opened. |
| 240 d.selForContextMenu = null; |
| 233 } | 241 } |
| 234 | 242 |
| 235 // STATE UPDATES | 243 // STATE UPDATES |
| 236 | 244 |
| 237 // Used to get the editor into a consistent state again when options change. | 245 // Used to get the editor into a consistent state again when options change. |
| 238 | 246 |
| 239 function loadMode(cm) { | 247 function loadMode(cm) { |
| 240 cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption); | 248 cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption); |
| 241 resetModeState(cm); | 249 resetModeState(cm); |
| 242 } | 250 } |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 448 on(d.scrollbarH, "mousedown", barMouseDown); | 456 on(d.scrollbarH, "mousedown", barMouseDown); |
| 449 } | 457 } |
| 450 cm.state.checkedOverlayScrollbar = true; | 458 cm.state.checkedOverlayScrollbar = true; |
| 451 } | 459 } |
| 452 } | 460 } |
| 453 | 461 |
| 454 // Compute the lines that are visible in a given viewport (defaults | 462 // Compute the lines that are visible in a given viewport (defaults |
| 455 // the the current scroll position). viewPort may contain top, | 463 // the the current scroll position). viewPort may contain top, |
| 456 // height, and ensure (see op.scrollToPos) properties. | 464 // height, and ensure (see op.scrollToPos) properties. |
| 457 function visibleLines(display, doc, viewPort) { | 465 function visibleLines(display, doc, viewPort) { |
| 458 var top = viewPort && viewPort.top != null ? viewPort.top : display.scroller
.scrollTop; | 466 var top = viewPort && viewPort.top != null ? Math.max(0, viewPort.top) : dis
play.scroller.scrollTop; |
| 459 top = Math.floor(top - paddingTop(display)); | 467 top = Math.floor(top - paddingTop(display)); |
| 460 var bottom = viewPort && viewPort.bottom != null ? viewPort.bottom : top + d
isplay.wrapper.clientHeight; | 468 var bottom = viewPort && viewPort.bottom != null ? viewPort.bottom : top + d
isplay.wrapper.clientHeight; |
| 461 | 469 |
| 462 var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom); | 470 var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom); |
| 463 // Ensure is a {from: {line, ch}, to: {line, ch}} object, and | 471 // Ensure is a {from: {line, ch}, to: {line, ch}} object, and |
| 464 // forces those lines into the viewport (if possible). | 472 // forces those lines into the viewport (if possible). |
| 465 if (viewPort && viewPort.ensure) { | 473 if (viewPort && viewPort.ensure) { |
| 466 var ensureFrom = viewPort.ensure.from.line, ensureTo = viewPort.ensure.to.
line; | 474 var ensureFrom = viewPort.ensure.from.line, ensureTo = viewPort.ensure.to.
line; |
| 467 if (ensureFrom < from) | 475 if (ensureFrom < from) |
| 468 return {from: ensureFrom, | 476 return {from: ensureFrom, |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 652 display.sizer.style.minWidth = minWidth + "px"; | 660 display.sizer.style.minWidth = minWidth + "px"; |
| 653 if (maxScrollLeft < cm.doc.scrollLeft) | 661 if (maxScrollLeft < cm.doc.scrollLeft) |
| 654 setScrollLeft(cm, Math.min(display.scroller.scrollLeft, maxScrollLeft), tr
ue); | 662 setScrollLeft(cm, Math.min(display.scroller.scrollLeft, maxScrollLeft), tr
ue); |
| 655 } | 663 } |
| 656 | 664 |
| 657 function setDocumentHeight(cm, measure) { | 665 function setDocumentHeight(cm, measure) { |
| 658 cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = measu
re.docHeight + "px"; | 666 cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = measu
re.docHeight + "px"; |
| 659 cm.display.gutters.style.height = Math.max(measure.docHeight, measure.client
Height - scrollerCutOff) + "px"; | 667 cm.display.gutters.style.height = Math.max(measure.docHeight, measure.client
Height - scrollerCutOff) + "px"; |
| 660 } | 668 } |
| 661 | 669 |
| 662 | |
| 663 function checkForWebkitWidthBug(cm, measure) { | 670 function checkForWebkitWidthBug(cm, measure) { |
| 664 // Work around Webkit bug where it sometimes reserves space for a | 671 // Work around Webkit bug where it sometimes reserves space for a |
| 665 // non-existing phantom scrollbar in the scroller (Issue #2420) | 672 // non-existing phantom scrollbar in the scroller (Issue #2420) |
| 666 if (cm.display.sizer.offsetWidth + cm.display.gutters.offsetWidth < cm.displ
ay.scroller.clientWidth - 1) { | 673 if (cm.display.sizer.offsetWidth + cm.display.gutters.offsetWidth < cm.displ
ay.scroller.clientWidth - 1) { |
| 667 cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = "0p
x"; | 674 cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = "0p
x"; |
| 668 cm.display.gutters.style.height = measure.docHeight + "px"; | 675 cm.display.gutters.style.height = measure.docHeight + "px"; |
| 669 } | 676 } |
| 670 } | 677 } |
| 671 | 678 |
| 672 // Read the actual heights of the rendered lines, and update their | 679 // Read the actual heights of the rendered lines, and update their |
| (...skipping 941 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1614 while (mStart + end < mEnd && isExtendingChar(prepared.line.text.charAt(mS
tart + end))) ++end; | 1621 while (mStart + end < mEnd && isExtendingChar(prepared.line.text.charAt(mS
tart + end))) ++end; |
| 1615 if (ie_upto8 && start == 0 && end == mEnd - mStart) { | 1622 if (ie_upto8 && start == 0 && end == mEnd - mStart) { |
| 1616 rect = node.parentNode.getBoundingClientRect(); | 1623 rect = node.parentNode.getBoundingClientRect(); |
| 1617 } else if (ie && cm.options.lineWrapping) { | 1624 } else if (ie && cm.options.lineWrapping) { |
| 1618 var rects = range(node, start, end).getClientRects(); | 1625 var rects = range(node, start, end).getClientRects(); |
| 1619 if (rects.length) | 1626 if (rects.length) |
| 1620 rect = rects[bias == "right" ? rects.length - 1 : 0]; | 1627 rect = rects[bias == "right" ? rects.length - 1 : 0]; |
| 1621 else | 1628 else |
| 1622 rect = nullRect; | 1629 rect = nullRect; |
| 1623 } else { | 1630 } else { |
| 1624 rect = range(node, start, end).getBoundingClientRect(); | 1631 rect = range(node, start, end).getBoundingClientRect() || nullRect; |
| 1625 } | 1632 } |
| 1626 } else { // If it is a widget, simply get the box for the whole widget. | 1633 } else { // If it is a widget, simply get the box for the whole widget. |
| 1627 if (start > 0) collapse = bias = "right"; | 1634 if (start > 0) collapse = bias = "right"; |
| 1628 var rects; | 1635 var rects; |
| 1629 if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1) | 1636 if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1) |
| 1630 rect = rects[bias == "right" ? rects.length - 1 : 0]; | 1637 rect = rects[bias == "right" ? rects.length - 1 : 0]; |
| 1631 else | 1638 else |
| 1632 rect = node.getBoundingClientRect(); | 1639 rect = node.getBoundingClientRect(); |
| 1633 } | 1640 } |
| 1634 if (ie_upto8 && !start && (!rect || !rect.left && !rect.right)) { | 1641 if (ie_upto8 && !start && (!rect || !rect.left && !rect.right)) { |
| (...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1915 op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom || | 1922 op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom || |
| 1916 op.scrollToPos.to.line >= display.viewTo) || | 1923 op.scrollToPos.to.line >= display.viewTo) || |
| 1917 display.maxLineChanged && cm.options.lineWrapping) { | 1924 display.maxLineChanged && cm.options.lineWrapping) { |
| 1918 var updated = updateDisplay(cm, {top: op.scrollTop, ensure: op.scrollToPos
}, op.forceUpdate); | 1925 var updated = updateDisplay(cm, {top: op.scrollTop, ensure: op.scrollToPos
}, op.forceUpdate); |
| 1919 if (cm.display.scroller.offsetHeight) cm.doc.scrollTop = cm.display.scroll
er.scrollTop; | 1926 if (cm.display.scroller.offsetHeight) cm.doc.scrollTop = cm.display.scroll
er.scrollTop; |
| 1920 } | 1927 } |
| 1921 // If no update was run, but the selection changed, redraw that. | 1928 // If no update was run, but the selection changed, redraw that. |
| 1922 if (!updated && op.selectionChanged) updateSelection(cm); | 1929 if (!updated && op.selectionChanged) updateSelection(cm); |
| 1923 if (!updated && op.startHeight != cm.doc.height) updateScrollbars(cm); | 1930 if (!updated && op.startHeight != cm.doc.height) updateScrollbars(cm); |
| 1924 | 1931 |
| 1932 // Abort mouse wheel delta measurement, when scrolling explicitly |
| 1933 if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft !=
null || op.scrollToPos)) |
| 1934 display.wheelStartX = display.wheelStartY = null; |
| 1935 |
| 1925 // Propagate the scroll position to the actual DOM scroller | 1936 // Propagate the scroll position to the actual DOM scroller |
| 1926 if (op.scrollTop != null && display.scroller.scrollTop != op.scrollTop) { | 1937 if (op.scrollTop != null && display.scroller.scrollTop != op.scrollTop) { |
| 1927 var top = Math.max(0, Math.min(display.scroller.scrollHeight - display.scr
oller.clientHeight, op.scrollTop)); | 1938 var top = Math.max(0, Math.min(display.scroller.scrollHeight - display.scr
oller.clientHeight, op.scrollTop)); |
| 1928 display.scroller.scrollTop = display.scrollbarV.scrollTop = doc.scrollTop
= top; | 1939 display.scroller.scrollTop = display.scrollbarV.scrollTop = doc.scrollTop
= top; |
| 1929 } | 1940 } |
| 1930 if (op.scrollLeft != null && display.scroller.scrollLeft != op.scrollLeft) { | 1941 if (op.scrollLeft != null && display.scroller.scrollLeft != op.scrollLeft) { |
| 1931 var left = Math.max(0, Math.min(display.scroller.scrollWidth - display.scr
oller.clientWidth, op.scrollLeft)); | 1942 var left = Math.max(0, Math.min(display.scroller.scrollWidth - display.scr
oller.clientWidth, op.scrollLeft)); |
| 1932 display.scroller.scrollLeft = display.scrollbarH.scrollLeft = doc.scrollLe
ft = left; | 1943 display.scroller.scrollLeft = display.scrollbarH.scrollLeft = doc.scrollLe
ft = left; |
| 1933 alignHorizontally(cm); | 1944 alignHorizontally(cm); |
| 1934 } | 1945 } |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2128 if (n < 0) return null; | 2139 if (n < 0) return null; |
| 2129 var view = cm.display.view; | 2140 var view = cm.display.view; |
| 2130 for (var i = 0; i < view.length; i++) { | 2141 for (var i = 0; i < view.length; i++) { |
| 2131 n -= view[i].size; | 2142 n -= view[i].size; |
| 2132 if (n < 0) return i; | 2143 if (n < 0) return i; |
| 2133 } | 2144 } |
| 2134 } | 2145 } |
| 2135 | 2146 |
| 2136 function viewCuttingPoint(cm, oldN, newN, dir) { | 2147 function viewCuttingPoint(cm, oldN, newN, dir) { |
| 2137 var index = findViewIndex(cm, oldN), diff, view = cm.display.view; | 2148 var index = findViewIndex(cm, oldN), diff, view = cm.display.view; |
| 2138 if (!sawCollapsedSpans) return {index: index, lineN: newN}; | 2149 if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size) |
| 2150 return {index: index, lineN: newN}; |
| 2139 for (var i = 0, n = cm.display.viewFrom; i < index; i++) | 2151 for (var i = 0, n = cm.display.viewFrom; i < index; i++) |
| 2140 n += view[i].size; | 2152 n += view[i].size; |
| 2141 if (n != oldN) { | 2153 if (n != oldN) { |
| 2142 if (dir > 0) { | 2154 if (dir > 0) { |
| 2143 if (index == view.length - 1) return null; | 2155 if (index == view.length - 1) return null; |
| 2144 diff = (n + view[index].size) - oldN; | 2156 diff = (n + view[index].size) - oldN; |
| 2145 index++; | 2157 index++; |
| 2146 } else { | 2158 } else { |
| 2147 diff = n - oldN; | 2159 diff = n - oldN; |
| 2148 } | 2160 } |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2239 // Work around nonsensical selection resetting in IE9/10 | 2251 // Work around nonsensical selection resetting in IE9/10 |
| 2240 if (ie && !ie_upto8 && cm.display.inputHasSelection === text) { | 2252 if (ie && !ie_upto8 && cm.display.inputHasSelection === text) { |
| 2241 resetInput(cm); | 2253 resetInput(cm); |
| 2242 return false; | 2254 return false; |
| 2243 } | 2255 } |
| 2244 | 2256 |
| 2245 var withOp = !cm.curOp; | 2257 var withOp = !cm.curOp; |
| 2246 if (withOp) startOperation(cm); | 2258 if (withOp) startOperation(cm); |
| 2247 cm.display.shift = false; | 2259 cm.display.shift = false; |
| 2248 | 2260 |
| 2261 if (text.charCodeAt(0) == 0x200b && doc.sel == cm.display.selForContextMenu
&& !prevInput) |
| 2262 prevInput = "\u200b"; |
| 2249 // Find the part of the input that is actually new | 2263 // Find the part of the input that is actually new |
| 2250 var same = 0, l = Math.min(prevInput.length, text.length); | 2264 var same = 0, l = Math.min(prevInput.length, text.length); |
| 2251 while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++sa
me; | 2265 while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++sa
me; |
| 2252 var inserted = text.slice(same), textLines = splitLines(inserted); | 2266 var inserted = text.slice(same), textLines = splitLines(inserted); |
| 2253 | 2267 |
| 2254 // When pasing N lines into N selections, insert one line per selection | 2268 // When pasing N lines into N selections, insert one line per selection |
| 2255 var multiPaste = cm.state.pasteIncoming && textLines.length > 1 && doc.sel.r
anges.length == textLines.length; | 2269 var multiPaste = cm.state.pasteIncoming && textLines.length > 1 && doc.sel.r
anges.length == textLines.length; |
| 2256 | 2270 |
| 2257 // Normal behavior is to insert the new text into every selection | 2271 // Normal behavior is to insert the new text into every selection |
| 2258 for (var i = doc.sel.ranges.length - 1; i >= 0; i--) { | 2272 for (var i = doc.sel.ranges.length - 1; i >= 0; i--) { |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2338 function registerEventHandlers(cm) { | 2352 function registerEventHandlers(cm) { |
| 2339 var d = cm.display; | 2353 var d = cm.display; |
| 2340 on(d.scroller, "mousedown", operation(cm, onMouseDown)); | 2354 on(d.scroller, "mousedown", operation(cm, onMouseDown)); |
| 2341 // Older IE's will not fire a second mousedown for a double click | 2355 // Older IE's will not fire a second mousedown for a double click |
| 2342 if (ie_upto10) | 2356 if (ie_upto10) |
| 2343 on(d.scroller, "dblclick", operation(cm, function(e) { | 2357 on(d.scroller, "dblclick", operation(cm, function(e) { |
| 2344 if (signalDOMEvent(cm, e)) return; | 2358 if (signalDOMEvent(cm, e)) return; |
| 2345 var pos = posFromMouse(cm, e); | 2359 var pos = posFromMouse(cm, e); |
| 2346 if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return
; | 2360 if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return
; |
| 2347 e_preventDefault(e); | 2361 e_preventDefault(e); |
| 2348 var word = findWordAt(cm.doc, pos); | 2362 var word = findWordAt(cm, pos); |
| 2349 extendSelection(cm.doc, word.anchor, word.head); | 2363 extendSelection(cm.doc, word.anchor, word.head); |
| 2350 })); | 2364 })); |
| 2351 else | 2365 else |
| 2352 on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preven
tDefault(e); }); | 2366 on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preven
tDefault(e); }); |
| 2353 // Prevent normal selection in the editor (we handle our own) | 2367 // Prevent normal selection in the editor (we handle our own) |
| 2354 on(d.lineSpace, "selectstart", function(e) { | 2368 on(d.lineSpace, "selectstart", function(e) { |
| 2355 if (!eventInWidget(d, e)) e_preventDefault(e); | 2369 if (!eventInWidget(d, e)) e_preventDefault(e); |
| 2356 }); | 2370 }); |
| 2357 // Some browsers fire contextmenu *after* opening the menu, at | 2371 // Some browsers fire contextmenu *after* opening the menu, at |
| 2358 // which point we can't mess with it anymore. Context menu is | 2372 // which point we can't mess with it anymore. Context menu is |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2379 on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);}); | 2393 on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);}); |
| 2380 on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);}); | 2394 on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);}); |
| 2381 | 2395 |
| 2382 // Prevent clicks in the scrollbars from killing focus | 2396 // Prevent clicks in the scrollbars from killing focus |
| 2383 function reFocus() { if (cm.state.focused) setTimeout(bind(focusInput, cm),
0); } | 2397 function reFocus() { if (cm.state.focused) setTimeout(bind(focusInput, cm),
0); } |
| 2384 on(d.scrollbarH, "mousedown", reFocus); | 2398 on(d.scrollbarH, "mousedown", reFocus); |
| 2385 on(d.scrollbarV, "mousedown", reFocus); | 2399 on(d.scrollbarV, "mousedown", reFocus); |
| 2386 // Prevent wrapper from ever scrolling | 2400 // Prevent wrapper from ever scrolling |
| 2387 on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollL
eft = 0; }); | 2401 on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollL
eft = 0; }); |
| 2388 | 2402 |
| 2389 // When the window resizes, we need to refresh active editors. | |
| 2390 var resizeTimer; | |
| 2391 function onResize() { | |
| 2392 if (resizeTimer == null) resizeTimer = setTimeout(function() { | |
| 2393 resizeTimer = null; | |
| 2394 // Might be a text scaling operation, clear size caches. | |
| 2395 d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = knownScrollb
arWidth = null; | |
| 2396 cm.setSize(); | |
| 2397 }, 100); | |
| 2398 } | |
| 2399 on(window, "resize", onResize); | |
| 2400 // The above handler holds on to the editor and its data | |
| 2401 // structures. Here we poll to unregister it when the editor is no | |
| 2402 // longer in the document, so that it can be garbage-collected. | |
| 2403 function unregister() { | |
| 2404 if (contains(document.body, d.wrapper)) setTimeout(unregister, 5000); | |
| 2405 else off(window, "resize", onResize); | |
| 2406 } | |
| 2407 setTimeout(unregister, 5000); | |
| 2408 | |
| 2409 on(d.input, "keyup", operation(cm, onKeyUp)); | 2403 on(d.input, "keyup", operation(cm, onKeyUp)); |
| 2410 on(d.input, "input", function() { | 2404 on(d.input, "input", function() { |
| 2411 if (ie && !ie_upto8 && cm.display.inputHasSelection) cm.display.inputHasSe
lection = null; | 2405 if (ie && !ie_upto8 && cm.display.inputHasSelection) cm.display.inputHasSe
lection = null; |
| 2412 fastPoll(cm); | 2406 fastPoll(cm); |
| 2413 }); | 2407 }); |
| 2414 on(d.input, "keydown", operation(cm, onKeyDown)); | 2408 on(d.input, "keydown", operation(cm, onKeyDown)); |
| 2415 on(d.input, "keypress", operation(cm, onKeyPress)); | 2409 on(d.input, "keypress", operation(cm, onKeyPress)); |
| 2416 on(d.input, "focus", bind(onFocus, cm)); | 2410 on(d.input, "focus", bind(onFocus, cm)); |
| 2417 on(d.input, "blur", bind(onBlur, cm)); | 2411 on(d.input, "blur", bind(onBlur, cm)); |
| 2418 | 2412 |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2475 on(d.input, "cut", prepareCopyCut); | 2469 on(d.input, "cut", prepareCopyCut); |
| 2476 on(d.input, "copy", prepareCopyCut); | 2470 on(d.input, "copy", prepareCopyCut); |
| 2477 | 2471 |
| 2478 // Needed to handle Tab key in KHTML | 2472 // Needed to handle Tab key in KHTML |
| 2479 if (khtml) on(d.sizer, "mouseup", function() { | 2473 if (khtml) on(d.sizer, "mouseup", function() { |
| 2480 if (activeElt() == d.input) d.input.blur(); | 2474 if (activeElt() == d.input) d.input.blur(); |
| 2481 focusInput(cm); | 2475 focusInput(cm); |
| 2482 }); | 2476 }); |
| 2483 } | 2477 } |
| 2484 | 2478 |
| 2479 // Called when the window resizes |
| 2480 function onResize(cm) { |
| 2481 // Might be a text scaling operation, clear size caches. |
| 2482 var d = cm.display; |
| 2483 d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; |
| 2484 cm.setSize(); |
| 2485 } |
| 2486 |
| 2485 // MOUSE EVENTS | 2487 // MOUSE EVENTS |
| 2486 | 2488 |
| 2487 // Return true when the given mouse event happened in a widget | 2489 // Return true when the given mouse event happened in a widget |
| 2488 function eventInWidget(display, e) { | 2490 function eventInWidget(display, e) { |
| 2489 for (var n = e_target(e); n != display.wrapper; n = n.parentNode) { | 2491 for (var n = e_target(e); n != display.wrapper; n = n.parentNode) { |
| 2490 if (!n || n.ignoreEvents || n.parentNode == display.sizer && n != display.
mover) return true; | 2492 if (!n || n.ignoreEvents || n.parentNode == display.sizer && n != display.
mover) return true; |
| 2491 } | 2493 } |
| 2492 } | 2494 } |
| 2493 | 2495 |
| 2494 // Given a mouse event, find the corresponding position. If liberal | 2496 // Given a mouse event, find the corresponding position. If liberal |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2622 } else { | 2624 } else { |
| 2623 ourRange = doc.sel.primary(); | 2625 ourRange = doc.sel.primary(); |
| 2624 } | 2626 } |
| 2625 | 2627 |
| 2626 if (e.altKey) { | 2628 if (e.altKey) { |
| 2627 type = "rect"; | 2629 type = "rect"; |
| 2628 if (!addNew) ourRange = new Range(start, start); | 2630 if (!addNew) ourRange = new Range(start, start); |
| 2629 start = posFromMouse(cm, e, true, true); | 2631 start = posFromMouse(cm, e, true, true); |
| 2630 ourIndex = -1; | 2632 ourIndex = -1; |
| 2631 } else if (type == "double") { | 2633 } else if (type == "double") { |
| 2632 var word = findWordAt(doc, start); | 2634 var word = findWordAt(cm, start); |
| 2633 if (cm.display.shift || doc.extend) | 2635 if (cm.display.shift || doc.extend) |
| 2634 ourRange = extendRange(doc, ourRange, word.anchor, word.head); | 2636 ourRange = extendRange(doc, ourRange, word.anchor, word.head); |
| 2635 else | 2637 else |
| 2636 ourRange = word; | 2638 ourRange = word; |
| 2637 } else if (type == "triple") { | 2639 } else if (type == "triple") { |
| 2638 var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1,
0))); | 2640 var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1,
0))); |
| 2639 if (cm.display.shift || doc.extend) | 2641 if (cm.display.shift || doc.extend) |
| 2640 ourRange = extendRange(doc, ourRange, line.anchor, line.head); | 2642 ourRange = extendRange(doc, ourRange, line.anchor, line.head); |
| 2641 else | 2643 else |
| 2642 ourRange = line; | 2644 ourRange = line; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2668 var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol
); | 2670 var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol
); |
| 2669 for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLi
ne(), Math.max(start.line, pos.line)); | 2671 for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLi
ne(), Math.max(start.line, pos.line)); |
| 2670 line <= end; line++) { | 2672 line <= end; line++) { |
| 2671 var text = getLine(doc, line).text, leftPos = findColumn(text, left, t
abSize); | 2673 var text = getLine(doc, line).text, leftPos = findColumn(text, left, t
abSize); |
| 2672 if (left == right) | 2674 if (left == right) |
| 2673 ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); | 2675 ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); |
| 2674 else if (text.length > leftPos) | 2676 else if (text.length > leftPos) |
| 2675 ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text,
right, tabSize)))); | 2677 ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text,
right, tabSize)))); |
| 2676 } | 2678 } |
| 2677 if (!ranges.length) ranges.push(new Range(start, start)); | 2679 if (!ranges.length) ranges.push(new Range(start, start)); |
| 2678 setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).
concat(ranges), ourIndex), sel_mouse); | 2680 setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).
concat(ranges), ourIndex), |
| 2681 {origin: "*mouse", scroll: false}); |
| 2682 cm.scrollIntoView(pos); |
| 2679 } else { | 2683 } else { |
| 2680 var oldRange = ourRange; | 2684 var oldRange = ourRange; |
| 2681 var anchor = oldRange.anchor, head = pos; | 2685 var anchor = oldRange.anchor, head = pos; |
| 2682 if (type != "single") { | 2686 if (type != "single") { |
| 2683 if (type == "double") | 2687 if (type == "double") |
| 2684 var range = findWordAt(doc, pos); | 2688 var range = findWordAt(cm, pos); |
| 2685 else | 2689 else |
| 2686 var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line +
1, 0))); | 2690 var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line +
1, 0))); |
| 2687 if (cmp(range.anchor, anchor) > 0) { | 2691 if (cmp(range.anchor, anchor) > 0) { |
| 2688 head = range.head; | 2692 head = range.head; |
| 2689 anchor = minPos(oldRange.from(), range.anchor); | 2693 anchor = minPos(oldRange.from(), range.anchor); |
| 2690 } else { | 2694 } else { |
| 2691 head = range.anchor; | 2695 head = range.anchor; |
| 2692 anchor = maxPos(oldRange.to(), range.head); | 2696 anchor = maxPos(oldRange.to(), range.head); |
| 2693 } | 2697 } |
| 2694 } | 2698 } |
| (...skipping 680 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3375 change.origin = type; | 3379 change.origin = type; |
| 3376 if (filter && !filterChange(doc, change, false)) { | 3380 if (filter && !filterChange(doc, change, false)) { |
| 3377 source.length = 0; | 3381 source.length = 0; |
| 3378 return; | 3382 return; |
| 3379 } | 3383 } |
| 3380 | 3384 |
| 3381 antiChanges.push(historyChangeFromChange(doc, change)); | 3385 antiChanges.push(historyChangeFromChange(doc, change)); |
| 3382 | 3386 |
| 3383 var after = i ? computeSelAfterChange(doc, change, null) : lst(source); | 3387 var after = i ? computeSelAfterChange(doc, change, null) : lst(source); |
| 3384 makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)); | 3388 makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)); |
| 3385 if (doc.cm) ensureCursorVisible(doc.cm); | 3389 if (!i && doc.cm) doc.cm.scrollIntoView(change); |
| 3386 var rebased = []; | 3390 var rebased = []; |
| 3387 | 3391 |
| 3388 // Propagate to the linked documents | 3392 // Propagate to the linked documents |
| 3389 linkedDocs(doc, function(doc, sharedHist) { | 3393 linkedDocs(doc, function(doc, sharedHist) { |
| 3390 if (!sharedHist && indexOf(rebased, doc.history) == -1) { | 3394 if (!sharedHist && indexOf(rebased, doc.history) == -1) { |
| 3391 rebaseHist(doc.history, change); | 3395 rebaseHist(doc.history, change); |
| 3392 rebased.push(doc.history); | 3396 rebased.push(doc.history); |
| 3393 } | 3397 } |
| 3394 makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change)); | 3398 makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change)); |
| 3395 }); | 3399 }); |
| 3396 } | 3400 } |
| 3397 } | 3401 } |
| 3398 | 3402 |
| 3399 // Sub-views need their line numbers shifted when text is added | 3403 // Sub-views need their line numbers shifted when text is added |
| 3400 // above or below them in the parent document. | 3404 // above or below them in the parent document. |
| 3401 function shiftDoc(doc, distance) { | 3405 function shiftDoc(doc, distance) { |
| 3406 if (distance == 0) return; |
| 3402 doc.first += distance; | 3407 doc.first += distance; |
| 3403 doc.sel = new Selection(map(doc.sel.ranges, function(range) { | 3408 doc.sel = new Selection(map(doc.sel.ranges, function(range) { |
| 3404 return new Range(Pos(range.anchor.line + distance, range.anchor.ch), | 3409 return new Range(Pos(range.anchor.line + distance, range.anchor.ch), |
| 3405 Pos(range.head.line + distance, range.head.ch)); | 3410 Pos(range.head.line + distance, range.head.ch)); |
| 3406 }), doc.sel.primIndex); | 3411 }), doc.sel.primIndex); |
| 3407 if (doc.cm) regChange(doc.cm, doc.first, doc.first - distance, distance); | 3412 if (doc.cm) { |
| 3413 regChange(doc.cm, doc.first, doc.first - distance, distance); |
| 3414 for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++) |
| 3415 regLineChange(doc.cm, l, "gutter"); |
| 3416 } |
| 3408 } | 3417 } |
| 3409 | 3418 |
| 3410 // More lower-level change function, handling only a single document | 3419 // More lower-level change function, handling only a single document |
| 3411 // (not linked ones). | 3420 // (not linked ones). |
| 3412 function makeChangeSingleDoc(doc, change, selAfter, spans) { | 3421 function makeChangeSingleDoc(doc, change, selAfter, spans) { |
| 3413 if (doc.cm && !doc.cm.curOp) | 3422 if (doc.cm && !doc.cm.curOp) |
| 3414 return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans
); | 3423 return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans
); |
| 3415 | 3424 |
| 3416 if (change.to.line < doc.first) { | 3425 if (change.to.line < doc.first) { |
| 3417 shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line)
); | 3426 shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line)
); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3489 if (changeHandler || changesHandler) { | 3498 if (changeHandler || changesHandler) { |
| 3490 var obj = { | 3499 var obj = { |
| 3491 from: from, to: to, | 3500 from: from, to: to, |
| 3492 text: change.text, | 3501 text: change.text, |
| 3493 removed: change.removed, | 3502 removed: change.removed, |
| 3494 origin: change.origin | 3503 origin: change.origin |
| 3495 }; | 3504 }; |
| 3496 if (changeHandler) signalLater(cm, "change", cm, obj); | 3505 if (changeHandler) signalLater(cm, "change", cm, obj); |
| 3497 if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).pu
sh(obj); | 3506 if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).pu
sh(obj); |
| 3498 } | 3507 } |
| 3508 cm.display.selForContextMenu = null; |
| 3499 } | 3509 } |
| 3500 | 3510 |
| 3501 function replaceRange(doc, code, from, to, origin) { | 3511 function replaceRange(doc, code, from, to, origin) { |
| 3502 if (!to) to = from; | 3512 if (!to) to = from; |
| 3503 if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; } | 3513 if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; } |
| 3504 if (typeof code == "string") code = splitLines(code); | 3514 if (typeof code == "string") code = splitLines(code); |
| 3505 makeChange(doc, {from: from, to: to, text: code, origin: origin}); | 3515 makeChange(doc, {from: from, to: to, text: code, origin: origin}); |
| 3506 } | 3516 } |
| 3507 | 3517 |
| 3508 // SCROLLING THINGS INTO VIEW | 3518 // SCROLLING THINGS INTO VIEW |
| (...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3756 else ch = dir < 0 ? lineObj.text.length : 0; | 3766 else ch = dir < 0 ? lineObj.text.length : 0; |
| 3757 } else return (possible = false); | 3767 } else return (possible = false); |
| 3758 } else ch = next; | 3768 } else ch = next; |
| 3759 return true; | 3769 return true; |
| 3760 } | 3770 } |
| 3761 | 3771 |
| 3762 if (unit == "char") moveOnce(); | 3772 if (unit == "char") moveOnce(); |
| 3763 else if (unit == "column") moveOnce(true); | 3773 else if (unit == "column") moveOnce(true); |
| 3764 else if (unit == "word" || unit == "group") { | 3774 else if (unit == "word" || unit == "group") { |
| 3765 var sawType = null, group = unit == "group"; | 3775 var sawType = null, group = unit == "group"; |
| 3776 var helper = doc.cm && doc.cm.getHelper(pos, "wordChars"); |
| 3766 for (var first = true;; first = false) { | 3777 for (var first = true;; first = false) { |
| 3767 if (dir < 0 && !moveOnce(!first)) break; | 3778 if (dir < 0 && !moveOnce(!first)) break; |
| 3768 var cur = lineObj.text.charAt(ch) || "\n"; | 3779 var cur = lineObj.text.charAt(ch) || "\n"; |
| 3769 var type = isWordChar(cur) ? "w" | 3780 var type = isWordChar(cur, helper) ? "w" |
| 3770 : group && cur == "\n" ? "n" | 3781 : group && cur == "\n" ? "n" |
| 3771 : !group || /\s/.test(cur) ? null | 3782 : !group || /\s/.test(cur) ? null |
| 3772 : "p"; | 3783 : "p"; |
| 3773 if (group && !first && !type) type = "s"; | 3784 if (group && !first && !type) type = "s"; |
| 3774 if (sawType && sawType != type) { | 3785 if (sawType && sawType != type) { |
| 3775 if (dir < 0) {dir = 1; moveOnce();} | 3786 if (dir < 0) {dir = 1; moveOnce();} |
| 3776 break; | 3787 break; |
| 3777 } | 3788 } |
| 3778 | 3789 |
| 3779 if (type) sawType = type; | 3790 if (type) sawType = type; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 3799 for (;;) { | 3810 for (;;) { |
| 3800 var target = coordsChar(cm, x, y); | 3811 var target = coordsChar(cm, x, y); |
| 3801 if (!target.outside) break; | 3812 if (!target.outside) break; |
| 3802 if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; } | 3813 if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; } |
| 3803 y += dir * 5; | 3814 y += dir * 5; |
| 3804 } | 3815 } |
| 3805 return target; | 3816 return target; |
| 3806 } | 3817 } |
| 3807 | 3818 |
| 3808 // Find the word at the given position (as returned by coordsChar). | 3819 // Find the word at the given position (as returned by coordsChar). |
| 3809 function findWordAt(doc, pos) { | 3820 function findWordAt(cm, pos) { |
| 3810 var line = getLine(doc, pos.line).text; | 3821 var doc = cm.doc, line = getLine(doc, pos.line).text; |
| 3811 var start = pos.ch, end = pos.ch; | 3822 var start = pos.ch, end = pos.ch; |
| 3812 if (line) { | 3823 if (line) { |
| 3824 var helper = cm.getHelper(pos, "wordChars"); |
| 3813 if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end; | 3825 if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end; |
| 3814 var startChar = line.charAt(start); | 3826 var startChar = line.charAt(start); |
| 3815 var check = isWordChar(startChar) ? isWordChar | 3827 var check = isWordChar(startChar, helper) |
| 3828 ? function(ch) { return isWordChar(ch, helper); } |
| 3816 : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);} | 3829 : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);} |
| 3817 : function(ch) {return !/\s/.test(ch) && !isWordChar(ch);}; | 3830 : function(ch) {return !/\s/.test(ch) && !isWordChar(ch);}; |
| 3818 while (start > 0 && check(line.charAt(start - 1))) --start; | 3831 while (start > 0 && check(line.charAt(start - 1))) --start; |
| 3819 while (end < line.length && check(line.charAt(end))) ++end; | 3832 while (end < line.length && check(line.charAt(end))) ++end; |
| 3820 } | 3833 } |
| 3821 return new Range(Pos(pos.line, start), Pos(pos.line, end)); | 3834 return new Range(Pos(pos.line, start), Pos(pos.line, end)); |
| 3822 } | 3835 } |
| 3823 | 3836 |
| 3824 // EDITOR METHODS | 3837 // EDITOR METHODS |
| 3825 | 3838 |
| (...skipping 784 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4610 spaces.push(new Array(tabSize - col % tabSize + 1).join(" ")); | 4623 spaces.push(new Array(tabSize - col % tabSize + 1).join(" ")); |
| 4611 } | 4624 } |
| 4612 cm.replaceSelections(spaces); | 4625 cm.replaceSelections(spaces); |
| 4613 }, | 4626 }, |
| 4614 defaultTab: function(cm) { | 4627 defaultTab: function(cm) { |
| 4615 if (cm.somethingSelected()) cm.indentSelection("add"); | 4628 if (cm.somethingSelected()) cm.indentSelection("add"); |
| 4616 else cm.execCommand("insertTab"); | 4629 else cm.execCommand("insertTab"); |
| 4617 }, | 4630 }, |
| 4618 transposeChars: function(cm) { | 4631 transposeChars: function(cm) { |
| 4619 runInOp(cm, function() { | 4632 runInOp(cm, function() { |
| 4620 var ranges = cm.listSelections(); | 4633 var ranges = cm.listSelections(), newSel = []; |
| 4621 for (var i = 0; i < ranges.length; i++) { | 4634 for (var i = 0; i < ranges.length; i++) { |
| 4622 var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text; | 4635 var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text; |
| 4623 if (cur.ch > 0 && cur.ch < line.length - 1) | 4636 if (line) { |
| 4624 cm.replaceRange(line.charAt(cur.ch) + line.charAt(cur.ch - 1), | 4637 if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1); |
| 4625 Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1)
); | 4638 if (cur.ch > 0) { |
| 4639 cur = new Pos(cur.line, cur.ch + 1); |
| 4640 cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2), |
| 4641 Pos(cur.line, cur.ch - 2), cur, "+transpose"); |
| 4642 } else if (cur.line > cm.doc.first) { |
| 4643 var prev = getLine(cm.doc, cur.line - 1).text; |
| 4644 if (prev) |
| 4645 cm.replaceRange(line.charAt(0) + "\n" + prev.charAt(prev.length
- 1), |
| 4646 Pos(cur.line - 1, prev.length - 1), Pos(cur.line
, 1), "+transpose"); |
| 4647 } |
| 4648 } |
| 4649 newSel.push(new Range(cur, cur)); |
| 4626 } | 4650 } |
| 4651 cm.setSelections(newSel); |
| 4627 }); | 4652 }); |
| 4628 }, | 4653 }, |
| 4629 newlineAndIndent: function(cm) { | 4654 newlineAndIndent: function(cm) { |
| 4630 runInOp(cm, function() { | 4655 runInOp(cm, function() { |
| 4631 var len = cm.listSelections().length; | 4656 var len = cm.listSelections().length; |
| 4632 for (var i = 0; i < len; i++) { | 4657 for (var i = 0; i < len; i++) { |
| 4633 var range = cm.listSelections()[i]; | 4658 var range = cm.listSelections()[i]; |
| 4634 cm.replaceRange("\n", range.anchor, range.head, "+input"); | 4659 cm.replaceRange("\n", range.anchor, range.head, "+input"); |
| 4635 cm.indentLine(range.from().line + 1, null, true); | 4660 cm.indentLine(range.from().line + 1, null, true); |
| 4636 ensureCursorVisible(cm); | 4661 ensureCursorVisible(cm); |
| (...skipping 939 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5576 } | 5601 } |
| 5577 | 5602 |
| 5578 function callBlankLine(mode, state) { | 5603 function callBlankLine(mode, state) { |
| 5579 if (mode.blankLine) return mode.blankLine(state); | 5604 if (mode.blankLine) return mode.blankLine(state); |
| 5580 if (!mode.innerMode) return; | 5605 if (!mode.innerMode) return; |
| 5581 var inner = CodeMirror.innerMode(mode, state); | 5606 var inner = CodeMirror.innerMode(mode, state); |
| 5582 if (inner.mode.blankLine) return inner.mode.blankLine(inner.state); | 5607 if (inner.mode.blankLine) return inner.mode.blankLine(inner.state); |
| 5583 } | 5608 } |
| 5584 | 5609 |
| 5585 function readToken(mode, stream, state) { | 5610 function readToken(mode, stream, state) { |
| 5586 var style = mode.token(stream, state); | 5611 for (var i = 0; i < 10; i++) { |
| 5587 if (stream.pos <= stream.start) | 5612 var style = mode.token(stream, state); |
| 5588 throw new Error("Mode " + mode.name + " failed to advance stream."); | 5613 if (stream.pos > stream.start) return style; |
| 5589 return style; | 5614 } |
| 5615 throw new Error("Mode " + mode.name + " failed to advance stream."); |
| 5590 } | 5616 } |
| 5591 | 5617 |
| 5592 // Run the given mode's parser over a line, calling f for each token. | 5618 // Run the given mode's parser over a line, calling f for each token. |
| 5593 function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) { | 5619 function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) { |
| 5594 var flattenSpans = mode.flattenSpans; | 5620 var flattenSpans = mode.flattenSpans; |
| 5595 if (flattenSpans == null) flattenSpans = cm.options.flattenSpans; | 5621 if (flattenSpans == null) flattenSpans = cm.options.flattenSpans; |
| 5596 var curStart = 0, curStyle = null; | 5622 var curStart = 0, curStyle = null; |
| 5597 var stream = new StringStream(text, cm.options.tabSize), style; | 5623 var stream = new StringStream(text, cm.options.tabSize), style; |
| 5598 if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses); | 5624 if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses); |
| 5599 while (!stream.eol()) { | 5625 while (!stream.eol()) { |
| (...skipping 1445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7045 target[prop] = obj[prop]; | 7071 target[prop] = obj[prop]; |
| 7046 return target; | 7072 return target; |
| 7047 } | 7073 } |
| 7048 | 7074 |
| 7049 function bind(f) { | 7075 function bind(f) { |
| 7050 var args = Array.prototype.slice.call(arguments, 1); | 7076 var args = Array.prototype.slice.call(arguments, 1); |
| 7051 return function(){return f.apply(null, args);}; | 7077 return function(){return f.apply(null, args);}; |
| 7052 } | 7078 } |
| 7053 | 7079 |
| 7054 var nonASCIISingleCaseWordChar = /[\u00df\u3040-\u309f\u30a0-\u30ff\u3400-\u4d
b5\u4e00-\u9fcc\uac00-\ud7af]/; | 7080 var nonASCIISingleCaseWordChar = /[\u00df\u3040-\u309f\u30a0-\u30ff\u3400-\u4d
b5\u4e00-\u9fcc\uac00-\ud7af]/; |
| 7055 var isWordChar = CodeMirror.isWordChar = function(ch) { | 7081 var isWordCharBasic = CodeMirror.isWordChar = function(ch) { |
| 7056 return /\w/.test(ch) || ch > "\x80" && | 7082 return /\w/.test(ch) || ch > "\x80" && |
| 7057 (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(c
h)); | 7083 (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(c
h)); |
| 7058 }; | 7084 }; |
| 7085 function isWordChar(ch, helper) { |
| 7086 if (!helper) return isWordCharBasic(ch); |
| 7087 if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) return true; |
| 7088 return helper.test(ch); |
| 7089 } |
| 7059 | 7090 |
| 7060 function isEmpty(obj) { | 7091 function isEmpty(obj) { |
| 7061 for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false; | 7092 for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false; |
| 7062 return true; | 7093 return true; |
| 7063 } | 7094 } |
| 7064 | 7095 |
| 7065 // Extending unicode characters. A series of a non-extending char + | 7096 // Extending unicode characters. A series of a non-extending char + |
| 7066 // any number of extending chars is treated as a single unit as far | 7097 // any number of extending chars is treated as a single unit as far |
| 7067 // as editing and measuring is concerned. This is not fully correct, | 7098 // as editing and measuring is concerned. This is not fully correct, |
| 7068 // since some scripts/fonts/browsers also treat other configurations | 7099 // since some scripts/fonts/browsers also treat other configurations |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7130 function addClass(node, cls) { | 7161 function addClass(node, cls) { |
| 7131 if (!classTest(cls).test(node.className)) node.className += " " + cls; | 7162 if (!classTest(cls).test(node.className)) node.className += " " + cls; |
| 7132 } | 7163 } |
| 7133 function joinClasses(a, b) { | 7164 function joinClasses(a, b) { |
| 7134 var as = a.split(" "); | 7165 var as = a.split(" "); |
| 7135 for (var i = 0; i < as.length; i++) | 7166 for (var i = 0; i < as.length; i++) |
| 7136 if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i]; | 7167 if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i]; |
| 7137 return b; | 7168 return b; |
| 7138 } | 7169 } |
| 7139 | 7170 |
| 7171 // WINDOW-WIDE EVENTS |
| 7172 |
| 7173 // These must be handled carefully, because naively registering a |
| 7174 // handler for each editor will cause the editors to never be |
| 7175 // garbage collected. |
| 7176 |
| 7177 function forEachCodeMirror(f) { |
| 7178 if (!document.body.getElementsByClassName) return; |
| 7179 var byClass = document.body.getElementsByClassName("CodeMirror"); |
| 7180 for (var i = 0; i < byClass.length; i++) { |
| 7181 var cm = byClass[i].CodeMirror; |
| 7182 if (cm) f(cm); |
| 7183 } |
| 7184 } |
| 7185 |
| 7186 var globalsRegistered = false; |
| 7187 function ensureGlobalHandlers() { |
| 7188 if (globalsRegistered) return; |
| 7189 registerGlobalHandlers(); |
| 7190 globalsRegistered = true; |
| 7191 } |
| 7192 function registerGlobalHandlers() { |
| 7193 // When the window resizes, we need to refresh active editors. |
| 7194 var resizeTimer; |
| 7195 on(window, "resize", function() { |
| 7196 if (resizeTimer == null) resizeTimer = setTimeout(function() { |
| 7197 resizeTimer = null; |
| 7198 knownScrollbarWidth = null; |
| 7199 forEachCodeMirror(onResize); |
| 7200 }, 100); |
| 7201 }); |
| 7202 // When the window loses focus, we want to show the editor as blurred |
| 7203 on(window, "blur", function() { |
| 7204 forEachCodeMirror(onBlur); |
| 7205 }); |
| 7206 } |
| 7207 |
| 7140 // FEATURE DETECTION | 7208 // FEATURE DETECTION |
| 7141 | 7209 |
| 7142 // Detect drag-and-drop | 7210 // Detect drag-and-drop |
| 7143 var dragAndDrop = function() { | 7211 var dragAndDrop = function() { |
| 7144 // There is *some* kind of drag-and-drop support in IE6-8, but I | 7212 // There is *some* kind of drag-and-drop support in IE6-8, but I |
| 7145 // couldn't get it to work yet. | 7213 // couldn't get it to work yet. |
| 7146 if (ie_upto8) return false; | 7214 if (ie_upto8) return false; |
| 7147 var div = elt('div'); | 7215 var div = elt('div'); |
| 7148 return "draggable" in div || "dragDrop" in div; | 7216 return "draggable" in div || "dragDrop" in div; |
| 7149 }(); | 7217 }(); |
| (...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7516 return order; | 7584 return order; |
| 7517 }; | 7585 }; |
| 7518 })(); | 7586 })(); |
| 7519 | 7587 |
| 7520 // THE END | 7588 // THE END |
| 7521 | 7589 |
| 7522 CodeMirror.version = "4.1.1"; | 7590 CodeMirror.version = "4.1.1"; |
| 7523 | 7591 |
| 7524 return CodeMirror; | 7592 return CodeMirror; |
| 7525 }); | 7593 }); |
| OLD | NEW |