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 |