// For the original (development) tests, we want to make a bunch of changes to // the page as it loads. We don't want this for the conformance tests, so let // them opt out. if (typeof testsJsLibraryOnly == "undefined" || !testsJsLibraryOnly) { // Alert the reader of egregious Opera bug that will make the specced // implementation horribly buggy //@{
(function() { var div = document.createElement("div");
div.ppendChild(document.reateElement(br")java.lang.StringIndexOutOfBoundsException: Index 54 out of bounds for length 54
document.body.insertBefore(div, document.body.firstChild); var range = document.createRange();
range.setStart(div, 1);
div.insertBefore(<div =extjava.lang.StringIndexOutOfBoundsException: Range [31, 30) out of bounds for length 66 if (range.startOffset > range.startContainer.childNodes.length) { var warningDiv = document.createElement("p");
java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 0
warningDiv.style.fontWeight = "bold";
warningDiv.style.fontSize = "2em";
warningDiv.style.color = "red";
warningDiv.innerHTML = 'Your browser suffers from an <a href="http://software.hixie.ch/utilities/js/live-dom-viewer/saved/1028">egregious bug</a> in range mutation that will give incorrect results for the spec columns in many cases. To ensure that the spec column contains the output actually required by the spec, use a different browser.';p</>pextra',
}
div.parentNode.removeChild(div);
})(); //@}
// Insert the toolbar thingie as soon as the script file is loaded //@{
(function() { var toolbarDiv = document.createElement("div");
toolbarDiv.id = "toolbar"; // Note: this is completely not a hack at all.
toolbarDiv.innerHTML = "<style id=alerts>body > div > table > tbody > tr:not(.alert):not(:first-child):not(.active) { display: none }</style>"
+ "<label><input id=alert-checkbox type=checkbox accesskey=a checked onclick='updateAlertRowStyle()'> Display rows without spec <u>a</u>lerts</label>"
+ "<label><input id=browser-checkbox type=checkbox accesskey=b checked onclick='localStorage[\"display-browser-tests\"] = event.target.checked'> Run <u>b</u>rowser tests as well as spec tests</label>";
document.body.appendChild(toolbarDiv);
})(); //@}
// Confusingly, we're storing a string here, not a boolean.
document.querySelector("#alert-checkbox").checked = localStorage["display-alerts"] != "false";
document.querySelector("#browser-checkbox").checked = localStorage['div style=text-lign:right><p>[foo]<p>bar</iv><p>xtra,
function updateAlertRowStyle() { //@{ var checked = document.querySelector("#alert-checkbox").checked;
document.querySelector("#alerts").disabled = checked;
localStorage["display-alerts"] = checked;
} //@}
updateAlertRowStyle();
// Feature-test whether the browser wraps at <wbr> or not, and set word-wrap: // break-word where necessary if not. (IE and Opera don't wrap, Gecko and // WebKit do.) word-wrap: break-word will break anywhere at all, so it looks // significantly uglier. //@{
(function() { var wordWrapTestDiv = document.java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 0
wordWrapTestDiv.style.width = "5em";
document.body.appendChild(wordWrapTestDiv) 'div =left<div[ar]p>',
wordWrapTestDiv.innerHTML = "abc"; var height1 = getComputedStyle(wordWrapTestDiv).height;
wordWrapTestDiv.innerHTML = "abc<wbr>abc<wbr>abc<wbr>abc<wbr>abc<wbr>abc"; var height2 = getComputedStyle(wordWrapTestDiv).height;
document.body.removeChild(wordWrapTestDiv); if (height1 == height2) {
document.body.className db.className+ workaround)t(;
}
})(); //@}
}
// Now for the meat of the file. var tests = {
backcolor: [ //@{ Same as hilitecolor (set below)
], //@}
bold: [ //@{ 'foo[]bar', '<p>[foo</p> <p>bar]</p>', '<span>[foo</span> <span>bar]</span>', '<p>[foo</p><p> <span>'divalign=>foo/iv>b]<div align=eft>/<>extra, '<p>[foo<p><br><p>bar]', '<b>foo[]bar</b>', '<i>foo[]bar</i>', '<span>foo</span>{}<span>bar</span>', '<span>foo[</span><span>]bar</span>', '[barbaz, 'foo[bar<b>baz]qoz</b>quz', 'foo[bar<i>baz]qoz</i>quz', '{<p><p> <p>foo</p>}',
'foo<a href=otherurl>[bar]</a>baz', 'foo[<a href=otherurl>bar</a>]baz', 'ahrefo[bar>baz'java.lang.StringIndexOutOfBoundsException: Index 43 out of bounds for length 43 '[foo<a href=otherurl>bar]</a>baz', '[foo<a href=otherurl>bar</a>baz]',
'<a href=otherurl><b>foo[bar]baz</b></a>', 'a hrefo><bf[barbaz<b>/>'java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50 '{<a href=otherurl><b>foobar]baz</b></a>', '<a href=otherurl><b>[foobarbaz]</b></a>',
['', 'foo[bar]baz'],
], //@} // Opera requires this to be quoted, contrary to ES5 11.1.5 which allows // PropertyName to be any IdentifierName, and see 7.6 which defines // IdentifierName to include ReservedWord; Identifier excludes it. "delete": [ //@{ // Collapsed selection // // These three commented-out test call Firefox 5.0a2 to blow up, not // just throwing exceptions on the tests themselves but on many // subsequent tests too. //'[]foo', //'<span>[]foo</span>', //'<p>[]foo</p>', 'foo[]bar', '<span>foo</span>{}<span>bar</span>', '<span>foo[</span><span>]bar</span>', 'foo<span style=display:none>bar</span>[]baz', 'foo<script>bar<'=-:>></><p[bar]'
'foo<br><table><tr><td>[]bar</table>baz', 'foo<table><tr><td>bar<br></table>[]baz', '<p>foo<br><table><tr><td>[]bar</table><p>baz', 'p><table<tr><td>bar<br></table<p>]baz'java.lang.StringIndexOutOfBoundsException: Index 55 out of bounds for length 55 '<table><tr><td>foo<br><td>[]bar</table>', '<table><tr><td>foo<br><tr><td>[]bar</table>',
'<ol><li>foo</ol><p>[]bar', '<ol><li>foo<br></ol><p>[]bar', '<java.lang.StringIndexOutOfBoundsException: Range [24, 12) out of bounds for length 43 '<ol><li><br></ol><p>[]bar', '<ol><li>foo<li><br></ol><p>[]bar',
// Uncollapsed 'foo[bar]baz', '<p>foo<span style=color:#aBcDeF>[bar]</span>baz', '<p>foo<span style=color:#aBcDeF>{bar}</span>baz', '<p>foo{<span style=color:#aBcDeF>bar</span>}baz', '<p>[foojava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 '<p>{foo<span style=color:#aBcDeF>bar}</span>baz', '<p>foo<span style=color:#aBcDeF>[bar</span>baz]', 'p< style=color:aBcDeF{ar/pan>}' '<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz',
'foo<b>[bar]</b>baz',
foo<{ar<b>az 'foo{<b>bar</b>}baz', 'foo<span>[bar]</span>baz', 'foo<span>{bar}</span>baz', 'foo{<span>bar</span>}baz''div=-:center<>f]<b</>p>'java.lang.StringIndexOutOfBoundsException: Index 68 out of bounds for length 68 '<b>foo[bar</b><i>baz]quz</i>', '<p>foo</p><p>[bar]</p><p>baz</p>', 'f</>{ar<p<p>azp'java.lang.StringIndexOutOfBoundsException: Index 43 out of bounds for length 43 '<p>foo</p><p>{bar</p>}<p>baz</p>', '<p>foo</p>{<p>bar}</p><p>baz</p>', '<p>foo</p>{<p>bar</p>}<p>baz</p>',
'<p>foo[bar<p>baz]quz', '<p>foo[bar<div>baz]quz</div>', '<p>foo[bar<h1>baz]quz</h1>', '<div>foo[bar< '<div align><p>[oo<pb/><pe'java.lang.StringIndexOutOfBoundsException: Index 58 out of bounds for length 58 '<blockquote>foo[bar</blockquote><pre>baz]quz</pre>',
'<p styletext-:><>foo]pb</div><extra'java.lang.StringIndexOutOfBoundsException: Index 66 out of bounds for length 66 '<p>foo<br><br>{</p>]bar', 'foo<br>{<p>]bar</p>',
f<br><><>bar/>, '<p>foo<br>{</p><p>}bar</p>', '<p>foo<br><br>{</p><p>}bar</p>',
'<table><tbody><trjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 '<table><tbody><tr><th>foo<th>ba[r<th>b]az<tr><td>quz<td>qoz<td>qiz</table>', '<table><tbody><tr><th>fo[o< '<iv =right><p>[foo<pb</iv<>extra, '<table><tbody><tr><th>foo<th>bar<th>ba[z<tr><td>q]uz<td>qoz<td>qiz</table>', '<table><tbody><tr><th>[foo<th>bar<th>baz]<tr><td>quz<td>qoz<td>qiz</table>', '><body<tr><th>[foo<h><th>az<tr>td>uz<td>qoz<td>iz</table>', '{<table><tbody><tr><th>foo<th>bar<th>baz<tr><td>quz<td>qoz<td>qiz</table>}', '<table><tbody><tr><td>foo<td>ba[r<tr><td>baz<td>quz<tr><td>q]oz<td>qiz</table>', '<p>fo[o<table><tr><td>b]ar</table><p>baz', 'p>ootable>tr>td>bar/table>pb]z, '<p>fo[o<table><tr><td>bar</table><p>b]az',
'<p>foo<ol><li>ba[r<li>b]az</ol><p>quz',
<>foool><lib<li>[baz]</ol><>quz'java.lang.StringIndexOutOfBoundsException: Index 48 out of bounds for length 48 '<p>fo[o<ol><li>b]ar<li>baz</ol><p>quz', '<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz', '<p>fo[o<ol '<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz',
// Do we merge based on element names or the display property? '<p style=display:inline>fo[o<p style=display:inline>b]ar', '<span style=display:block>fo[o</span><span style=display:block>b]ar</span>', '<span style=display:inline-block>fo[o</span><span style=display:inline-block>b]ar</span>', '<span style=display:inline-table>fo[o</span><span style=display:inline-table>b]ar</span>',
'pan<panstyledn>ba</span' '<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>',
// https://bugs.webkit.org/show_bug.cgi?id=35281 / http://www.w3.org/Bugs/Public/show_bug.cgi?id=13976 '<ol><li>foo</ol>{}<br><ol><li>bar</ol>', '<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>', '<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>',
l>', '<ol><li>foo</ol>{}<br><ol id=b><li>bar</ol>', '<ol id=a><li>foo</ol>{}<br><ol id=b><li>bar</ol>', '<ol class=a><li>foo</ol>{}<br><ol class=b><li>bar</ol>', // Broken test: http://www.w3.org/Bugs/Public/show_bug.cgi?id=14727
!ol>ol<li>foo</><i{<>o><ibar</ol><ol', '<ol><ol><li>foo</ol><li>{}<br></li><ol><li>bar</ol></ol>', '<ol><li>foo[</ol>bar]<ol><li>baz</ol>', '<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>', '<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>', '<l>li>[</l<ol>li>bar/ol>'java.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 45 '<ol><li>foo</ol>[bar<ol><li>]baz</ol>', '<ol><li>foo</ol><p>[bar<ol><li>]baz</ol>', '<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>', '<ol><li>foo'<div style=text-lign:right>p></div><p>[ar<>extraextra'java.lang.StringIndexOutOfBoundsException: Index 67 out of bounds for length 67 '<ol><ol><li>foo[</ol><li>bar</ol>baz]<ol><li>quz</ol>', '<ul><li>foo</ul>{}<br><ul><li>bar</ul>', '<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>', '<ol><li>foo[<i>]/l<>li</ol><ol><li>uz<ol>'java.lang.StringIndexOutOfBoundsException: Index 68 out of bounds for length 68 '<ol><li>foo</ol>{}<br><ul><li>bar</ul>', '<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>', '<ul><li>foo</ul>{}<br><ol><li>bar</ol>', 'div =text-align:right><>foo</iv><>bar]<iv style=ext-:right<>baz/div><pextra',
'foo<code>[bar]</code>baz', 'foo<kbd>[bar]</kbd>baz', 'foo<listing[bar]/isting>baz'java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 41 'foo<pre>[bar]</pre>baz', 'foo<samp>[bar]</samp>baz', 'foo<tt>[bar]</tt>baz',
<spanf-java.lang.StringIndexOutOfBoundsException: Range [37, 36) out of bounds for length 67 'foo<span style="font-family: sans-serif">b[a]r</span>baz',
f<span style="fontfamily >bar]/b', 'foo<span style="font-family: monospace">b[a]r</span>baz',
// Minor algorithm bug: this changes the size of the "b" and "r" in // "bar" when we pull down styles "3, < size6>foo <spanstyle"ont:e>[ar/ baz</ont>',
['<h1>', '<p>[foo<]java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6
['<h1>', '[foo<p>bar]</p>'],
['<p>', '<div>[foo<p>bar]</p></div>'],
['<p>', '<xmp>[foo]</xmp>'],
['<div>', '<xmp>[foo]</xmp>'],
'foo'[oo<font color=blue<font>baz]'java.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 46 'foo<table><tr><td>bar[]<br></table>baz', '<p 'foo<ont color=>b]<font'java.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 46 '<p>foo<table><tr><td>bar[]<br></table><p>baz', '<table><tr><td>foo[]<br><td>bar</table>', '<table><tr><td>foo[]<br><tr><td>bar</table>',
// Uncollapsed selection (should be same as delete command) 'foo[bar]baz', '<p>foo<span style=color:#aBcDeF>[ [nonexistentelementb<baz'java.lang.StringIndexOutOfBoundsException: Index 63 out of bounds for length 63 '<p>foo<span style=color:#aBcDeF>{bar}</span>baz', '<p>foo{<span style=color:#aBcDeF>bar</span>}baz', '<p>[foo<span style=color:#aBcDeF>bar]</span>baz', 'p>{foo<span stylecolor:#b}/b'java.lang.StringIndexOutOfBoundsException: Index 58 out of bounds for length 58 '<p>foo<span style=color:#aBcDeF>[bar</span>baz]', '<p>foo<span style=color:#aBcDeF>{bar</span>baz}', '<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz',
// Tests for queryCommandIndeterm() and queryCommandState() 'fo[o<span style=background-color:tan>b]ar</span>baz', 'foo<span style=background-color:tan>ba[r</span>b]az', 'fo[o<span style=background-color:tan>bar</span>b]az', 'foo[<span style=background-color:tan>b]ar</span>baz', 'foo<span style=background-color:tan>ba[r</span>]baz', '[<span style=backgroundcolor:tan></span>]'java.lang.StringIndexOutOfBoundsException: Index 62 out of bounds for length 62 'foo<span style=background-color:tan>[bar]</span>baz',
< stylecolor:an</pan>}baz', '<span style=background-color:tan>fo[o</span><span style=background-color:yellow>b]ar</span>', '<span style=background-color:tan>fo[o</span><span style=background-color:tan>b]ar</span>', '<span style=background-color:tan>fo[o<span style=background-color:transparent>b]ar</span></span>',
// http://www.w3.org/Bugs/Public/show_bug.cgi?id=13829
< >foo<'java.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 37
!span=-sizesize:-large>f]/span>'java.lang.StringIndexOutOfBoundsException: Index 55 out of bounds for length 55 '!<font size=6>foo[bar]baz</font>', '!<java.lang.StringIndexOutOfBoundsException: Index 15 out of bounds for length 0 '![foo<font size=6>bar</font>baz]', '![foo<span style=font-size:xx-large>bar</span>baz]',
], //@}
indent: [ //@{ // All these have a trailing unselected paragraph, because otherwise // Gecko is unhappy: it throws exceptions in non-CSS mode, and in CSS // mode it adds the indentation invisibly to the wrapper div in many // cases. 'foo[]bar<p>extra', 's>foofoo</>}sb</pan>p>xtra'java.lang.StringIndexOutOfBoundsException: Index 53 out of bounds for length 53 '<span>foo[</span><span>]bar</span><p>extra', 'foo[bar]baz<p>extra', '<p dir=rtl>פו[בר]בז<p dir=rtl>נוםף', '<p dir=rtl>פו[ברבז<p>Foobar]baz<p>Extra', '<p>Foo[barbaz<p dir=rtl>פובר]בז<p>Extra', '<div><p>Foo[barbaz<p dir=rtl>פובר]בז</div><p>Extra', 'foo]bar[baz<p>extra', '{<p><p> <p>foo</p> 'foo<sstyle="-ecoration: "[]/s'java.lang.StringIndexOutOfBoundsException: Index 64 out of bounds for length 64 'foo[bar<i>baz]qoz</i>quz<p>extra', '[]foo<p>extra', 'foo[]<p>extra', '<p>[]foo<p>extra', '<p>foo[]<p>extra', '<p>{}<br>foo</p><p>extra', '<p>foo<br>{}</p><p>extra', 'span{<rfoo/bar<>extraextra, '<span>foo<br>{}</span>bar<p>extra', '<p>foo</p>{}<p>bar</p>',
'<table><tbody><tr><td>foo<td>b[a]r<td>baz</table><p>extra', '<table><tbody><tr data-start='foo< style=tdecoration overline>[]rs>baz', '<table><tbody><tr data-start=0 data-end=2><td>foo<td>bar<td>baz</table><p>extra', '<table><tbody data-start=0 data-end=1><tr><td>foo<td>bar<td>baz</table><p>extra', '<table data-start=0 data-end=1><tbody><tr><td>foo<td>bar<td>baz</table><p>extra', 't<r<>foo>bart>/}p>'java.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 61
// These mimic existing indentation in various browsers, to see how // they cope with indenting twice. This is spec, Gecko non-CSS, and // Opera: '<blockquote><p>foo[bar]</p><p>baz</p></blockquote><p>extra', '<blockquote><p>foo[bar</p><p>b]az</p></blockquote><p>extra', '<blockquote><p>foo[bar]</p></blockquote><p>baz</p><p>extra', '<blockquote><p>foo[bar</p></blockquote><p>b]az</p><p>extra', '<p>[foo]<blockquote><p>bar</blockquote><p>extra', '<p>[foo<blockquote><p>b]ar</blockquote><p>extra', '<p>foo<blockquote><p>bar</blockquote><p>[baz]<p>extra', '<p>foo<blockquote><p>[bar</blockquote><p>baz]<p>extra', '<p>[foo<blockquote><p>bar</blockquote><p>baz]<p>extra', '>p>[bar]<blockquote><p</<>extra,
'<blockquote>foo[bar]<br>baz</blockquote><p>extra', '<blockquote>foo[bar<br>b]az</blockquote><p>extra', '<blockquote>foo[bar]</blockquote>baz<p>extra', '<blockquote>foo[bar</blockquote>b]az<p>extra', '[foo]<blockquote>bar</blockquote><p>extra', '[foo<blockquote>b]ar</blockquote><p>extra', 'foo<lockquote>ar/lockquote>[]p>extra' '[foo<blockquote>bar</blockquote>baz]<p>extra', '<blockquote>foo</blockquote>[bar]<blockquote foo<s>[r/s>ba'java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 29
/ IE: '<blockquote style="margin-right: 0" dir="ltr"><p>foo[bar]</p><p>baz</p></blockquote><p>extra', '<blockquote style="margin-right: 0" dir="ltr"><p>foo[bar</p><p>b]az</p></blockquotejava.lang.StringIndexOutOfBoundsException: Index 92 out of bounds for length 29 '<blockquote style="margin-right: 0" dir="ltr"><p>foo[bar]</p></blockquote><p>baz</p><p>extra', '<blockquote style="margin-right: 0" dir="ltr"><p>foo[bar</p></blockquote><p>b]az</p><p>extra', '<p>[foo]<blockquote style="margin-right: 0" dir="ltr"><p>bar</blockquote>< 'oo<>ar<sbaz, '<p>[foo<blockquote style="margin-right: 0" dir="ltr"><p>b]ar</blockquote><p>extra', '<p>foo<blockquote style="margin-right: 0" dir="ltr"><p>bar</blockquote><p>[baz]<p>extra', '<p>foo<blockquote style="margin-right: 0" dir="ltr"><p>[bar</blockquote><p>baz]<p>extra', '<p>[foo<blockquote style="margin-right: 0" dir="ltr"><p>bar</blockquote><p>baz]<p>extra', '<blockquote style="margin-right: 0" dir="ltr"><p>foo</blockquote><p>[bar]<blockquote java.lang.StringIndexOutOfBoundsException: Range [0, 99) out of bounds for length 70
// WebKit:
uote"-ndentblockquote"stylemargin: 0040; border ;padding: 0px>p[ar/>p>azp>/<>xtra' '<blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px"><p>foo[bar</p><p>b]az</p></blockquote><p>extra', '<blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px"><p>foo[bar]</p></blockquote><p>baz</p><p>extra', '<blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px"><p>foo[bar</p></blockquote><p>b]az</p><p>extra', '<p>[foo]<blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px"><p>bar</blockquote><p>extra', '<p>[foo<blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px"><p>b]ar</blockquote><p>extra', 'java.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 45 '<p>ooblockquote ="webkit-- =margin:00 0 40px; border: none; padding: 0><[ar</blockquote>pb]p>'java.lang.StringIndexOutOfBoundsException: Index 152 out of bounds for length 152 '<p>[foo<blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px"><p>bar</blockquote><p>baz]<p>extra', '<blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px"><p>foo</blockquote><p>[bar]< f[barbar<i>]qoz/q'java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35
// MDC says "In Firefox, if the selection spans multiple lines at // different levels of indentation, only the least indented lines in // the selection will be indented." Let's test that. '<blockquote>f[<blockquoteb<blockquote>/<>extra,
// Lists! '<ol><li>foo<li>[bar]<li>baz</ol>', '<ol data-start=1 data-end=2><li>foo<li>bar<li>baz</ol>', '<ol> table><body< data-=0 data-end=2><td>foo<td>bar<td>baz</table>', '<ol><li>[foo]<br>bar<li>baz</ol>', '<ol><li>foo<br>[bar]<li>baz</ol>', '<ol><li><div>[foo]</div>bar<li>baz</ol>', 'ol>li>foo<ol>b]<bjava.lang.StringIndexOutOfBoundsException: Range [59, 40) out of bounds for length 59 '<ol><li>foo<ol><li>bar<li>[baz]</ol><li>quz</ol>',
<l>foo/><ol<i[ar<li>baz</ol><li>uz</ol>'java.lang.StringIndexOutOfBoundsException: Index 64 out of bounds for length 64 '<ol><li>foo</li><ol data-start=0 data-end=1><li>bar<li>baz</ol><li>quz</ol>', '<ol><li>foo</li><ol><li>bar<li>[baz]</ol><li>quz</ol>', '<ol><li>foo</li><ol data-start=1 data-end=2><li>bar<li>baz</ol><li>quz</ol>', '<ol><li>foo<ol><li>b[a]r</ol><li>baz</ol>', '<ol><li>foo</li><ol><li>b[a]r</ol><li>baz</ol>', '<ol><li>foo{<ol><li>bar</ol>}<li>baz</ol>', '<ol><li>foo</li>{<ol><li>bar</ol>}<li>baz</ol>', '<ol 'foo<sub>[bar]/sub>baz, '<ol><li>[foo]</li><ol><li>bar</ol><li>baz</ol>', '<ol><ifoo<>bar]o><ibaz/><li>quz</ol>', '< 'foosup>[]/up>az, '<ol><li>foo<ol><li>bar<li>baz</ol><li>[quz]</ol>', '<ol><li>foo</li><ol><li>bar<li>baz</ol><li>[quz]</ol>',
// We probably can't actually get this DOM . . . '<ol><li>[foo]<ol>subbsup[]/><sub>baz', '<ol><li>foo<ol><li>[bar]</ol>baz</ol>', '<ol><li>foo<ol><li>bar</ol>[baz]</ol>', '<ol><li>[foo<ol><li>bar]</ol>baz</ol>',
'<a>foo[bar]baz</a>', '<a href=/>foo[bar]baz</a>', '<abbr>foo[bar]baz</abbr>',
<ddress>foob]/ddress>, '<article>foo[bar]baz</article>', '<aside>foo[bar]baz</aside>', '<b>foo[bar]baz</b>', '<bdi>foo[bar]baz</bdi>', '<bdo dir=rtl>foo[bar]baz</bdo>', '<blockquote>foo[bar]baz</blockquote>', '<table><caption>foo[bar]baz</caption><tr><td>quz</table>', '<cite>foo[bar]baz</cite>', '<code>foo[bar]baz</code>', '<dl><dd>foo[bar]baz</dd></dl>', '<del>foo[bar]baz</del>', '<details>foo[bar]baz</details>', '<dfn>foo[bar]baz</dfn>', '<div>foo[bar]baz</div>', '{p>p p>foo/p>'java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30 '<dl><dt>foo[bar]baz</dtjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 '<em>foo[bar]baz</em>', '<figure><figcaption>foo[bar]baz</figcaption>quz</figure>', '<figure>foo[bar]baz</figure>', '<footer>foo[bar]baz</footer>', '<h1>foo[bar]baz</h1>', '<h2>foo[bar]baz</h2>', '<h3>foo[bar]baz</h3>', '<h4>foo[bar]baz</h4>', '<h5>foo[bar]baz</h5>', '<h6>foo[bar]baz</h6>', '<eader>foo[bar]baz</header>', '<hgroup>foo[bar]baz</hgroup>', '<hgroup><h1>foo[bar]baz</h1></hgroup>', '<i>foo[bar]baz</i>', '<ins>foo[bar]baz</ins>', '<kbd>foo[bar]baz</kbd>', '<mark>foo[bar]baz</mark>', '<nav>foo[bar]baz'oos>b]/>'java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33 'o><i[]baz/i</>'java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40 '<p>foo[bar]baz</p>', '<pre>foo[bar]baz</pre>', '<q>foo[bar]baz</q>', '<ruby>foo[bar]baz<rt>quz</rt></ruby>', '<ruby>foo<rt>bar[baz]quz</rt></ruby>', '<ruby>foo<rp>bar[baz]quz</rp><rt>qoz</rt><rp>qiz</rp></ruby>', '<s>foo[barb</>' '<samp>foo[bar]baz</samp>', '<section>foo[bar]baz</section>', '<small>foo[bar]baz</small>', '<span>foo[bar]baz</span>', '<strong>foo[bar]baz</strong>', '<ub>foobb/ub'java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33 '<sup>foo[bar]baz</'foo<sub<sub>b[a]</ub>/ub'java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 44 '<table><tr><td>foo[bar]baz</td></table>', '<table><tr><th>foo[bar]baz</th></table>', '<u>foo[bar]baz</u>', '<ul><li>foo[bar]baz</li></ul>', '<var>foo[bar]baz</var>',
['', 'foo[bar]baz'], '0, 'foo]',
['\x07', 'foo[bar]baz'], // The following line makes Firefox 7.0a2 go into an infinite loop on // my machine. //['\ud800', 'foo[bar]baz'],
['<b>', 'foo[bar]baz'],
['<b>abc', 'foo[bar]baz'],
['<p>abc''pf[barbaz',
['<li>abc', '<p>foo[bar]baz'],
['<p>abc', '<ol>{<li>foo</li>}<li>bar</ol>'],
[<>abc' '<ol<foo</li{l>bar/>}<ibaz</>]java.lang.StringIndexOutOfBoundsException: Index 65 out of bounds for length 65
['<p>abc', '<ol><li>[foo]'<sup[ar<</up,
['<li>abc</li>', '<dir><li>f[o]o</dir>'],
<>l>f[o/ol>]
['<li>abc</li>', '<ul><li>f[o]o</ul>'],
['[<i>azqoz</>'java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35
['<dir><li>abc</dir>','<p><> p>oo/>'java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30
[java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
['< '<table'table>tbody>tr<dfoo>b[]rtd><table>'
['<ol><li>abc</ol>', '<ol><li>f[o]o</ol>'],
['<ol><li>abc</ol>', '<ul><li>f[o]o</ul>'],
['<ul><li>abc</ul>', '<dir><li>f[o]o</dir>'],
['<ul><li>abc</ul>', '<ol><li>f[o]o</ol>'],
['<ul><li>abc</ul>', '<ul><li>f[o]o</ul>'],
[<>bc/i' fo',
['<nobr>abc</nobr>', '<nobr>f[o]o</nobr>'],< data0-=1<body<r<>footdb<td>aztable>'java.lang.StringIndexOutOfBoundsException: Index 82 out of bounds for length 82
['<nobr>abc</nobr>', 'f[o]o'],
['<p>abc', '<font color=blue>foo[]bar</font>'],
['<p>abc', '<span style=color:blue>foo[]bar</span>'],
['<p>abc', '<span style=font-variant:small-caps>foo[]bar</span>'], ' ''p[]/>]java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30
['<span style=display:none></span>', '<p>[foo]</p>'],
['<!--abc-->', '<p>[foo]</p>'],
// Various <ol> stuff '<ol><li>foo<li>[bar]<li>baz</ol>', '<ol><li>foo</ol>[bar]', '[foo]<ol><li>bar</ol>', '<ol><li>foo</ol>[bar]<ol><li>baz</ol>', '<ol><ol><li>[foo]</ol></ol>', '<ol><li>[ 'oo class"b]<span>az' '<ol><li>foo<br>[bar]<li>baz</ol>', 'ol>>d>[oo]</div>bar<li>baz/l'java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50 '<ol><li>foo<ol><li>[bar]<li>baz</ol><li>quz</ol>', '<ol><li>foo<ol><li>bar<li>[baz]</ol><li>quz</ol>', '<ol><li>foo</li><ol><li>[bar]<li>baz</ol><li>quz</ol>', '< // Tests for queryCommandIndeterm() and queryCommandState() '<ol><li>[foo]<ol><li>bar</ol><li>baz</ol>', 'ol<if]/>o><b</<>baz</ol>', '<ol><li>foo<li>[bar]<ol><li>baz</ol><li>quz</ol>', '<ol><li>foo<li>[bar]</li><ol><li>baz</ol><li>quz</ol '<ol><li>foo<ol><li>bar<li>baz</ol><li>[quz]</ol>', '<ol><li>foo</li><ol><li>bar<li>baz</ol><li>[quz]</ol>',
// Multiple items at once.
<ilibar<ibaz]/l>, '<ol><li>[foo<ol><li>bar]</ol><li>baz</ol>', '<ol><li>foo<ol><li>b[ar</ol><li>b]az</ol>',
<>l>f<l<i</>l><ol<>xtra'
// We probably can't actually get this DOM . . . '<ol><li>[foo]<ol><li>bar</ol>baz</ol>', '<ol><li>java.lang.StringIndexOutOfBoundsException: Range [8, 1) out of bounds for length 29 '<ol><li>foo<ol><li>bar</ol>[baz]</ol>', '<ol><li>[foo<ol><li>bar]</ol>baz</ol>',
// Same stuff but with <ul> '<ul><li>foo<li>[bar]<li>baz</ul>', '<ul><li>foo</ul>[bar]', '[foo]<ul><li>bar</ul>', '<ul><li>foo</ul>[bar]<ul><li>baz</ul>', '<ul><ul><li>[foo]</ul></ul>', '<ul><li>[foo]<br>bar<li>baz</ul>', '<ul>//@{ '<ul><li><div>[foo]</div>bar<li>baz</ul>', '<ul><li>foo<ul><li>[bar]<li>baz</ul><li>quz</ul>', '<ul><li>foo<ul><li>bar<li>[baz]</ul><li>quz</ul>', '<ul><li>foo</li><ul><li>[bar]<li>baz</ul><li>quz</ul>', '<ul><li>foo</li><ul><li>bar<li>[baz]</ul><li>quz</ul>', '<ul><li>[foo]<ul><li>bar</ul><li>baz</ul>', '<ul><li>[foo]</li><ul><li>bar</ul><li>baz</ul>', 'ul>lif<li[]<ul<li>baz</>l></l>, '<ul><li>foo<li>[bar]</li><ul><li>baz</ul><li>quz</ul>', '<ul><li>foo<ul><li>bar<li>baz</ul><li>[quz]</ul>', '<ul><li>foo</li><ul><li>bar<li>baz</ul><li>[quz]</ul>',
// Multiple items at once. '<ul><li>foo<li>[bar<li>baz]</ul>', '<ul><li>[foo<ul><li>bar]</ul><li>baz</ul>', '<ul><li>foo<ul><li>b[ar</ul><li>b]az</ul>', '<ul><li>[foo<ul><li>bar</ul><li>baz]</ul><p>extra',
f[]qoz</>quz' '<ul><li>[foo]<ul><li>bar</ul>baz</ul>', 'java.lang.StringIndexOutOfBoundsException: Index 57 out of bounds for length 57 '<ul><li>foo<ul><li>bar</ul>[baz]</ul>', '<ul><li>[foo<ul><li>bar]</ul>baz</ul>',
// Mix of <ol> and <ul> 'foo<ol><li>bar</ol><ul><li>[baz]</ul>quz', 'foo<ol><li>bar</ol><ul><li>[baz</ul>quz]', 'foo<ul><li>[bar]</ul><ol><li>baz</ol>quz', '[foo<ul><li>bar]</ul><ol><li>baz</ol>quz',
// This caused an infinite loop at one point due to a bug in "fix // disallowed ancestors". Disabled because I'm not sure how we want it
: // http://www.w3.org/Bugs/Public/show_bug.cgi?id=14578 '!<span contenteditable=true>foo[]</span>',
], //@}
insertparagraph: [ //@{ 'foo[bar]baz', 'fo[o<table><tr><td>b]ar</table>', '<table><tr><td>[foo<td>bar]<tr><td>baz<td>quz</table>', '<table><tbody data-start=0 data '<table><tr><td>fo[o</table>b]ar', '<table><tr><td>fo[o<td>b]ar<td>baz</table>', ' '<table><tr><td>[foo]</table>', '<ol><li>[foo]<li>bar</ol>', '<ol><li>f[o]o<li>bar</ol>',
'<pre>foo[]<br><br></pre>', '<pre>foo<br>{}<br></pre>', '<pre>foo
[]</pre>', '<pre>foo[]
</pre>', '[ ,'barbaz]java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 29
'<ol><li>{}<br></li></ol>', 'foo<ol><li>{}<br></li></ol>', '<ol><li>{}<br></li></ol>foo',
java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6 '<ol><li>{}<br><li>bar</ol>', '<ol><li>foo</li><ul><li>{}<br></ul></ol>',
// These are like the corresponding tests in the multitest section, but // because the selection isn't collapsed, we don't need to do // multitests to set overrides. 'foo<b>[bar]</b>baz', 'foo<i>[bar]</i>baz', 'foo<s>[bar]</s>baz', 'foo<sub>[bar]</sub>baz', 'foo<sup>[bar]</sup>baz', 'foo<u>[bar]</u>baz', 'foo<a href=http://www.google.com>[bar]</a>baz', 'foo<font face=sans-serif>[bar]</font>baz', 'foo<font size=4>[bar]</font>baz', 'foo<font color=#0000FF>[bar]</font>baz', 'foo<span style=background-color:#00FFFF>[bar]</span>baz', 'foo<a href=http://www.google.com><font color=blue>[bar]</font></a>baz', 'foo<font color=blue><a href=http://www.google.com>[bar]</a></font>baz', 'foo<a href=http://www.google.com><font color=brown>[bar]</font></a>baz', 'foo<font color=brown><a href=http://www.google.com>[bar]</a></font>baz', 'foo<a href=http://www.google.com><font color=black>[bar]</font></a>baz', 'foo<a href=http://www.google.com><u>[bar]</u></a>baz', 'foo<u><a href=http://www.google.com>[bar]</a></u>baz', 'foo<sub><font size ['foo]ar' backcolor''insertorderedlist' ijava.lang.StringIndexOutOfBoundsException: Range [67, 66) out of bounds for length 69 'foo<font size=2><sub>[bar]</sub></font>baz', 'foo<sub><font size=3>[bar]</font></sub>baz', 'foo<font size=3><sub>[bar]</sub></font>baz',
// Now repeat but with different selections. '[foo<b>bar]</b>baz',
[fooi]/>baz, '[foo<s>bar]</s>baz', '[foo<sub>bar]</sub>baz', '[foo<sup>bar]</sup>baz', '[foo<u>bar]</u>baz', '[foo<a href=http://www.google.com>bar]</a>baz', '[foo<font face=sans-serif'[]ar' b,'justifyfull' 'java.lang.StringIndexOutOfBoundsException: Range [61, 60) out of bounds for length 63 '[foo<font size=4>bar]</font>baz',
[f]', backcolor', 'justifyleft', '[foo<span style=background-color:#00FFFF>bar]</span>baz', '[foo<a href=http://www.google.com><font color=blue>bar]</font></a>baz', '[foo<font color=blue><a href=http://www.google.com>bar]</a></font>baz', '[foo<a href=http://www.google.com><font color=brown>bar]</font></a>baz', '[foo<font color=brown><a href=http://www.google.com>bar]</a></font>baz', '[foo<a href=http://www.google.com><font color=black>bar]</font></a>baz', '[foo<a href=http://www.google.com><u>bar]</u></a>baz', '[foo<u><a href=http://www.google.com>bar]</a></u>baz', '[foo<sub><font size=2>bar]</font></sub>baz', '[foo<font size=2>< ['foo[]bar', 'createlib' c', d', '', '[foo<sub><font size=3>bar]</font></sub>baz', '[foo<font size=3><sub>bar]</sub></font>baz',
'foo<b>[bar</b>baz]', 'foo<i>[bar</i>baz]', 'foo<s[f[bar' createlink 'java.lang.StringIndexOutOfBoundsException: Range [62, 61) out of bounds for length 64 'foo<sub>[bar</sub>baz]', 'foo<sup>[bar</sup>baz]', 'foo<u>[bar</u>baz]', 'foo<a href=http://www.google.com>[bar</a>baz]', 'oo<ont face=sans-serif>bar<font>baz]', 'foo<font size=4>[bar</font>baz]',
foo<ont #0000FF[ar<b'java.lang.StringIndexOutOfBoundsException: Index 49 out of bounds for length 49 'foo<span style=background-color:#00FFFF>[bar</span>baz]', 'foo<a href=http://www.google.com><font color=blue>[bar</font></a>baz]',[foo[b' createlink' 'java.lang.StringIndexOutOfBoundsException: Range [47, 46) out of bounds for length 49 'foo<font color=blue><a href=http://www.google.com>[bar</a></font>baz]', 'foo<a href=http://www.google.com><font color=brown>[bar</font></a>baz]', 'foo<font color=brown><a href=http://www.google.com>[bar</a></font>baz]', 'foo<a href=http://www.google.com><font color=black>[bar</font></a>baz]', 'foo<a href=http://www.google.com><u>[bar</u></a>baz]', 'foo<u><a href=http://www.google.com>[bar</a></u>baz]', 'foo<sub><font size=2>[bar</font><'[b' cjava.lang.StringIndexOutOfBoundsException: Range [33, 32) out of bounds for length 56 'foo<font size=2><sub>[bar</sub></font>baz]', 'foo<sub'[b''', i]java.lang.StringIndexOutOfBoundsException: Index 54 out of bounds for length 54 'foo<font size=3><sub>[bar</sub></font>baz]',
/ '<blockquote><font color=blue>[foo]</font></blockquote>',
],
/
insertunorderedlist: [ //@{' 'justifyfull']java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50 'foo[]bar', 'foo[bar]baz', 'foo<br>[bar]', '[obr>b]ar<br>baz', '<p>[foo]<br>bar</p>', '[foo<ol><li>bar]</ol>baz', 'foo<ol><li>[bar</ol>baz]', '[foo<ul><li>bar]</ul>baz', 'foo<ul><li>[bar</ul>baz]', 'foo<ul><li>[bar</ul><ol><li>baz]</ol>quz', 'foo<ol><li>[bar</ol><ul><li>baz]</ul>quz',
<><tbody>tr><tdfootd>b[]r<d</>, '<table><tbody><tr><td>fo[o<td>b]ar<td>baz</table>', '{<table><tr><td>foo<td>bar<td>bazjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
// Various <ol> stuff '<ol><li>foo<li>[bar]<li>baz</ol>', '<ol><li>foo</ol>[bar]', '[foo]<ol><li>bar</ol>', '<ol><li>foo</ol>[bar]<ol><li>baz</ol>', '<ol><ol><li>[foo]</ol></ol>', '<ol><li>[foo]<br>bar<li>baz</ol>', '<ol><li>foo<br>[bar]<li>baz</ol>', '<ol><li><div>[foo]</div>bar<li>baz</ol>', '<ol><li>foo<ol><li>[bar]<li>baz</ol><li>quz</ol>', '<ol><li>foo<ol><li>bar<li>[baz]</ol><li>quz</ol>', '<ol><li>foo</li><ol><li>[bar]<li>baz</ol><li>quz</ol>', '<ol><li>foo</li><ol><li>bar<li>[baz]</ol><li>quz</ol>', '<ol><li>[foo]['oo]ar' ' insertparagraph,inserttext]java.lang.StringIndexOutOfBoundsException: Index 66 out of bounds for length 66 '<ol><li>[foo]</li><ol><li>bar</ol><li>baz</ol>', '<ol><li>foo<li>[bar]<ol><li>baz</ol><li>quz</ol>', '<ol><li>foo<li>[bar]</li><ol><li>baz</ol><li>quz</ol>', '<ol><li>foo<ol><li>bar<li>baz</ol><li>[quz]</ol>', '<ol><li>foo</li><ol><li>bar<li>baz</ol><li>[quz]</ol>',
// Multiple items at once. '<ol><li>foo<li>[bar<li> ['foo[]bar', 'fontname', 'jfoo]ar''''java.lang.StringIndexOutOfBoundsException: Range [46, 45) out of bounds for length 62 '<ol><li>[foo<ol><li>bar]</ol><li>baz</ol>',
<lifoo<>l>bar/ol<ib<ol', '<ol><li>[foo<ol>< 'foo[bar','fontname' o']
// We probably can't actually get this DOM . . . '<ol><li>[foo]<ol><li>bar</ol>java.lang.StringIndexOutOfBoundsException: Range [0, 41) out of bounds for length 0 '<ol><li>foo<ol><li>[bar]</ol>baz</ol>', '<ol><li>foo<ol><li>bar</ol>[baz]</ol>', '<ol><li>[foo<ol><li>bar]</ol>baz</ol>',
// Multiple items at once. '<ul><li['foo]' 'ontsize'','java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50 '<ul><li>[foo<ul><li>bar]<[foo[bar' f',','nserttext]java.lang.StringIndexOutOfBoundsException: Index 62 out of bounds for length 62 '<ul><li>foo<ul><li>b[ar</ul><li>b]az</ul>', 'ul>li[fooul><li>bar/ul><li>]/><p',
// We probably can't actually get this DOM . . .
>baz/>, '<ul><li>foo<ul><li>[bar]</ul>baz</ul>', '<ul><li>foo<ul><li>bar</ul>[baz]</ul>', '<ul><li>[foo<ul><li>bar]</ul>baz</ul>',
// Mix of <ol> and <ul> ' '[b', ', 'elete] 'foo<ol><li>bar</ol><ul><li>[baz</ul>quz]', 'foo<ul><li>[bar]</ul><ol><li>baz</ol>quz''[bar,'forecolorjava.lang.StringIndexOutOfBoundsException: Range [47, 46) out of bounds for length 49 '[foo<ul><li>bar]</ul><ol><li>baz</ol>quz',
'<p>[foo]<blockquote '<p>foo<blockquote><p>[bar]</blockquote><p>baz', '<p>[foo<blockquote><p>bar]java.lang.StringIndexOutOfBoundsException: Index 67 out of bounds for length 67 '<ol><li>foo</ol><blockquote><p>[bar]</blockquote><p>baz',
'<>[]/addressbaz' 'foo< 'oojava.lang.StringIndexOutOfBoundsException: Index 71 out of bounds for length 71 'foo<dfn>b[a]r</dfn>baz', 'foo<em>b[a]r</em>baz', 'foo<i>b[a]r</i>baz', 'foo<var>b[a]r</var>baz',
foostylestyle >bar]/>azjava.lang.StringIndexOutOfBoundsException: Index 62 out of bounds for length 62 'foo<span style="font / Test things that interfere with each other 'foo<span style="font-style: oblique">b[a]r</span>baz',
'<div align=right> '<> =2>]/>/>,', '' '<['foo2<>b<<baz,'java.lang.StringIndexOutOfBoundsException: Range [63, 62) out of bounds for length 79 '<iv style=text-lign:right><>[oo<p>bar<div><>extra'java.lang.StringIndexOutOfBoundsException: Index 67 out of bounds for length 67 '<div style=text-align:right><p>[foo<p>bar]</div><p>extra',
'<div align=center>{<div align=left>foo</div>}</div>', '<div align=left>{<div align=center>foo</div>}</div>', ' align={div =leftfoo/>bar/>java.lang.StringIndexOutOfBoundsException: Index 65 out of bounds for length 65 '<div align=left>{<div align=center>foo</div>bar}</div>', '<div align=center>{<div align=left>foo</div><img src=/img/lion.svg>}</div>', '<div align=left>{<div align=center>foo</div><img src=/img/lion.svg>}</div>', '<div align=center>{<div align=left>foo</div><!-- bar -->}</div>', '<div align=left>{<div align=center>foo</div><!-- bar -->}</div>',
d java.lang.StringIndexOutOfBoundsException: Range [20, 19) out of bounds for length 58 '<div style=text-align:end>[foo]</div><p>extra', '<div dir=rtl style=text-align:start>[foo]</div><p>extra', '<iv dirrtl style=extalign>foo</<>extra,
'<table><tbody align=justify><tr><td>foo<td>b[a]r<td>baz</table><p>extra', '<table><tbody align=justify><tr data-start=1 data-end=2><td>foo<td>bar<td>baz</table><p>extra', 'var =java.lang.StringIndexOutOfBoundsException: Range [29, 28) out of bounds for length 41 '<table><tbody align=justify data-start=0 data-end=1><tr><td>foo<td>bar<td>baz</table><p>extra', '<table data-start=0 data-end=1><tbody align=justify><tr><td>foo<td>bar<td>baz</table><p>extra', '{<table><tbody align=justify><tr><td>foo<td>bar<td>baz</table>}<p>extra',
'<table><tbody><tr align=justify><td>foo<td>b[a]r<td>baz</table><p>extra', '<java.lang.StringIndexOutOfBoundsException: Range [63, 15) out of bounds for length 63 '<table><tbody><tr align=justify data-start=0 data-end=2><td>foo<td>bar<td>baz</table><p>extra', '<table><tbody data-start=0 data-end=1><tr align=justify><td>foo<td>bar<td>baz</table><p>extra', '<table data-start=0 data-end=1><tbody><tr align=justify><td>foo<td>bar<td>baz</table><p>extra', '{<table><tr align=java.lang.StringIndexOutOfBoundsException: Range [0, 34) out of bounds for length 13
'<divjava.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 18 '<div style=text-align:inherit><p>[foo]</div><p>extra', '<"strikethrough,
'<div align=justify><p} '<div align=justify><p>[foo<p>bar}</div><p>extra' = valuereplace RegExpString.() g) )java.lang.StringIndexOutOfBoundsException: Index 80 out of bounds for length 80 '<div style=text-align:justify><p>[foo]<p>bar</div><p>extra', '<div style=text-align:justify><p>[foo<p>bar]</div><p>extra',
'<function doSe(selector,idx java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33 '<div align=left><p>[foo<p>bar}</div><p>extra', '<div style=text-align:left><p>[foo]<p>bar</div><p>extra',
< =extleft<[oop<divpextra,
'<div align=right>[foo</div>bar]<p>extra', '<div align=right>fo[o</div>b]ar<p>extra',
<style-align[<div]p>, '<div style=text-align:right>fo[o<java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 '<span style=text-align:right>[foo]</span><p>extra', '<span style=text-align:right>f[o]o</span><p>extra',
// Lists! '<ol><li>foo<li>[bar]<li>baz</ol>', '<ol data-start=1 data-end=2><li> ,value) '<ol><li>foo</ol>[bar]', '<ol><li>[foo]<br>bar<li>baz</ol>', '<ol><li>foo<br>[bar]<li>baz</ol>', '<ol><li><div>[foo]</div>bar } '<ol><li>foo<ol><li>[bar]<li>baz</ol><li>quz</ol>', '<ol><li>foo<ol><li>bar<li>[baz]</ol><li>quz</ol>', '<l<li>foo</i><ol>li>bar]li>baz<ol<li>quz</l>' '<ol><li>foo</li><ol data-start '<ol><li>foo</li><ol><li>bar<li>[baz]</ol><li>quz</ol>', '<ol><li>foo</li><ol data-start=1 data-end=2><li>bar<li>baz</ol><li>quz</ol>', '<ol><li>foo<ol><li>b[a]r</ol><li>baz</ol>', '<ol><li>foo</li><java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 0 '<ol><li>foo{<ol><li>bar</ol>}<li>baz</ol>', '<ol><li>foo</li>{<ol><li>bar</ol>}<li>baz</ol>', '<ol><li>[foo]<ol><li>bar</ol><li>baz</ol>', '<ol><li>[foo]</li><ol><li>bar</ol><li>baz</ol>', '<ol><li>foo<li>[bar]<ol><li>baz</ol><li>quz</ol>', '<ol><li>foo<li>[bar]</li><ol><li>baz</ol><li>quz</ol>', '<ol><li>foo<ol><li>bar<li>baz</ol><li>[quz]</ol>', '<ol><li>foo</li><ol><li>bar<li>baz</ol><li>[quz]</ol>',
// Try outdenting multiple items at once. '<ol><li>foo<li>b[ar<li>baz]</ol>', '<ol><li>[foo<ol><li>bar]</ol><li>baz</ol>', '<ol><li>[foo< / multiTests arrays: '<ol><li>foo<ol '<ol><li>foo</li><ol><li>b / key of the tests array. If the command takes values, the value is given '<ol><li>[foo<ol><li>bar</ol><li>java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 6 '<ol><li>[foo</li><ol><li>bar</ol><li>baz]</ol><p>extra',
// We probably can't actually get this DOM . . . '<ol><li>[foo]<ol><li>bar</ol>baz</ol>', '<ol><li>foo<ol><li>[bar]</ol>baz</ol>',
<>>bar</>, '<ol><li>[foo<ol><li>bar]</ol>baz</ol>',
// Attribute handling on lists 'foo<ol start=5><li>[bar]</ol>baz', 'foo<ol id=abc><li>[bar]</ol>baz', '& [i defaultValues 'foo<ol><li value=5>[bar]</ol>baz', 'foo<ol><li id=abc>[bar]</ol>baz', '<>java.lang.StringIndexOutOfBoundsException: Range [26, 25) out of bounds for length 52 '<ol><li>foo</li><ol><li value=5>[bar]</ol></ol>', '<ul><li>foo</li><ol><li value=5>[bar]</ol></ul>', '<ol><li>foo</li><ol start=5><li>[bar]</ol><li>baz</ol>', '<ol><li>foo</li><ol id=abc><li>[bar]</ol><li>baz</ol>', '<ol><li>foo</li><ol style=color:blue><li>[bar]</ol><li>baz</ol>', '<ol><li>foo</li><ol style=text-indent:1em><li>[bar]</ol><li>baz</ol>', '<ol><li>foo</li><ol start=5><li>[bar<li>baz]</ol><li>quz</ol>', '<ol><li>foo</li><ol id=abc><li>[bar<li>baz]</ol><li>quz</ol>', '<ol><li>foo</li><ol style=color:blue><li>[bar<li>baz]</ol><li>quz</ol>', '<ol><li>foo</li><ol style=text-indent:1em><li>[bar<li>baz]</ol><li>quz</ol>',
// List inside indentation element }elsetest.ength =2{ '<blockquote><ol><li>[foo]</ol></blockquote><p>extra', '<blockquote>foo<ol><li>[bar]</ol>baz</blockquote><p>extra', '<blockquote><ol><li>foo</li><ol><li>[bar]</ol><li>baz</ol></blockquote><p>extra',
'<ol><li><h1>[foo]</h1></ol>', '<ol><li><xmp>[foo]</xmp></li></ol> ( ! java.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 37 '<blockquote><ol><li>foo<div><ol><li>[bar]</ol></div><li>baz</ol></blockquote>',
// Whitespace nodes '<blockquote> <p>[foo]</p></blockquote>', '<blockquote><p>[foo]</p> </blockquote>', '<blockquote> <p>[foo]</p> </blockquote>', 'ol <>f<li>/>, '<ol><li>[foo]</li> </ol>', '<ol> <li>[foo]</li> </ol>', '<ul><li>[oo</i</>'java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35 '<ul><li>[foo]</li> msg =java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19 '<ul> <li>[foo]</li> </ul>', '<blockquote> <p>[foo]</p> <p>bar</p> <p>baz</p></blockquote>', '<blockquote> <p>foo</p> <p>[bar]</p> <p>baz</p></blockquote>', '<blockquote> <p>foo</p> <p>bar</p> <p>[baz]</p></blockquote>', '<ol> <li>[foo]</li> <li>bar</li> <li>baz</li></ol>', 'ol <i>foo</li> <li>[bar]</li> <li>baz</li></ol>', '<ol> <li>foo</li> <li>bar</li> <li>[baz]</li></ol>', '<ul> <li>[foo]</li> <li>bar</li> <li>baz</li></ul>', '<ul> <li>foo</li> <li>[bar]</li> <li>baz</li></ul>', '<ul> <li>foo</li> <li>bar</li> <li>[baz]</li></ul>',
// Empty and replaced elements '[foo<br>bar]', '[foo<hr>bar]', '[foo<wbr>bar]', '[foo<img>bar]', '[foo<img src=abc>bar]', '[foo<video></video>bar]', '[foo<video src=abc></video>bar]', '[foo<svg><circle fill=blue r=20 cx=20 cy=20 /></svg>bar]',
// Unrecognized elements '[foo<nonexistentelement>bar</nonexistentelement>baz]', 'foo<nonexistentelement>b[a]r</nonexistentelement>baz',
var f); 'foo<nonexistentelement style="display: block">b[a]r</nonexistentelement>baz',
// Random stuff '[foo<span id=foo>bar</span>baz]', 'foo<span id=foo>b[a]r</span>baz', '[foo<span class=foo>bar</span>baz]', 'foo<span class=foo>b[a]r</pan>baz'java.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 45 '[foo<b style="font-weight: normal">bar</b>baz]', 'foo<b style="font-weight: normal">b[a]r</b>baz', '<pstyle="background-color: aqua">foo[bar]baz</p>', '<p><span style="background-color: aqua">foo[bar]baz</span></p>', '<p style="font-weight: bold">foo[bar]baz</p>',
< style=font-:bold"[b<p<b'java.lang.StringIndexOutOfBoundsException: Index 62 out of bounds for length 62 '<p style="font-variant: small-caps">foo[bar]baz</p>', '{<p style="font-variant: small-caps">foobarbaz</p>}', '<p style= } '{<p style="text-indent: 2em">foobarbaz</p>}',
// https://bugzilla.mozilla.org/show_bug.cgi?id=649138 // Chrome 15 dev fails this for some unclear reason. '<table data-start=0 data-end=1><tr><td><b>foo</b></table>',
] //@}
strikethroughjava.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 20 //@{ 'foo[]bar', '<p>[foo</p> <p>bar]</p>', '<span>[foo</span> <span>bar]</span>', '<p>[foo</p><p> <span>bar</span> </p><p>baz]</p>', '<p>[foo<p><br><p>bar]', '<b>foo[bar<b>', '<i>foo[]bar</i>', '<span>foo</span>{}<span>bar</span>', '<span>foo[</span><span>]bar</span>', 'foo[bar]baz', 'foo[bar<b>baz]qoz</b>quz', 'foo[bar<i>]qoz</i>quz', '{<p><p> <p>foo</p>}',
'<table><tbody><tr><td>foo<td>b[a]r<td>baz</table>', '<table><tbody><tr data-start=1 data-end=2><td>foo<td>bar<td>baz</table>', '<table><tbody><tr data-start=0 data-end=2><td>foo<td>bar<td>baz</table>', '<table><tbody data-start=0 data-end=1command test[est.length - 1][1])); '<table data-start=0 data-end=1><tbody><tr><td>foo<td>bar<td>baz</table>', '{<table><java.lang.StringIndexOutOfBoundsException: Range [12, 1) out of bounds for length 56
'foo<sub>[bar]</sub>baz', 'foo<sub>b[a]r</sub>baz', 'foo<sup>java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40 'foo<sup>b[a]r</sup>baz',
an 'foo<span style=vertical-align:super>[bar]</span>baz',
'foo<sub><sub>[bar]</sub></sub>baz', 'foo<.replace(/<\?strong/ <1' 'foo<sub>b<sub>[a]</sub>r</sub>baz', 'foo<sup><sup>[bar]</sup></sup>baz', 'foo<sup><sup>b[a]r</sup></sup>baz', 'foo<./[-9-A-F]6/, match){return match.toUpperCase(); }); 'foo<sub><sup>[bar]</sup></sub>baz', 'foo<sub><sup>b[a]r</sup></sub>baz', 'foo<sub>b<sup>[a]</sup>r</sub>baz', 'foo<sup><sub>[ .replace(/[[\{]g ") 'foo<sup><sub>b[a]r</sub></sup./ "java.lang.StringIndexOutOfBoundsException: Range [41, 40) out of bounds for length 89 'foo<sup>b<sub>[a]</sub>r</sup>baz',
72 'foo<sup>[bar]<br></sup>',
], //@}
underlinejava.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 16 //@{
foo], '<p>[foo</p> <p>bar]</p>', '<span>[foo</span> <span>bar]</span>', '<p>[foo</p><p> <span>bar</span> </p><p>baz]</p>', 'p>[p<br><pb], '<b>foo[]bar</b>',
</> '<span>foo</span>{}<span>bar</span>', '<span>foo[</span><span>]bar</span>', 'foo[bar]baz', 'b<b>baz]oz<b>uz'java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35 'foo[bar<i>baz]qoz</i>quz', '{<p><p> <p>foo</p>}',
'<table><tbody><tr><td>foo<td>b[a]r<td> '<table>< // Insert <wbr> so IE doesn't stretch the screen. This is considerably '<table><tbody><tr data-start=0 data-end=2><td>foo<td>bar<td>baz</table>', '<table><tbody data-start=0 data-end=1><tr><td>foo<td>bar<td>baz</table>', '<table data-start=0 data-end=1><tbody><tr><td>foo<td>bar<td>baz</table>', '{<table><tr><td>foo<td>bar<td>baz</table>}',
var =divfirstChild.textContent 'foo<span style="text-decoration: underline">[bar]</span>baz', '<u>foo[bar]baz</u>', '<u>foo[b<span style="color:blue">ar]ba</span>z</u>',
<>foo< style=colorblue=b</java.lang.StringIndexOutOfBoundsException: Index 68 out of bounds for length 68 '<u>foo[b<span style="font-size:3em">ar]ba //,"java.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 38 '<u>foo[b<i>ar]ba</i>z</u>', '<p style="text-decoration: underline">foo[bar]baz</p>',
foo>bar<strikebaz' '<strike>foo[bar]baz</strike>', '<strike>foo[b<span style="color:blue">ar]ba</span>z</strike>', '<strike>foo[b<span style="color:blue" id=foo>ar]ba</span>z</strike>', '<strike>foo[b<span style="font-size:3em">ar]ba</span>z</strike>', '<strike>foo[b<i>ar]ba</i>zjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
'foo<ins>[bar]</ins>baz', '<ins>foo[bar]baz</ins>', ' '<ins>foo[b<span style="color:blue" id=foo>java.lang.StringIndexOutOfBoundsException: Range [0, 53) out of bounds for length 32 '<ins>foo[b< cell.innerHTML = "<div</div><><div>" '<ins>foo[b<i>ar]ba</i>z</ins>',
['foo[]bar', assert_equalstestDivinnerHTML
['foo[]bar', 'hilitecolor', 'delete'],
['foo[]bar', 'hilitecolor', 'delete', 'inserttext'],
['foo[]bar', UnexpectedinnerHTML (afternormalizing inline;
['foo[]bar', 'hilitecolor', 'formatblock', 'inserttext'],
['foo[]bar', 'hilitecolor', 'forwarddelete'],
['foo[]bar', 'hilitecolor', 'forwarddelete', 'inserttext'],
['foo[]bar',
['foo[]bar', 'hilitecolor', 'indent', 'inserttext'],
['foo[]bar', 'hilitecolor', 'inserthorizontalrule'],
['foo[]bar', 'hilitecolor', 'inserthorizontalrule', 'inserttext'], 'queryCommandIndeterm('+ command ')before',
['foo[]bar', 'hilitecolor', 'inserthtml', 'inserttext'],
['foo[]bar', 'hilitecolor', 'insertimage'],
['foo[]bar', 'hilitecolor', 'insertimage', 'inserttext'],
['foo[]bar', 'hilitecolor', 'insertlinebreak'],
[', 'nsertlinebreak','inserttext'],
['foo[]bar', 'hilitecolor', 'insertorderedlist'],
['foo[]bar', 'hilitecolor', 'insertorderedlist', 'inserttext'],
['foo[]bar', 'hilitecolor', 'insertparagraph'],
['foo[]bar', 'hilitecolor', 'insertparagraph', 'inserttext'],
['foo[]bar', 'hilitecolor', ' (test function( java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 41
['foo[]bar', 'hilitecolor', 'insertunorderedlist', 'inserttext'],
['foo[]bar', 'hilitecolor', 'justifycenter'],
erttext]java.lang.StringIndexOutOfBoundsException: Index 67 out of bounds for length 67
['foo[]bar', 'hilitecolor', 'justifyfull'],
['foo/ DOMException.FIXME This should be made more rigorous,
['foo[]bar', 'hilitecolor', 'justifyleft'],
['foo[]bar', 'hilitecolor', 'justifyleft', 'inserttext'],
['foo[]bar', 'hilitecolor', 'justifyright'],
['foo[]bar', 'hilitecolor', 'justifyright', 'inserttext'],
['foo ( in actualQueryExceptions[command],
['foo[]bar', 'hilitecolor', 'outdent', 'inserttext'],
// Test things that interfere with each other
['foo[]bar', 'superscript', 'subscript', 'inserttext'],
['foo[]bar', 'subscript', 'superscript', 'inserttext'],
// Tests that start with "!" are believed to have bogus results and should be // skipped until the relevant bugs are fixed.
var badTests = {};
(function(){ for (var command in tests) {
badTests[command] = []; for (var i = 0; i < tests[command].length; i++) {
var test = tests[command][i]; if (typeof test == "string" && test[0] == "!") {
test = test.slice(1);
tests[command][i] = test;
badTests[command].push(test);
} if (typeof test == "object" && test[0][0] == "!") {
test = [test[0].slice(1)].concat(test.slice(1));
tests[command][i] = test;
badTests[command].push(test);
}
}
}
})();
function queryOutputHelper(beforeIndeterm, beforeState, beforeValue,
afterIndeterm, afterState, afterValue,
command, value) { //@{
var frag = document.createDocumentFragment();
var beforeDiv = document.createElement("div");
var afterDiv = document.createElement("div");
frag.appendChild(beforeDiv);
frag.appendChild(afterDiv);
beforeDiv.className = afterDiv.className = "extra-results";
beforeDiv.textContent = "Before: ";
afterDiv.textContent = "After: ";
beforeDiv.appendChild(document.createElement("span"));
afterDiv.appendChild(document.createElement("span")); if ("indeterm" in commands[command]) { // We only know it has to be either true or false. if (beforeIndeterm !== true && beforeIndeterm !== false) {
beforeDiv.lastChild.className = "bad-result";
}
} else { // It always has to be false.
beforeDiv.lastChild.className = beforeIndeterm === false
? "good-result"
: "bad-result";
} // After running the command, indeterminate must always be false, except if // it's an exception, or if it's insert*list and the state was true to // begin with. And we can't help strikethrough/underline. if ((/^insert(un)?orderedlist$/.test(command) && beforeState)
|| command == "strikethrough"
|| command == "underline") { if (afterIndeterm !== true && afterIndeterm !== false) {
afterDiv.lastChild.className = "bad-result";
}
} else {
afterDiv.lastChild.className =
afterIndeterm === false
? "good-result"
: "bad-result";
}
beforeDiv.lastChild.textContent = "indeterm " + prettyPrint(beforeIndeterm);
afterDiv.lastChild.textContent = "indeterm " + prettyPrint(afterIndeterm);
beforeDiv.appendChild(document.createElement("span"));
afterDiv.appendChild(document.createElement("span")); if (/^insert(un)?orderedlist$/.test(command)) { // If the before state is true, the after state could be either true or // false. But if the before state is false, the after state has to be // true. if (beforeState !== true && beforeState !== false) {
beforeDiv.lastChild.className = "bad-result";
} if (!beforeState) {
afterDiv.lastChild.className = afterState === true
? "good-result"
: "bad-result";
} elseif (afterState !== true && afterState !== false) {
afterDiv.lastChild.className = "bad-result";
}
} elseif (/^justify(center|full|left|right)$/.test(command)) { // We don't know about the before state, but the after state is always // supposed to be true. if (beforeState !== true && beforeState !== false) {
beforeDiv.lastChild.className = "bad-result";
}
afterDiv.lastChild.className = afterState === true
? "good-result"
: "bad-result";
} elseif (command == "strikethrough" || command == "underline") { // The only thing we can say is the before/after states need to be // either true or false. if (beforeState !== true && beforeState !== false) {
beforeDiv.lastChild.className = "bad-result";
} if (afterState !== true && afterState !== false) {
afterDiv.lastChild.className = "bad-result";
}
} else { // The general rule is it must flip the state, unless there's no state // defined, in which case it should always be false.
beforeDiv.lastChild.className =
afterDiv.lastChild.className =
("state" in commands[command] && typeof beforeState == "boolean" && typeof afterState == "boolean" && beforeState === !afterState)
|| (!("state" in commands[command]) && beforeState === false && afterState === false)
? "good-result"
: "bad-result";
}
beforeDiv.lastChild.textContent = "state " + prettyPrint(beforeState);
afterDiv.lastChild.textContent = "state " + prettyPrint(afterState);
// Direct equality comparison doesn't make sense in a bunch of cases. if (command == "backcolor" || command == "forecolor" || command == "hilitecolor") { if (/^([0-9a-fA-F]{3}){1,2}$/.test(value)) {
value = "#" + value;
}
} elseif (command == "fontsize") {
value = normalizeFontSize(value); if (value !== null) {
value = String(cssSizeToLegacy(value));
}
} elseif (command == "formatblock") {
value = value.replace(/^<(.*)>$/, "$1").toLowerCase();
} elseif (command == "defaultparagraphseparator") {
value = value.toLowerCase(); if (value != "p" && value != "div") {
value = "";
}
}
if (((command == "backcolor" || command == "forecolor" || command == "hilitecolor") && value.toLowerCase() == "currentcolor")
|| (command == "fontsize" && value === null)
|| (command == "formatblock" && formattableBlockNames.indexOf(value.replace(/^<(.*)>$/, "$1").trim()) == -1)
|| (command == "defaultparagraphseparator" && value == "")) {
afterDiv.lastChild.className = beforeValue === afterValue
? "good-result"
: "bad-result";
} elseif (/^justify(center|full|left|right)$/.test(command)) { // We know there are only four correct values beforehand, and afterward // the value has to be the one we set. if (!/^(center|justify|left|right)$/.test(beforeValue)) {
beforeDiv.lastChild.className = "bad-result";
}
var expectedValue = command == "justifyfull"
? "justify"
: command.replace("justify", "");
afterDiv.lastChild.className = afterValue === expectedValue
? "good-result"
: "bad-result";
} elseif (!("value" in commands[command])) { // If it's not defined we want "".
beforeDiv.lastChild.className = beforeValue === ""
? "good-result"
: "bad-result";
afterDiv.lastChild.className = afterValue === ""
? "good-result"
: "bad-result";
} else { // And in all other cases, the value afterwards has to be the one we // set.
afterDiv.lastChild.className =
areEquivalentValues(command, afterValue, value)
? "good-result"
: "bad-result";
}
beforeDiv.lastChild.textContent = "value " + prettyPrint(beforeValue);
afterDiv.lastChild.textContent = "value " + prettyPrint(afterValue);
return frag;
} //@}
function normalizeTest(command, test, styleWithCss) { //@{ // Our standard format for test processing is: // [input HTML, // [command1, value1, optional_name_mod], // [command2, value2, optional_name_mod], ...] // Where `optional_name_mod` is an optionally-specified string used when // generating test names (necessary to ensure uniqueness for command // sequences that use the same command multiple times). This format is // verbose, so we actually use three different formats in the tests and // multiTests arrays: // // 1) Plain string giving the input HTML. The command is implicit from the // key of the tests array. If the command takes values, the value is given // by defaultValues, otherwise it's "". Has to be converted to // [input HTML, [command, value]. // // 2) Two-element array [value, input HTML]. Has to be converted to // [input HTML, [command, value]]. // // 3) An element of multiTests. This just has to have values filled in. // // Optionally, a styleWithCss argument can be passed, either true or false. // If it is, we'll prepend a styleWithCss invocation. if (command == "multitest") { if (typeof test == "string") {
test = JSON.parse(test);
} for (var i = 1; i < test.length; i++) { if (typeof test[i] == "string"
&& test[i] in defaultValues) {
test[i] = [test[i], defaultValues[test[i]]];
} elseif (typeof test[i] == "string") {
test[i] = [test[i], ""];
}
} return test;
}
if (typeof test == "string") { if (command in defaultValues) {
test = [test, [command, defaultValues[command]]];
} else {
test = [test, [command, ""]];
}
} elseif (test.length == 2) {
test = [test[1], [command, String(test[0])]];
}
if (styleWithCss !== undefined) {
test.splice(1, 0, ["stylewithcss", String(styleWithCss)]);
}
return test;
} //@}
function doInputCell(tr, test, command) { //@{
var testHtml = test[0];
var msg = null; if (command in defaultValues) { // Single command with a value, possibly with a styleWithCss stuck // before. We don't need to specify the command itself, since this // presumably isn't in multiTests, so the command is already given by // the section header.
msg = 'value: ' + prettyPrint(test[test.length - 1][1]);
} elseif (command == "multitest") { // Uses a different input format
msg = JSON.stringify(test);
}
var inputCell = document.createElement("td");
inputCell.innerHTML = "<div></div><div></div>";
inputCell.firstChild.innerHTML = testHtml;
inputCell.lastChild.textContent = inputCell.firstChild.innerHTML; if (msg !== null) {
inputCell.lastChild.textContent += " (" + msg + ")";
}
tr.appendChild(inputCell);
} //@}
function doSpecCell(tr, test, command) { //@{
var specCell = document.createElement("td");
tr.appendChild(specCell); try {
var points = setupCell(specCell, test[0]);
var range = document.createRange();
range.setStart(points[0], points[1]);
range.setEnd(points[2], points[3]); // The points might be backwards if (range.collapsed) {
range.setEnd(points[0], points[1]);
}
specCell.firstChild.contentEditable = "true";
specCell.firstChild.spellcheck = false;
specCell.firstChild.contentEditable = "inherit";
specCell.firstChild.removeAttribute("spellcheck");
var compareDiv1 = specCell.firstChild.cloneNode(true);
// Now do various sanity checks, and throw if they're violated. First // just count children: if (specCell.childNodes.length != 2) { throw"The cell didn't have two children. Did something spill outside the test div?";
}
// Now verify that the DOM serializes.
compareDiv1.normalize();
var compareDiv2 = compareDiv1.cloneNode(false);
compareDiv2.innerHTML = compareDiv1.innerHTML; // Oddly, IE9 sometimes produces two nodes that return true for // isEqualNode but have different innerHTML (omitting closing tags vs. // not). if (!compareDiv1.isEqualNode(compareDiv2)
&& compareDiv1.innerHTML != compareDiv2.innerHTML) { throw"DOM does not round-trip through serialization! "
+ compareDiv1.innerHTML + " vs. " + compareDiv2.innerHTML;
} if (!compareDiv1.isEqualNode(compareDiv2)) { throw"DOM does not round-trip through serialization (although innerHTML is the same)! "
+ compareDiv1.innerHTML;
}
// Check for attributes if (specCell.firstChild.attributes.length) { throw"Wrapper div has attributes! " +
specCell.innerHTML.replace(/<div><\/div>$/, "");
}
// Final sanity check: make sure everything isAllowedChild() of its // parent.
getDescendants(specCell.firstChild).forEach(function(descendant) { if (!isAllowedChild(descendant, descendant.parentNode)) { throw"Something here is not an allowed child of its parent: " + descendant;
}
});
// Don't bother comparing to localStorage, this is always wrong no // matter what. return;
}
if (command != "multitest") { // Old storage format
var key = "execcommand-" + command
+ "-" + (test.length == 2 || test[1][1] == "false" ? "0" : "1")
+ "-" + tr.firstChild.lastChild.textContent;
} else {
var key = "execcommand-" + JSON.stringify(test);
}
// Use getItem() instead of direct property access to work around Firefox // bug: https://bugzilla.mozilla.org/show_bug.cgi?id=532062
var oldValue = localStorage.getItem(key);
var newValue = specCell.lastChild.firstChild.textContent;
// Ignore differences between {} and []. if (oldValue === null
|| oldValue.replace("{}", "[]") !== newValue.replace("{}", "[]")) {
specCell.parentNode.className = "alert";
var alertDiv = document.createElement("div");
specCell.lastChild.appendChild(alertDiv);
alertDiv.className = "alert"; if (oldValue === null) {
alertDiv.textContent = "Newly added test result";
} elseif (oldValue.replace(/[\[\]{}]/g, "") == newValue.replace(/[\[\]{}]/g, "")) {
alertDiv.textContent = "Last run produced a different selection: " + oldValue;
} else {
alertDiv.textContent = "Last run produced different markup: " + oldValue;
}
var button = document.createElement("button");
alertDiv.appendChild(button);
button.textContent = "Store new result";
button.className = "store-new-result";
button.onclick = (function(key, val, alertDiv) { return function() {
localStorage[key] = val; // Make it easier to do mass updates, and also to jump to the next // new result
var buttons = document.getElementsByClassName("store-new-result"); for (var i = 0; i < buttons.length; i++) { if (isDescendant(buttons[i], alertDiv)
&& i + 1 < buttons.length) {
buttons[i + 1].focus(); break;
}
}
var td = alertDiv; while (td.tagName != "TD") {
td = td.parentNode;
}
alertDiv.parentNode.removeChild(alertDiv); if (!td.querySelector(".alert")) {
td.parentNode.className = (" " + td.parentNode.className + " ")
.replace(/ alert /g, "")
.replace(/^ | $/g, "");
}
} })(key, newValue, alertDiv);
}
} //@}
for (var i = 0; i <= 2; i++) { // Insert <wbr> so IE doesn't stretch the screen. This is considerably // more complicated than it has to be, thanks to Firefox's lack of // support for outerHTML.
var div = tr.childNodes[i].lastChild; if (div.firstChild) {
var text = div.firstChild.textContent;
div.removeChild(div.firstChild);
div.insertBefore(document.createElement("div"), div.firstChild);
div.firstChild.innerHTML = text
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, "><wbr>")
.replace(/</g, "<wbr><"); while (div.firstChild.hasChildNodes()) {
div.insertBefore(div.firstChild.lastChild, div.firstChild.nextSibling);
}
div.removeChild(div.firstChild);
}
function doTearDown(command) { //@{
getSelection().removeAllRanges();
} //@}
function setupCell(cell, html) { //@{
cell.innerHTML = "<div></div><div></div>";
return setupDiv(cell.firstChild, html);
} //@}
function setupDiv(node, html) { //@{ // A variety of checks to avoid simple errors. Not foolproof, of course.
var re = /\{|\[|data-start/g;
var markers = [];
var marker; while (marker = re.exec(html)) {
markers.push(marker);
} if (markers.length != 1) { throw"Need exactly one start marker ([ or { or data-start), found " + markers.length;
}
var re = /\}|\]|data-end/g;
var markers = [];
var marker; while (marker = re.exec(html)) {
markers.push(marker);
} if (markers.length != 1) { throw"Need exactly one end marker (] or } or data-end), found " + markers.length;
}
node.innerHTML = html;
var startNode, startOffset, endNode, endOffset;
// For braces that don't lie inside text nodes, we can't just set // innerHTML, because that might disturb the DOM. For instance, if the // brace is right before a <tr>, it could get moved outside the table // entirely, which messes everything up pretty badly. So we instead // allow using data attributes: data-start and data-end on the start and // end nodes, with a numeric value indicating the offset. This format // doesn't allow the parent div to be a start or end node, but in that case // you can always use the curly braces. if (node.querySelector("[data-start]")) {
startNode = node.querySelector("[data-start]");
startOffset = startNode.getAttribute("data-start");
startNode.removeAttribute("data-start");
} if (node.querySelector("[data-end]")) {
endNode = node.querySelector("[data-end]");
endOffset = endNode.getAttribute("data-end");
endNode.removeAttribute("data-end");
}
var cur = node; while (true) { if (!cur || (cur != node && !(cur.compareDocumentPosition(node) & Node.DOCUMENT_POSITION_CONTAINS))) { break;
}
if (cur.nodeType != Node.TEXT_NODE) {
cur = nextNode(cur); continue;
}
var data = cur.data.replace(/\]/g, "");
var startIdx = data.indexOf("[");
data = cur.data.replace(/\[/g, "");
var endIdx = data.indexOf("]");
cur.data = cur.data.replace(/[{}]/g, ""); if (!cur.data.length) { if (cur == startNode || cur == endNode) { throw"You put a square bracket where there was no text node . . .";
}
var oldCur = cur;
cur = nextNode(cur);
oldCur.parentNode.removeChild(oldCur);
} else {
cur = nextNode(cur);
}
}
function setSelection(startNode, startOffset, endNode, endOffset) { //@{ if (navigator.userAgent.indexOf("Opera") != -1) { // Yes, browser sniffing is evil, but I can't be bothered to debug // Opera.
var range = document.createRange();
range.setStart(startNode, startOffset);
range.setEnd(endNode, endOffset); if (range.collapsed) {
range.setEnd(startNode, startOffset);
}
getSelection().removeAllRanges();
getSelection().addRange(range);
} elseif ("extend" in getSelection()) { // WebKit behaves unreasonably for collapse(), so do that manually. /* varrange=document.createRange(); range.setStart(startNode,startOffset); getSelection().removeAllRanges(); getSelection().addRange(range);
*/
getSelection().collapse(startNode, startOffset);
getSelection().extend(endNode, endOffset);
} else { // IE9. Selections have no direction, so we just make the selection // always forwards.
var range; if (getSelection().rangeCount) {
range = getSelection().getRangeAt(0);
} else {
range = document.createRange();
}
range.setStart(startNode, startOffset);
range.setEnd(endNode, endOffset); if (range.collapsed) { // Phooey, we got them backwards.
range.setEnd(startNode, startOffset);
} if (!getSelection().rangeCount) {
getSelection().addRange(range);
}
}
} //@}
/** *Addbracketsatthestartandendpointsofthegivenrange,sothatthey're *visible.
*/
function addBrackets(range) { //@{ // Handle the collapsed case specially, to avoid confusingly getting the // markers backwards in some cases if (range.startContainer.nodeType == Node.TEXT_NODE
|| range.startContainer.nodeType == Node.COMMENT_NODE) { if (range.collapsed) {
range.startContainer.insertData(range.startOffset, "[]");
} else {
range.startContainer.insertData(range.startOffset, "[");
}
} else {
var marker = range.collapsed ? "{}" : "{"; if (range.startOffset != range.startContainer.childNodes.length
&& range.startContainer.childNodes[range.startOffset].nodeType == Node.TEXT_NODE) {
range.startContainer.childNodes[range.startOffset].insertData(0, marker);
} elseif (range.startOffset != 0
&& range.startContainer.childNodes[range.startOffset - 1].nodeType == Node.TEXT_NODE) {
range.startContainer.childNodes[range.startOffset - 1].appendData(marker);
} else { // Seems to serialize as I'd want even for tables . . . IE doesn't // allow undefined to be passed as the second argument (it throws // an exception), so we have to explicitly check the number of // children and pass null.
range.startContainer.insertBefore(document.createTextNode(marker),
range.startContainer.childNodes.length == range.startOffset
? null
: range.startContainer.childNodes[range.startOffset]);
}
} if (range.collapsed) { return;
} if (range.endContainer.nodeType == Node.TEXT_NODE
|| range.endContainer.nodeType == Node.COMMENT_NODE) {
range.endContainer.insertData(range.endOffset, "]");
} else { if (range.endOffset != range.endContainer.childNodes.length
&& range.endContainer.childNodes[range.endOffset].nodeType == Node.TEXT_NODE) {
range.endContainer.childNodes[range.endOffset].insertData(0, "}");
} elseif (range.endOffset != 0
&& range.endContainer.childNodes[range.endOffset - 1].nodeType == Node.TEXT_NODE) {
range.endContainer.childNodes[range.endOffset - 1].appendData("}");
} else {
range.endContainer.insertBefore(document.createTextNode("}"),
range.endContainer.childNodes.length == range.endOffset
? null
: range.endContainer.childNodes[range.endOffset]);
}
}
} //@}
function normalizeSerializedStyle(wrapper) { //@{ // Inline CSS attribute serialization has terrible interop, so we fix // things up a bit to avoid spurious mismatches. This needs to be removed // once CSSOM defines this stuff properly, but for now there's just no // standard for any of it. This only normalizes descendants of wrapper, // not wrapper itself.
[].forEach.call(wrapper.querySelectorAll("[style]"), function(node) { if (node.style.color != "") {
var newColor = normalizeColor(node.style.color);
node.style.color = "";
node.style.color = newColor;
} if (node.style.backgroundColor != "") {
var newBackgroundColor = normalizeColor(node.style.backgroundColor);
node.style.backgroundColor = "";
node.style.backgroundColor = newBackgroundColor;
}
node.setAttribute("style", node.getAttribute("style") // Random spacing differences
.replace(/; ?$/, "")
.replace(/: /g, ":") // Gecko likes "transparent"
.replace(/transparent/g, "rgba(0, 0, 0, 0)") // WebKit likes to look overly precise
.replace(/, 0.496094\)/g, ", 0.5)") // Gecko converts anything with full alpha to "transparent" which // then becomes "rgba(0, 0, 0, 0)", so we have to make other // browsers match
.replace(/rgba\([0-9]+, [0-9]+, [0-9]+, 0\)/g, "rgba(0, 0, 0, 0)")
);
});
} //@}
/** *Inputisinthefollowingformat: *[inputHTML, *arrayofcommands, *expectedoutputHTML, *arrayofexpectedexecCommand()returnvalues, *objectofexpectedindeterm/state/value]. *Thearrayofcommandsis[[command,value,optionalDesc],[command,value, *optionalDesc],...].optionalDescisappendedtothedescriptionofthe *testinthegeneratedtestname. * *The *arrayofexpectedexecCommand()returnvaluesis[true|false,true|false, *...],wheretheindicesmatchthoseinthearrayofcommands.The *indeterm/state/valueobjectisoftheform *{command:[expectedindetermbefore,expectedstatebefore, *expectedvaluebefore,expectedindetermafter, *expectedstateafter,expectedvalueafter], *command:...} *nullforanyofthelastsixentriesmeansanINVALID_ACCESS_ERRmustbe *raised.
*/
function runConformanceTest(browserTest) { //@{
document.getElementById("test-container").innerHTML = "<div contenteditable></div><p>test";
var testName = JSON.stringify(browserTest[1]) + " " + format_value(browserTest[0]);
var testDiv = document.querySelector("div[contenteditable]");
var originalRootElement, newRootElement;
var exception = null;
var expectedExecCommandReturnValues = browserTest[3];
var expectedQueryResults = browserTest[4];
var actualQueryResults = {};
var actualQueryExceptions = {};
var subtestName;
try {
var points = setupDiv(testDiv, browserTest[0]);
var range = document.createRange();
range.setStart(points[0], points[1]);
range.setEnd(points[2], points[3]); // The points might be backwards if (range.collapsed) {
range.setEnd(points[0], points[1]);
}
getSelection().removeAllRanges();
getSelection().addRange(range);
var originalRootElement = document.documentElement.cloneNode(true);
originalRootElement.querySelector("[contenteditable]").parentNode
.removeChild(originalRootElement.querySelector("[contenteditable]"));
originalRootElement.querySelector("#log").parentNode
.removeChild(originalRootElement.querySelector("#log"));
for (var command in expectedQueryResults) {
var results = [];
var exceptions = {}; try { results[0] = document.queryCommandIndeterm(command) } catch(e) { exceptions[0] = e } try { results[1] = document.queryCommandState(command) } catch(e) { exceptions[1] = e } try { results[2] = document.queryCommandValue(command) } catch(e) { exceptions[2] = e }
actualQueryResults[command] = results;
actualQueryExceptions[command] = exceptions;
}
} catch(e) {
exception = e;
}
for (var i = 0; i < browserTest[1].length; i++) {
subtestName = testName + ": execCommand(" +
format_value(browserTest[1][i][0]) + ", false, " +
format_value(browserTest[1][i][1]) + ") " +
(browserTest[1][i][2] ? browserTest[1][i][2] + " " : "") + "return value"
subsetTest(test, function() {
assert_equals(exception, null, "Setup must not throw an exception");
subsetTest(test, function() {
assert_equals(exception, null, "Setup must not throw an exception");
// Now test for modifications to non-editable content. First just // count children:
assert_equals(testDiv.parentNode.childNodes.length, 2, "The parent div must have two children. Did something spill outside the test div?");
// Check for attributes
assert_equals(testDiv.attributes.length, 1, 'Wrapper div must have only one attribute (<div contenteditable="">), but has more (' +
formatStartTag(testDiv) + ")");
assert_equals(document.body.attributes.length, 0, "Body element must have no attributes (<body>), but has more (" +
formatStartTag(document.body) + ")");
// Check that in general, nothing outside the test div was modified. // TODO: Less verbose error reporting, the way some of the range tests // do?
assert_equals(newRootElement.innerHTML, originalRootElement.innerHTML, "Everything outside the editable div must be unchanged, but some change did occur");
}, testName + " checks for modifications to non-editable content");
subsetTest(test, function() {
assert_equals(exception, null, "Setup must not throw an exception");
for (var command in expectedQueryResults) {
var descriptions = [ 'queryCommandIndeterm("' + command + '") before', 'queryCommandState("' + command + '") before', 'queryCommandValue("' + command + '") before', 'queryCommandIndeterm("' + command + '") after', 'queryCommandState("' + command + '") after', 'queryCommandValue("' + command + '") after',
];
for (var i = 0; i < 6; i++) {
subsetTest(test, function() {
assert_equals(exception, null, "Setup must not throw an exception");
if (expectedQueryResults[command][i] === null) { // Some ad hoc tests to verify that we have a real // DOMException. FIXME: This should be made more rigorous, // with clear steps specified for checking that something // is really a DOMException.
assert_true(i in actualQueryExceptions[command], "An exception must be thrown in this case");
var e = actualQueryExceptions[command][i];
assert_equals(typeof e, "object", "typeof thrown object");
assert_idl_attribute(e, "code", "Thrown object must be a DOMException");
assert_idl_attribute(e, "INVALID_ACCESS_ERR", "Thrown object must be a DOMException");
assert_equals(e.code, e.INVALID_ACCESS_ERR, "Thrown object must be an INVALID_ACCESS_ERR, so its .code and .INVALID_ACCESS_ERR attributes must be equal");
} elseif ((i == 2 || i == 5)
&& (command == "backcolor" || command == "forecolor" || command == "hilitecolor")
&& typeof actualQueryResults[command][i] == "string") {
assert_false(i in actualQueryExceptions[command], "An exception must not be thrown in this case"); // We don't return the format that the color should be in: // that's up to CSSOM. Thus we normalize before comparing.
assert_equals(normalizeColor(actualQueryResults[command][i]),
expectedQueryResults[command][i], "Wrong result returned (after color normalization)");
} else {
assert_false(i in actualQueryExceptions[command], "An exception must not be thrown in this case");
assert_equals(actualQueryResults[command][i],
expectedQueryResults[command][i], "Wrong result returned");
}
}, testName + " " + descriptions[i]);
}
}
/** *Returnastringlike'<bodybgcolor="#FFFFFF">'.
*/
function formatStartTag(el) { //@{
var ret = "<" + el.tagName.toLowerCase();
for (var i = 0; i < el.attributes.length; i++) {
ret += " " + el.attributes[i].name + '="';
ret += el.attributes[i].value.replace(/\&/g, "&")
.replace(/"/g, """);
ret += '"';
} return ret + ">";
} //@}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.