<!DOCTYPE html>
<html>
<body>
<p>This test ensures WebKit does not fire DOM mutation events while execCommand is in progress.</p>
<div id="test" contenteditable></div>
<pre>
<script>
if (window.testRunner)
testRunner.dumpAsText();
var commands = [
{name: 'BackColor', value: 'blue'},
{name: 'CreateLink', value: 'about:blank'},
{name: 'Delete', value: null},
{name: 'FontName', value: 'Arial'},
{name: 'FontSize', value: '5'},
{name: 'FontSizeDelta', value: '5'},
{name: 'ForeColor', value: 'blue'},
{name: 'FormatBlock', value: 'pre'},
{name: 'ForwardDelete', value: null},
{name: 'HiliteColor', value: 'red'},
{name: 'Indent', value: null},
{name: 'InsertHTML', value: "<i>hello</i>"},
{name: 'InsertHorizontalRule', value: null},
{name: 'InsertImage', value: '../resources/abe.png'},
{name: 'InsertLineBreak', value: null},
{name: 'InsertNewlineInQuotedContent', value: null, selector: function (test) { window.getSelection().collapse(document.querySelector('a'), 0); }},
{name: 'InsertOrderedList', value: null},
{name: 'InsertParagraph', value: null},
{name: 'InsertText', value: 'webkit'},
{name: 'InsertUnorderedList', value: null},
{name: 'Italic', value: null},
{name: 'JustifyCenter', value: null},
{name: 'JustifyFull', value: null},
{name: 'JustifyLeft', value: null},
{name: 'JustifyNone', value: null},
{name: 'JustifyRight', value: null},
{name: 'Outdent', value: null},
{name: 'RemoveFormat', value: null},
{name: 'Strikethrough', value: null},
{name: 'Subscript', value: null},
{name: 'Superscript', value: null},
{name: 'Transpose', value: null, selector: function (test) { window.getSelection().collapse(test.firstChild, 1); }},
{name: 'Underline', value: null},
{name: 'Unlink', value: null},
];
var events = {
'DOMCharacterDataModified': false,
'DOMSubtreeModified': false,
'DOMNodeInserted': false,
'DOMNodeRemoved': false,
'DOMNodeRemovedFromDocument': false,
'DOMNodeInsertedIntoDocument': true, // this event can never be observed.
'DOMFocusIn': false,
'DOMFocusOut': false,
'focusin': false,
'focusout': false,
};
var log = [];
var test = document.getElementById('test');
function addEventListeners(node) {
for (var e in events) {
node.addEventListener(e, function (event) {
log.push(test.innerHTML);
events[event.type] = true;
}, false);
}
}
function isLogConsistent() {
for (var i= 1; i < log.length; i++) {
if (log[0] != log[i]) {
console.log(log);
return false;
}
}
return true;
}
addEventListeners(test);
var initial = 'hello, <input type="text"><blockquote type="cite" align="right"><u><a href="about:blank">world</a></u></blockquote>';
for (var i = 0; i < commands.length; i++) {
test.innerHTML = initial;
if (i)
document.write("\n");
if (test.innerHTML != initial) {
document.write("FAIL: initial innerHTML didn't match");
continue;
}
if (commands[i].selector)
commands[i].selector(test);
else {
document.getElementsByTagName('input')[0].focus();
window.getSelection().selectAllChildren(test);
}
addEventListeners(test.childNodes[2]);
log = []; // clear log
document.execCommand(commands[i].name, false, commands[i].value);
var quotedValue = commands[i].value ? "'" + commands[i].value.replace('<', '<') + "'" : null;
var action = "execCommand('" + commands[i].name + "', false, " + quotedValue + ")";
if (test.innerHTML == initial || log.length <= 0)
document.write('FAIL: ' + action + ' made no change to the DOM.');
else if (!isLogConsistent())
document.write('FAIL: ' + action + ' dispatched events before finalizing the DOM tree.');
else
document.write('PASS: ' + action);
}
test.style.display = 'none';
document.write('\n');
for (var e in events) {
if (!events[e])
document.write('\nWARNING: ' + e + ' was never observed.');
}
document.write('\n\nDONE');
</script>
</pre>
</body>
</html>