OLD | NEW |
1 // CodeMirror version 3.12 | |
2 // | |
3 // CodeMirror is the only global var we claim | 1 // CodeMirror is the only global var we claim |
4 window.CodeMirror = (function() { | 2 window.CodeMirror = (function() { |
5 "use strict"; | 3 "use strict"; |
6 | 4 |
7 // BROWSER SNIFFING | 5 // BROWSER SNIFFING |
8 | 6 |
9 // Crude, but necessary to handle a number of hard-to-feature-detect | 7 // Crude, but necessary to handle a number of hard-to-feature-detect |
10 // bugs and behavior differences. | 8 // bugs and behavior differences. |
11 var gecko = /gecko\/\d/i.test(navigator.userAgent); | 9 var gecko = /gecko\/\d/i.test(navigator.userAgent); |
12 var ie = /MSIE \d/.test(navigator.userAgent); | 10 var ie = /MSIE \d/.test(navigator.userAgent); |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
92 // DISPLAY CONSTRUCTOR | 90 // DISPLAY CONSTRUCTOR |
93 | 91 |
94 function makeDisplay(place, docStart) { | 92 function makeDisplay(place, docStart) { |
95 var d = {}; | 93 var d = {}; |
96 | 94 |
97 var input = d.input = elt("textarea", null, null, "position: absolute; paddi
ng: 0; width: 1px; height: 1em; outline: none; font-size: 4px;"); | 95 var input = d.input = elt("textarea", null, null, "position: absolute; paddi
ng: 0; width: 1px; height: 1em; outline: none; font-size: 4px;"); |
98 if (webkit) input.style.width = "1000px"; | 96 if (webkit) input.style.width = "1000px"; |
99 else input.setAttribute("wrap", "off"); | 97 else input.setAttribute("wrap", "off"); |
100 // if border: 0; -- iOS fails to open keyboard (issue #1287) | 98 // if border: 0; -- iOS fails to open keyboard (issue #1287) |
101 if (ios) input.style.border = "1px solid black"; | 99 if (ios) input.style.border = "1px solid black"; |
102 input.setAttribute("autocorrect", "off"); input.setAttribute("autocapitalize
", "off"); | 100 input.setAttribute("autocorrect", "off"); input.setAttribute("autocapitalize
", "off"); input.setAttribute("spellcheck", "false"); |
103 | 101 |
104 // Wraps and hides input textarea | 102 // Wraps and hides input textarea |
105 d.inputDiv = elt("div", [input], null, "overflow: hidden; position: relative
; width: 3px; height: 0px;"); | 103 d.inputDiv = elt("div", [input], null, "overflow: hidden; position: relative
; width: 3px; height: 0px;"); |
106 // The actual fake scrollbars. | 104 // The actual fake scrollbars. |
107 d.scrollbarH = elt("div", [elt("div", null, null, "height: 1px")], "CodeMirr
or-hscrollbar"); | 105 d.scrollbarH = elt("div", [elt("div", null, null, "height: 1px")], "CodeMirr
or-hscrollbar"); |
108 d.scrollbarV = elt("div", [elt("div", null, null, "width: 1px")], "CodeMirro
r-vscrollbar"); | 106 d.scrollbarV = elt("div", [elt("div", null, null, "width: 1px")], "CodeMirro
r-vscrollbar"); |
109 d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler"); | 107 d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler"); |
| 108 d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler"); |
110 // DIVs containing the selection and the actual code | 109 // DIVs containing the selection and the actual code |
111 d.lineDiv = elt("div"); | 110 d.lineDiv = elt("div", null, "CodeMirror-code"); |
112 d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1"); | 111 d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1"); |
113 // Blinky cursor, and element used to ensure cursor fits at the end of a lin
e | 112 // Blinky cursor, and element used to ensure cursor fits at the end of a lin
e |
114 d.cursor = elt("div", "\u00a0", "CodeMirror-cursor"); | 113 d.cursor = elt("div", "\u00a0", "CodeMirror-cursor"); |
115 // Secondary cursor, shown when on a 'jump' in bi-directional text | 114 // Secondary cursor, shown when on a 'jump' in bi-directional text |
116 d.otherCursor = elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondary
cursor"); | 115 d.otherCursor = elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondary
cursor"); |
117 // Used to measure text size | 116 // Used to measure text size |
118 d.measure = elt("div", null, "CodeMirror-measure"); | 117 d.measure = elt("div", null, "CodeMirror-measure"); |
119 // Wraps everything that needs to exist inside the vertically-padded coordin
ate system | 118 // Wraps everything that needs to exist inside the vertically-padded coordin
ate system |
120 d.lineSpace = elt("div", [d.measure, d.selectionDiv, d.lineDiv, d.cursor, d.
otherCursor], | 119 d.lineSpace = elt("div", [d.measure, d.selectionDiv, d.lineDiv, d.cursor, d.
otherCursor], |
121 null, "position: relative; outline: none"); | 120 null, "position: relative; outline: none"); |
122 // Moved around its parent to cover visible view | 121 // Moved around its parent to cover visible view |
123 d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null,
"position: relative"); | 122 d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null,
"position: relative"); |
124 // Set to the height of the text, causes scrolling | 123 // Set to the height of the text, causes scrolling |
125 d.sizer = elt("div", [d.mover], "CodeMirror-sizer"); | 124 d.sizer = elt("div", [d.mover], "CodeMirror-sizer"); |
126 // D is needed because behavior of elts with overflow: auto and padding is i
nconsistent across browsers | 125 // D is needed because behavior of elts with overflow: auto and padding is i
nconsistent across browsers |
127 d.heightForcer = elt("div", null, null, "position: absolute; height: " + scr
ollerCutOff + "px; width: 1px;"); | 126 d.heightForcer = elt("div", null, null, "position: absolute; height: " + scr
ollerCutOff + "px; width: 1px;"); |
128 // Will contain the gutters, if any | 127 // Will contain the gutters, if any |
129 d.gutters = elt("div", null, "CodeMirror-gutters"); | 128 d.gutters = elt("div", null, "CodeMirror-gutters"); |
130 d.lineGutter = null; | 129 d.lineGutter = null; |
131 // Helper element to properly size the gutter backgrounds | |
132 var scrollerInner = elt("div", [d.sizer, d.heightForcer, d.gutters], null, "
position: relative; min-height: 100%"); | |
133 // Provides scrolling | 130 // Provides scrolling |
134 d.scroller = elt("div", [scrollerInner], "CodeMirror-scroll"); | 131 d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-sc
roll"); |
135 d.scroller.setAttribute("tabIndex", "-1"); | 132 d.scroller.setAttribute("tabIndex", "-1"); |
136 // The element in which the editor lives. | 133 // The element in which the editor lives. |
137 d.wrapper = elt("div", [d.inputDiv, d.scrollbarH, d.scrollbarV, | 134 d.wrapper = elt("div", [d.inputDiv, d.scrollbarH, d.scrollbarV, |
138 d.scrollbarFiller, d.scroller], "CodeMirror"); | 135 d.scrollbarFiller, d.gutterFiller, d.scroller], "Cod
eMirror"); |
139 // Work around IE7 z-index bug | 136 // Work around IE7 z-index bug |
140 if (ie_lt8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0
; } | 137 if (ie_lt8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0
; } |
141 if (place.appendChild) place.appendChild(d.wrapper); else place(d.wrapper); | 138 if (place.appendChild) place.appendChild(d.wrapper); else place(d.wrapper); |
142 | 139 |
143 // Needed to hide big blue blinking cursor on Mobile Safari | 140 // Needed to hide big blue blinking cursor on Mobile Safari |
144 if (ios) input.style.width = "0px"; | 141 if (ios) input.style.width = "0px"; |
145 if (!webkit) d.scroller.draggable = true; | 142 if (!webkit) d.scroller.draggable = true; |
146 // Needed to handle Tab key in KHTML | 143 // Needed to handle Tab key in KHTML |
147 if (khtml) { d.inputDiv.style.height = "1px"; d.inputDiv.style.position = "a
bsolute"; } | 144 if (khtml) { d.inputDiv.style.height = "1px"; d.inputDiv.style.position = "a
bsolute"; } |
148 // Need to set a minimum width to see the scrollbar on IE7 (but must not set
it on IE8). | 145 // Need to set a minimum width to see the scrollbar on IE7 (but must not set
it on IE8). |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
207 if (cm.options.lineWrapping) { | 204 if (cm.options.lineWrapping) { |
208 cm.display.wrapper.className += " CodeMirror-wrap"; | 205 cm.display.wrapper.className += " CodeMirror-wrap"; |
209 cm.display.sizer.style.minWidth = ""; | 206 cm.display.sizer.style.minWidth = ""; |
210 } else { | 207 } else { |
211 cm.display.wrapper.className = cm.display.wrapper.className.replace(" Code
Mirror-wrap", ""); | 208 cm.display.wrapper.className = cm.display.wrapper.className.replace(" Code
Mirror-wrap", ""); |
212 computeMaxLength(cm); | 209 computeMaxLength(cm); |
213 } | 210 } |
214 estimateLineHeights(cm); | 211 estimateLineHeights(cm); |
215 regChange(cm); | 212 regChange(cm); |
216 clearCaches(cm); | 213 clearCaches(cm); |
217 setTimeout(function(){updateScrollbars(cm.display, cm.doc.height);}, 100); | 214 setTimeout(function(){updateScrollbars(cm);}, 100); |
218 } | 215 } |
219 | 216 |
220 function estimateHeight(cm) { | 217 function estimateHeight(cm) { |
221 var th = textHeight(cm.display), wrapping = cm.options.lineWrapping; | 218 var th = textHeight(cm.display), wrapping = cm.options.lineWrapping; |
222 var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / char
Width(cm.display) - 3); | 219 var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / char
Width(cm.display) - 3); |
223 return function(line) { | 220 return function(line) { |
224 if (lineIsHidden(cm.doc, line)) | 221 if (lineIsHidden(cm.doc, line)) |
225 return 0; | 222 return 0; |
226 else if (wrapping) | 223 else if (wrapping) |
227 return (Math.ceil(line.text.length / perLine) || 1) * th; | 224 return (Math.ceil(line.text.length / perLine) || 1) * th; |
(...skipping 18 matching lines...) Expand all Loading... |
246 | 243 |
247 function themeChanged(cm) { | 244 function themeChanged(cm) { |
248 cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s
-\S+/g, "") + | 245 cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s
-\S+/g, "") + |
249 cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-"); | 246 cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-"); |
250 clearCaches(cm); | 247 clearCaches(cm); |
251 } | 248 } |
252 | 249 |
253 function guttersChanged(cm) { | 250 function guttersChanged(cm) { |
254 updateGutters(cm); | 251 updateGutters(cm); |
255 regChange(cm); | 252 regChange(cm); |
| 253 setTimeout(function(){alignHorizontally(cm);}, 20); |
256 } | 254 } |
257 | 255 |
258 function updateGutters(cm) { | 256 function updateGutters(cm) { |
259 var gutters = cm.display.gutters, specs = cm.options.gutters; | 257 var gutters = cm.display.gutters, specs = cm.options.gutters; |
260 removeChildren(gutters); | 258 removeChildren(gutters); |
261 for (var i = 0; i < specs.length; ++i) { | 259 for (var i = 0; i < specs.length; ++i) { |
262 var gutterClass = specs[i]; | 260 var gutterClass = specs[i]; |
263 var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gut
terClass)); | 261 var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gut
terClass)); |
264 if (gutterClass == "CodeMirror-linenumbers") { | 262 if (gutterClass == "CodeMirror-linenumbers") { |
265 cm.display.lineGutter = gElt; | 263 cm.display.lineGutter = gElt; |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
312 } | 310 } |
313 } | 311 } |
314 if (!found && options.lineNumbers) | 312 if (!found && options.lineNumbers) |
315 options.gutters.push("CodeMirror-linenumbers"); | 313 options.gutters.push("CodeMirror-linenumbers"); |
316 } | 314 } |
317 | 315 |
318 // SCROLLBARS | 316 // SCROLLBARS |
319 | 317 |
320 // Re-synchronize the fake scrollbars with the actual size of the | 318 // Re-synchronize the fake scrollbars with the actual size of the |
321 // content. Optionally force a scrollTop. | 319 // content. Optionally force a scrollTop. |
322 function updateScrollbars(d /* display */, docHeight) { | 320 function updateScrollbars(cm) { |
| 321 var d = cm.display, docHeight = cm.doc.height; |
323 var totalHeight = docHeight + paddingVert(d); | 322 var totalHeight = docHeight + paddingVert(d); |
324 d.sizer.style.minHeight = d.heightForcer.style.top = totalHeight + "px"; | 323 d.sizer.style.minHeight = d.heightForcer.style.top = totalHeight + "px"; |
| 324 d.gutters.style.height = Math.max(totalHeight, d.scroller.clientHeight - scr
ollerCutOff) + "px"; |
325 var scrollHeight = Math.max(totalHeight, d.scroller.scrollHeight); | 325 var scrollHeight = Math.max(totalHeight, d.scroller.scrollHeight); |
326 var needsH = d.scroller.scrollWidth > d.scroller.clientWidth; | 326 var needsH = d.scroller.scrollWidth > d.scroller.clientWidth; |
327 var needsV = scrollHeight > d.scroller.clientHeight; | 327 var needsV = scrollHeight > d.scroller.clientHeight; |
328 if (needsV) { | 328 if (needsV) { |
329 d.scrollbarV.style.display = "block"; | 329 d.scrollbarV.style.display = "block"; |
330 d.scrollbarV.style.bottom = needsH ? scrollbarWidth(d.measure) + "px" : "0
"; | 330 d.scrollbarV.style.bottom = needsH ? scrollbarWidth(d.measure) + "px" : "0
"; |
331 d.scrollbarV.firstChild.style.height = | 331 d.scrollbarV.firstChild.style.height = |
332 (scrollHeight - d.scroller.clientHeight + d.scrollbarV.clientHeight) + "
px"; | 332 (scrollHeight - d.scroller.clientHeight + d.scrollbarV.clientHeight) + "
px"; |
333 } else d.scrollbarV.style.display = ""; | 333 } else d.scrollbarV.style.display = ""; |
334 if (needsH) { | 334 if (needsH) { |
335 d.scrollbarH.style.display = "block"; | 335 d.scrollbarH.style.display = "block"; |
336 d.scrollbarH.style.right = needsV ? scrollbarWidth(d.measure) + "px" : "0"
; | 336 d.scrollbarH.style.right = needsV ? scrollbarWidth(d.measure) + "px" : "0"
; |
337 d.scrollbarH.firstChild.style.width = | 337 d.scrollbarH.firstChild.style.width = |
338 (d.scroller.scrollWidth - d.scroller.clientWidth + d.scrollbarH.clientWi
dth) + "px"; | 338 (d.scroller.scrollWidth - d.scroller.clientWidth + d.scrollbarH.clientWi
dth) + "px"; |
339 } else d.scrollbarH.style.display = ""; | 339 } else d.scrollbarH.style.display = ""; |
340 if (needsH && needsV) { | 340 if (needsH && needsV) { |
341 d.scrollbarFiller.style.display = "block"; | 341 d.scrollbarFiller.style.display = "block"; |
342 d.scrollbarFiller.style.height = d.scrollbarFiller.style.width = scrollbar
Width(d.measure) + "px"; | 342 d.scrollbarFiller.style.height = d.scrollbarFiller.style.width = scrollbar
Width(d.measure) + "px"; |
343 } else d.scrollbarFiller.style.display = ""; | 343 } else d.scrollbarFiller.style.display = ""; |
| 344 if (needsH && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutte
r) { |
| 345 d.gutterFiller.style.display = "block"; |
| 346 d.gutterFiller.style.height = scrollbarWidth(d.measure) + "px"; |
| 347 d.gutterFiller.style.width = d.gutters.offsetWidth + "px"; |
| 348 } else d.gutterFiller.style.display = ""; |
344 | 349 |
345 if (mac_geLion && scrollbarWidth(d.measure) === 0) | 350 if (mac_geLion && scrollbarWidth(d.measure) === 0) |
346 d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = mac_geMountai
nLion ? "18px" : "12px"; | 351 d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = mac_geMountai
nLion ? "18px" : "12px"; |
347 } | 352 } |
348 | 353 |
349 function visibleLines(display, doc, viewPort) { | 354 function visibleLines(display, doc, viewPort) { |
350 var top = display.scroller.scrollTop, height = display.wrapper.clientHeight; | 355 var top = display.scroller.scrollTop, height = display.wrapper.clientHeight; |
351 if (typeof viewPort == "number") top = viewPort; | 356 if (typeof viewPort == "number") top = viewPort; |
352 else if (viewPort) {top = viewPort.top; height = viewPort.bottom - viewPort.
top;} | 357 else if (viewPort) {top = viewPort.top; height = viewPort.bottom - viewPort.
top;} |
353 top = Math.floor(top - paddingTop(display)); | 358 top = Math.floor(top - paddingTop(display)); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
392 function compensateForHScroll(display) { | 397 function compensateForHScroll(display) { |
393 return getRect(display.scroller).left - getRect(display.sizer).left; | 398 return getRect(display.scroller).left - getRect(display.sizer).left; |
394 } | 399 } |
395 | 400 |
396 // DISPLAY DRAWING | 401 // DISPLAY DRAWING |
397 | 402 |
398 function updateDisplay(cm, changes, viewPort) { | 403 function updateDisplay(cm, changes, viewPort) { |
399 var oldFrom = cm.display.showingFrom, oldTo = cm.display.showingTo, updated; | 404 var oldFrom = cm.display.showingFrom, oldTo = cm.display.showingTo, updated; |
400 var visible = visibleLines(cm.display, cm.doc, viewPort); | 405 var visible = visibleLines(cm.display, cm.doc, viewPort); |
401 for (;;) { | 406 for (;;) { |
402 if (updateDisplayInner(cm, changes, visible)) { | 407 if (!updateDisplayInner(cm, changes, visible)) break; |
403 updated = true; | 408 updated = true; |
404 signalLater(cm, "update", cm); | |
405 if (cm.display.showingFrom != oldFrom || cm.display.showingTo != oldTo) | |
406 signalLater(cm, "viewportChange", cm, cm.display.showingFrom, cm.displ
ay.showingTo); | |
407 } else break; | |
408 updateSelection(cm); | 409 updateSelection(cm); |
409 updateScrollbars(cm.display, cm.doc.height); | 410 updateScrollbars(cm); |
410 | 411 |
411 // Clip forced viewport to actual scrollable area | 412 // Clip forced viewport to actual scrollable area |
412 if (viewPort) | 413 if (viewPort) |
413 viewPort = Math.min(cm.display.scroller.scrollHeight - cm.display.scroll
er.clientHeight, | 414 viewPort = Math.min(cm.display.scroller.scrollHeight - cm.display.scroll
er.clientHeight, |
414 typeof viewPort == "number" ? viewPort : viewPort.to
p); | 415 typeof viewPort == "number" ? viewPort : viewPort.to
p); |
415 visible = visibleLines(cm.display, cm.doc, viewPort); | 416 visible = visibleLines(cm.display, cm.doc, viewPort); |
416 if (visible.from >= cm.display.showingFrom && visible.to <= cm.display.sho
wingTo) | 417 if (visible.from >= cm.display.showingFrom && visible.to <= cm.display.sho
wingTo) |
417 break; | 418 break; |
418 changes = []; | 419 changes = []; |
419 } | 420 } |
420 | 421 |
| 422 if (updated) { |
| 423 signalLater(cm, "update", cm); |
| 424 if (cm.display.showingFrom != oldFrom || cm.display.showingTo != oldTo) |
| 425 signalLater(cm, "viewportChange", cm, cm.display.showingFrom, cm.display
.showingTo); |
| 426 } |
421 return updated; | 427 return updated; |
422 } | 428 } |
423 | 429 |
424 // Uses a set of changes plus the current scroll position to | 430 // Uses a set of changes plus the current scroll position to |
425 // determine which DOM updates have to be made, and makes the | 431 // determine which DOM updates have to be made, and makes the |
426 // updates. | 432 // updates. |
427 function updateDisplayInner(cm, changes, visible) { | 433 function updateDisplayInner(cm, changes, visible) { |
428 var display = cm.display, doc = cm.doc; | 434 var display = cm.display, doc = cm.doc; |
429 if (!display.wrapper.clientWidth) { | 435 if (!display.wrapper.clientWidth) { |
430 display.showingFrom = display.showingTo = doc.first; | 436 display.showingFrom = display.showingTo = doc.first; |
(...skipping 540 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
971 top: r.top, bottom: r.bottom}; | 977 top: r.top, bottom: r.bottom}; |
972 } | 978 } |
973 | 979 |
974 function findCachedMeasurement(cm, line) { | 980 function findCachedMeasurement(cm, line) { |
975 var cache = cm.display.measureLineCache; | 981 var cache = cm.display.measureLineCache; |
976 for (var i = 0; i < cache.length; ++i) { | 982 for (var i = 0; i < cache.length; ++i) { |
977 var memo = cache[i]; | 983 var memo = cache[i]; |
978 if (memo.text == line.text && memo.markedSpans == line.markedSpans && | 984 if (memo.text == line.text && memo.markedSpans == line.markedSpans && |
979 cm.display.scroller.clientWidth == memo.width && | 985 cm.display.scroller.clientWidth == memo.width && |
980 memo.classes == line.textClass + "|" + line.bgClass + "|" + line.wrapC
lass) | 986 memo.classes == line.textClass + "|" + line.bgClass + "|" + line.wrapC
lass) |
981 return memo.measure; | 987 return memo; |
982 } | 988 } |
983 } | 989 } |
984 | 990 |
| 991 function clearCachedMeasurement(cm, line) { |
| 992 var exists = findCachedMeasurement(cm, line); |
| 993 if (exists) exists.text = exists.measure = exists.markedSpans = null; |
| 994 } |
| 995 |
985 function measureLine(cm, line) { | 996 function measureLine(cm, line) { |
986 // First look in the cache | 997 // First look in the cache |
987 var measure = findCachedMeasurement(cm, line); | 998 var cached = findCachedMeasurement(cm, line); |
988 if (!measure) { | 999 if (cached) return cached.measure; |
989 // Failing that, recompute and store result in cache | 1000 |
990 measure = measureLineInner(cm, line); | 1001 // Failing that, recompute and store result in cache |
991 var cache = cm.display.measureLineCache; | 1002 var measure = measureLineInner(cm, line); |
992 var memo = {text: line.text, width: cm.display.scroller.clientWidth, | 1003 var cache = cm.display.measureLineCache; |
993 markedSpans: line.markedSpans, measure: measure, | 1004 var memo = {text: line.text, width: cm.display.scroller.clientWidth, |
994 classes: line.textClass + "|" + line.bgClass + "|" + line.wrap
Class}; | 1005 markedSpans: line.markedSpans, measure: measure, |
995 if (cache.length == 16) cache[++cm.display.measureLineCachePos % 16] = mem
o; | 1006 classes: line.textClass + "|" + line.bgClass + "|" + line.wrapCl
ass}; |
996 else cache.push(memo); | 1007 if (cache.length == 16) cache[++cm.display.measureLineCachePos % 16] = memo; |
997 } | 1008 else cache.push(memo); |
998 return measure; | 1009 return measure; |
999 } | 1010 } |
1000 | 1011 |
1001 function measureLineInner(cm, line) { | 1012 function measureLineInner(cm, line) { |
1002 var display = cm.display, measure = emptyArray(line.text.length); | 1013 var display = cm.display, measure = emptyArray(line.text.length); |
1003 var pre = lineContent(cm, line, measure); | 1014 var pre = lineContent(cm, line, measure); |
1004 | 1015 |
1005 // IE does not cache element positions of inline elements between | 1016 // IE does not cache element positions of inline elements between |
1006 // calls to getBoundingClientRect. This makes the loop below, | 1017 // calls to getBoundingClientRect. This makes the loop below, |
1007 // which gathers the positions of all the characters on the line, | 1018 // which gathers the positions of all the characters on the line, |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1063 return data; | 1074 return data; |
1064 } | 1075 } |
1065 | 1076 |
1066 function measureLineWidth(cm, line) { | 1077 function measureLineWidth(cm, line) { |
1067 var hasBadSpan = false; | 1078 var hasBadSpan = false; |
1068 if (line.markedSpans) for (var i = 0; i < line.markedSpans; ++i) { | 1079 if (line.markedSpans) for (var i = 0; i < line.markedSpans; ++i) { |
1069 var sp = line.markedSpans[i]; | 1080 var sp = line.markedSpans[i]; |
1070 if (sp.collapsed && (sp.to == null || sp.to == line.text.length)) hasBadSp
an = true; | 1081 if (sp.collapsed && (sp.to == null || sp.to == line.text.length)) hasBadSp
an = true; |
1071 } | 1082 } |
1072 var cached = !hasBadSpan && findCachedMeasurement(cm, line); | 1083 var cached = !hasBadSpan && findCachedMeasurement(cm, line); |
1073 if (cached) return measureChar(cm, line, line.text.length, cached).right; | 1084 if (cached) return measureChar(cm, line, line.text.length, cached.measure).r
ight; |
1074 | 1085 |
1075 var pre = lineContent(cm, line); | 1086 var pre = lineContent(cm, line); |
1076 var end = pre.appendChild(zeroWidthElement(cm.display.measure)); | 1087 var end = pre.appendChild(zeroWidthElement(cm.display.measure)); |
1077 removeChildrenAndAdd(cm.display.measure, pre); | 1088 removeChildrenAndAdd(cm.display.measure, pre); |
1078 return getRect(end).right - getRect(cm.display.lineDiv).left; | 1089 return getRect(end).right - getRect(cm.display.lineDiv).left; |
1079 } | 1090 } |
1080 | 1091 |
1081 function clearCaches(cm) { | 1092 function clearCaches(cm) { |
1082 cm.display.measureLineCache.length = cm.display.measureLineCachePos = 0; | 1093 cm.display.measureLineCache.length = cm.display.measureLineCachePos = 0; |
1083 cm.display.cachedCharWidth = cm.display.cachedTextHeight = null; | 1094 cm.display.cachedCharWidth = cm.display.cachedTextHeight = null; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1131 } | 1142 } |
1132 | 1143 |
1133 function cursorCoords(cm, pos, context, lineObj, measurement) { | 1144 function cursorCoords(cm, pos, context, lineObj, measurement) { |
1134 lineObj = lineObj || getLine(cm.doc, pos.line); | 1145 lineObj = lineObj || getLine(cm.doc, pos.line); |
1135 if (!measurement) measurement = measureLine(cm, lineObj); | 1146 if (!measurement) measurement = measureLine(cm, lineObj); |
1136 function get(ch, right) { | 1147 function get(ch, right) { |
1137 var m = measureChar(cm, lineObj, ch, measurement); | 1148 var m = measureChar(cm, lineObj, ch, measurement); |
1138 if (right) m.left = m.right; else m.right = m.left; | 1149 if (right) m.left = m.right; else m.right = m.left; |
1139 return intoCoordSystem(cm, lineObj, m, context); | 1150 return intoCoordSystem(cm, lineObj, m, context); |
1140 } | 1151 } |
| 1152 function getBidi(ch, partPos) { |
| 1153 var part = order[partPos], right = part.level % 2; |
| 1154 if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].lev
el) { |
| 1155 part = order[--partPos]; |
| 1156 ch = bidiRight(part) - (part.level % 2 ? 0 : 1); |
| 1157 right = true; |
| 1158 } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.lev
el < order[partPos + 1].level) { |
| 1159 part = order[++partPos]; |
| 1160 ch = bidiLeft(part) - part.level % 2; |
| 1161 right = false; |
| 1162 } |
| 1163 if (right && ch == part.to && ch > part.from) return get(ch - 1); |
| 1164 return get(ch, right); |
| 1165 } |
1141 var order = getOrder(lineObj), ch = pos.ch; | 1166 var order = getOrder(lineObj), ch = pos.ch; |
1142 if (!order) return get(ch); | 1167 if (!order) return get(ch); |
1143 var main, other, linedir = order[0].level; | 1168 var partPos = getBidiPartAt(order, ch); |
1144 for (var i = 0; i < order.length; ++i) { | 1169 var val = getBidi(ch, partPos); |
1145 var part = order[i], rtl = part.level % 2, nb, here; | 1170 if (bidiOther != null) val.other = getBidi(ch, bidiOther); |
1146 if (part.from < ch && part.to > ch) return get(ch, rtl); | 1171 return val; |
1147 var left = rtl ? part.to : part.from, right = rtl ? part.from : part.to; | |
1148 if (left == ch) { | |
1149 // IE returns bogus offsets and widths for edges where the | |
1150 // direction flips, but only for the side with the lower | |
1151 // level. So we try to use the side with the higher level. | |
1152 if (i && part.level < (nb = order[i-1]).level) here = get(nb.level % 2 ?
nb.from : nb.to - 1, true); | |
1153 else here = get(rtl && part.from != part.to ? ch - 1 : ch); | |
1154 if (rtl == linedir) main = here; else other = here; | |
1155 } else if (right == ch) { | |
1156 var nb = i < order.length - 1 && order[i+1]; | |
1157 if (!rtl && nb && nb.from == nb.to) continue; | |
1158 if (nb && part.level < nb.level) here = get(nb.level % 2 ? nb.to - 1 : n
b.from); | |
1159 else here = get(rtl ? ch : ch - 1, true); | |
1160 if (rtl == linedir) main = here; else other = here; | |
1161 } | |
1162 } | |
1163 if (linedir && !ch) other = get(order[0].to - 1); | |
1164 if (!main) return other; | |
1165 if (other) main.other = other; | |
1166 return main; | |
1167 } | 1172 } |
1168 | 1173 |
1169 function PosMaybeOutside(line, ch, outside) { | 1174 function PosMaybeOutside(line, ch, outside) { |
1170 var pos = new Pos(line, ch); | 1175 var pos = new Pos(line, ch); |
1171 if (outside) pos.outside = true; | 1176 if (outside) pos.outside = true; |
1172 return pos; | 1177 return pos; |
1173 } | 1178 } |
1174 | 1179 |
1175 // Coords must be lineSpace-local | 1180 // Coords must be lineSpace-local |
1176 function coordsChar(cm, x, y) { | 1181 function coordsChar(cm, x, y) { |
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1501 | 1506 |
1502 on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);}); | 1507 on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);}); |
1503 on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);}); | 1508 on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);}); |
1504 | 1509 |
1505 function reFocus() { if (cm.state.focused) setTimeout(bind(focusInput, cm),
0); } | 1510 function reFocus() { if (cm.state.focused) setTimeout(bind(focusInput, cm),
0); } |
1506 on(d.scrollbarH, "mousedown", reFocus); | 1511 on(d.scrollbarH, "mousedown", reFocus); |
1507 on(d.scrollbarV, "mousedown", reFocus); | 1512 on(d.scrollbarV, "mousedown", reFocus); |
1508 // Prevent wrapper from ever scrolling | 1513 // Prevent wrapper from ever scrolling |
1509 on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollL
eft = 0; }); | 1514 on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollL
eft = 0; }); |
1510 | 1515 |
| 1516 var resizeTimer = new Delayed(); |
1511 function onResize() { | 1517 function onResize() { |
1512 // Might be a text scaling operation, clear size caches. | 1518 resizeTimer.set(function() { |
1513 d.cachedCharWidth = d.cachedTextHeight = null; | 1519 // Might be a text scaling operation, clear size caches. |
1514 clearCaches(cm); | 1520 d.cachedCharWidth = d.cachedTextHeight = null; |
1515 runInOp(cm, bind(regChange, cm)); | 1521 clearCaches(cm); |
| 1522 runInOp(cm, bind(regChange, cm)); |
| 1523 }, 200); |
1516 } | 1524 } |
1517 on(window, "resize", onResize); | 1525 on(window, "resize", onResize); |
1518 // Above handler holds on to the editor and its data structures. | 1526 // Above handler holds on to the editor and its data structures. |
1519 // Here we poll to unregister it when the editor is no longer in | 1527 // Here we poll to unregister it when the editor is no longer in |
1520 // the document, so that it can be garbage-collected. | 1528 // the document, so that it can be garbage-collected. |
1521 function unregister() { | 1529 function unregister() { |
1522 for (var p = d.wrapper.parentNode; p && p != document.body; p = p.parentNo
de) {} | 1530 for (var p = d.wrapper.parentNode; p && p != document.body; p = p.parentNo
de) {} |
1523 if (p) setTimeout(unregister, 5000); | 1531 if (p) setTimeout(unregister, 5000); |
1524 else off(window, "resize", onResize); | 1532 else off(window, "resize", onResize); |
1525 } | 1533 } |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1580 n.parentNode == display.sizer && n != display.mover) return true; | 1588 n.parentNode == display.sizer && n != display.mover) return true; |
1581 } | 1589 } |
1582 } | 1590 } |
1583 | 1591 |
1584 function posFromMouse(cm, e, liberal) { | 1592 function posFromMouse(cm, e, liberal) { |
1585 var display = cm.display; | 1593 var display = cm.display; |
1586 if (!liberal) { | 1594 if (!liberal) { |
1587 var target = e_target(e); | 1595 var target = e_target(e); |
1588 if (target == display.scrollbarH || target == display.scrollbarH.firstChil
d || | 1596 if (target == display.scrollbarH || target == display.scrollbarH.firstChil
d || |
1589 target == display.scrollbarV || target == display.scrollbarV.firstChil
d || | 1597 target == display.scrollbarV || target == display.scrollbarV.firstChil
d || |
1590 target == display.scrollbarFiller) return null; | 1598 target == display.scrollbarFiller || target == display.gutterFiller) r
eturn null; |
1591 } | 1599 } |
1592 var x, y, space = getRect(display.lineSpace); | 1600 var x, y, space = getRect(display.lineSpace); |
1593 // Fails unpredictably on IE[67] when mouse is dragged around quickly. | 1601 // Fails unpredictably on IE[67] when mouse is dragged around quickly. |
1594 try { x = e.clientX; y = e.clientY; } catch (e) { return null; } | 1602 try { x = e.clientX; y = e.clientY; } catch (e) { return null; } |
1595 return coordsChar(cm, x - space.left, y - space.top); | 1603 return coordsChar(cm, x - space.left, y - space.top); |
1596 } | 1604 } |
1597 | 1605 |
1598 var lastClick, lastDoubleClick; | 1606 var lastClick, lastDoubleClick; |
1599 function onMouseDown(e) { | 1607 function onMouseDown(e) { |
1600 var cm = this, display = cm.display, doc = cm.doc, sel = doc.sel; | 1608 var cm = this, display = cm.display, doc = cm.doc, sel = doc.sel; |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1713 if (outside) setTimeout(operation(cm, function() { | 1721 if (outside) setTimeout(operation(cm, function() { |
1714 if (counter != curCount) return; | 1722 if (counter != curCount) return; |
1715 display.scroller.scrollTop += outside; | 1723 display.scroller.scrollTop += outside; |
1716 extend(e); | 1724 extend(e); |
1717 }), 50); | 1725 }), 50); |
1718 } | 1726 } |
1719 } | 1727 } |
1720 | 1728 |
1721 function done(e) { | 1729 function done(e) { |
1722 counter = Infinity; | 1730 counter = Infinity; |
1723 var cur = posFromMouse(cm, e); | |
1724 if (cur) doSelect(cur); | |
1725 e_preventDefault(e); | 1731 e_preventDefault(e); |
1726 focusInput(cm); | 1732 focusInput(cm); |
1727 off(document, "mousemove", move); | 1733 off(document, "mousemove", move); |
1728 off(document, "mouseup", up); | 1734 off(document, "mouseup", up); |
1729 } | 1735 } |
1730 | 1736 |
1731 var move = operation(cm, function(e) { | 1737 var move = operation(cm, function(e) { |
1732 if (!ie && !e_button(e)) done(e); | 1738 if (!ie && !e_button(e)) done(e); |
1733 else extend(e); | 1739 else extend(e); |
1734 }); | 1740 }); |
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2085 var oldCSS = display.input.style.cssText; | 2091 var oldCSS = display.input.style.cssText; |
2086 display.inputDiv.style.position = "absolute"; | 2092 display.inputDiv.style.position = "absolute"; |
2087 display.input.style.cssText = "position: fixed; width: 30px; height: 30px; t
op: " + (e.clientY - 5) + | 2093 display.input.style.cssText = "position: fixed; width: 30px; height: 30px; t
op: " + (e.clientY - 5) + |
2088 "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: white; ou
tline: none;" + | 2094 "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: white; ou
tline: none;" + |
2089 "border-width: 0; outline: none; overflow: hidden; opacity: .05; -ms-opaci
ty: .05; filter: alpha(opacity=5);"; | 2095 "border-width: 0; outline: none; overflow: hidden; opacity: .05; -ms-opaci
ty: .05; filter: alpha(opacity=5);"; |
2090 focusInput(cm); | 2096 focusInput(cm); |
2091 resetInput(cm, true); | 2097 resetInput(cm, true); |
2092 // Adds "Select all" to context menu in FF | 2098 // Adds "Select all" to context menu in FF |
2093 if (posEq(sel.from, sel.to)) display.input.value = display.prevInput = " "; | 2099 if (posEq(sel.from, sel.to)) display.input.value = display.prevInput = " "; |
2094 | 2100 |
| 2101 function prepareSelectAllHack() { |
| 2102 if (display.input.selectionStart != null) { |
| 2103 var extval = display.input.value = " " + (posEq(sel.from, sel.to) ? "" :
display.input.value); |
| 2104 display.prevInput = " "; |
| 2105 display.input.selectionStart = 1; display.input.selectionEnd = extval.le
ngth; |
| 2106 } |
| 2107 } |
2095 function rehide() { | 2108 function rehide() { |
2096 display.inputDiv.style.position = "relative"; | 2109 display.inputDiv.style.position = "relative"; |
2097 display.input.style.cssText = oldCSS; | 2110 display.input.style.cssText = oldCSS; |
2098 if (ie_lt9) display.scrollbarV.scrollTop = display.scroller.scrollTop = sc
rollPos; | 2111 if (ie_lt9) display.scrollbarV.scrollTop = display.scroller.scrollTop = sc
rollPos; |
2099 slowPoll(cm); | 2112 slowPoll(cm); |
2100 | 2113 |
2101 // Try to detect the user choosing select-all | 2114 // Try to detect the user choosing select-all |
2102 if (display.input.selectionStart != null && (!ie || ie_lt9)) { | 2115 if (display.input.selectionStart != null) { |
| 2116 if (!ie || ie_lt9) prepareSelectAllHack(); |
2103 clearTimeout(detectingSelectAll); | 2117 clearTimeout(detectingSelectAll); |
2104 var extval = display.input.value = " " + (posEq(sel.from, sel.to) ? "" :
display.input.value), i = 0; | 2118 var i = 0, poll = function(){ |
2105 display.prevInput = " "; | |
2106 display.input.selectionStart = 1; display.input.selectionEnd = extval.le
ngth; | |
2107 var poll = function(){ | |
2108 if (display.prevInput == " " && display.input.selectionStart == 0) | 2119 if (display.prevInput == " " && display.input.selectionStart == 0) |
2109 operation(cm, commands.selectAll)(cm); | 2120 operation(cm, commands.selectAll)(cm); |
2110 else if (i++ < 10) detectingSelectAll = setTimeout(poll, 500); | 2121 else if (i++ < 10) detectingSelectAll = setTimeout(poll, 500); |
2111 else resetInput(cm); | 2122 else resetInput(cm); |
2112 }; | 2123 }; |
2113 detectingSelectAll = setTimeout(poll, 200); | 2124 detectingSelectAll = setTimeout(poll, 200); |
2114 } | 2125 } |
2115 } | 2126 } |
2116 | 2127 |
| 2128 if (ie && !ie_lt9) prepareSelectAllHack(); |
2117 if (captureMiddleClick) { | 2129 if (captureMiddleClick) { |
2118 e_stop(e); | 2130 e_stop(e); |
2119 var mouseup = function() { | 2131 var mouseup = function() { |
2120 off(window, "mouseup", mouseup); | 2132 off(window, "mouseup", mouseup); |
2121 setTimeout(rehide, 20); | 2133 setTimeout(rehide, 20); |
2122 }; | 2134 }; |
2123 on(window, "mouseup", mouseup); | 2135 on(window, "mouseup", mouseup); |
2124 } else { | 2136 } else { |
2125 setTimeout(rehide, 50); | 2137 setTimeout(rehide, 50); |
2126 } | 2138 } |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2167 if (posLess(pos, change.from)) return pos; | 2179 if (posLess(pos, change.from)) return pos; |
2168 if (!posLess(change.to, pos)) return end; | 2180 if (!posLess(change.to, pos)) return end; |
2169 | 2181 |
2170 var line = pos.line + change.text.length - (change.to.line - change.from.l
ine) - 1, ch = pos.ch; | 2182 var line = pos.line + change.text.length - (change.to.line - change.from.l
ine) - 1, ch = pos.ch; |
2171 if (pos.line == change.to.line) ch += end.ch - change.to.ch; | 2183 if (pos.line == change.to.line) ch += end.ch - change.to.ch; |
2172 return Pos(line, ch); | 2184 return Pos(line, ch); |
2173 }; | 2185 }; |
2174 return {anchor: adjustPos(doc.sel.anchor), head: adjustPos(doc.sel.head)}; | 2186 return {anchor: adjustPos(doc.sel.anchor), head: adjustPos(doc.sel.head)}; |
2175 } | 2187 } |
2176 | 2188 |
2177 function filterChange(doc, change) { | 2189 function filterChange(doc, change, update) { |
2178 var obj = { | 2190 var obj = { |
2179 canceled: false, | 2191 canceled: false, |
2180 from: change.from, | 2192 from: change.from, |
2181 to: change.to, | 2193 to: change.to, |
2182 text: change.text, | 2194 text: change.text, |
2183 origin: change.origin, | 2195 origin: change.origin, |
2184 update: function(from, to, text, origin) { | |
2185 if (from) this.from = clipPos(doc, from); | |
2186 if (to) this.to = clipPos(doc, to); | |
2187 if (text) this.text = text; | |
2188 if (origin !== undefined) this.origin = origin; | |
2189 }, | |
2190 cancel: function() { this.canceled = true; } | 2196 cancel: function() { this.canceled = true; } |
2191 }; | 2197 }; |
| 2198 if (update) obj.update = function(from, to, text, origin) { |
| 2199 if (from) this.from = clipPos(doc, from); |
| 2200 if (to) this.to = clipPos(doc, to); |
| 2201 if (text) this.text = text; |
| 2202 if (origin !== undefined) this.origin = origin; |
| 2203 }; |
2192 signal(doc, "beforeChange", doc, obj); | 2204 signal(doc, "beforeChange", doc, obj); |
2193 if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj); | 2205 if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj); |
2194 | 2206 |
2195 if (obj.canceled) return null; | 2207 if (obj.canceled) return null; |
2196 return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}; | 2208 return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}; |
2197 } | 2209 } |
2198 | 2210 |
2199 // Replace the range from from to to by the strings in replacement. | 2211 // Replace the range from from to to by the strings in replacement. |
2200 // change is a {from, to, text [, origin]} object | 2212 // change is a {from, to, text [, origin]} object |
2201 function makeChange(doc, change, selUpdate, ignoreReadOnly) { | 2213 function makeChange(doc, change, selUpdate, ignoreReadOnly) { |
2202 if (doc.cm) { | 2214 if (doc.cm) { |
2203 if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, selUp
date, ignoreReadOnly); | 2215 if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, selUp
date, ignoreReadOnly); |
2204 if (doc.cm.state.suppressEdits) return; | 2216 if (doc.cm.state.suppressEdits) return; |
2205 } | 2217 } |
2206 | 2218 |
2207 if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeC
hange")) { | 2219 if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeC
hange")) { |
2208 change = filterChange(doc, change); | 2220 change = filterChange(doc, change, true); |
2209 if (!change) return; | 2221 if (!change) return; |
2210 } | 2222 } |
2211 | 2223 |
2212 // Possibly split or suppress the update based on the presence | 2224 // Possibly split or suppress the update based on the presence |
2213 // of read-only spans in its range. | 2225 // of read-only spans in its range. |
2214 var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc,
change.from, change.to); | 2226 var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc,
change.from, change.to); |
2215 if (split) { | 2227 if (split) { |
2216 for (var i = split.length - 1; i >= 1; --i) | 2228 for (var i = split.length - 1; i >= 1; --i) |
2217 makeChangeNoReadonly(doc, {from: split[i].from, to: split[i].to, text: [
""]}); | 2229 makeChangeNoReadonly(doc, {from: split[i].from, to: split[i].to, text: [
""]}); |
2218 if (split.length) | 2230 if (split.length) |
(...skipping 24 matching lines...) Expand all Loading... |
2243 | 2255 |
2244 var hist = doc.history; | 2256 var hist = doc.history; |
2245 var event = (type == "undo" ? hist.done : hist.undone).pop(); | 2257 var event = (type == "undo" ? hist.done : hist.undone).pop(); |
2246 if (!event) return; | 2258 if (!event) return; |
2247 hist.dirtyCounter += type == "undo" ? -1 : 1; | 2259 hist.dirtyCounter += type == "undo" ? -1 : 1; |
2248 | 2260 |
2249 var anti = {changes: [], anchorBefore: event.anchorAfter, headBefore: event.
headAfter, | 2261 var anti = {changes: [], anchorBefore: event.anchorAfter, headBefore: event.
headAfter, |
2250 anchorAfter: event.anchorBefore, headAfter: event.headBefore}; | 2262 anchorAfter: event.anchorBefore, headAfter: event.headBefore}; |
2251 (type == "undo" ? hist.undone : hist.done).push(anti); | 2263 (type == "undo" ? hist.undone : hist.done).push(anti); |
2252 | 2264 |
| 2265 var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm,
"beforeChange"); |
| 2266 |
2253 for (var i = event.changes.length - 1; i >= 0; --i) { | 2267 for (var i = event.changes.length - 1; i >= 0; --i) { |
2254 var change = event.changes[i]; | 2268 var change = event.changes[i]; |
2255 change.origin = type; | 2269 change.origin = type; |
| 2270 if (filter && !filterChange(doc, change, false)) { |
| 2271 (type == "undo" ? hist.done : hist.undone).length = 0; |
| 2272 return; |
| 2273 } |
| 2274 |
2256 anti.changes.push(historyChangeFromChange(doc, change)); | 2275 anti.changes.push(historyChangeFromChange(doc, change)); |
2257 | 2276 |
2258 var after = i ? computeSelAfterChange(doc, change, null) | 2277 var after = i ? computeSelAfterChange(doc, change, null) |
2259 : {anchor: event.anchorBefore, head: event.headBefore}; | 2278 : {anchor: event.anchorBefore, head: event.headBefore}; |
2260 makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)); | 2279 makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)); |
2261 var rebased = []; | 2280 var rebased = []; |
2262 | 2281 |
2263 linkedDocs(doc, function(doc, sharedHist) { | 2282 linkedDocs(doc, function(doc, sharedHist) { |
2264 if (!sharedHist && indexOf(rebased, doc.history) == -1) { | 2283 if (!sharedHist && indexOf(rebased, doc.history) == -1) { |
2265 rebaseHist(doc.history, change); | 2284 rebaseHist(doc.history, change); |
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2507 } | 2526 } |
2508 } | 2527 } |
2509 } | 2528 } |
2510 return curPos; | 2529 return curPos; |
2511 } | 2530 } |
2512 } | 2531 } |
2513 | 2532 |
2514 // SCROLLING | 2533 // SCROLLING |
2515 | 2534 |
2516 function scrollCursorIntoView(cm) { | 2535 function scrollCursorIntoView(cm) { |
2517 var coords = scrollPosIntoView(cm, cm.doc.sel.head); | 2536 var coords = scrollPosIntoView(cm, cm.doc.sel.head, cm.options.cursorScrollM
argin); |
2518 if (!cm.state.focused) return; | 2537 if (!cm.state.focused) return; |
2519 var display = cm.display, box = getRect(display.sizer), doScroll = null, pTo
p = paddingTop(cm.display); | 2538 var display = cm.display, box = getRect(display.sizer), doScroll = null, pTo
p = paddingTop(cm.display); |
2520 if (coords.top + pTop + box.top < 0) doScroll = true; | 2539 if (coords.top + pTop + box.top < 0) doScroll = true; |
2521 else if (coords.bottom + pTop + box.top > (window.innerHeight || document.do
cumentElement.clientHeight)) doScroll = false; | 2540 else if (coords.bottom + pTop + box.top > (window.innerHeight || document.do
cumentElement.clientHeight)) doScroll = false; |
2522 if (doScroll != null && !phantom) { | 2541 if (doScroll != null && !phantom) { |
2523 var hidden = display.cursor.style.display == "none"; | 2542 var hidden = display.cursor.style.display == "none"; |
2524 if (hidden) { | 2543 if (hidden) { |
2525 display.cursor.style.display = ""; | 2544 display.cursor.style.display = ""; |
2526 display.cursor.style.left = coords.left + "px"; | 2545 display.cursor.style.left = coords.left + "px"; |
2527 display.cursor.style.top = (coords.top - display.viewOffset) + "px"; | 2546 display.cursor.style.top = (coords.top - display.viewOffset) + "px"; |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2638 var no = handle, line = handle, doc = cm.doc; | 2657 var no = handle, line = handle, doc = cm.doc; |
2639 if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle)); | 2658 if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle)); |
2640 else no = lineNo(handle); | 2659 else no = lineNo(handle); |
2641 if (no == null) return null; | 2660 if (no == null) return null; |
2642 if (op(line, no)) regChange(cm, no, no + 1); | 2661 if (op(line, no)) regChange(cm, no, no + 1); |
2643 else return null; | 2662 else return null; |
2644 return line; | 2663 return line; |
2645 } | 2664 } |
2646 | 2665 |
2647 function findPosH(doc, pos, dir, unit, visually) { | 2666 function findPosH(doc, pos, dir, unit, visually) { |
2648 var line = pos.line, ch = pos.ch; | 2667 var line = pos.line, ch = pos.ch, origDir = dir; |
2649 var lineObj = getLine(doc, line); | 2668 var lineObj = getLine(doc, line); |
2650 var possible = true; | 2669 var possible = true; |
2651 function findNextLine() { | 2670 function findNextLine() { |
2652 var l = line + dir; | 2671 var l = line + dir; |
2653 if (l < doc.first || l >= doc.first + doc.size) return (possible = false); | 2672 if (l < doc.first || l >= doc.first + doc.size) return (possible = false); |
2654 line = l; | 2673 line = l; |
2655 return lineObj = getLine(doc, l); | 2674 return lineObj = getLine(doc, l); |
2656 } | 2675 } |
2657 function moveOnce(boundToLine) { | 2676 function moveOnce(boundToLine) { |
2658 var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, tru
e); | 2677 var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, tru
e); |
(...skipping 18 matching lines...) Expand all Loading... |
2677 : /\s/.test(cur) ? null | 2696 : /\s/.test(cur) ? null |
2678 : "p"; | 2697 : "p"; |
2679 if (sawType && sawType != type) { | 2698 if (sawType && sawType != type) { |
2680 if (dir < 0) {dir = 1; moveOnce();} | 2699 if (dir < 0) {dir = 1; moveOnce();} |
2681 break; | 2700 break; |
2682 } | 2701 } |
2683 if (type) sawType = type; | 2702 if (type) sawType = type; |
2684 if (dir > 0 && !moveOnce(!first)) break; | 2703 if (dir > 0 && !moveOnce(!first)) break; |
2685 } | 2704 } |
2686 } | 2705 } |
2687 var result = skipAtomic(doc, Pos(line, ch), dir, true); | 2706 var result = skipAtomic(doc, Pos(line, ch), origDir, true); |
2688 if (!possible) result.hitSide = true; | 2707 if (!possible) result.hitSide = true; |
2689 return result; | 2708 return result; |
2690 } | 2709 } |
2691 | 2710 |
2692 function findPosV(cm, pos, dir, unit) { | 2711 function findPosV(cm, pos, dir, unit) { |
2693 var doc = cm.doc, x = pos.left, y; | 2712 var doc = cm.doc, x = pos.left, y; |
2694 if (unit == "page") { | 2713 if (unit == "page") { |
2695 var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeigh
t || document.documentElement.clientHeight); | 2714 var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeigh
t || document.documentElement.clientHeight); |
2696 y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.displ
ay)); | 2715 y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.displ
ay)); |
2697 } else if (unit == "line") { | 2716 } else if (unit == "line") { |
(...skipping 25 matching lines...) Expand all Loading... |
2723 function selectLine(cm, line) { | 2742 function selectLine(cm, line) { |
2724 extendSelection(cm.doc, Pos(line, 0), clipPos(cm.doc, Pos(line + 1, 0))); | 2743 extendSelection(cm.doc, Pos(line, 0), clipPos(cm.doc, Pos(line + 1, 0))); |
2725 } | 2744 } |
2726 | 2745 |
2727 // PROTOTYPE | 2746 // PROTOTYPE |
2728 | 2747 |
2729 // The publicly visible API. Note that operation(null, f) means | 2748 // The publicly visible API. Note that operation(null, f) means |
2730 // 'wrap f in an operation, performed on its `this` parameter' | 2749 // 'wrap f in an operation, performed on its `this` parameter' |
2731 | 2750 |
2732 CodeMirror.prototype = { | 2751 CodeMirror.prototype = { |
| 2752 constructor: CodeMirror, |
2733 focus: function(){window.focus(); focusInput(this); onFocus(this); fastPoll(
this);}, | 2753 focus: function(){window.focus(); focusInput(this); onFocus(this); fastPoll(
this);}, |
2734 | 2754 |
2735 setOption: function(option, value) { | 2755 setOption: function(option, value) { |
2736 var options = this.options, old = options[option]; | 2756 var options = this.options, old = options[option]; |
2737 if (options[option] == value && option != "mode") return; | 2757 if (options[option] == value && option != "mode") return; |
2738 options[option] = value; | 2758 options[option] = value; |
2739 if (optionHandlers.hasOwnProperty(option)) | 2759 if (optionHandlers.hasOwnProperty(option)) |
2740 operation(this, optionHandlers[option])(this, value, old); | 2760 operation(this, optionHandlers[option])(this, value, old); |
2741 }, | 2761 }, |
2742 | 2762 |
(...skipping 15 matching lines...) Expand all Loading... |
2758 addOverlay: operation(null, function(spec, options) { | 2778 addOverlay: operation(null, function(spec, options) { |
2759 var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec); | 2779 var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec); |
2760 if (mode.startState) throw new Error("Overlays may not be stateful."); | 2780 if (mode.startState) throw new Error("Overlays may not be stateful."); |
2761 this.state.overlays.push({mode: mode, modeSpec: spec, opaque: options && o
ptions.opaque}); | 2781 this.state.overlays.push({mode: mode, modeSpec: spec, opaque: options && o
ptions.opaque}); |
2762 this.state.modeGen++; | 2782 this.state.modeGen++; |
2763 regChange(this); | 2783 regChange(this); |
2764 }), | 2784 }), |
2765 removeOverlay: operation(null, function(spec) { | 2785 removeOverlay: operation(null, function(spec) { |
2766 var overlays = this.state.overlays; | 2786 var overlays = this.state.overlays; |
2767 for (var i = 0; i < overlays.length; ++i) { | 2787 for (var i = 0; i < overlays.length; ++i) { |
2768 if (overlays[i].modeSpec == spec) { | 2788 var cur = overlays[i].modeSpec; |
| 2789 if (cur == spec || typeof spec == "string" && cur.name == spec) { |
2769 overlays.splice(i, 1); | 2790 overlays.splice(i, 1); |
2770 this.state.modeGen++; | 2791 this.state.modeGen++; |
2771 regChange(this); | 2792 regChange(this); |
2772 return; | 2793 return; |
2773 } | 2794 } |
2774 } | 2795 } |
2775 }), | 2796 }), |
2776 | 2797 |
2777 indentLine: operation(null, function(n, dir, aggressive) { | 2798 indentLine: operation(null, function(n, dir, aggressive) { |
2778 if (typeof dir != "string") { | 2799 if (typeof dir != "string") { |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2983 var sel = this.doc.sel; | 3004 var sel = this.doc.sel; |
2984 var pos = cursorCoords(this, sel.head, "div"); | 3005 var pos = cursorCoords(this, sel.head, "div"); |
2985 if (sel.goalColumn != null) pos.left = sel.goalColumn; | 3006 if (sel.goalColumn != null) pos.left = sel.goalColumn; |
2986 var target = findPosV(this, pos, dir, unit); | 3007 var target = findPosV(this, pos, dir, unit); |
2987 | 3008 |
2988 if (unit == "page") addToScrollPos(this, 0, charCoords(this, target, "div"
).top - pos.top); | 3009 if (unit == "page") addToScrollPos(this, 0, charCoords(this, target, "div"
).top - pos.top); |
2989 extendSelection(this.doc, target, target, dir); | 3010 extendSelection(this.doc, target, target, dir); |
2990 sel.goalColumn = pos.left; | 3011 sel.goalColumn = pos.left; |
2991 }), | 3012 }), |
2992 | 3013 |
2993 toggleOverwrite: function() { | 3014 toggleOverwrite: function(value) { |
| 3015 if (value != null && value == this.state.overwrite) return; |
2994 if (this.state.overwrite = !this.state.overwrite) | 3016 if (this.state.overwrite = !this.state.overwrite) |
2995 this.display.cursor.className += " CodeMirror-overwrite"; | 3017 this.display.cursor.className += " CodeMirror-overwrite"; |
2996 else | 3018 else |
2997 this.display.cursor.className = this.display.cursor.className.replace("
CodeMirror-overwrite", ""); | 3019 this.display.cursor.className = this.display.cursor.className.replace("
CodeMirror-overwrite", ""); |
2998 }, | 3020 }, |
2999 hasFocus: function() { return this.state.focused; }, | 3021 hasFocus: function() { return this.state.focused; }, |
3000 | 3022 |
3001 scrollTo: operation(null, function(x, y) { | 3023 scrollTo: operation(null, function(x, y) { |
3002 updateScrollPos(this, x, y); | 3024 updateScrollPos(this, x, y); |
3003 }), | 3025 }), |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3106 | 3128 |
3107 option("lineWrapping", false, wrappingChanged, true); | 3129 option("lineWrapping", false, wrappingChanged, true); |
3108 option("gutters", [], function(cm) { | 3130 option("gutters", [], function(cm) { |
3109 setGuttersForLineNumbers(cm.options); | 3131 setGuttersForLineNumbers(cm.options); |
3110 guttersChanged(cm); | 3132 guttersChanged(cm); |
3111 }, true); | 3133 }, true); |
3112 option("fixedGutter", true, function(cm, val) { | 3134 option("fixedGutter", true, function(cm, val) { |
3113 cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px
" : "0"; | 3135 cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px
" : "0"; |
3114 cm.refresh(); | 3136 cm.refresh(); |
3115 }, true); | 3137 }, true); |
| 3138 option("coverGutterNextToScrollbar", false, updateScrollbars, true); |
3116 option("lineNumbers", false, function(cm) { | 3139 option("lineNumbers", false, function(cm) { |
3117 setGuttersForLineNumbers(cm.options); | 3140 setGuttersForLineNumbers(cm.options); |
3118 guttersChanged(cm); | 3141 guttersChanged(cm); |
3119 }, true); | 3142 }, true); |
3120 option("firstLineNumber", 1, guttersChanged, true); | 3143 option("firstLineNumber", 1, guttersChanged, true); |
3121 option("lineNumberFormatter", function(integer) {return integer;}, guttersChan
ged, true); | 3144 option("lineNumberFormatter", function(integer) {return integer;}, guttersChan
ged, true); |
3122 option("showCursorWhenSelecting", false, updateSelection, true); | 3145 option("showCursorWhenSelecting", false, updateSelection, true); |
3123 | 3146 |
3124 option("readOnly", false, function(cm, val) { | 3147 option("readOnly", false, function(cm, val) { |
3125 if (val == "nocursor") {onBlur(cm); cm.display.input.blur();} | 3148 if (val == "nocursor") {onBlur(cm); cm.display.input.blur();} |
3126 else if (!val) resetInput(cm, true); | 3149 else if (!val) resetInput(cm, true); |
3127 }); | 3150 }); |
3128 option("dragDrop", true); | 3151 option("dragDrop", true); |
3129 | 3152 |
3130 option("cursorBlinkRate", 530); | 3153 option("cursorBlinkRate", 530); |
| 3154 option("cursorScrollMargin", 0); |
3131 option("cursorHeight", 1); | 3155 option("cursorHeight", 1); |
3132 option("workTime", 100); | 3156 option("workTime", 100); |
3133 option("workDelay", 100); | 3157 option("workDelay", 100); |
3134 option("flattenSpans", true); | 3158 option("flattenSpans", true); |
3135 option("pollInterval", 100); | 3159 option("pollInterval", 100); |
3136 option("undoDepth", 40, function(cm, val){cm.doc.history.undoDepth = val;}); | 3160 option("undoDepth", 40, function(cm, val){cm.doc.history.undoDepth = val;}); |
3137 option("historyEventDelay", 500); | 3161 option("historyEventDelay", 500); |
3138 option("viewportMargin", 10, function(cm){cm.refresh();}, true); | 3162 option("viewportMargin", 10, function(cm){cm.refresh();}, true); |
3139 option("maxHighlightLength", 10000, function(cm){loadMode(cm); cm.refresh();},
true); | 3163 option("maxHighlightLength", 10000, function(cm){loadMode(cm); cm.refresh();},
true); |
3140 option("moveInputWithCursor", true, function(cm, val) { | 3164 option("moveInputWithCursor", true, function(cm, val) { |
(...skipping 17 matching lines...) Expand all Loading... |
3158 for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(argument
s[i]); | 3182 for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(argument
s[i]); |
3159 } | 3183 } |
3160 modes[name] = mode; | 3184 modes[name] = mode; |
3161 }; | 3185 }; |
3162 | 3186 |
3163 CodeMirror.defineMIME = function(mime, spec) { | 3187 CodeMirror.defineMIME = function(mime, spec) { |
3164 mimeModes[mime] = spec; | 3188 mimeModes[mime] = spec; |
3165 }; | 3189 }; |
3166 | 3190 |
3167 CodeMirror.resolveMode = function(spec) { | 3191 CodeMirror.resolveMode = function(spec) { |
3168 if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) | 3192 if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { |
3169 spec = mimeModes[spec]; | 3193 spec = mimeModes[spec]; |
3170 else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) | 3194 } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(
spec.name)) { |
| 3195 var found = mimeModes[spec.name]; |
| 3196 spec = createObj(found, spec); |
| 3197 spec.name = found.name; |
| 3198 } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec))
{ |
3171 return CodeMirror.resolveMode("application/xml"); | 3199 return CodeMirror.resolveMode("application/xml"); |
| 3200 } |
3172 if (typeof spec == "string") return {name: spec}; | 3201 if (typeof spec == "string") return {name: spec}; |
3173 else return spec || {name: "null"}; | 3202 else return spec || {name: "null"}; |
3174 }; | 3203 }; |
3175 | 3204 |
3176 CodeMirror.getMode = function(options, spec) { | 3205 CodeMirror.getMode = function(options, spec) { |
3177 spec = CodeMirror.resolveMode(spec); | 3206 spec = CodeMirror.resolveMode(spec); |
3178 var mfactory = modes[spec.name]; | 3207 var mfactory = modes[spec.name]; |
3179 if (!mfactory) return CodeMirror.getMode(options, "text/plain"); | 3208 if (!mfactory) return CodeMirror.getMode(options, "text/plain"); |
3180 var modeObj = mfactory(options, spec); | 3209 var modeObj = mfactory(options, spec); |
3181 if (modeExtensions.hasOwnProperty(spec.name)) { | 3210 if (modeExtensions.hasOwnProperty(spec.name)) { |
(...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3591 if (span.from != null || span.to != null) { | 3620 if (span.from != null || span.to != null) { |
3592 var found = lineNo(line); | 3621 var found = lineNo(line); |
3593 if (span.from != null) from = Pos(found, span.from); | 3622 if (span.from != null) from = Pos(found, span.from); |
3594 if (span.to != null) to = Pos(found, span.to); | 3623 if (span.to != null) to = Pos(found, span.to); |
3595 } | 3624 } |
3596 } | 3625 } |
3597 if (this.type == "bookmark") return from; | 3626 if (this.type == "bookmark") return from; |
3598 return from && {from: from, to: to}; | 3627 return from && {from: from, to: to}; |
3599 }; | 3628 }; |
3600 | 3629 |
3601 TextMarker.prototype.getOptions = function(copyWidget) { | 3630 TextMarker.prototype.changed = function() { |
3602 var repl = this.replacedWith; | 3631 var pos = this.find(), cm = this.doc.cm; |
3603 return {className: this.className, | 3632 if (!pos || !cm) return; |
3604 inclusiveLeft: this.inclusiveLeft, inclusiveRight: this.inclusiveRig
ht, | 3633 var line = getLine(this.doc, pos.from.line); |
3605 atomic: this.atomic, | 3634 clearCachedMeasurement(cm, line); |
3606 collapsed: this.collapsed, | 3635 if (pos.from.line >= cm.display.showingFrom && pos.from.line < cm.display.sh
owingTo) { |
3607 replacedWith: copyWidget ? repl && repl.cloneNode(true) : repl, | 3636 for (var node = cm.display.lineDiv.firstChild; node; node = node.nextSibli
ng) if (node.lineObj == line) { |
3608 readOnly: this.readOnly, | 3637 if (node.offsetHeight != line.height) updateLineHeight(line, node.offset
Height); |
3609 startStyle: this.startStyle, endStyle: this.endStyle}; | 3638 break; |
| 3639 } |
| 3640 runInOp(cm, function() { cm.curOp.selectionChanged = true; }); |
| 3641 } |
3610 }; | 3642 }; |
3611 | 3643 |
3612 TextMarker.prototype.attachLine = function(line) { | 3644 TextMarker.prototype.attachLine = function(line) { |
3613 if (!this.lines.length && this.doc.cm) { | 3645 if (!this.lines.length && this.doc.cm) { |
3614 var op = this.doc.cm.curOp; | 3646 var op = this.doc.cm.curOp; |
3615 if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1) | 3647 if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1) |
3616 (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); | 3648 (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); |
3617 } | 3649 } |
3618 this.lines.push(line); | 3650 this.lines.push(line); |
3619 }; | 3651 }; |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3699 SharedTextMarker.prototype.clear = function() { | 3731 SharedTextMarker.prototype.clear = function() { |
3700 if (this.explicitlyCleared) return; | 3732 if (this.explicitlyCleared) return; |
3701 this.explicitlyCleared = true; | 3733 this.explicitlyCleared = true; |
3702 for (var i = 0; i < this.markers.length; ++i) | 3734 for (var i = 0; i < this.markers.length; ++i) |
3703 this.markers[i].clear(); | 3735 this.markers[i].clear(); |
3704 signalLater(this, "clear"); | 3736 signalLater(this, "clear"); |
3705 }; | 3737 }; |
3706 SharedTextMarker.prototype.find = function() { | 3738 SharedTextMarker.prototype.find = function() { |
3707 return this.primary.find(); | 3739 return this.primary.find(); |
3708 }; | 3740 }; |
3709 SharedTextMarker.prototype.getOptions = function(copyWidget) { | |
3710 var inner = this.primary.getOptions(copyWidget); | |
3711 inner.shared = true; | |
3712 return inner; | |
3713 }; | |
3714 | 3741 |
3715 function markTextShared(doc, from, to, options, type) { | 3742 function markTextShared(doc, from, to, options, type) { |
3716 options = copyObj(options); | 3743 options = copyObj(options); |
3717 options.shared = false; | 3744 options.shared = false; |
3718 var markers = [markText(doc, from, to, options, type)], primary = markers[0]
; | 3745 var markers = [markText(doc, from, to, options, type)], primary = markers[0]
; |
3719 var widget = options.replacedWith; | 3746 var widget = options.replacedWith; |
3720 linkedDocs(doc, function(doc) { | 3747 linkedDocs(doc, function(doc) { |
3721 if (widget) options.replacedWith = widget.cloneNode(true); | 3748 if (widget) options.replacedWith = widget.cloneNode(true); |
3722 markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options,
type)); | 3749 markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options,
type)); |
3723 for (var i = 0; i < doc.linked.length; ++i) | 3750 for (var i = 0; i < doc.linked.length; ++i) |
(...skipping 487 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4211 builder.pre.appendChild(content); | 4238 builder.pre.appendChild(content); |
4212 } | 4239 } |
4213 | 4240 |
4214 function buildTokenMeasure(builder, text, style, startStyle, endStyle) { | 4241 function buildTokenMeasure(builder, text, style, startStyle, endStyle) { |
4215 var wrapping = builder.cm.options.lineWrapping; | 4242 var wrapping = builder.cm.options.lineWrapping; |
4216 for (var i = 0; i < text.length; ++i) { | 4243 for (var i = 0; i < text.length; ++i) { |
4217 var ch = text.charAt(i), start = i == 0; | 4244 var ch = text.charAt(i), start = i == 0; |
4218 if (ch >= "\ud800" && ch < "\udbff" && i < text.length - 1) { | 4245 if (ch >= "\ud800" && ch < "\udbff" && i < text.length - 1) { |
4219 ch = text.slice(i, i + 2); | 4246 ch = text.slice(i, i + 2); |
4220 ++i; | 4247 ++i; |
4221 } else if (i && wrapping && | 4248 } else if (i && wrapping && spanAffectsWrapping(text, i)) { |
4222 spanAffectsWrapping.test(text.slice(i - 1, i + 1))) { | |
4223 builder.pre.appendChild(elt("wbr")); | 4249 builder.pre.appendChild(elt("wbr")); |
4224 } | 4250 } |
4225 var span = builder.measure[builder.pos] = | 4251 var span = builder.measure[builder.pos] = |
4226 buildToken(builder, ch, style, | 4252 buildToken(builder, ch, style, |
4227 start && startStyle, i == text.length - 1 && endStyle); | 4253 start && startStyle, i == text.length - 1 && endStyle); |
4228 // In IE single-space nodes wrap differently than spaces | 4254 // In IE single-space nodes wrap differently than spaces |
4229 // embedded in larger text nodes, except when set to | 4255 // embedded in larger text nodes, except when set to |
4230 // white-space: normal (issue #1268). | 4256 // white-space: normal (issue #1268). |
4231 if (ie && wrapping && ch == " " && i && !/\s/.test(text.charAt(i - 1)) && | 4257 if (ie && wrapping && ch == " " && i && !/\s/.test(text.charAt(i - 1)) && |
4232 i < text.length - 1 && !/\s/.test(text.charAt(i + 1))) | 4258 i < text.length - 1 && !/\s/.test(text.charAt(i + 1))) |
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4511 var start = Pos(firstLine, 0); | 4537 var start = Pos(firstLine, 0); |
4512 this.sel = {from: start, to: start, head: start, anchor: start, shift: false
, extend: false, goalColumn: null}; | 4538 this.sel = {from: start, to: start, head: start, anchor: start, shift: false
, extend: false, goalColumn: null}; |
4513 this.id = ++nextDocId; | 4539 this.id = ++nextDocId; |
4514 this.modeOption = mode; | 4540 this.modeOption = mode; |
4515 | 4541 |
4516 if (typeof text == "string") text = splitLines(text); | 4542 if (typeof text == "string") text = splitLines(text); |
4517 updateDoc(this, {from: start, to: start, text: text}, null, {head: start, an
chor: start}); | 4543 updateDoc(this, {from: start, to: start, text: text}, null, {head: start, an
chor: start}); |
4518 }; | 4544 }; |
4519 | 4545 |
4520 Doc.prototype = createObj(BranchChunk.prototype, { | 4546 Doc.prototype = createObj(BranchChunk.prototype, { |
| 4547 constructor: Doc, |
4521 iter: function(from, to, op) { | 4548 iter: function(from, to, op) { |
4522 if (op) this.iterN(from - this.first, to - from, op); | 4549 if (op) this.iterN(from - this.first, to - from, op); |
4523 else this.iterN(this.first, this.first + this.size, from); | 4550 else this.iterN(this.first, this.first + this.size, from); |
4524 }, | 4551 }, |
4525 | 4552 |
4526 insert: function(at, lines) { | 4553 insert: function(at, lines) { |
4527 var height = 0; | 4554 var height = 0; |
4528 for (var i = 0, e = lines.length; i < e; ++i) height += lines[i].height; | 4555 for (var i = 0, e = lines.length; i < e; ++i) height += lines[i].height; |
4529 this.insertInner(at - this.first, lines, height); | 4556 this.insertInner(at - this.first, lines, height); |
4530 }, | 4557 }, |
(...skipping 644 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5175 function emptyArray(size) { | 5202 function emptyArray(size) { |
5176 for (var a = [], i = 0; i < size; ++i) a.push(undefined); | 5203 for (var a = [], i = 0; i < size; ++i) a.push(undefined); |
5177 return a; | 5204 return a; |
5178 } | 5205 } |
5179 | 5206 |
5180 function bind(f) { | 5207 function bind(f) { |
5181 var args = Array.prototype.slice.call(arguments, 1); | 5208 var args = Array.prototype.slice.call(arguments, 1); |
5182 return function(){return f.apply(null, args);}; | 5209 return function(){return f.apply(null, args);}; |
5183 } | 5210 } |
5184 | 5211 |
5185 var nonASCIISingleCaseWordChar = /[\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e
00-\u9fcc]/; | 5212 var nonASCIISingleCaseWordChar = /[\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e
00-\u9fcc\uac00-\ud7af]/; |
5186 function isWordChar(ch) { | 5213 function isWordChar(ch) { |
5187 return /\w/.test(ch) || ch > "\x80" && | 5214 return /\w/.test(ch) || ch > "\x80" && |
5188 (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(c
h)); | 5215 (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(c
h)); |
5189 } | 5216 } |
5190 | 5217 |
5191 function isEmpty(obj) { | 5218 function isEmpty(obj) { |
5192 for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false; | 5219 for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false; |
5193 return true; | 5220 return true; |
5194 } | 5221 } |
5195 | 5222 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5236 // couldn't get it to work yet. | 5263 // couldn't get it to work yet. |
5237 if (ie_lt9) return false; | 5264 if (ie_lt9) return false; |
5238 var div = elt('div'); | 5265 var div = elt('div'); |
5239 return "draggable" in div || "dragDrop" in div; | 5266 return "draggable" in div || "dragDrop" in div; |
5240 }(); | 5267 }(); |
5241 | 5268 |
5242 // For a reason I have yet to figure out, some browsers disallow | 5269 // For a reason I have yet to figure out, some browsers disallow |
5243 // word wrapping between certain characters *only* if a new inline | 5270 // word wrapping between certain characters *only* if a new inline |
5244 // element is started between them. This makes it hard to reliably | 5271 // element is started between them. This makes it hard to reliably |
5245 // measure the position of things, since that requires inserting an | 5272 // measure the position of things, since that requires inserting an |
5246 // extra span. This terribly fragile set of regexps matches the | 5273 // extra span. This terribly fragile set of tests matches the |
5247 // character combinations that suffer from this phenomenon on the | 5274 // character combinations that suffer from this phenomenon on the |
5248 // various browsers. | 5275 // various browsers. |
5249 var spanAffectsWrapping = /^$/; // Won't match any two-character string | 5276 function spanAffectsWrapping() { return false; } |
5250 if (gecko) spanAffectsWrapping = /$'/; | 5277 if (gecko) // Only for "$'" |
5251 else if (safari && !/Version\/([6-9]|\d\d)\b/.test(navigator.userAgent)) spanA
ffectsWrapping = /\-[^ \-?]|\?[^ !'\"\),.\-\/:;\?\]\}]/; | 5278 spanAffectsWrapping = function(str, i) { |
5252 else if (webkit) spanAffectsWrapping = /[~!#%&*)=+}\]|\"\.>,:;][({[<]|-[^\-?\.
]|\?[\w~`@#$%\^&*(_=+{[|><]/; | 5279 return str.charCodeAt(i - 1) == 36 && str.charCodeAt(i) == 39; |
| 5280 }; |
| 5281 else if (safari && !/Version\/([6-9]|\d\d)\b/.test(navigator.userAgent)) |
| 5282 spanAffectsWrapping = function(str, i) { |
| 5283 return /\-[^ \-?]|\?[^ !\'\"\),.\-\/:;\?\]\}]/.test(str.slice(i - 1, i + 1
)); |
| 5284 }; |
| 5285 else if (webkit) |
| 5286 spanAffectsWrapping = function(str, i) { |
| 5287 if (i > 1 && str.charCodeAt(i - 1) == 45 && /\w/.test(str.charAt(i - 2)) &
& /[^\-?\.]/.test(str.charAt(i))) |
| 5288 return true; |
| 5289 return /[~!#%&*)=+}\]|\"\.>,:;][({[<]|\?[\w~`@#$%\^&*(_=+{[|><]/.test(str.
slice(i - 1, i + 1)); |
| 5290 }; |
5253 | 5291 |
5254 var knownScrollbarWidth; | 5292 var knownScrollbarWidth; |
5255 function scrollbarWidth(measure) { | 5293 function scrollbarWidth(measure) { |
5256 if (knownScrollbarWidth != null) return knownScrollbarWidth; | 5294 if (knownScrollbarWidth != null) return knownScrollbarWidth; |
5257 var test = elt("div", null, null, "width: 50px; height: 50px; overflow-x: sc
roll"); | 5295 var test = elt("div", null, null, "width: 50px; height: 50px; overflow-x: sc
roll"); |
5258 removeChildrenAndAdd(measure, test); | 5296 removeChildrenAndAdd(measure, test); |
5259 if (test.offsetWidth) | 5297 if (test.offsetWidth) |
5260 knownScrollbarWidth = test.offsetHeight - test.clientHeight; | 5298 knownScrollbarWidth = test.offsetHeight - test.clientHeight; |
5261 return knownScrollbarWidth || 0; | 5299 return knownScrollbarWidth || 0; |
5262 } | 5300 } |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5361 } | 5399 } |
5362 function lineEnd(cm, lineN) { | 5400 function lineEnd(cm, lineN) { |
5363 var merged, line; | 5401 var merged, line; |
5364 while (merged = collapsedSpanAtEnd(line = getLine(cm.doc, lineN))) | 5402 while (merged = collapsedSpanAtEnd(line = getLine(cm.doc, lineN))) |
5365 lineN = merged.find().to.line; | 5403 lineN = merged.find().to.line; |
5366 var order = getOrder(line); | 5404 var order = getOrder(line); |
5367 var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : l
ineRight(line); | 5405 var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : l
ineRight(line); |
5368 return Pos(lineN, ch); | 5406 return Pos(lineN, ch); |
5369 } | 5407 } |
5370 | 5408 |
| 5409 function compareBidiLevel(order, a, b) { |
| 5410 var linedir = order[0].level; |
| 5411 if (a == linedir) return true; |
| 5412 if (b == linedir) return false; |
| 5413 return a < b; |
| 5414 } |
| 5415 var bidiOther; |
| 5416 function getBidiPartAt(order, pos) { |
| 5417 for (var i = 0, found; i < order.length; ++i) { |
| 5418 var cur = order[i]; |
| 5419 if (cur.from < pos && cur.to > pos) { bidiOther = null; return i; } |
| 5420 if (cur.from == pos || cur.to == pos) { |
| 5421 if (found == null) { |
| 5422 found = i; |
| 5423 } else if (compareBidiLevel(order, cur.level, order[found].level)) { |
| 5424 bidiOther = found; |
| 5425 return i; |
| 5426 } else { |
| 5427 bidiOther = i; |
| 5428 return found; |
| 5429 } |
| 5430 } |
| 5431 } |
| 5432 bidiOther = null; |
| 5433 return found; |
| 5434 } |
| 5435 |
| 5436 function moveInLine(line, pos, dir, byUnit) { |
| 5437 if (!byUnit) return pos + dir; |
| 5438 do pos += dir; |
| 5439 while (pos > 0 && isExtendingChar.test(line.text.charAt(pos))); |
| 5440 return pos; |
| 5441 } |
| 5442 |
5371 // This is somewhat involved. It is needed in order to move | 5443 // This is somewhat involved. It is needed in order to move |
5372 // 'visually' through bi-directional text -- i.e., pressing left | 5444 // 'visually' through bi-directional text -- i.e., pressing left |
5373 // should make the cursor go left, even when in RTL text. The | 5445 // should make the cursor go left, even when in RTL text. The |
5374 // tricky part is the 'jumps', where RTL and LTR text touch each | 5446 // tricky part is the 'jumps', where RTL and LTR text touch each |
5375 // other. This often requires the cursor offset to move more than | 5447 // other. This often requires the cursor offset to move more than |
5376 // one unit, in order to visually move one unit. | 5448 // one unit, in order to visually move one unit. |
5377 function moveVisually(line, start, dir, byUnit) { | 5449 function moveVisually(line, start, dir, byUnit) { |
5378 var bidi = getOrder(line); | 5450 var bidi = getOrder(line); |
5379 if (!bidi) return moveLogically(line, start, dir, byUnit); | 5451 if (!bidi) return moveLogically(line, start, dir, byUnit); |
5380 var moveOneUnit = byUnit ? function(pos, dir) { | 5452 var pos = getBidiPartAt(bidi, start), part = bidi[pos]; |
5381 do pos += dir; | 5453 var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit); |
5382 while (pos > 0 && isExtendingChar.test(line.text.charAt(pos))); | |
5383 return pos; | |
5384 } : function(pos, dir) { return pos + dir; }; | |
5385 var linedir = bidi[0].level; | |
5386 for (var i = 0; i < bidi.length; ++i) { | |
5387 var part = bidi[i], sticky = part.level % 2 == linedir; | |
5388 if ((part.from < start && part.to > start) || | |
5389 (sticky && (part.from == start || part.to == start))) break; | |
5390 } | |
5391 var target = moveOneUnit(start, part.level % 2 ? -dir : dir); | |
5392 | 5454 |
5393 while (target != null) { | 5455 for (;;) { |
5394 if (part.level % 2 == linedir) { | 5456 if (target > part.from && target < part.to) return target; |
5395 if (target < part.from || target > part.to) { | 5457 if (target == part.from || target == part.to) { |
5396 part = bidi[i += dir]; | 5458 if (getBidiPartAt(bidi, target) == pos) return target; |
5397 target = part && (dir > 0 == part.level % 2 ? moveOneUnit(part.to, -1)
: moveOneUnit(part.from, 1)); | 5459 part = bidi[pos += dir]; |
5398 } else break; | 5460 return (dir > 0) == part.level % 2 ? part.to : part.from; |
5399 } else { | 5461 } else { |
5400 if (target == bidiLeft(part)) { | 5462 part = bidi[pos += dir]; |
5401 part = bidi[--i]; | 5463 if (!part) return null; |
5402 target = part && bidiRight(part); | 5464 if ((dir > 0) == part.level % 2) |
5403 } else if (target == bidiRight(part)) { | 5465 target = moveInLine(line, part.to, -1, byUnit); |
5404 part = bidi[++i]; | 5466 else |
5405 target = part && bidiLeft(part); | 5467 target = moveInLine(line, part.from, 1, byUnit); |
5406 } else break; | |
5407 } | 5468 } |
5408 } | 5469 } |
5409 | |
5410 return target < 0 || target > line.text.length ? null : target; | |
5411 } | 5470 } |
5412 | 5471 |
5413 function moveLogically(line, start, dir, byUnit) { | 5472 function moveLogically(line, start, dir, byUnit) { |
5414 var target = start + dir; | 5473 var target = start + dir; |
5415 if (byUnit) while (target > 0 && isExtendingChar.test(line.text.charAt(targe
t))) target += dir; | 5474 if (byUnit) while (target > 0 && isExtendingChar.test(line.text.charAt(targe
t))) target += dir; |
5416 return target < 0 || target > line.text.length ? null : target; | 5475 return target < 0 || target > line.text.length ? null : target; |
5417 } | 5476 } |
5418 | 5477 |
5419 // Bidirectional ordering algorithm | 5478 // Bidirectional ordering algorithm |
5420 // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm | 5479 // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5572 } | 5631 } |
5573 if (order[0].level != lst(order).level) | 5632 if (order[0].level != lst(order).level) |
5574 order.push({from: len, to: len, level: order[0].level}); | 5633 order.push({from: len, to: len, level: order[0].level}); |
5575 | 5634 |
5576 return order; | 5635 return order; |
5577 }; | 5636 }; |
5578 })(); | 5637 })(); |
5579 | 5638 |
5580 // THE END | 5639 // THE END |
5581 | 5640 |
5582 CodeMirror.version = "3.12"; | 5641 CodeMirror.version = "3.13 +"; |
5583 | 5642 |
5584 return CodeMirror; | 5643 return CodeMirror; |
5585 })(); | 5644 })(); |
OLD | NEW |