1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/devtools/sourceeditor/test/cm_test.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1878 @@ 1.4 +var Pos = CodeMirror.Pos; 1.5 + 1.6 +CodeMirror.defaults.rtlMoveVisually = true; 1.7 + 1.8 +function forEach(arr, f) { 1.9 + for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]); 1.10 +} 1.11 + 1.12 +function addDoc(cm, width, height) { 1.13 + var content = [], line = ""; 1.14 + for (var i = 0; i < width; ++i) line += "x"; 1.15 + for (var i = 0; i < height; ++i) content.push(line); 1.16 + cm.setValue(content.join("\n")); 1.17 +} 1.18 + 1.19 +function byClassName(elt, cls) { 1.20 + if (elt.getElementsByClassName) return elt.getElementsByClassName(cls); 1.21 + var found = [], re = new RegExp("\\b" + cls + "\\b"); 1.22 + function search(elt) { 1.23 + if (elt.nodeType == 3) return; 1.24 + if (re.test(elt.className)) found.push(elt); 1.25 + for (var i = 0, e = elt.childNodes.length; i < e; ++i) 1.26 + search(elt.childNodes[i]); 1.27 + } 1.28 + search(elt); 1.29 + return found; 1.30 +} 1.31 + 1.32 +var ie_lt8 = /MSIE [1-7]\b/.test(navigator.userAgent); 1.33 +var ie_lt9 = /MSIE [1-8]\b/.test(navigator.userAgent); 1.34 +var mac = /Mac/.test(navigator.platform); 1.35 +var phantom = /PhantomJS/.test(navigator.userAgent); 1.36 +var opera = /Opera\/\./.test(navigator.userAgent); 1.37 +var opera_version = opera && navigator.userAgent.match(/Version\/(\d+\.\d+)/); 1.38 +if (opera_version) opera_version = Number(opera_version); 1.39 +var opera_lt10 = opera && (!opera_version || opera_version < 10); 1.40 + 1.41 +namespace = "core_"; 1.42 + 1.43 +test("core_fromTextArea", function() { 1.44 + var te = document.getElementById("code"); 1.45 + te.value = "CONTENT"; 1.46 + var cm = CodeMirror.fromTextArea(te); 1.47 + is(!te.offsetHeight); 1.48 + eq(cm.getValue(), "CONTENT"); 1.49 + cm.setValue("foo\nbar"); 1.50 + eq(cm.getValue(), "foo\nbar"); 1.51 + cm.save(); 1.52 + is(/^foo\r?\nbar$/.test(te.value)); 1.53 + cm.setValue("xxx"); 1.54 + cm.toTextArea(); 1.55 + is(te.offsetHeight); 1.56 + eq(te.value, "xxx"); 1.57 +}); 1.58 + 1.59 +testCM("getRange", function(cm) { 1.60 + eq(cm.getLine(0), "1234"); 1.61 + eq(cm.getLine(1), "5678"); 1.62 + eq(cm.getLine(2), null); 1.63 + eq(cm.getLine(-1), null); 1.64 + eq(cm.getRange(Pos(0, 0), Pos(0, 3)), "123"); 1.65 + eq(cm.getRange(Pos(0, -1), Pos(0, 200)), "1234"); 1.66 + eq(cm.getRange(Pos(0, 2), Pos(1, 2)), "34\n56"); 1.67 + eq(cm.getRange(Pos(1, 2), Pos(100, 0)), "78"); 1.68 +}, {value: "1234\n5678"}); 1.69 + 1.70 +testCM("replaceRange", function(cm) { 1.71 + eq(cm.getValue(), ""); 1.72 + cm.replaceRange("foo\n", Pos(0, 0)); 1.73 + eq(cm.getValue(), "foo\n"); 1.74 + cm.replaceRange("a\nb", Pos(0, 1)); 1.75 + eq(cm.getValue(), "fa\nboo\n"); 1.76 + eq(cm.lineCount(), 3); 1.77 + cm.replaceRange("xyzzy", Pos(0, 0), Pos(1, 1)); 1.78 + eq(cm.getValue(), "xyzzyoo\n"); 1.79 + cm.replaceRange("abc", Pos(0, 0), Pos(10, 0)); 1.80 + eq(cm.getValue(), "abc"); 1.81 + eq(cm.lineCount(), 1); 1.82 +}); 1.83 + 1.84 +testCM("selection", function(cm) { 1.85 + cm.setSelection(Pos(0, 4), Pos(2, 2)); 1.86 + is(cm.somethingSelected()); 1.87 + eq(cm.getSelection(), "11\n222222\n33"); 1.88 + eqPos(cm.getCursor(false), Pos(2, 2)); 1.89 + eqPos(cm.getCursor(true), Pos(0, 4)); 1.90 + cm.setSelection(Pos(1, 0)); 1.91 + is(!cm.somethingSelected()); 1.92 + eq(cm.getSelection(), ""); 1.93 + eqPos(cm.getCursor(true), Pos(1, 0)); 1.94 + cm.replaceSelection("abc", "around"); 1.95 + eq(cm.getSelection(), "abc"); 1.96 + eq(cm.getValue(), "111111\nabc222222\n333333"); 1.97 + cm.replaceSelection("def", "end"); 1.98 + eq(cm.getSelection(), ""); 1.99 + eqPos(cm.getCursor(true), Pos(1, 3)); 1.100 + cm.setCursor(Pos(2, 1)); 1.101 + eqPos(cm.getCursor(true), Pos(2, 1)); 1.102 + cm.setCursor(1, 2); 1.103 + eqPos(cm.getCursor(true), Pos(1, 2)); 1.104 +}, {value: "111111\n222222\n333333"}); 1.105 + 1.106 +testCM("extendSelection", function(cm) { 1.107 + cm.setExtending(true); 1.108 + addDoc(cm, 10, 10); 1.109 + cm.setSelection(Pos(3, 5)); 1.110 + eqPos(cm.getCursor("head"), Pos(3, 5)); 1.111 + eqPos(cm.getCursor("anchor"), Pos(3, 5)); 1.112 + cm.setSelection(Pos(2, 5), Pos(5, 5)); 1.113 + eqPos(cm.getCursor("head"), Pos(5, 5)); 1.114 + eqPos(cm.getCursor("anchor"), Pos(2, 5)); 1.115 + eqPos(cm.getCursor("start"), Pos(2, 5)); 1.116 + eqPos(cm.getCursor("end"), Pos(5, 5)); 1.117 + cm.setSelection(Pos(5, 5), Pos(2, 5)); 1.118 + eqPos(cm.getCursor("head"), Pos(2, 5)); 1.119 + eqPos(cm.getCursor("anchor"), Pos(5, 5)); 1.120 + eqPos(cm.getCursor("start"), Pos(2, 5)); 1.121 + eqPos(cm.getCursor("end"), Pos(5, 5)); 1.122 + cm.extendSelection(Pos(3, 2)); 1.123 + eqPos(cm.getCursor("head"), Pos(3, 2)); 1.124 + eqPos(cm.getCursor("anchor"), Pos(5, 5)); 1.125 + cm.extendSelection(Pos(6, 2)); 1.126 + eqPos(cm.getCursor("head"), Pos(6, 2)); 1.127 + eqPos(cm.getCursor("anchor"), Pos(5, 5)); 1.128 + cm.extendSelection(Pos(6, 3), Pos(6, 4)); 1.129 + eqPos(cm.getCursor("head"), Pos(6, 4)); 1.130 + eqPos(cm.getCursor("anchor"), Pos(5, 5)); 1.131 + cm.extendSelection(Pos(0, 3), Pos(0, 4)); 1.132 + eqPos(cm.getCursor("head"), Pos(0, 3)); 1.133 + eqPos(cm.getCursor("anchor"), Pos(5, 5)); 1.134 + cm.extendSelection(Pos(4, 5), Pos(6, 5)); 1.135 + eqPos(cm.getCursor("head"), Pos(6, 5)); 1.136 + eqPos(cm.getCursor("anchor"), Pos(4, 5)); 1.137 + cm.setExtending(false); 1.138 + cm.extendSelection(Pos(0, 3), Pos(0, 4)); 1.139 + eqPos(cm.getCursor("head"), Pos(0, 3)); 1.140 + eqPos(cm.getCursor("anchor"), Pos(0, 4)); 1.141 +}); 1.142 + 1.143 +testCM("lines", function(cm) { 1.144 + eq(cm.getLine(0), "111111"); 1.145 + eq(cm.getLine(1), "222222"); 1.146 + eq(cm.getLine(-1), null); 1.147 + cm.replaceRange("", Pos(1, 0), Pos(2, 0)) 1.148 + cm.replaceRange("abc", Pos(1, 0), Pos(1)); 1.149 + eq(cm.getValue(), "111111\nabc"); 1.150 +}, {value: "111111\n222222\n333333"}); 1.151 + 1.152 +testCM("indent", function(cm) { 1.153 + cm.indentLine(1); 1.154 + eq(cm.getLine(1), " blah();"); 1.155 + cm.setOption("indentUnit", 8); 1.156 + cm.indentLine(1); 1.157 + eq(cm.getLine(1), "\tblah();"); 1.158 + cm.setOption("indentUnit", 10); 1.159 + cm.setOption("tabSize", 4); 1.160 + cm.indentLine(1); 1.161 + eq(cm.getLine(1), "\t\t blah();"); 1.162 +}, {value: "if (x) {\nblah();\n}", indentUnit: 3, indentWithTabs: true, tabSize: 8}); 1.163 + 1.164 +testCM("indentByNumber", function(cm) { 1.165 + cm.indentLine(0, 2); 1.166 + eq(cm.getLine(0), " foo"); 1.167 + cm.indentLine(0, -200); 1.168 + eq(cm.getLine(0), "foo"); 1.169 + cm.setSelection(Pos(0, 0), Pos(1, 2)); 1.170 + cm.indentSelection(3); 1.171 + eq(cm.getValue(), " foo\n bar\nbaz"); 1.172 +}, {value: "foo\nbar\nbaz"}); 1.173 + 1.174 +test("core_defaults", function() { 1.175 + var defsCopy = {}, defs = CodeMirror.defaults; 1.176 + for (var opt in defs) defsCopy[opt] = defs[opt]; 1.177 + defs.indentUnit = 5; 1.178 + defs.value = "uu"; 1.179 + defs.indentWithTabs = true; 1.180 + defs.tabindex = 55; 1.181 + var place = document.getElementById("testground"), cm = CodeMirror(place); 1.182 + try { 1.183 + eq(cm.getOption("indentUnit"), 5); 1.184 + cm.setOption("indentUnit", 10); 1.185 + eq(defs.indentUnit, 5); 1.186 + eq(cm.getValue(), "uu"); 1.187 + eq(cm.getOption("indentWithTabs"), true); 1.188 + eq(cm.getInputField().tabIndex, 55); 1.189 + } 1.190 + finally { 1.191 + for (var opt in defsCopy) defs[opt] = defsCopy[opt]; 1.192 + place.removeChild(cm.getWrapperElement()); 1.193 + } 1.194 +}); 1.195 + 1.196 +testCM("lineInfo", function(cm) { 1.197 + eq(cm.lineInfo(-1), null); 1.198 + var mark = document.createElement("span"); 1.199 + var lh = cm.setGutterMarker(1, "FOO", mark); 1.200 + var info = cm.lineInfo(1); 1.201 + eq(info.text, "222222"); 1.202 + eq(info.gutterMarkers.FOO, mark); 1.203 + eq(info.line, 1); 1.204 + eq(cm.lineInfo(2).gutterMarkers, null); 1.205 + cm.setGutterMarker(lh, "FOO", null); 1.206 + eq(cm.lineInfo(1).gutterMarkers, null); 1.207 + cm.setGutterMarker(1, "FOO", mark); 1.208 + cm.setGutterMarker(0, "FOO", mark); 1.209 + cm.clearGutter("FOO"); 1.210 + eq(cm.lineInfo(0).gutterMarkers, null); 1.211 + eq(cm.lineInfo(1).gutterMarkers, null); 1.212 +}, {value: "111111\n222222\n333333"}); 1.213 + 1.214 +testCM("coords", function(cm) { 1.215 + cm.setSize(null, 100); 1.216 + addDoc(cm, 32, 200); 1.217 + var top = cm.charCoords(Pos(0, 0)); 1.218 + var bot = cm.charCoords(Pos(200, 30)); 1.219 + is(top.left < bot.left); 1.220 + is(top.top < bot.top); 1.221 + is(top.top < top.bottom); 1.222 + cm.scrollTo(null, 100); 1.223 + var top2 = cm.charCoords(Pos(0, 0)); 1.224 + is(top.top > top2.top); 1.225 + eq(top.left, top2.left); 1.226 +}); 1.227 + 1.228 +testCM("coordsChar", function(cm) { 1.229 + addDoc(cm, 35, 70); 1.230 + for (var i = 0; i < 2; ++i) { 1.231 + var sys = i ? "local" : "page"; 1.232 + for (var ch = 0; ch <= 35; ch += 5) { 1.233 + for (var line = 0; line < 70; line += 5) { 1.234 + cm.setCursor(line, ch); 1.235 + var coords = cm.charCoords(Pos(line, ch), sys); 1.236 + var pos = cm.coordsChar({left: coords.left + 1, top: coords.top + 1}, sys); 1.237 + eqPos(pos, Pos(line, ch)); 1.238 + } 1.239 + } 1.240 + } 1.241 +}, {lineNumbers: true}); 1.242 + 1.243 +testCM("posFromIndex", function(cm) { 1.244 + cm.setValue( 1.245 + "This function should\n" + 1.246 + "convert a zero based index\n" + 1.247 + "to line and ch." 1.248 + ); 1.249 + 1.250 + var examples = [ 1.251 + { index: -1, line: 0, ch: 0 }, // <- Tests clipping 1.252 + { index: 0, line: 0, ch: 0 }, 1.253 + { index: 10, line: 0, ch: 10 }, 1.254 + { index: 39, line: 1, ch: 18 }, 1.255 + { index: 55, line: 2, ch: 7 }, 1.256 + { index: 63, line: 2, ch: 15 }, 1.257 + { index: 64, line: 2, ch: 15 } // <- Tests clipping 1.258 + ]; 1.259 + 1.260 + for (var i = 0; i < examples.length; i++) { 1.261 + var example = examples[i]; 1.262 + var pos = cm.posFromIndex(example.index); 1.263 + eq(pos.line, example.line); 1.264 + eq(pos.ch, example.ch); 1.265 + if (example.index >= 0 && example.index < 64) 1.266 + eq(cm.indexFromPos(pos), example.index); 1.267 + } 1.268 +}); 1.269 + 1.270 +testCM("undo", function(cm) { 1.271 + cm.replaceRange("def", Pos(0, 0), Pos(0)); 1.272 + eq(cm.historySize().undo, 1); 1.273 + cm.undo(); 1.274 + eq(cm.getValue(), "abc"); 1.275 + eq(cm.historySize().undo, 0); 1.276 + eq(cm.historySize().redo, 1); 1.277 + cm.redo(); 1.278 + eq(cm.getValue(), "def"); 1.279 + eq(cm.historySize().undo, 1); 1.280 + eq(cm.historySize().redo, 0); 1.281 + cm.setValue("1\n\n\n2"); 1.282 + cm.clearHistory(); 1.283 + eq(cm.historySize().undo, 0); 1.284 + for (var i = 0; i < 20; ++i) { 1.285 + cm.replaceRange("a", Pos(0, 0)); 1.286 + cm.replaceRange("b", Pos(3, 0)); 1.287 + } 1.288 + eq(cm.historySize().undo, 40); 1.289 + for (var i = 0; i < 40; ++i) 1.290 + cm.undo(); 1.291 + eq(cm.historySize().redo, 40); 1.292 + eq(cm.getValue(), "1\n\n\n2"); 1.293 +}, {value: "abc"}); 1.294 + 1.295 +testCM("undoDepth", function(cm) { 1.296 + cm.replaceRange("d", Pos(0)); 1.297 + cm.replaceRange("e", Pos(0)); 1.298 + cm.replaceRange("f", Pos(0)); 1.299 + cm.undo(); cm.undo(); cm.undo(); 1.300 + eq(cm.getValue(), "abcd"); 1.301 +}, {value: "abc", undoDepth: 4}); 1.302 + 1.303 +testCM("undoDoesntClearValue", function(cm) { 1.304 + cm.undo(); 1.305 + eq(cm.getValue(), "x"); 1.306 +}, {value: "x"}); 1.307 + 1.308 +testCM("undoMultiLine", function(cm) { 1.309 + cm.operation(function() { 1.310 + cm.replaceRange("x", Pos(0, 0)); 1.311 + cm.replaceRange("y", Pos(1, 0)); 1.312 + }); 1.313 + cm.undo(); 1.314 + eq(cm.getValue(), "abc\ndef\nghi"); 1.315 + cm.operation(function() { 1.316 + cm.replaceRange("y", Pos(1, 0)); 1.317 + cm.replaceRange("x", Pos(0, 0)); 1.318 + }); 1.319 + cm.undo(); 1.320 + eq(cm.getValue(), "abc\ndef\nghi"); 1.321 + cm.operation(function() { 1.322 + cm.replaceRange("y", Pos(2, 0)); 1.323 + cm.replaceRange("x", Pos(1, 0)); 1.324 + cm.replaceRange("z", Pos(2, 0)); 1.325 + }); 1.326 + cm.undo(); 1.327 + eq(cm.getValue(), "abc\ndef\nghi", 3); 1.328 +}, {value: "abc\ndef\nghi"}); 1.329 + 1.330 +testCM("undoComposite", function(cm) { 1.331 + cm.replaceRange("y", Pos(1)); 1.332 + cm.operation(function() { 1.333 + cm.replaceRange("x", Pos(0)); 1.334 + cm.replaceRange("z", Pos(2)); 1.335 + }); 1.336 + eq(cm.getValue(), "ax\nby\ncz\n"); 1.337 + cm.undo(); 1.338 + eq(cm.getValue(), "a\nby\nc\n"); 1.339 + cm.undo(); 1.340 + eq(cm.getValue(), "a\nb\nc\n"); 1.341 + cm.redo(); cm.redo(); 1.342 + eq(cm.getValue(), "ax\nby\ncz\n"); 1.343 +}, {value: "a\nb\nc\n"}); 1.344 + 1.345 +testCM("undoSelection", function(cm) { 1.346 + cm.setSelection(Pos(0, 2), Pos(0, 4)); 1.347 + cm.replaceSelection(""); 1.348 + cm.setCursor(Pos(1, 0)); 1.349 + cm.undo(); 1.350 + eqPos(cm.getCursor(true), Pos(0, 2)); 1.351 + eqPos(cm.getCursor(false), Pos(0, 4)); 1.352 + cm.setCursor(Pos(1, 0)); 1.353 + cm.redo(); 1.354 + eqPos(cm.getCursor(true), Pos(0, 2)); 1.355 + eqPos(cm.getCursor(false), Pos(0, 2)); 1.356 +}, {value: "abcdefgh\n"}); 1.357 + 1.358 +testCM("undoSelectionAsBefore", function(cm) { 1.359 + cm.replaceSelection("abc", "around"); 1.360 + cm.undo(); 1.361 + cm.redo(); 1.362 + eq(cm.getSelection(), "abc"); 1.363 +}); 1.364 + 1.365 +testCM("markTextSingleLine", function(cm) { 1.366 + forEach([{a: 0, b: 1, c: "", f: 2, t: 5}, 1.367 + {a: 0, b: 4, c: "", f: 0, t: 2}, 1.368 + {a: 1, b: 2, c: "x", f: 3, t: 6}, 1.369 + {a: 4, b: 5, c: "", f: 3, t: 5}, 1.370 + {a: 4, b: 5, c: "xx", f: 3, t: 7}, 1.371 + {a: 2, b: 5, c: "", f: 2, t: 3}, 1.372 + {a: 2, b: 5, c: "abcd", f: 6, t: 7}, 1.373 + {a: 2, b: 6, c: "x", f: null, t: null}, 1.374 + {a: 3, b: 6, c: "", f: null, t: null}, 1.375 + {a: 0, b: 9, c: "hallo", f: null, t: null}, 1.376 + {a: 4, b: 6, c: "x", f: 3, t: 4}, 1.377 + {a: 4, b: 8, c: "", f: 3, t: 4}, 1.378 + {a: 6, b: 6, c: "a", f: 3, t: 6}, 1.379 + {a: 8, b: 9, c: "", f: 3, t: 6}], function(test) { 1.380 + cm.setValue("1234567890"); 1.381 + var r = cm.markText(Pos(0, 3), Pos(0, 6), {className: "foo"}); 1.382 + cm.replaceRange(test.c, Pos(0, test.a), Pos(0, test.b)); 1.383 + var f = r.find(); 1.384 + eq(f && f.from.ch, test.f); eq(f && f.to.ch, test.t); 1.385 + }); 1.386 +}); 1.387 + 1.388 +testCM("markTextMultiLine", function(cm) { 1.389 + function p(v) { return v && Pos(v[0], v[1]); } 1.390 + forEach([{a: [0, 0], b: [0, 5], c: "", f: [0, 0], t: [2, 5]}, 1.391 + {a: [0, 0], b: [0, 5], c: "foo\n", f: [1, 0], t: [3, 5]}, 1.392 + {a: [0, 1], b: [0, 10], c: "", f: [0, 1], t: [2, 5]}, 1.393 + {a: [0, 5], b: [0, 6], c: "x", f: [0, 6], t: [2, 5]}, 1.394 + {a: [0, 0], b: [1, 0], c: "", f: [0, 0], t: [1, 5]}, 1.395 + {a: [0, 6], b: [2, 4], c: "", f: [0, 5], t: [0, 7]}, 1.396 + {a: [0, 6], b: [2, 4], c: "aa", f: [0, 5], t: [0, 9]}, 1.397 + {a: [1, 2], b: [1, 8], c: "", f: [0, 5], t: [2, 5]}, 1.398 + {a: [0, 5], b: [2, 5], c: "xx", f: null, t: null}, 1.399 + {a: [0, 0], b: [2, 10], c: "x", f: null, t: null}, 1.400 + {a: [1, 5], b: [2, 5], c: "", f: [0, 5], t: [1, 5]}, 1.401 + {a: [2, 0], b: [2, 3], c: "", f: [0, 5], t: [2, 2]}, 1.402 + {a: [2, 5], b: [3, 0], c: "a\nb", f: [0, 5], t: [2, 5]}, 1.403 + {a: [2, 3], b: [3, 0], c: "x", f: [0, 5], t: [2, 3]}, 1.404 + {a: [1, 1], b: [1, 9], c: "1\n2\n3", f: [0, 5], t: [4, 5]}], function(test) { 1.405 + cm.setValue("aaaaaaaaaa\nbbbbbbbbbb\ncccccccccc\ndddddddd\n"); 1.406 + var r = cm.markText(Pos(0, 5), Pos(2, 5), 1.407 + {className: "CodeMirror-matchingbracket"}); 1.408 + cm.replaceRange(test.c, p(test.a), p(test.b)); 1.409 + var f = r.find(); 1.410 + eqPos(f && f.from, p(test.f)); eqPos(f && f.to, p(test.t)); 1.411 + }); 1.412 +}); 1.413 + 1.414 +testCM("markTextUndo", function(cm) { 1.415 + var marker1, marker2, bookmark; 1.416 + marker1 = cm.markText(Pos(0, 1), Pos(0, 3), 1.417 + {className: "CodeMirror-matchingbracket"}); 1.418 + marker2 = cm.markText(Pos(0, 0), Pos(2, 1), 1.419 + {className: "CodeMirror-matchingbracket"}); 1.420 + bookmark = cm.setBookmark(Pos(1, 5)); 1.421 + cm.operation(function(){ 1.422 + cm.replaceRange("foo", Pos(0, 2)); 1.423 + cm.replaceRange("bar\nbaz\nbug\n", Pos(2, 0), Pos(3, 0)); 1.424 + }); 1.425 + var v1 = cm.getValue(); 1.426 + cm.setValue(""); 1.427 + eq(marker1.find(), null); eq(marker2.find(), null); eq(bookmark.find(), null); 1.428 + cm.undo(); 1.429 + eqPos(bookmark.find(), Pos(1, 5), "still there"); 1.430 + cm.undo(); 1.431 + var m1Pos = marker1.find(), m2Pos = marker2.find(); 1.432 + eqPos(m1Pos.from, Pos(0, 1)); eqPos(m1Pos.to, Pos(0, 3)); 1.433 + eqPos(m2Pos.from, Pos(0, 0)); eqPos(m2Pos.to, Pos(2, 1)); 1.434 + eqPos(bookmark.find(), Pos(1, 5)); 1.435 + cm.redo(); cm.redo(); 1.436 + eq(bookmark.find(), null); 1.437 + cm.undo(); 1.438 + eqPos(bookmark.find(), Pos(1, 5)); 1.439 + eq(cm.getValue(), v1); 1.440 +}, {value: "1234\n56789\n00\n"}); 1.441 + 1.442 +testCM("markTextStayGone", function(cm) { 1.443 + var m1 = cm.markText(Pos(0, 0), Pos(0, 1)); 1.444 + cm.replaceRange("hi", Pos(0, 2)); 1.445 + m1.clear(); 1.446 + cm.undo(); 1.447 + eq(m1.find(), null); 1.448 +}, {value: "hello"}); 1.449 + 1.450 +testCM("markTextAllowEmpty", function(cm) { 1.451 + var m1 = cm.markText(Pos(0, 1), Pos(0, 2), {clearWhenEmpty: false}); 1.452 + is(m1.find()); 1.453 + cm.replaceRange("x", Pos(0, 0)); 1.454 + is(m1.find()); 1.455 + cm.replaceRange("y", Pos(0, 2)); 1.456 + is(m1.find()); 1.457 + cm.replaceRange("z", Pos(0, 3), Pos(0, 4)); 1.458 + is(!m1.find()); 1.459 + var m2 = cm.markText(Pos(0, 1), Pos(0, 2), {clearWhenEmpty: false, 1.460 + inclusiveLeft: true, 1.461 + inclusiveRight: true}); 1.462 + cm.replaceRange("q", Pos(0, 1), Pos(0, 2)); 1.463 + is(m2.find()); 1.464 + cm.replaceRange("", Pos(0, 0), Pos(0, 3)); 1.465 + is(!m2.find()); 1.466 + var m3 = cm.markText(Pos(0, 1), Pos(0, 1), {clearWhenEmpty: false}); 1.467 + cm.replaceRange("a", Pos(0, 3)); 1.468 + is(m3.find()); 1.469 + cm.replaceRange("b", Pos(0, 1)); 1.470 + is(!m3.find()); 1.471 +}, {value: "abcde"}); 1.472 + 1.473 +testCM("markTextStacked", function(cm) { 1.474 + var m1 = cm.markText(Pos(0, 0), Pos(0, 0), {clearWhenEmpty: false}); 1.475 + var m2 = cm.markText(Pos(0, 0), Pos(0, 0), {clearWhenEmpty: false}); 1.476 + cm.replaceRange("B", Pos(0, 1)); 1.477 + is(m1.find() && m2.find()); 1.478 +}, {value: "A"}); 1.479 + 1.480 +testCM("undoPreservesNewMarks", function(cm) { 1.481 + cm.markText(Pos(0, 3), Pos(0, 4)); 1.482 + cm.markText(Pos(1, 1), Pos(1, 3)); 1.483 + cm.replaceRange("", Pos(0, 3), Pos(3, 1)); 1.484 + var mBefore = cm.markText(Pos(0, 0), Pos(0, 1)); 1.485 + var mAfter = cm.markText(Pos(0, 5), Pos(0, 6)); 1.486 + var mAround = cm.markText(Pos(0, 2), Pos(0, 4)); 1.487 + cm.undo(); 1.488 + eqPos(mBefore.find().from, Pos(0, 0)); 1.489 + eqPos(mBefore.find().to, Pos(0, 1)); 1.490 + eqPos(mAfter.find().from, Pos(3, 3)); 1.491 + eqPos(mAfter.find().to, Pos(3, 4)); 1.492 + eqPos(mAround.find().from, Pos(0, 2)); 1.493 + eqPos(mAround.find().to, Pos(3, 2)); 1.494 + var found = cm.findMarksAt(Pos(2, 2)); 1.495 + eq(found.length, 1); 1.496 + eq(found[0], mAround); 1.497 +}, {value: "aaaa\nbbbb\ncccc\ndddd"}); 1.498 + 1.499 +testCM("markClearBetween", function(cm) { 1.500 + cm.setValue("aaa\nbbb\nccc\nddd\n"); 1.501 + cm.markText(Pos(0, 0), Pos(2)); 1.502 + cm.replaceRange("aaa\nbbb\nccc", Pos(0, 0), Pos(2)); 1.503 + eq(cm.findMarksAt(Pos(1, 1)).length, 0); 1.504 +}); 1.505 + 1.506 +testCM("deleteSpanCollapsedInclusiveLeft", function(cm) { 1.507 + var from = Pos(1, 0), to = Pos(1, 1); 1.508 + var m = cm.markText(from, to, {collapsed: true, inclusiveLeft: true}); 1.509 + // Delete collapsed span. 1.510 + cm.replaceRange("", from, to); 1.511 +}, {value: "abc\nX\ndef"}); 1.512 + 1.513 +testCM("bookmark", function(cm) { 1.514 + function p(v) { return v && Pos(v[0], v[1]); } 1.515 + forEach([{a: [1, 0], b: [1, 1], c: "", d: [1, 4]}, 1.516 + {a: [1, 1], b: [1, 1], c: "xx", d: [1, 7]}, 1.517 + {a: [1, 4], b: [1, 5], c: "ab", d: [1, 6]}, 1.518 + {a: [1, 4], b: [1, 6], c: "", d: null}, 1.519 + {a: [1, 5], b: [1, 6], c: "abc", d: [1, 5]}, 1.520 + {a: [1, 6], b: [1, 8], c: "", d: [1, 5]}, 1.521 + {a: [1, 4], b: [1, 4], c: "\n\n", d: [3, 1]}, 1.522 + {bm: [1, 9], a: [1, 1], b: [1, 1], c: "\n", d: [2, 8]}], function(test) { 1.523 + cm.setValue("1234567890\n1234567890\n1234567890"); 1.524 + var b = cm.setBookmark(p(test.bm) || Pos(1, 5)); 1.525 + cm.replaceRange(test.c, p(test.a), p(test.b)); 1.526 + eqPos(b.find(), p(test.d)); 1.527 + }); 1.528 +}); 1.529 + 1.530 +testCM("bookmarkInsertLeft", function(cm) { 1.531 + var br = cm.setBookmark(Pos(0, 2), {insertLeft: false}); 1.532 + var bl = cm.setBookmark(Pos(0, 2), {insertLeft: true}); 1.533 + cm.setCursor(Pos(0, 2)); 1.534 + cm.replaceSelection("hi"); 1.535 + eqPos(br.find(), Pos(0, 2)); 1.536 + eqPos(bl.find(), Pos(0, 4)); 1.537 + cm.replaceRange("", Pos(0, 4), Pos(0, 5)); 1.538 + cm.replaceRange("", Pos(0, 2), Pos(0, 4)); 1.539 + cm.replaceRange("", Pos(0, 1), Pos(0, 2)); 1.540 + // Verify that deleting next to bookmarks doesn't kill them 1.541 + eqPos(br.find(), Pos(0, 1)); 1.542 + eqPos(bl.find(), Pos(0, 1)); 1.543 +}, {value: "abcdef"}); 1.544 + 1.545 +testCM("bookmarkCursor", function(cm) { 1.546 + var pos01 = cm.cursorCoords(Pos(0, 1)), pos11 = cm.cursorCoords(Pos(1, 1)), 1.547 + pos20 = cm.cursorCoords(Pos(2, 0)), pos30 = cm.cursorCoords(Pos(3, 0)), 1.548 + pos41 = cm.cursorCoords(Pos(4, 1)); 1.549 + cm.setBookmark(Pos(0, 1), {widget: document.createTextNode("←"), insertLeft: true}); 1.550 + cm.setBookmark(Pos(2, 0), {widget: document.createTextNode("←"), insertLeft: true}); 1.551 + cm.setBookmark(Pos(1, 1), {widget: document.createTextNode("→")}); 1.552 + cm.setBookmark(Pos(3, 0), {widget: document.createTextNode("→")}); 1.553 + var new01 = cm.cursorCoords(Pos(0, 1)), new11 = cm.cursorCoords(Pos(1, 1)), 1.554 + new20 = cm.cursorCoords(Pos(2, 0)), new30 = cm.cursorCoords(Pos(3, 0)); 1.555 + near(new01.left, pos01.left, 1); 1.556 + near(new01.top, pos01.top, 1); 1.557 + is(new11.left > pos11.left, "at right, middle of line"); 1.558 + near(new11.top == pos11.top, 1); 1.559 + near(new20.left, pos20.left, 1); 1.560 + near(new20.top, pos20.top, 1); 1.561 + is(new30.left > pos30.left, "at right, empty line"); 1.562 + near(new30.top, pos30, 1); 1.563 + cm.setBookmark(Pos(4, 0), {widget: document.createTextNode("→")}); 1.564 + is(cm.cursorCoords(Pos(4, 1)).left > pos41.left, "single-char bug"); 1.565 +}, {value: "foo\nbar\n\n\nx\ny"}); 1.566 + 1.567 +testCM("multiBookmarkCursor", function(cm) { 1.568 + if (phantom) return; 1.569 + var ms = [], m; 1.570 + function add(insertLeft) { 1.571 + for (var i = 0; i < 3; ++i) { 1.572 + var node = document.createElement("span"); 1.573 + node.innerHTML = "X"; 1.574 + ms.push(cm.setBookmark(Pos(0, 1), {widget: node, insertLeft: insertLeft})); 1.575 + } 1.576 + } 1.577 + var base1 = cm.cursorCoords(Pos(0, 1)).left, base4 = cm.cursorCoords(Pos(0, 4)).left; 1.578 + add(true); 1.579 + near(base1, cm.cursorCoords(Pos(0, 1)).left, 1); 1.580 + while (m = ms.pop()) m.clear(); 1.581 + add(false); 1.582 + near(base4, cm.cursorCoords(Pos(0, 1)).left, 1); 1.583 +}, {value: "abcdefg"}); 1.584 + 1.585 +testCM("getAllMarks", function(cm) { 1.586 + addDoc(cm, 10, 10); 1.587 + var m1 = cm.setBookmark(Pos(0, 2)); 1.588 + var m2 = cm.markText(Pos(0, 2), Pos(3, 2)); 1.589 + var m3 = cm.markText(Pos(1, 2), Pos(1, 8)); 1.590 + var m4 = cm.markText(Pos(8, 0), Pos(9, 0)); 1.591 + eq(cm.getAllMarks().length, 4); 1.592 + m1.clear(); 1.593 + m3.clear(); 1.594 + eq(cm.getAllMarks().length, 2); 1.595 +}); 1.596 + 1.597 +testCM("bug577", function(cm) { 1.598 + cm.setValue("a\nb"); 1.599 + cm.clearHistory(); 1.600 + cm.setValue("fooooo"); 1.601 + cm.undo(); 1.602 +}); 1.603 + 1.604 +testCM("scrollSnap", function(cm) { 1.605 + cm.setSize(100, 100); 1.606 + addDoc(cm, 200, 200); 1.607 + cm.setCursor(Pos(100, 180)); 1.608 + var info = cm.getScrollInfo(); 1.609 + is(info.left > 0 && info.top > 0); 1.610 + cm.setCursor(Pos(0, 0)); 1.611 + info = cm.getScrollInfo(); 1.612 + is(info.left == 0 && info.top == 0, "scrolled clean to top"); 1.613 + cm.setCursor(Pos(100, 180)); 1.614 + cm.setCursor(Pos(199, 0)); 1.615 + info = cm.getScrollInfo(); 1.616 + is(info.left == 0 && info.top + 2 > info.height - cm.getScrollerElement().clientHeight, "scrolled clean to bottom"); 1.617 +}); 1.618 + 1.619 +testCM("scrollIntoView", function(cm) { 1.620 + if (phantom) return; 1.621 + var outer = cm.getWrapperElement().getBoundingClientRect(); 1.622 + function test(line, ch, msg) { 1.623 + var pos = Pos(line, ch); 1.624 + cm.scrollIntoView(pos); 1.625 + var box = cm.charCoords(pos, "window"); 1.626 + is(box.left >= outer.left, msg + " (left)"); 1.627 + is(box.right <= outer.right, msg + " (right)"); 1.628 + is(box.top >= outer.top, msg + " (top)"); 1.629 + is(box.bottom <= outer.bottom, msg + " (bottom)"); 1.630 + } 1.631 + addDoc(cm, 200, 200); 1.632 + test(199, 199, "bottom right"); 1.633 + test(0, 0, "top left"); 1.634 + test(100, 100, "center"); 1.635 + test(199, 0, "bottom left"); 1.636 + test(0, 199, "top right"); 1.637 + test(100, 100, "center again"); 1.638 +}); 1.639 + 1.640 +testCM("scrollBackAndForth", function(cm) { 1.641 + addDoc(cm, 1, 200); 1.642 + cm.operation(function() { 1.643 + cm.scrollIntoView(Pos(199, 0)); 1.644 + cm.scrollIntoView(Pos(4, 0)); 1.645 + }); 1.646 + is(cm.getScrollInfo().top > 0); 1.647 +}); 1.648 + 1.649 +testCM("selectAllNoScroll", function(cm) { 1.650 + addDoc(cm, 1, 200); 1.651 + cm.execCommand("selectAll"); 1.652 + eq(cm.getScrollInfo().top, 0); 1.653 + cm.setCursor(199); 1.654 + cm.execCommand("selectAll"); 1.655 + is(cm.getScrollInfo().top > 0); 1.656 +}); 1.657 + 1.658 +testCM("selectionPos", function(cm) { 1.659 + if (phantom) return; 1.660 + cm.setSize(100, 100); 1.661 + addDoc(cm, 200, 100); 1.662 + cm.setSelection(Pos(1, 100), Pos(98, 100)); 1.663 + var lineWidth = cm.charCoords(Pos(0, 200), "local").left; 1.664 + var lineHeight = (cm.charCoords(Pos(99)).top - cm.charCoords(Pos(0)).top) / 100; 1.665 + cm.scrollTo(0, 0); 1.666 + var selElt = byClassName(cm.getWrapperElement(), "CodeMirror-selected"); 1.667 + var outer = cm.getWrapperElement().getBoundingClientRect(); 1.668 + var sawMiddle, sawTop, sawBottom; 1.669 + for (var i = 0, e = selElt.length; i < e; ++i) { 1.670 + var box = selElt[i].getBoundingClientRect(); 1.671 + var atLeft = box.left - outer.left < 30; 1.672 + var width = box.right - box.left; 1.673 + var atRight = box.right - outer.left > .8 * lineWidth; 1.674 + if (atLeft && atRight) { 1.675 + sawMiddle = true; 1.676 + is(box.bottom - box.top > 90 * lineHeight, "middle high"); 1.677 + is(width > .9 * lineWidth, "middle wide"); 1.678 + } else { 1.679 + is(width > .4 * lineWidth, "top/bot wide enough"); 1.680 + is(width < .6 * lineWidth, "top/bot slim enough"); 1.681 + if (atLeft) { 1.682 + sawBottom = true; 1.683 + is(box.top - outer.top > 96 * lineHeight, "bot below"); 1.684 + } else if (atRight) { 1.685 + sawTop = true; 1.686 + is(box.top - outer.top < 2.1 * lineHeight, "top above"); 1.687 + } 1.688 + } 1.689 + } 1.690 + is(sawTop && sawBottom && sawMiddle, "all parts"); 1.691 +}, null); 1.692 + 1.693 +testCM("restoreHistory", function(cm) { 1.694 + cm.setValue("abc\ndef"); 1.695 + cm.replaceRange("hello", Pos(1, 0), Pos(1)); 1.696 + cm.replaceRange("goop", Pos(0, 0), Pos(0)); 1.697 + cm.undo(); 1.698 + var storedVal = cm.getValue(), storedHist = cm.getHistory(); 1.699 + if (window.JSON) storedHist = JSON.parse(JSON.stringify(storedHist)); 1.700 + eq(storedVal, "abc\nhello"); 1.701 + cm.setValue(""); 1.702 + cm.clearHistory(); 1.703 + eq(cm.historySize().undo, 0); 1.704 + cm.setValue(storedVal); 1.705 + cm.setHistory(storedHist); 1.706 + cm.redo(); 1.707 + eq(cm.getValue(), "goop\nhello"); 1.708 + cm.undo(); cm.undo(); 1.709 + eq(cm.getValue(), "abc\ndef"); 1.710 +}); 1.711 + 1.712 +testCM("doubleScrollbar", function(cm) { 1.713 + var dummy = document.body.appendChild(document.createElement("p")); 1.714 + dummy.style.cssText = "height: 50px; overflow: scroll; width: 50px"; 1.715 + var scrollbarWidth = dummy.offsetWidth + 1 - dummy.clientWidth; 1.716 + document.body.removeChild(dummy); 1.717 + if (scrollbarWidth < 2) return; 1.718 + cm.setSize(null, 100); 1.719 + addDoc(cm, 1, 300); 1.720 + var wrap = cm.getWrapperElement(); 1.721 + is(wrap.offsetWidth - byClassName(wrap, "CodeMirror-lines")[0].offsetWidth <= scrollbarWidth * 1.5); 1.722 +}); 1.723 + 1.724 +testCM("weirdLinebreaks", function(cm) { 1.725 + cm.setValue("foo\nbar\rbaz\r\nquux\n\rplop"); 1.726 + is(cm.getValue(), "foo\nbar\nbaz\nquux\n\nplop"); 1.727 + is(cm.lineCount(), 6); 1.728 + cm.setValue("\n\n"); 1.729 + is(cm.lineCount(), 3); 1.730 +}); 1.731 + 1.732 +testCM("setSize", function(cm) { 1.733 + cm.setSize(100, 100); 1.734 + var wrap = cm.getWrapperElement(); 1.735 + is(wrap.offsetWidth, 100); 1.736 + is(wrap.offsetHeight, 100); 1.737 + cm.setSize("100%", "3em"); 1.738 + is(wrap.style.width, "100%"); 1.739 + is(wrap.style.height, "3em"); 1.740 + cm.setSize(null, 40); 1.741 + is(wrap.style.width, "100%"); 1.742 + is(wrap.style.height, "40px"); 1.743 +}); 1.744 + 1.745 +function foldLines(cm, start, end, autoClear) { 1.746 + return cm.markText(Pos(start, 0), Pos(end - 1), { 1.747 + inclusiveLeft: true, 1.748 + inclusiveRight: true, 1.749 + collapsed: true, 1.750 + clearOnEnter: autoClear 1.751 + }); 1.752 +} 1.753 + 1.754 +testCM("collapsedLines", function(cm) { 1.755 + addDoc(cm, 4, 10); 1.756 + var range = foldLines(cm, 4, 5), cleared = 0; 1.757 + CodeMirror.on(range, "clear", function() {cleared++;}); 1.758 + cm.setCursor(Pos(3, 0)); 1.759 + CodeMirror.commands.goLineDown(cm); 1.760 + eqPos(cm.getCursor(), Pos(5, 0)); 1.761 + cm.replaceRange("abcdefg", Pos(3, 0), Pos(3)); 1.762 + cm.setCursor(Pos(3, 6)); 1.763 + CodeMirror.commands.goLineDown(cm); 1.764 + eqPos(cm.getCursor(), Pos(5, 4)); 1.765 + cm.replaceRange("ab", Pos(3, 0), Pos(3)); 1.766 + cm.setCursor(Pos(3, 2)); 1.767 + CodeMirror.commands.goLineDown(cm); 1.768 + eqPos(cm.getCursor(), Pos(5, 2)); 1.769 + cm.operation(function() {range.clear(); range.clear();}); 1.770 + eq(cleared, 1); 1.771 +}); 1.772 + 1.773 +testCM("collapsedRangeCoordsChar", function(cm) { 1.774 + var pos_1_3 = cm.charCoords(Pos(1, 3)); 1.775 + pos_1_3.left += 2; pos_1_3.top += 2; 1.776 + var opts = {collapsed: true, inclusiveLeft: true, inclusiveRight: true}; 1.777 + var m1 = cm.markText(Pos(0, 0), Pos(2, 0), opts); 1.778 + eqPos(cm.coordsChar(pos_1_3), Pos(3, 3)); 1.779 + m1.clear(); 1.780 + var m1 = cm.markText(Pos(0, 0), Pos(1, 1), {collapsed: true, inclusiveLeft: true}); 1.781 + var m2 = cm.markText(Pos(1, 1), Pos(2, 0), {collapsed: true, inclusiveRight: true}); 1.782 + eqPos(cm.coordsChar(pos_1_3), Pos(3, 3)); 1.783 + m1.clear(); m2.clear(); 1.784 + var m1 = cm.markText(Pos(0, 0), Pos(1, 6), opts); 1.785 + eqPos(cm.coordsChar(pos_1_3), Pos(3, 3)); 1.786 +}, {value: "123456\nabcdef\nghijkl\nmnopqr\n"}); 1.787 + 1.788 +testCM("collapsedRangeBetweenLinesSelected", function(cm) { 1.789 + var widget = document.createElement("span"); 1.790 + widget.textContent = "\u2194"; 1.791 + cm.markText(Pos(0, 3), Pos(1, 0), {replacedWith: widget}); 1.792 + cm.setSelection(Pos(0, 3), Pos(1, 0)); 1.793 + var selElts = byClassName(cm.getWrapperElement(), "CodeMirror-selected"); 1.794 + for (var i = 0, w = 0; i < selElts.length; i++) 1.795 + w += selElts[i].offsetWidth; 1.796 + is(w > 0); 1.797 +}, {value: "one\ntwo"}); 1.798 + 1.799 +testCM("randomCollapsedRanges", function(cm) { 1.800 + addDoc(cm, 20, 500); 1.801 + cm.operation(function() { 1.802 + for (var i = 0; i < 200; i++) { 1.803 + var start = Pos(Math.floor(Math.random() * 500), Math.floor(Math.random() * 20)); 1.804 + if (i % 4) 1.805 + try { cm.markText(start, Pos(start.line + 2, 1), {collapsed: true}); } 1.806 + catch(e) { if (!/overlapping/.test(String(e))) throw e; } 1.807 + else 1.808 + cm.markText(start, Pos(start.line, start.ch + 4), {"className": "foo"}); 1.809 + } 1.810 + }); 1.811 +}); 1.812 + 1.813 +testCM("hiddenLinesAutoUnfold", function(cm) { 1.814 + var range = foldLines(cm, 1, 3, true), cleared = 0; 1.815 + CodeMirror.on(range, "clear", function() {cleared++;}); 1.816 + cm.setCursor(Pos(3, 0)); 1.817 + eq(cleared, 0); 1.818 + cm.execCommand("goCharLeft"); 1.819 + eq(cleared, 1); 1.820 + range = foldLines(cm, 1, 3, true); 1.821 + CodeMirror.on(range, "clear", function() {cleared++;}); 1.822 + eqPos(cm.getCursor(), Pos(3, 0)); 1.823 + cm.setCursor(Pos(0, 3)); 1.824 + cm.execCommand("goCharRight"); 1.825 + eq(cleared, 2); 1.826 +}, {value: "abc\ndef\nghi\njkl"}); 1.827 + 1.828 +testCM("hiddenLinesSelectAll", function(cm) { // Issue #484 1.829 + addDoc(cm, 4, 20); 1.830 + foldLines(cm, 0, 10); 1.831 + foldLines(cm, 11, 20); 1.832 + CodeMirror.commands.selectAll(cm); 1.833 + eqPos(cm.getCursor(true), Pos(10, 0)); 1.834 + eqPos(cm.getCursor(false), Pos(10, 4)); 1.835 +}); 1.836 + 1.837 + 1.838 +testCM("everythingFolded", function(cm) { 1.839 + addDoc(cm, 2, 2); 1.840 + function enterPress() { 1.841 + cm.triggerOnKeyDown({type: "keydown", keyCode: 13, preventDefault: function(){}, stopPropagation: function(){}}); 1.842 + } 1.843 + var fold = foldLines(cm, 0, 2); 1.844 + enterPress(); 1.845 + eq(cm.getValue(), "xx\nxx"); 1.846 + fold.clear(); 1.847 + fold = foldLines(cm, 0, 2, true); 1.848 + eq(fold.find(), null); 1.849 + enterPress(); 1.850 + eq(cm.getValue(), "\nxx\nxx"); 1.851 +}); 1.852 + 1.853 +testCM("structuredFold", function(cm) { 1.854 + if (phantom) return; 1.855 + addDoc(cm, 4, 8); 1.856 + var range = cm.markText(Pos(1, 2), Pos(6, 2), { 1.857 + replacedWith: document.createTextNode("Q") 1.858 + }); 1.859 + cm.setCursor(0, 3); 1.860 + CodeMirror.commands.goLineDown(cm); 1.861 + eqPos(cm.getCursor(), Pos(6, 2)); 1.862 + CodeMirror.commands.goCharLeft(cm); 1.863 + eqPos(cm.getCursor(), Pos(1, 2)); 1.864 + CodeMirror.commands.delCharAfter(cm); 1.865 + eq(cm.getValue(), "xxxx\nxxxx\nxxxx"); 1.866 + addDoc(cm, 4, 8); 1.867 + range = cm.markText(Pos(1, 2), Pos(6, 2), { 1.868 + replacedWith: document.createTextNode("M"), 1.869 + clearOnEnter: true 1.870 + }); 1.871 + var cleared = 0; 1.872 + CodeMirror.on(range, "clear", function(){++cleared;}); 1.873 + cm.setCursor(0, 3); 1.874 + CodeMirror.commands.goLineDown(cm); 1.875 + eqPos(cm.getCursor(), Pos(6, 2)); 1.876 + CodeMirror.commands.goCharLeft(cm); 1.877 + eqPos(cm.getCursor(), Pos(6, 1)); 1.878 + eq(cleared, 1); 1.879 + range.clear(); 1.880 + eq(cleared, 1); 1.881 + range = cm.markText(Pos(1, 2), Pos(6, 2), { 1.882 + replacedWith: document.createTextNode("Q"), 1.883 + clearOnEnter: true 1.884 + }); 1.885 + range.clear(); 1.886 + cm.setCursor(1, 2); 1.887 + CodeMirror.commands.goCharRight(cm); 1.888 + eqPos(cm.getCursor(), Pos(1, 3)); 1.889 + range = cm.markText(Pos(2, 0), Pos(4, 4), { 1.890 + replacedWith: document.createTextNode("M") 1.891 + }); 1.892 + cm.setCursor(1, 0); 1.893 + CodeMirror.commands.goLineDown(cm); 1.894 + eqPos(cm.getCursor(), Pos(2, 0)); 1.895 +}, null); 1.896 + 1.897 +testCM("nestedFold", function(cm) { 1.898 + addDoc(cm, 10, 3); 1.899 + function fold(ll, cl, lr, cr) { 1.900 + return cm.markText(Pos(ll, cl), Pos(lr, cr), {collapsed: true}); 1.901 + } 1.902 + var inner1 = fold(0, 6, 1, 3), inner2 = fold(0, 2, 1, 8), outer = fold(0, 1, 2, 3), inner0 = fold(0, 5, 0, 6); 1.903 + cm.setCursor(0, 1); 1.904 + CodeMirror.commands.goCharRight(cm); 1.905 + eqPos(cm.getCursor(), Pos(2, 3)); 1.906 + inner0.clear(); 1.907 + CodeMirror.commands.goCharLeft(cm); 1.908 + eqPos(cm.getCursor(), Pos(0, 1)); 1.909 + outer.clear(); 1.910 + CodeMirror.commands.goCharRight(cm); 1.911 + eqPos(cm.getCursor(), Pos(0, 2)); 1.912 + CodeMirror.commands.goCharRight(cm); 1.913 + eqPos(cm.getCursor(), Pos(1, 8)); 1.914 + inner2.clear(); 1.915 + CodeMirror.commands.goCharLeft(cm); 1.916 + eqPos(cm.getCursor(), Pos(1, 7)); 1.917 + cm.setCursor(0, 5); 1.918 + CodeMirror.commands.goCharRight(cm); 1.919 + eqPos(cm.getCursor(), Pos(0, 6)); 1.920 + CodeMirror.commands.goCharRight(cm); 1.921 + eqPos(cm.getCursor(), Pos(1, 3)); 1.922 +}); 1.923 + 1.924 +testCM("badNestedFold", function(cm) { 1.925 + addDoc(cm, 4, 4); 1.926 + cm.markText(Pos(0, 2), Pos(3, 2), {collapsed: true}); 1.927 + var caught; 1.928 + try {cm.markText(Pos(0, 1), Pos(0, 3), {collapsed: true});} 1.929 + catch(e) {caught = e;} 1.930 + is(caught instanceof Error, "no error"); 1.931 + is(/overlap/i.test(caught.message), "wrong error"); 1.932 +}); 1.933 + 1.934 +testCM("nestedFoldOnSide", function(cm) { 1.935 + var m1 = cm.markText(Pos(0, 1), Pos(2, 1), {collapsed: true, inclusiveRight: true}); 1.936 + var m2 = cm.markText(Pos(0, 1), Pos(0, 2), {collapsed: true}); 1.937 + cm.markText(Pos(0, 1), Pos(0, 2), {collapsed: true}).clear(); 1.938 + try { cm.markText(Pos(0, 1), Pos(0, 2), {collapsed: true, inclusiveLeft: true}); } 1.939 + catch(e) { var caught = e; } 1.940 + is(caught && /overlap/i.test(caught.message)); 1.941 + var m3 = cm.markText(Pos(2, 0), Pos(2, 1), {collapsed: true}); 1.942 + var m4 = cm.markText(Pos(2, 0), Pos(2, 1), {collapse: true, inclusiveRight: true}); 1.943 + m1.clear(); m4.clear(); 1.944 + m1 = cm.markText(Pos(0, 1), Pos(2, 1), {collapsed: true}); 1.945 + cm.markText(Pos(2, 0), Pos(2, 1), {collapsed: true}).clear(); 1.946 + try { cm.markText(Pos(2, 0), Pos(2, 1), {collapsed: true, inclusiveRight: true}); } 1.947 + catch(e) { var caught = e; } 1.948 + is(caught && /overlap/i.test(caught.message)); 1.949 +}, {value: "ab\ncd\ef"}); 1.950 + 1.951 +testCM("editInFold", function(cm) { 1.952 + addDoc(cm, 4, 6); 1.953 + var m = cm.markText(Pos(1, 2), Pos(3, 2), {collapsed: true}); 1.954 + cm.replaceRange("", Pos(0, 0), Pos(1, 3)); 1.955 + cm.replaceRange("", Pos(2, 1), Pos(3, 3)); 1.956 + cm.replaceRange("a\nb\nc\nd", Pos(0, 1), Pos(1, 0)); 1.957 + cm.cursorCoords(Pos(0, 0)); 1.958 +}); 1.959 + 1.960 +testCM("wrappingInlineWidget", function(cm) { 1.961 + cm.setSize("11em"); 1.962 + var w = document.createElement("span"); 1.963 + w.style.color = "red"; 1.964 + w.innerHTML = "one two three four"; 1.965 + cm.markText(Pos(0, 6), Pos(0, 9), {replacedWith: w}); 1.966 + var cur0 = cm.cursorCoords(Pos(0, 0)), cur1 = cm.cursorCoords(Pos(0, 10)); 1.967 + is(cur0.top < cur1.top); 1.968 + is(cur0.bottom < cur1.bottom); 1.969 + var curL = cm.cursorCoords(Pos(0, 6)), curR = cm.cursorCoords(Pos(0, 9)); 1.970 + eq(curL.top, cur0.top); 1.971 + eq(curL.bottom, cur0.bottom); 1.972 + eq(curR.top, cur1.top); 1.973 + eq(curR.bottom, cur1.bottom); 1.974 + cm.replaceRange("", Pos(0, 9), Pos(0)); 1.975 + curR = cm.cursorCoords(Pos(0, 9)); 1.976 + if (phantom) return; 1.977 + eq(curR.top, cur1.top); 1.978 + eq(curR.bottom, cur1.bottom); 1.979 +}, {value: "1 2 3 xxx 4", lineWrapping: true}); 1.980 + 1.981 +testCM("changedInlineWidget", function(cm) { 1.982 + cm.setSize("10em"); 1.983 + var w = document.createElement("span"); 1.984 + w.innerHTML = "x"; 1.985 + var m = cm.markText(Pos(0, 4), Pos(0, 5), {replacedWith: w}); 1.986 + w.innerHTML = "and now the widget is really really long all of a sudden and a scrollbar is needed"; 1.987 + m.changed(); 1.988 + var hScroll = byClassName(cm.getWrapperElement(), "CodeMirror-hscrollbar")[0]; 1.989 + is(hScroll.scrollWidth > hScroll.clientWidth); 1.990 +}, {value: "hello there"}); 1.991 + 1.992 +testCM("changedBookmark", function(cm) { 1.993 + cm.setSize("10em"); 1.994 + var w = document.createElement("span"); 1.995 + w.innerHTML = "x"; 1.996 + var m = cm.setBookmark(Pos(0, 4), {widget: w}); 1.997 + w.innerHTML = "and now the widget is really really long all of a sudden and a scrollbar is needed"; 1.998 + m.changed(); 1.999 + var hScroll = byClassName(cm.getWrapperElement(), "CodeMirror-hscrollbar")[0]; 1.1000 + is(hScroll.scrollWidth > hScroll.clientWidth); 1.1001 +}, {value: "abcdefg"}); 1.1002 + 1.1003 +testCM("inlineWidget", function(cm) { 1.1004 + var w = cm.setBookmark(Pos(0, 2), {widget: document.createTextNode("uu")}); 1.1005 + cm.setCursor(0, 2); 1.1006 + CodeMirror.commands.goLineDown(cm); 1.1007 + eqPos(cm.getCursor(), Pos(1, 4)); 1.1008 + cm.setCursor(0, 2); 1.1009 + cm.replaceSelection("hi"); 1.1010 + eqPos(w.find(), Pos(0, 2)); 1.1011 + cm.setCursor(0, 1); 1.1012 + cm.replaceSelection("ay"); 1.1013 + eqPos(w.find(), Pos(0, 4)); 1.1014 + eq(cm.getLine(0), "uayuhiuu"); 1.1015 +}, {value: "uuuu\nuuuuuu"}); 1.1016 + 1.1017 +testCM("wrappingAndResizing", function(cm) { 1.1018 + cm.setSize(null, "auto"); 1.1019 + cm.setOption("lineWrapping", true); 1.1020 + var wrap = cm.getWrapperElement(), h0 = wrap.offsetHeight; 1.1021 + var doc = "xxx xxx xxx xxx xxx"; 1.1022 + cm.setValue(doc); 1.1023 + for (var step = 10, w = cm.charCoords(Pos(0, 18), "div").right;; w += step) { 1.1024 + cm.setSize(w); 1.1025 + if (wrap.offsetHeight <= h0 * (opera_lt10 ? 1.2 : 1.5)) { 1.1026 + if (step == 10) { w -= 10; step = 1; } 1.1027 + else break; 1.1028 + } 1.1029 + } 1.1030 + // Ensure that putting the cursor at the end of the maximally long 1.1031 + // line doesn't cause wrapping to happen. 1.1032 + cm.setCursor(Pos(0, doc.length)); 1.1033 + eq(wrap.offsetHeight, h0); 1.1034 + cm.replaceSelection("x"); 1.1035 + is(wrap.offsetHeight > h0, "wrapping happens"); 1.1036 + // Now add a max-height and, in a document consisting of 1.1037 + // almost-wrapped lines, go over it so that a scrollbar appears. 1.1038 + cm.setValue(doc + "\n" + doc + "\n"); 1.1039 + cm.getScrollerElement().style.maxHeight = "100px"; 1.1040 + cm.replaceRange("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n!\n", Pos(2, 0)); 1.1041 + forEach([Pos(0, doc.length), Pos(0, doc.length - 1), 1.1042 + Pos(0, 0), Pos(1, doc.length), Pos(1, doc.length - 1)], 1.1043 + function(pos) { 1.1044 + var coords = cm.charCoords(pos); 1.1045 + eqPos(pos, cm.coordsChar({left: coords.left + 2, top: coords.top + 5})); 1.1046 + }); 1.1047 +}, null, ie_lt8); 1.1048 + 1.1049 +testCM("measureEndOfLine", function(cm) { 1.1050 + cm.setSize(null, "auto"); 1.1051 + var inner = byClassName(cm.getWrapperElement(), "CodeMirror-lines")[0].firstChild; 1.1052 + var lh = inner.offsetHeight; 1.1053 + for (var step = 10, w = cm.charCoords(Pos(0, 7), "div").right;; w += step) { 1.1054 + cm.setSize(w); 1.1055 + if (inner.offsetHeight < 2.5 * lh) { 1.1056 + if (step == 10) { w -= 10; step = 1; } 1.1057 + else break; 1.1058 + } 1.1059 + } 1.1060 + cm.setValue(cm.getValue() + "\n\n"); 1.1061 + var endPos = cm.charCoords(Pos(0, 18), "local"); 1.1062 + is(endPos.top > lh * .8, "not at top"); 1.1063 + is(endPos.left > w - 20, "not at right"); 1.1064 + endPos = cm.charCoords(Pos(0, 18)); 1.1065 + eqPos(cm.coordsChar({left: endPos.left, top: endPos.top + 5}), Pos(0, 18)); 1.1066 +}, {mode: "text/html", value: "<!-- foo barrr -->", lineWrapping: true}, ie_lt8 || opera_lt10); 1.1067 + 1.1068 +testCM("scrollVerticallyAndHorizontally", function(cm) { 1.1069 + cm.setSize(100, 100); 1.1070 + addDoc(cm, 40, 40); 1.1071 + cm.setCursor(39); 1.1072 + var wrap = cm.getWrapperElement(), bar = byClassName(wrap, "CodeMirror-vscrollbar")[0]; 1.1073 + is(bar.offsetHeight < wrap.offsetHeight, "vertical scrollbar limited by horizontal one"); 1.1074 + var cursorBox = byClassName(wrap, "CodeMirror-cursor")[0].getBoundingClientRect(); 1.1075 + var editorBox = wrap.getBoundingClientRect(); 1.1076 + is(cursorBox.bottom < editorBox.top + cm.getScrollerElement().clientHeight, 1.1077 + "bottom line visible"); 1.1078 +}, {lineNumbers: true}); 1.1079 + 1.1080 +testCM("moveVstuck", function(cm) { 1.1081 + var lines = byClassName(cm.getWrapperElement(), "CodeMirror-lines")[0].firstChild, h0 = lines.offsetHeight; 1.1082 + var val = "fooooooooooooooooooooooooo baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar\n"; 1.1083 + cm.setValue(val); 1.1084 + for (var w = cm.charCoords(Pos(0, 26), "div").right * 2.8;; w += 5) { 1.1085 + cm.setSize(w); 1.1086 + if (lines.offsetHeight <= 3.5 * h0) break; 1.1087 + } 1.1088 + cm.setCursor(Pos(0, val.length - 1)); 1.1089 + cm.moveV(-1, "line"); 1.1090 + eqPos(cm.getCursor(), Pos(0, 26)); 1.1091 +}, {lineWrapping: true}, ie_lt8 || opera_lt10); 1.1092 + 1.1093 +testCM("collapseOnMove", function(cm) { 1.1094 + cm.setSelection(Pos(0, 1), Pos(2, 4)); 1.1095 + cm.execCommand("goLineUp"); 1.1096 + is(!cm.somethingSelected()); 1.1097 + eqPos(cm.getCursor(), Pos(0, 1)); 1.1098 + cm.setSelection(Pos(0, 1), Pos(2, 4)); 1.1099 + cm.execCommand("goPageDown"); 1.1100 + is(!cm.somethingSelected()); 1.1101 + eqPos(cm.getCursor(), Pos(2, 4)); 1.1102 + cm.execCommand("goLineUp"); 1.1103 + cm.execCommand("goLineUp"); 1.1104 + eqPos(cm.getCursor(), Pos(0, 4)); 1.1105 + cm.setSelection(Pos(0, 1), Pos(2, 4)); 1.1106 + cm.execCommand("goCharLeft"); 1.1107 + is(!cm.somethingSelected()); 1.1108 + eqPos(cm.getCursor(), Pos(0, 1)); 1.1109 +}, {value: "aaaaa\nb\nccccc"}); 1.1110 + 1.1111 +testCM("clickTab", function(cm) { 1.1112 + var p0 = cm.charCoords(Pos(0, 0)); 1.1113 + eqPos(cm.coordsChar({left: p0.left + 5, top: p0.top + 5}), Pos(0, 0)); 1.1114 + eqPos(cm.coordsChar({left: p0.right - 5, top: p0.top + 5}), Pos(0, 1)); 1.1115 +}, {value: "\t\n\n", lineWrapping: true, tabSize: 8}); 1.1116 + 1.1117 +testCM("verticalScroll", function(cm) { 1.1118 + cm.setSize(100, 200); 1.1119 + cm.setValue("foo\nbar\nbaz\n"); 1.1120 + var sc = cm.getScrollerElement(), baseWidth = sc.scrollWidth; 1.1121 + cm.replaceRange("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaah", Pos(0, 0), Pos(0)); 1.1122 + is(sc.scrollWidth > baseWidth, "scrollbar present"); 1.1123 + cm.replaceRange("foo", Pos(0, 0), Pos(0)); 1.1124 + if (!phantom) eq(sc.scrollWidth, baseWidth, "scrollbar gone"); 1.1125 + cm.replaceRange("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaah", Pos(0, 0), Pos(0)); 1.1126 + cm.replaceRange("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbh", Pos(1, 0), Pos(1)); 1.1127 + is(sc.scrollWidth > baseWidth, "present again"); 1.1128 + var curWidth = sc.scrollWidth; 1.1129 + cm.replaceRange("foo", Pos(0, 0), Pos(0)); 1.1130 + is(sc.scrollWidth < curWidth, "scrollbar smaller"); 1.1131 + is(sc.scrollWidth > baseWidth, "but still present"); 1.1132 +}); 1.1133 + 1.1134 +testCM("extraKeys", function(cm) { 1.1135 + var outcome; 1.1136 + function fakeKey(expected, code, props) { 1.1137 + if (typeof code == "string") code = code.charCodeAt(0); 1.1138 + var e = {type: "keydown", keyCode: code, preventDefault: function(){}, stopPropagation: function(){}}; 1.1139 + if (props) for (var n in props) e[n] = props[n]; 1.1140 + outcome = null; 1.1141 + cm.triggerOnKeyDown(e); 1.1142 + eq(outcome, expected); 1.1143 + } 1.1144 + CodeMirror.commands.testCommand = function() {outcome = "tc";}; 1.1145 + CodeMirror.commands.goTestCommand = function() {outcome = "gtc";}; 1.1146 + cm.setOption("extraKeys", {"Shift-X": function() {outcome = "sx";}, 1.1147 + "X": function() {outcome = "x";}, 1.1148 + "Ctrl-Alt-U": function() {outcome = "cau";}, 1.1149 + "End": "testCommand", 1.1150 + "Home": "goTestCommand", 1.1151 + "Tab": false}); 1.1152 + fakeKey(null, "U"); 1.1153 + fakeKey("cau", "U", {ctrlKey: true, altKey: true}); 1.1154 + fakeKey(null, "U", {shiftKey: true, ctrlKey: true, altKey: true}); 1.1155 + fakeKey("x", "X"); 1.1156 + fakeKey("sx", "X", {shiftKey: true}); 1.1157 + fakeKey("tc", 35); 1.1158 + fakeKey(null, 35, {shiftKey: true}); 1.1159 + fakeKey("gtc", 36); 1.1160 + fakeKey("gtc", 36, {shiftKey: true}); 1.1161 + fakeKey(null, 9); 1.1162 +}, null, window.opera && mac); 1.1163 + 1.1164 +testCM("wordMovementCommands", function(cm) { 1.1165 + cm.execCommand("goWordLeft"); 1.1166 + eqPos(cm.getCursor(), Pos(0, 0)); 1.1167 + cm.execCommand("goWordRight"); cm.execCommand("goWordRight"); 1.1168 + eqPos(cm.getCursor(), Pos(0, 7)); 1.1169 + cm.execCommand("goWordLeft"); 1.1170 + eqPos(cm.getCursor(), Pos(0, 5)); 1.1171 + cm.execCommand("goWordRight"); cm.execCommand("goWordRight"); 1.1172 + eqPos(cm.getCursor(), Pos(0, 12)); 1.1173 + cm.execCommand("goWordLeft"); 1.1174 + eqPos(cm.getCursor(), Pos(0, 9)); 1.1175 + cm.execCommand("goWordRight"); cm.execCommand("goWordRight"); cm.execCommand("goWordRight"); 1.1176 + eqPos(cm.getCursor(), Pos(0, 24)); 1.1177 + cm.execCommand("goWordRight"); cm.execCommand("goWordRight"); 1.1178 + eqPos(cm.getCursor(), Pos(1, 9)); 1.1179 + cm.execCommand("goWordRight"); 1.1180 + eqPos(cm.getCursor(), Pos(1, 13)); 1.1181 + cm.execCommand("goWordRight"); cm.execCommand("goWordRight"); 1.1182 + eqPos(cm.getCursor(), Pos(2, 0)); 1.1183 +}, {value: "this is (the) firstline.\na foo12\u00e9\u00f8\u00d7bar\n"}); 1.1184 + 1.1185 +testCM("groupMovementCommands", function(cm) { 1.1186 + cm.execCommand("goGroupLeft"); 1.1187 + eqPos(cm.getCursor(), Pos(0, 0)); 1.1188 + cm.execCommand("goGroupRight"); 1.1189 + eqPos(cm.getCursor(), Pos(0, 4)); 1.1190 + cm.execCommand("goGroupRight"); 1.1191 + eqPos(cm.getCursor(), Pos(0, 7)); 1.1192 + cm.execCommand("goGroupRight"); 1.1193 + eqPos(cm.getCursor(), Pos(0, 10)); 1.1194 + cm.execCommand("goGroupLeft"); 1.1195 + eqPos(cm.getCursor(), Pos(0, 7)); 1.1196 + cm.execCommand("goGroupRight"); cm.execCommand("goGroupRight"); cm.execCommand("goGroupRight"); 1.1197 + eqPos(cm.getCursor(), Pos(0, 15)); 1.1198 + cm.setCursor(Pos(0, 17)); 1.1199 + cm.execCommand("goGroupLeft"); 1.1200 + eqPos(cm.getCursor(), Pos(0, 16)); 1.1201 + cm.execCommand("goGroupLeft"); 1.1202 + eqPos(cm.getCursor(), Pos(0, 14)); 1.1203 + cm.execCommand("goGroupRight"); cm.execCommand("goGroupRight"); 1.1204 + eqPos(cm.getCursor(), Pos(0, 20)); 1.1205 + cm.execCommand("goGroupRight"); 1.1206 + eqPos(cm.getCursor(), Pos(1, 0)); 1.1207 + cm.execCommand("goGroupRight"); 1.1208 + eqPos(cm.getCursor(), Pos(1, 2)); 1.1209 + cm.execCommand("goGroupRight"); 1.1210 + eqPos(cm.getCursor(), Pos(1, 5)); 1.1211 + cm.execCommand("goGroupLeft"); cm.execCommand("goGroupLeft"); 1.1212 + eqPos(cm.getCursor(), Pos(1, 0)); 1.1213 + cm.execCommand("goGroupLeft"); 1.1214 + eqPos(cm.getCursor(), Pos(0, 20)); 1.1215 + cm.execCommand("goGroupLeft"); 1.1216 + eqPos(cm.getCursor(), Pos(0, 16)); 1.1217 +}, {value: "booo ba---quux. ffff\n abc d"}); 1.1218 + 1.1219 +testCM("groupsAndWhitespace", function(cm) { 1.1220 + var positions = [Pos(0, 0), Pos(0, 2), Pos(0, 5), Pos(0, 9), Pos(0, 11), 1.1221 + Pos(1, 0), Pos(1, 2), Pos(1, 5)]; 1.1222 + for (var i = 1; i < positions.length; i++) { 1.1223 + cm.execCommand("goGroupRight"); 1.1224 + eqPos(cm.getCursor(), positions[i]); 1.1225 + } 1.1226 + for (var i = positions.length - 2; i >= 0; i--) { 1.1227 + cm.execCommand("goGroupLeft"); 1.1228 + eqPos(cm.getCursor(), i == 2 ? Pos(0, 6) : positions[i]); 1.1229 + } 1.1230 +}, {value: " foo +++ \n bar"}); 1.1231 + 1.1232 +testCM("charMovementCommands", function(cm) { 1.1233 + cm.execCommand("goCharLeft"); cm.execCommand("goColumnLeft"); 1.1234 + eqPos(cm.getCursor(), Pos(0, 0)); 1.1235 + cm.execCommand("goCharRight"); cm.execCommand("goCharRight"); 1.1236 + eqPos(cm.getCursor(), Pos(0, 2)); 1.1237 + cm.setCursor(Pos(1, 0)); 1.1238 + cm.execCommand("goColumnLeft"); 1.1239 + eqPos(cm.getCursor(), Pos(1, 0)); 1.1240 + cm.execCommand("goCharLeft"); 1.1241 + eqPos(cm.getCursor(), Pos(0, 5)); 1.1242 + cm.execCommand("goColumnRight"); 1.1243 + eqPos(cm.getCursor(), Pos(0, 5)); 1.1244 + cm.execCommand("goCharRight"); 1.1245 + eqPos(cm.getCursor(), Pos(1, 0)); 1.1246 + cm.execCommand("goLineEnd"); 1.1247 + eqPos(cm.getCursor(), Pos(1, 5)); 1.1248 + cm.execCommand("goLineStartSmart"); 1.1249 + eqPos(cm.getCursor(), Pos(1, 1)); 1.1250 + cm.execCommand("goLineStartSmart"); 1.1251 + eqPos(cm.getCursor(), Pos(1, 0)); 1.1252 + cm.setCursor(Pos(2, 0)); 1.1253 + cm.execCommand("goCharRight"); cm.execCommand("goColumnRight"); 1.1254 + eqPos(cm.getCursor(), Pos(2, 0)); 1.1255 +}, {value: "line1\n ine2\n"}); 1.1256 + 1.1257 +testCM("verticalMovementCommands", function(cm) { 1.1258 + cm.execCommand("goLineUp"); 1.1259 + eqPos(cm.getCursor(), Pos(0, 0)); 1.1260 + cm.execCommand("goLineDown"); 1.1261 + if (!phantom) // This fails in PhantomJS, though not in a real Webkit 1.1262 + eqPos(cm.getCursor(), Pos(1, 0)); 1.1263 + cm.setCursor(Pos(1, 12)); 1.1264 + cm.execCommand("goLineDown"); 1.1265 + eqPos(cm.getCursor(), Pos(2, 5)); 1.1266 + cm.execCommand("goLineDown"); 1.1267 + eqPos(cm.getCursor(), Pos(3, 0)); 1.1268 + cm.execCommand("goLineUp"); 1.1269 + eqPos(cm.getCursor(), Pos(2, 5)); 1.1270 + cm.execCommand("goLineUp"); 1.1271 + eqPos(cm.getCursor(), Pos(1, 12)); 1.1272 + cm.execCommand("goPageDown"); 1.1273 + eqPos(cm.getCursor(), Pos(5, 0)); 1.1274 + cm.execCommand("goPageDown"); cm.execCommand("goLineDown"); 1.1275 + eqPos(cm.getCursor(), Pos(5, 0)); 1.1276 + cm.execCommand("goPageUp"); 1.1277 + eqPos(cm.getCursor(), Pos(0, 0)); 1.1278 +}, {value: "line1\nlong long line2\nline3\n\nline5\n"}); 1.1279 + 1.1280 +testCM("verticalMovementCommandsWrapping", function(cm) { 1.1281 + cm.setSize(120); 1.1282 + cm.setCursor(Pos(0, 5)); 1.1283 + cm.execCommand("goLineDown"); 1.1284 + eq(cm.getCursor().line, 0); 1.1285 + is(cm.getCursor().ch > 5, "moved beyond wrap"); 1.1286 + for (var i = 0; ; ++i) { 1.1287 + is(i < 20, "no endless loop"); 1.1288 + cm.execCommand("goLineDown"); 1.1289 + var cur = cm.getCursor(); 1.1290 + if (cur.line == 1) eq(cur.ch, 5); 1.1291 + if (cur.line == 2) { eq(cur.ch, 1); break; } 1.1292 + } 1.1293 +}, {value: "a very long line that wraps around somehow so that we can test cursor movement\nshortone\nk", 1.1294 + lineWrapping: true}); 1.1295 + 1.1296 +testCM("rtlMovement", function(cm) { 1.1297 + forEach(["خحج", "خحabcخحج", "abخحخحجcd", "abخde", "abخح2342خ1حج", "خ1ح2خح3حxج", 1.1298 + "خحcd", "1خحcd", "abcdeح1ج", "خمرحبها مها!", "foobarر", "خ ة ق", 1.1299 + "<img src=\"/בדיקה3.jpg\">"], function(line) { 1.1300 + var inv = line.charAt(0) == "خ"; 1.1301 + cm.setValue(line + "\n"); cm.execCommand(inv ? "goLineEnd" : "goLineStart"); 1.1302 + var cursors = byClassName(cm.getWrapperElement(), "CodeMirror-cursors")[0]; 1.1303 + var cursor = cursors.firstChild; 1.1304 + var prevX = cursor.offsetLeft, prevY = cursor.offsetTop; 1.1305 + for (var i = 0; i <= line.length; ++i) { 1.1306 + cm.execCommand("goCharRight"); 1.1307 + cursor = cursors.firstChild; 1.1308 + if (i == line.length) is(cursor.offsetTop > prevY, "next line"); 1.1309 + else is(cursor.offsetLeft > prevX, "moved right"); 1.1310 + prevX = cursor.offsetLeft; prevY = cursor.offsetTop; 1.1311 + } 1.1312 + cm.setCursor(0, 0); cm.execCommand(inv ? "goLineStart" : "goLineEnd"); 1.1313 + prevX = cursors.firstChild.offsetLeft; 1.1314 + for (var i = 0; i < line.length; ++i) { 1.1315 + cm.execCommand("goCharLeft"); 1.1316 + cursor = cursors.firstChild; 1.1317 + is(cursor.offsetLeft < prevX, "moved left"); 1.1318 + prevX = cursor.offsetLeft; 1.1319 + } 1.1320 + }); 1.1321 +}, null, ie_lt9); 1.1322 + 1.1323 +// Verify that updating a line clears its bidi ordering 1.1324 +testCM("bidiUpdate", function(cm) { 1.1325 + cm.setCursor(Pos(0, 2)); 1.1326 + cm.replaceSelection("خحج", "start"); 1.1327 + cm.execCommand("goCharRight"); 1.1328 + eqPos(cm.getCursor(), Pos(0, 4)); 1.1329 +}, {value: "abcd\n"}); 1.1330 + 1.1331 +testCM("movebyTextUnit", function(cm) { 1.1332 + cm.setValue("בְּרֵאשִ\nééé́\n"); 1.1333 + cm.execCommand("goLineEnd"); 1.1334 + for (var i = 0; i < 4; ++i) cm.execCommand("goCharRight"); 1.1335 + eqPos(cm.getCursor(), Pos(0, 0)); 1.1336 + cm.execCommand("goCharRight"); 1.1337 + eqPos(cm.getCursor(), Pos(1, 0)); 1.1338 + cm.execCommand("goCharRight"); 1.1339 + cm.execCommand("goCharRight"); 1.1340 + eqPos(cm.getCursor(), Pos(1, 4)); 1.1341 + cm.execCommand("goCharRight"); 1.1342 + eqPos(cm.getCursor(), Pos(1, 7)); 1.1343 +}); 1.1344 + 1.1345 +testCM("lineChangeEvents", function(cm) { 1.1346 + addDoc(cm, 3, 5); 1.1347 + var log = [], want = ["ch 0", "ch 1", "del 2", "ch 0", "ch 0", "del 1", "del 3", "del 4"]; 1.1348 + for (var i = 0; i < 5; ++i) { 1.1349 + CodeMirror.on(cm.getLineHandle(i), "delete", function(i) { 1.1350 + return function() {log.push("del " + i);}; 1.1351 + }(i)); 1.1352 + CodeMirror.on(cm.getLineHandle(i), "change", function(i) { 1.1353 + return function() {log.push("ch " + i);}; 1.1354 + }(i)); 1.1355 + } 1.1356 + cm.replaceRange("x", Pos(0, 1)); 1.1357 + cm.replaceRange("xy", Pos(1, 1), Pos(2)); 1.1358 + cm.replaceRange("foo\nbar", Pos(0, 1)); 1.1359 + cm.replaceRange("", Pos(0, 0), Pos(cm.lineCount())); 1.1360 + eq(log.length, want.length, "same length"); 1.1361 + for (var i = 0; i < log.length; ++i) 1.1362 + eq(log[i], want[i]); 1.1363 +}); 1.1364 + 1.1365 +testCM("scrollEntirelyToRight", function(cm) { 1.1366 + if (phantom) return; 1.1367 + addDoc(cm, 500, 2); 1.1368 + cm.setCursor(Pos(0, 500)); 1.1369 + var wrap = cm.getWrapperElement(), cur = byClassName(wrap, "CodeMirror-cursor")[0]; 1.1370 + is(wrap.getBoundingClientRect().right > cur.getBoundingClientRect().left); 1.1371 +}); 1.1372 + 1.1373 +testCM("lineWidgets", function(cm) { 1.1374 + addDoc(cm, 500, 3); 1.1375 + var last = cm.charCoords(Pos(2, 0)); 1.1376 + var node = document.createElement("div"); 1.1377 + node.innerHTML = "hi"; 1.1378 + var widget = cm.addLineWidget(1, node); 1.1379 + is(last.top < cm.charCoords(Pos(2, 0)).top, "took up space"); 1.1380 + cm.setCursor(Pos(1, 1)); 1.1381 + cm.execCommand("goLineDown"); 1.1382 + eqPos(cm.getCursor(), Pos(2, 1)); 1.1383 + cm.execCommand("goLineUp"); 1.1384 + eqPos(cm.getCursor(), Pos(1, 1)); 1.1385 +}); 1.1386 + 1.1387 +testCM("lineWidgetFocus", function(cm) { 1.1388 + var place = document.getElementById("testground"); 1.1389 + place.className = "offscreen"; 1.1390 + try { 1.1391 + addDoc(cm, 500, 10); 1.1392 + var node = document.createElement("input"); 1.1393 + var widget = cm.addLineWidget(1, node); 1.1394 + node.focus(); 1.1395 + eq(document.activeElement, node); 1.1396 + cm.replaceRange("new stuff", Pos(1, 0)); 1.1397 + eq(document.activeElement, node); 1.1398 + } finally { 1.1399 + place.className = ""; 1.1400 + } 1.1401 +}); 1.1402 + 1.1403 +testCM("lineWidgetCautiousRedraw", function(cm) { 1.1404 + var node = document.createElement("div"); 1.1405 + node.innerHTML = "hahah"; 1.1406 + var w = cm.addLineWidget(0, node); 1.1407 + var redrawn = false; 1.1408 + w.on("redraw", function() { redrawn = true; }); 1.1409 + cm.replaceSelection("0"); 1.1410 + is(!redrawn); 1.1411 +}, {value: "123\n456"}); 1.1412 + 1.1413 +testCM("lineWidgetChanged", function(cm) { 1.1414 + addDoc(cm, 2, 300); 1.1415 + cm.setSize(null, cm.defaultTextHeight() * 50); 1.1416 + cm.scrollTo(null, cm.heightAtLine(125, "local")); 1.1417 + function w() { 1.1418 + var node = document.createElement("div"); 1.1419 + node.style.cssText = "background: yellow; height: 50px;"; 1.1420 + return node; 1.1421 + } 1.1422 + var info0 = cm.getScrollInfo(); 1.1423 + var w0 = cm.addLineWidget(0, w()); 1.1424 + var w150 = cm.addLineWidget(150, w()); 1.1425 + var w300 = cm.addLineWidget(300, w()); 1.1426 + var info1 = cm.getScrollInfo(); 1.1427 + eq(info0.height + 150, info1.height); 1.1428 + eq(info0.top + 50, info1.top); 1.1429 + w0.node.style.height = w150.node.style.height = w300.node.style.height = "10px"; 1.1430 + w0.changed(); w150.changed(); w300.changed(); 1.1431 + var info2 = cm.getScrollInfo(); 1.1432 + eq(info0.height + 30, info2.height); 1.1433 + eq(info0.top + 10, info2.top); 1.1434 +}); 1.1435 + 1.1436 +testCM("getLineNumber", function(cm) { 1.1437 + addDoc(cm, 2, 20); 1.1438 + var h1 = cm.getLineHandle(1); 1.1439 + eq(cm.getLineNumber(h1), 1); 1.1440 + cm.replaceRange("hi\nbye\n", Pos(0, 0)); 1.1441 + eq(cm.getLineNumber(h1), 3); 1.1442 + cm.setValue(""); 1.1443 + eq(cm.getLineNumber(h1), null); 1.1444 +}); 1.1445 + 1.1446 +testCM("jumpTheGap", function(cm) { 1.1447 + if (phantom) return; 1.1448 + var longLine = "abcdef ghiklmnop qrstuvw xyz "; 1.1449 + longLine += longLine; longLine += longLine; longLine += longLine; 1.1450 + cm.replaceRange(longLine, Pos(2, 0), Pos(2)); 1.1451 + cm.setSize("200px", null); 1.1452 + cm.getWrapperElement().style.lineHeight = 2; 1.1453 + cm.refresh(); 1.1454 + cm.setCursor(Pos(0, 1)); 1.1455 + cm.execCommand("goLineDown"); 1.1456 + eqPos(cm.getCursor(), Pos(1, 1)); 1.1457 + cm.execCommand("goLineDown"); 1.1458 + eqPos(cm.getCursor(), Pos(2, 1)); 1.1459 + cm.execCommand("goLineDown"); 1.1460 + eq(cm.getCursor().line, 2); 1.1461 + is(cm.getCursor().ch > 1); 1.1462 + cm.execCommand("goLineUp"); 1.1463 + eqPos(cm.getCursor(), Pos(2, 1)); 1.1464 + cm.execCommand("goLineUp"); 1.1465 + eqPos(cm.getCursor(), Pos(1, 1)); 1.1466 + var node = document.createElement("div"); 1.1467 + node.innerHTML = "hi"; node.style.height = "30px"; 1.1468 + cm.addLineWidget(0, node); 1.1469 + cm.addLineWidget(1, node.cloneNode(true), {above: true}); 1.1470 + cm.setCursor(Pos(0, 2)); 1.1471 + cm.execCommand("goLineDown"); 1.1472 + eqPos(cm.getCursor(), Pos(1, 2)); 1.1473 + cm.execCommand("goLineUp"); 1.1474 + eqPos(cm.getCursor(), Pos(0, 2)); 1.1475 +}, {lineWrapping: true, value: "abc\ndef\nghi\njkl\n"}); 1.1476 + 1.1477 +testCM("addLineClass", function(cm) { 1.1478 + function cls(line, text, bg, wrap) { 1.1479 + var i = cm.lineInfo(line); 1.1480 + eq(i.textClass, text); 1.1481 + eq(i.bgClass, bg); 1.1482 + eq(i.wrapClass, wrap); 1.1483 + } 1.1484 + cm.addLineClass(0, "text", "foo"); 1.1485 + cm.addLineClass(0, "text", "bar"); 1.1486 + cm.addLineClass(1, "background", "baz"); 1.1487 + cm.addLineClass(1, "wrap", "foo"); 1.1488 + cls(0, "foo bar", null, null); 1.1489 + cls(1, null, "baz", "foo"); 1.1490 + var lines = cm.display.lineDiv; 1.1491 + eq(byClassName(lines, "foo").length, 2); 1.1492 + eq(byClassName(lines, "bar").length, 1); 1.1493 + eq(byClassName(lines, "baz").length, 1); 1.1494 + cm.removeLineClass(0, "text", "foo"); 1.1495 + cls(0, "bar", null, null); 1.1496 + cm.removeLineClass(0, "text", "foo"); 1.1497 + cls(0, "bar", null, null); 1.1498 + cm.removeLineClass(0, "text", "bar"); 1.1499 + cls(0, null, null, null); 1.1500 + cm.addLineClass(1, "wrap", "quux"); 1.1501 + cls(1, null, "baz", "foo quux"); 1.1502 + cm.removeLineClass(1, "wrap"); 1.1503 + cls(1, null, "baz", null); 1.1504 +}, {value: "hohoho\n"}); 1.1505 + 1.1506 +testCM("atomicMarker", function(cm) { 1.1507 + addDoc(cm, 10, 10); 1.1508 + function atom(ll, cl, lr, cr, li, ri) { 1.1509 + return cm.markText(Pos(ll, cl), Pos(lr, cr), 1.1510 + {atomic: true, inclusiveLeft: li, inclusiveRight: ri}); 1.1511 + } 1.1512 + var m = atom(0, 1, 0, 5); 1.1513 + cm.setCursor(Pos(0, 1)); 1.1514 + cm.execCommand("goCharRight"); 1.1515 + eqPos(cm.getCursor(), Pos(0, 5)); 1.1516 + cm.execCommand("goCharLeft"); 1.1517 + eqPos(cm.getCursor(), Pos(0, 1)); 1.1518 + m.clear(); 1.1519 + m = atom(0, 0, 0, 5, true); 1.1520 + eqPos(cm.getCursor(), Pos(0, 5), "pushed out"); 1.1521 + cm.execCommand("goCharLeft"); 1.1522 + eqPos(cm.getCursor(), Pos(0, 5)); 1.1523 + m.clear(); 1.1524 + m = atom(8, 4, 9, 10, false, true); 1.1525 + cm.setCursor(Pos(9, 8)); 1.1526 + eqPos(cm.getCursor(), Pos(8, 4), "set"); 1.1527 + cm.execCommand("goCharRight"); 1.1528 + eqPos(cm.getCursor(), Pos(8, 4), "char right"); 1.1529 + cm.execCommand("goLineDown"); 1.1530 + eqPos(cm.getCursor(), Pos(8, 4), "line down"); 1.1531 + cm.execCommand("goCharLeft"); 1.1532 + eqPos(cm.getCursor(), Pos(8, 3)); 1.1533 + m.clear(); 1.1534 + m = atom(1, 1, 3, 8); 1.1535 + cm.setCursor(Pos(0, 0)); 1.1536 + cm.setCursor(Pos(2, 0)); 1.1537 + eqPos(cm.getCursor(), Pos(3, 8)); 1.1538 + cm.execCommand("goCharLeft"); 1.1539 + eqPos(cm.getCursor(), Pos(1, 1)); 1.1540 + cm.execCommand("goCharRight"); 1.1541 + eqPos(cm.getCursor(), Pos(3, 8)); 1.1542 + cm.execCommand("goLineUp"); 1.1543 + eqPos(cm.getCursor(), Pos(1, 1)); 1.1544 + cm.execCommand("goLineDown"); 1.1545 + eqPos(cm.getCursor(), Pos(3, 8)); 1.1546 + cm.execCommand("delCharBefore"); 1.1547 + eq(cm.getValue().length, 80, "del chunk"); 1.1548 + m = atom(3, 0, 5, 5); 1.1549 + cm.setCursor(Pos(3, 0)); 1.1550 + cm.execCommand("delWordAfter"); 1.1551 + eq(cm.getValue().length, 53, "del chunk"); 1.1552 +}); 1.1553 + 1.1554 +testCM("readOnlyMarker", function(cm) { 1.1555 + function mark(ll, cl, lr, cr, at) { 1.1556 + return cm.markText(Pos(ll, cl), Pos(lr, cr), 1.1557 + {readOnly: true, atomic: at}); 1.1558 + } 1.1559 + var m = mark(0, 1, 0, 4); 1.1560 + cm.setCursor(Pos(0, 2)); 1.1561 + cm.replaceSelection("hi", "end"); 1.1562 + eqPos(cm.getCursor(), Pos(0, 2)); 1.1563 + eq(cm.getLine(0), "abcde"); 1.1564 + cm.execCommand("selectAll"); 1.1565 + cm.replaceSelection("oops", "around"); 1.1566 + eq(cm.getValue(), "oopsbcd"); 1.1567 + cm.undo(); 1.1568 + eqPos(m.find().from, Pos(0, 1)); 1.1569 + eqPos(m.find().to, Pos(0, 4)); 1.1570 + m.clear(); 1.1571 + cm.setCursor(Pos(0, 2)); 1.1572 + cm.replaceSelection("hi", "around"); 1.1573 + eq(cm.getLine(0), "abhicde"); 1.1574 + eqPos(cm.getCursor(), Pos(0, 4)); 1.1575 + m = mark(0, 2, 2, 2, true); 1.1576 + cm.setSelection(Pos(1, 1), Pos(2, 4)); 1.1577 + cm.replaceSelection("t", "end"); 1.1578 + eqPos(cm.getCursor(), Pos(2, 3)); 1.1579 + eq(cm.getLine(2), "klto"); 1.1580 + cm.execCommand("goCharLeft"); 1.1581 + cm.execCommand("goCharLeft"); 1.1582 + eqPos(cm.getCursor(), Pos(0, 2)); 1.1583 + cm.setSelection(Pos(0, 1), Pos(0, 3)); 1.1584 + cm.replaceSelection("xx", "around"); 1.1585 + eqPos(cm.getCursor(), Pos(0, 3)); 1.1586 + eq(cm.getLine(0), "axxhicde"); 1.1587 +}, {value: "abcde\nfghij\nklmno\n"}); 1.1588 + 1.1589 +testCM("dirtyBit", function(cm) { 1.1590 + eq(cm.isClean(), true); 1.1591 + cm.replaceSelection("boo", null, "test"); 1.1592 + eq(cm.isClean(), false); 1.1593 + cm.undo(); 1.1594 + eq(cm.isClean(), true); 1.1595 + cm.replaceSelection("boo", null, "test"); 1.1596 + cm.replaceSelection("baz", null, "test"); 1.1597 + cm.undo(); 1.1598 + eq(cm.isClean(), false); 1.1599 + cm.markClean(); 1.1600 + eq(cm.isClean(), true); 1.1601 + cm.undo(); 1.1602 + eq(cm.isClean(), false); 1.1603 + cm.redo(); 1.1604 + eq(cm.isClean(), true); 1.1605 +}); 1.1606 + 1.1607 +testCM("changeGeneration", function(cm) { 1.1608 + cm.replaceSelection("x"); 1.1609 + var softGen = cm.changeGeneration(); 1.1610 + cm.replaceSelection("x"); 1.1611 + cm.undo(); 1.1612 + eq(cm.getValue(), ""); 1.1613 + is(!cm.isClean(softGen)); 1.1614 + cm.replaceSelection("x"); 1.1615 + var hardGen = cm.changeGeneration(true); 1.1616 + cm.replaceSelection("x"); 1.1617 + cm.undo(); 1.1618 + eq(cm.getValue(), "x"); 1.1619 + is(cm.isClean(hardGen)); 1.1620 +}); 1.1621 + 1.1622 +testCM("addKeyMap", function(cm) { 1.1623 + function sendKey(code) { 1.1624 + cm.triggerOnKeyDown({type: "keydown", keyCode: code, 1.1625 + preventDefault: function(){}, stopPropagation: function(){}}); 1.1626 + } 1.1627 + 1.1628 + sendKey(39); 1.1629 + eqPos(cm.getCursor(), Pos(0, 1)); 1.1630 + var test = 0; 1.1631 + var map1 = {Right: function() { ++test; }}, map2 = {Right: function() { test += 10; }} 1.1632 + cm.addKeyMap(map1); 1.1633 + sendKey(39); 1.1634 + eqPos(cm.getCursor(), Pos(0, 1)); 1.1635 + eq(test, 1); 1.1636 + cm.addKeyMap(map2, true); 1.1637 + sendKey(39); 1.1638 + eq(test, 2); 1.1639 + cm.removeKeyMap(map1); 1.1640 + sendKey(39); 1.1641 + eq(test, 12); 1.1642 + cm.removeKeyMap(map2); 1.1643 + sendKey(39); 1.1644 + eq(test, 12); 1.1645 + eqPos(cm.getCursor(), Pos(0, 2)); 1.1646 + cm.addKeyMap({Right: function() { test = 55; }, name: "mymap"}); 1.1647 + sendKey(39); 1.1648 + eq(test, 55); 1.1649 + cm.removeKeyMap("mymap"); 1.1650 + sendKey(39); 1.1651 + eqPos(cm.getCursor(), Pos(0, 3)); 1.1652 +}, {value: "abc"}); 1.1653 + 1.1654 +testCM("findPosH", function(cm) { 1.1655 + forEach([{from: Pos(0, 0), to: Pos(0, 1), by: 1}, 1.1656 + {from: Pos(0, 0), to: Pos(0, 0), by: -1, hitSide: true}, 1.1657 + {from: Pos(0, 0), to: Pos(0, 4), by: 1, unit: "word"}, 1.1658 + {from: Pos(0, 0), to: Pos(0, 8), by: 2, unit: "word"}, 1.1659 + {from: Pos(0, 0), to: Pos(2, 0), by: 20, unit: "word", hitSide: true}, 1.1660 + {from: Pos(0, 7), to: Pos(0, 5), by: -1, unit: "word"}, 1.1661 + {from: Pos(0, 4), to: Pos(0, 8), by: 1, unit: "word"}, 1.1662 + {from: Pos(1, 0), to: Pos(1, 18), by: 3, unit: "word"}, 1.1663 + {from: Pos(1, 22), to: Pos(1, 5), by: -3, unit: "word"}, 1.1664 + {from: Pos(1, 15), to: Pos(1, 10), by: -5}, 1.1665 + {from: Pos(1, 15), to: Pos(1, 10), by: -5, unit: "column"}, 1.1666 + {from: Pos(1, 15), to: Pos(1, 0), by: -50, unit: "column", hitSide: true}, 1.1667 + {from: Pos(1, 15), to: Pos(1, 24), by: 50, unit: "column", hitSide: true}, 1.1668 + {from: Pos(1, 15), to: Pos(2, 0), by: 50, hitSide: true}], function(t) { 1.1669 + var r = cm.findPosH(t.from, t.by, t.unit || "char"); 1.1670 + eqPos(r, t.to); 1.1671 + eq(!!r.hitSide, !!t.hitSide); 1.1672 + }); 1.1673 +}, {value: "line one\nline two.something.other\n"}); 1.1674 + 1.1675 +testCM("beforeChange", function(cm) { 1.1676 + cm.on("beforeChange", function(cm, change) { 1.1677 + var text = []; 1.1678 + for (var i = 0; i < change.text.length; ++i) 1.1679 + text.push(change.text[i].replace(/\s/g, "_")); 1.1680 + change.update(null, null, text); 1.1681 + }); 1.1682 + cm.setValue("hello, i am a\nnew document\n"); 1.1683 + eq(cm.getValue(), "hello,_i_am_a\nnew_document\n"); 1.1684 + CodeMirror.on(cm.getDoc(), "beforeChange", function(doc, change) { 1.1685 + if (change.from.line == 0) change.cancel(); 1.1686 + }); 1.1687 + cm.setValue("oops"); // Canceled 1.1688 + eq(cm.getValue(), "hello,_i_am_a\nnew_document\n"); 1.1689 + cm.replaceRange("hey hey hey", Pos(1, 0), Pos(2, 0)); 1.1690 + eq(cm.getValue(), "hello,_i_am_a\nhey_hey_hey"); 1.1691 +}, {value: "abcdefghijk"}); 1.1692 + 1.1693 +testCM("beforeChangeUndo", function(cm) { 1.1694 + cm.replaceRange("hi", Pos(0, 0), Pos(0)); 1.1695 + cm.replaceRange("bye", Pos(0, 0), Pos(0)); 1.1696 + eq(cm.historySize().undo, 2); 1.1697 + cm.on("beforeChange", function(cm, change) { 1.1698 + is(!change.update); 1.1699 + change.cancel(); 1.1700 + }); 1.1701 + cm.undo(); 1.1702 + eq(cm.historySize().undo, 0); 1.1703 + eq(cm.getValue(), "bye\ntwo"); 1.1704 +}, {value: "one\ntwo"}); 1.1705 + 1.1706 +testCM("beforeSelectionChange", function(cm) { 1.1707 + function notAtEnd(cm, pos) { 1.1708 + var len = cm.getLine(pos.line).length; 1.1709 + if (!len || pos.ch == len) return Pos(pos.line, pos.ch - 1); 1.1710 + return pos; 1.1711 + } 1.1712 + cm.on("beforeSelectionChange", function(cm, obj) { 1.1713 + obj.update([{anchor: notAtEnd(cm, obj.ranges[0].anchor), 1.1714 + head: notAtEnd(cm, obj.ranges[0].head)}]); 1.1715 + }); 1.1716 + 1.1717 + addDoc(cm, 10, 10); 1.1718 + cm.execCommand("goLineEnd"); 1.1719 + eqPos(cm.getCursor(), Pos(0, 9)); 1.1720 + cm.execCommand("selectAll"); 1.1721 + eqPos(cm.getCursor("start"), Pos(0, 0)); 1.1722 + eqPos(cm.getCursor("end"), Pos(9, 9)); 1.1723 +}); 1.1724 + 1.1725 +testCM("change_removedText", function(cm) { 1.1726 + cm.setValue("abc\ndef"); 1.1727 + 1.1728 + var removedText = []; 1.1729 + cm.on("change", function(cm, change) { 1.1730 + removedText.push(change.removed); 1.1731 + }); 1.1732 + 1.1733 + cm.operation(function() { 1.1734 + cm.replaceRange("xyz", Pos(0, 0), Pos(1,1)); 1.1735 + cm.replaceRange("123", Pos(0,0)); 1.1736 + }); 1.1737 + 1.1738 + eq(removedText.length, 2); 1.1739 + eq(removedText[0].join("\n"), "abc\nd"); 1.1740 + eq(removedText[1].join("\n"), ""); 1.1741 + 1.1742 + var removedText = []; 1.1743 + cm.undo(); 1.1744 + eq(removedText.length, 2); 1.1745 + eq(removedText[0].join("\n"), "123"); 1.1746 + eq(removedText[1].join("\n"), "xyz"); 1.1747 + 1.1748 + var removedText = []; 1.1749 + cm.redo(); 1.1750 + eq(removedText.length, 2); 1.1751 + eq(removedText[0].join("\n"), "abc\nd"); 1.1752 + eq(removedText[1].join("\n"), ""); 1.1753 +}); 1.1754 + 1.1755 +testCM("lineStyleFromMode", function(cm) { 1.1756 + CodeMirror.defineMode("test_mode", function() { 1.1757 + return {token: function(stream) { 1.1758 + if (stream.match(/^\[[^\]]*\]/)) return " line-brackets "; 1.1759 + if (stream.match(/^\([^\)]*\)/)) return " line-background-parens "; 1.1760 + if (stream.match(/^<[^>]*>/)) return " span line-line line-background-bg "; 1.1761 + stream.match(/^\s+|^\S+/); 1.1762 + }}; 1.1763 + }); 1.1764 + cm.setOption("mode", "test_mode"); 1.1765 + var bracketElts = byClassName(cm.getWrapperElement(), "brackets"); 1.1766 + eq(bracketElts.length, 1, "brackets count"); 1.1767 + eq(bracketElts[0].nodeName, "PRE"); 1.1768 + is(!/brackets.*brackets/.test(bracketElts[0].className)); 1.1769 + var parenElts = byClassName(cm.getWrapperElement(), "parens"); 1.1770 + eq(parenElts.length, 1, "parens count"); 1.1771 + eq(parenElts[0].nodeName, "DIV"); 1.1772 + is(!/parens.*parens/.test(parenElts[0].className)); 1.1773 + eq(parenElts[0].parentElement.nodeName, "DIV"); 1.1774 + 1.1775 + eq(byClassName(cm.getWrapperElement(), "bg").length, 1); 1.1776 + eq(byClassName(cm.getWrapperElement(), "line").length, 1); 1.1777 + var spanElts = byClassName(cm.getWrapperElement(), "cm-span"); 1.1778 + eq(spanElts.length, 2); 1.1779 + is(/^\s*cm-span\s*$/.test(spanElts[0].className)); 1.1780 +}, {value: "line1: [br] [br]\nline2: (par) (par)\nline3: <tag> <tag>"}); 1.1781 + 1.1782 +CodeMirror.registerHelper("xxx", "a", "A"); 1.1783 +CodeMirror.registerHelper("xxx", "b", "B"); 1.1784 +CodeMirror.defineMode("yyy", function() { 1.1785 + return { 1.1786 + token: function(stream) { stream.skipToEnd(); }, 1.1787 + xxx: ["a", "b", "q"] 1.1788 + }; 1.1789 +}); 1.1790 +CodeMirror.registerGlobalHelper("xxx", "c", function(m) { return m.enableC; }, "C"); 1.1791 + 1.1792 +testCM("helpers", function(cm) { 1.1793 + cm.setOption("mode", "yyy"); 1.1794 + eq(cm.getHelpers(Pos(0, 0), "xxx").join("/"), "A/B"); 1.1795 + cm.setOption("mode", {name: "yyy", modeProps: {xxx: "b", enableC: true}}); 1.1796 + eq(cm.getHelpers(Pos(0, 0), "xxx").join("/"), "B/C"); 1.1797 + cm.setOption("mode", "javascript"); 1.1798 + eq(cm.getHelpers(Pos(0, 0), "xxx").join("/"), ""); 1.1799 +}); 1.1800 + 1.1801 +testCM("selectionHistory", function(cm) { 1.1802 + for (var i = 0; i < 3; i++) { 1.1803 + cm.setExtending(true); 1.1804 + cm.execCommand("goCharRight"); 1.1805 + cm.setExtending(false); 1.1806 + cm.execCommand("goCharRight"); 1.1807 + cm.execCommand("goCharRight"); 1.1808 + } 1.1809 + cm.execCommand("undoSelection"); 1.1810 + eq(cm.getSelection(), "c"); 1.1811 + cm.execCommand("undoSelection"); 1.1812 + eq(cm.getSelection(), ""); 1.1813 + eqPos(cm.getCursor(), Pos(0, 4)); 1.1814 + cm.execCommand("undoSelection"); 1.1815 + eq(cm.getSelection(), "b"); 1.1816 + cm.execCommand("redoSelection"); 1.1817 + eq(cm.getSelection(), ""); 1.1818 + eqPos(cm.getCursor(), Pos(0, 4)); 1.1819 + cm.execCommand("redoSelection"); 1.1820 + eq(cm.getSelection(), "c"); 1.1821 + cm.execCommand("redoSelection"); 1.1822 + eq(cm.getSelection(), ""); 1.1823 + eqPos(cm.getCursor(), Pos(0, 6)); 1.1824 +}, {value: "a b c d"}); 1.1825 + 1.1826 +testCM("selectionChangeReducesRedo", function(cm) { 1.1827 + cm.replaceSelection("X"); 1.1828 + cm.execCommand("goCharRight"); 1.1829 + cm.undoSelection(); 1.1830 + cm.execCommand("selectAll"); 1.1831 + cm.undoSelection(); 1.1832 + eq(cm.getValue(), "Xabc"); 1.1833 + eqPos(cm.getCursor(), Pos(0, 1)); 1.1834 + cm.undoSelection(); 1.1835 + eq(cm.getValue(), "abc"); 1.1836 +}, {value: "abc"}); 1.1837 + 1.1838 +testCM("selectionHistoryNonOverlapping", function(cm) { 1.1839 + cm.setSelection(Pos(0, 0), Pos(0, 1)); 1.1840 + cm.setSelection(Pos(0, 2), Pos(0, 3)); 1.1841 + cm.execCommand("undoSelection"); 1.1842 + eqPos(cm.getCursor("anchor"), Pos(0, 0)); 1.1843 + eqPos(cm.getCursor("head"), Pos(0, 1)); 1.1844 +}, {value: "1234"}); 1.1845 + 1.1846 +testCM("cursorMotionSplitsHistory", function(cm) { 1.1847 + cm.replaceSelection("a"); 1.1848 + cm.execCommand("goCharRight"); 1.1849 + cm.replaceSelection("b"); 1.1850 + cm.replaceSelection("c"); 1.1851 + cm.undo(); 1.1852 + eq(cm.getValue(), "a1234"); 1.1853 + eqPos(cm.getCursor(), Pos(0, 2)); 1.1854 + cm.undo(); 1.1855 + eq(cm.getValue(), "1234"); 1.1856 + eqPos(cm.getCursor(), Pos(0, 0)); 1.1857 +}, {value: "1234"}); 1.1858 + 1.1859 +testCM("selChangeInOperationDoesNotSplit", function(cm) { 1.1860 + for (var i = 0; i < 4; i++) { 1.1861 + cm.operation(function() { 1.1862 + cm.replaceSelection("x"); 1.1863 + cm.setCursor(Pos(0, cm.getCursor().ch - 1)); 1.1864 + }); 1.1865 + } 1.1866 + eqPos(cm.getCursor(), Pos(0, 0)); 1.1867 + eq(cm.getValue(), "xxxxa"); 1.1868 + cm.undo(); 1.1869 + eq(cm.getValue(), "a"); 1.1870 +}, {value: "a"}); 1.1871 + 1.1872 +testCM("alwaysMergeSelEventWithChangeOrigin", function(cm) { 1.1873 + cm.replaceSelection("U", null, "foo"); 1.1874 + cm.setSelection(Pos(0, 0), Pos(0, 1), {origin: "foo"}); 1.1875 + cm.undoSelection(); 1.1876 + eq(cm.getValue(), "a"); 1.1877 + cm.replaceSelection("V", null, "foo"); 1.1878 + cm.setSelection(Pos(0, 0), Pos(0, 1), {origin: "bar"}); 1.1879 + cm.undoSelection(); 1.1880 + eq(cm.getValue(), "Va"); 1.1881 +}, {value: "a"});