Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(382)

Side by Side Diff: Source/devtools/front_end/cm/codemirror.js

Issue 15846008: DevTools: update CM to TOT version 3.13+ (6edd771495) (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/devtools/front_end/cm/codemirror.css ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 })();
OLDNEW
« no previous file with comments | « Source/devtools/front_end/cm/codemirror.css ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698