blob: 2c9e0f33ad1bafa20b4dd2c595dd35df5a31f5d0 [file] [log] [blame]
<html>
<head>
<title>This tests the new EditContext APIs while in composition</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<div id="test"></div>
<div id="test2"></div>
<script>
test(function() {
const editContextDict = {
text: "Hello world",
selectionStart: 11,
selectionEnd: 11,
inputMode: "text",
inputPanelPolicy: "auto",
enterKeyHint: "enter"
};
const editContext = new EditContext(editContextDict);
assert_not_equals(editContext, null);
// Verify all the members of the EditContext
assert_equals(editContext.text, "Hello world");
assert_equals(editContext.selectionStart, 11);
assert_equals(editContext.selectionEnd, 11);
assert_equals(editContext.inputMode, "text");
assert_equals(editContext.inputPanelPolicy, "auto");
assert_equals(editContext.enterKeyHint, "enter");
}, 'Testing EditContext Dictionary Init');
test(function() {
const editContext = new EditContext();
assert_not_equals(editContext, null);
const test = document.getElementById('test');
test.innerHTML = "";
editContext.addEventListener("textupdate", e => {
test.innerHTML = e.updateText;
});
test.editContext = editContext;
test.focus();
eventSender.keyDown('a');
assert_equals(test.innerHTML, "a");
}, 'Testing EditContext English typing');
test(function() {
const iframe = document.createElement("iframe");
document.body.appendChild(iframe);
const childDocument = iframe.contentDocument;
const childDiv = childDocument.createElement('div');
iframe.remove();
childDiv.editContext = new EditContext();
}, 'Setting .editContext on a stray div should not crash.');
test(function() {
const editContext = new EditContext();
assert_not_equals(editContext, null);
const new_div = document.createElement("DIV");
assert_equals(new_div.editContext, null);
document.body.appendChild(new_div);
new_div.editContext = editContext;
assert_equals(new_div.editContext, editContext);
new_div.editContext = null;
assert_equals(new_div.editContext, null);
document.body.removeChild(new_div);
}, 'Testing Element.editContext');
test(function() {
const editContext = new EditContext();
assert_not_equals(editContext, null);
const disconnected_div = document.createElement("DIV");
assert_equals(disconnected_div.editContext, null);
disconnected_div.editContext = editContext;
assert_equals(disconnected_div.editContext, null);
assert_equals(editContext.attachedElements().length, 0);
}, 'EditContext can only be associated with an element that is in an active document.');
test(function() {
const editContext = new EditContext();
assert_not_equals(editContext, null);
const div = document.createElement("DIV");
assert_equals(div.editContext, null);
document.body.appendChild(div);
div.editContext = editContext;
assert_equals(div.editContext, editContext);
assert_equals(editContext.attachedElements().length, 1);
assert_equals(editContext.attachedElements()[0], div);
document.body.removeChild(div);
assert_equals(div.editContext, null);
assert_equals(editContext.attachedElements().length, 0);
}, 'If an element is removed from tree, it will disconnect its associated EditContext.');
test(function() {
const editContext = new EditContext();
const div_parent = document.createElement("DIV");
const div_child = document.createElement("DIV");
document.body.appendChild(div_parent);
div_parent.appendChild(div_child);
div_child.editContext = editContext;
assert_equals(div_child.editContext, editContext);
assert_equals(div_parent.editContext, null);
assert_equals(editContext.attachedElements().length, 1);
assert_equals(editContext.attachedElements()[0], div_child);
document.body.removeChild(div_parent);
assert_equals(div_child.editContext, null);
assert_equals(editContext.attachedElements().length, 0);
}, 'If an element\'s ancestor is removed from tree, the element will disconnect its associated EditContext.');
test(function() {
const editContext = new EditContext();
const test = document.getElementById("test");
const test2 = document.getElementById("test2");
test.editContext = editContext;
test2.editContext = editContext;
assert_equals(test.editContext, editContext);
assert_equals(test2.editContext, editContext);
assert_equals(editContext.attachedElements().length, 2);
assert_equals(editContext.attachedElements()[0], test);
assert_equals(editContext.attachedElements()[1], test2);
test.editContext = null;
assert_equals(editContext.attachedElements().length, 1);
assert_equals(editContext.attachedElements()[0], test2);
}, '.attachedElements() should return associated elements');
test(function() {
const editContext = new EditContext();
assert_not_equals(editContext, null);
const test = document.getElementById('test');
test.innerHTML = "";
test.editContext = editContext;
test.focus();
textInputController.setComposition("foo");
assert_equals(test.innerHTML, "");
eventSender.keyDown('a');
assert_equals(test.innerHTML, "");
}, 'EditContext should disable DOM mutation');
test(function() {
const editContext = new EditContext();
assert_not_equals(editContext, null);
const test = document.getElementById('test');
test.innerHTML = "";
// Add EditContext event listeners
editContext.addEventListener("textupdate", e => {
// Update the text in the div
const buffer = test.innerText;
test.innerHTML = buffer.substr(0, e.updateRangeStart) + e.updateText.toUpperCase() + buffer.substr(e.updateRangeEnd);
});
test.focus();
test.editContext = editContext;
textInputController.setComposition("foo");
assert_equals(test.innerHTML, "FOO");
}, 'Testing attaching EditContext AFTER the element is focused.');
test(function() {
const editContext = new EditContext();
assert_not_equals(editContext, null);
const test = document.getElementById('test');
test.innerHTML = "";
// Add EditContext event listeners
editContext.addEventListener("textupdate", e => {
// Update the text in the div
const buffer = test.innerText;
test.innerHTML = buffer.substr(0, e.updateRangeStart) + e.updateText.toUpperCase() + buffer.substr(e.updateRangeEnd);
});
test.editContext = editContext;
test.focus();
textInputController.setComposition("foo");
assert_equals(test.innerHTML, "FOO");
textInputController.setComposition("bar");
assert_equals(test.innerHTML, "BAR");
}, 'Testing EditContext TextUpdate');
test(function() {
const editContext = new EditContext();
assert_not_equals(editContext, null);
const test = document.getElementById('test');
test.focus();
test.editContext = editContext;
test.addEventListener("beforeinput", e => {
if (e.inputType === "insertText") {
e.preventDefault();
}
});
eventSender.keyDown('a');
assert_equals(editContext.text, "");
}, 'beforeInput(insertText) should be cancelable');
test(function() {
const editContext = new EditContext();
assert_not_equals(editContext, null);
const test = document.getElementById('test');
test.innerHTML = "";
// Add EditContext event listeners
editContext.addEventListener("textupdate", e => {
// Update the text in the div
const buffer = test.innerText;
test.innerHTML = buffer.substr(0, e.updateRangeStart) + e.updateText.toUpperCase() + buffer.substr(e.updateRangeEnd);
});
test.editContext = editContext;
test.focus();
textInputController.setComposition("foo");
assert_equals(test.innerHTML, "FOO");
textInputController.setComposition("");
assert_equals(test.innerHTML, "");
}, 'Testing EditContext TextUpdate with empty strings');
test(function() {
const editContext = new EditContext();
assert_not_equals(editContext, null);
const test = document.getElementById('test');
test.innerHTML = "";
let textFormats = [];
// Add EditContext event listeners
editContext.addEventListener("textupdate", e => {
// Update the text in the div
const buffer = test.innerText;
test.innerHTML = buffer.substr(0, e.updateRangeStart) + e.updateText.toUpperCase() + buffer.substr(e.updateRangeEnd);
});
editContext.addEventListener("textformatupdate", e => {
//TODO: Currently Chromium only fires default styles
textFormats = e.getTextFormats();
});
test.editContext = editContext;
test.focus();
textInputController.setComposition("foo");
assert_equals(test.innerHTML, "FOO");
assert_equals(textFormats.length, 1);
assert_equals(textFormats[0].rangeStart, 0);
assert_equals(textFormats[0].rangeEnd, 3);
assert_equals(textFormats[0].underlineColor, "rgba(0, 0, 0, 0)");
assert_equals(textFormats[0].backgroundColor, "rgba(0, 0, 0, 0)");
assert_equals(textFormats[0].textColor, "rgba(0, 0, 0, 0)");
assert_equals(textFormats[0].underlineStyle, "Solid");
assert_equals(textFormats[0].underlineThickness, "Thin");
}, 'Testing EditContext TextFormatUpdate');
test(function() {
const editContext1 = new EditContext();
const editContext2 = new EditContext();
assert_not_equals(editContext1, null);
assert_not_equals(editContext2, null);
const test = document.getElementById('test');
test.innerHTML = "";
// Add EditContext event listeners
editContext1.addEventListener("textupdate", e => {
// Update the text in the div
const buffer = test.innerText;
test.innerHTML = buffer.substr(0, e.updateRangeStart) + e.updateText.toUpperCase() + buffer.substr(e.updateRangeEnd);
});
editContext2.addEventListener("textupdate", e => {
// Update the text in the div
const buffer = test.innerText;
test.innerHTML = buffer.substr(0, e.updateRangeStart) + e.updateText.toLowerCase() + buffer.substr(e.updateRangeEnd);
});
test.editContext = editContext1;
test.focus();
textInputController.setComposition("foo");
assert_equals(test.innerHTML, "FOO");
textInputController.setComposition("bar");
assert_equals(test.innerHTML, "BAR");
test.innerHTML = "";
test.editContext = editContext2;
textInputController.setComposition("HELLO");
assert_equals(test.innerHTML, "hello");
textInputController.setComposition("WORLD");
assert_equals(test.innerHTML, "world");
}, 'Testing Multiple EditContext TextUpdates');
test(function() {
const editContext = new EditContext();
assert_not_equals(editContext, null);
const test = document.getElementById('test');
test.innerHTML = "";
var compositionStartFired = 0;
var compositionEndFired = 0;
// Add EditContext event listeners
editContext.addEventListener("textupdate", e => {
// Update the text in the div
const buffer = test.innerText;
test.innerHTML = buffer.substr(0, e.updateRangeStart) + e.updateText.toUpperCase() + buffer.substr(e.updateRangeEnd);
});
editContext.addEventListener("compositionstart", e => {
// Update the text in the div
compositionStartFired++;
});
editContext.addEventListener("compositionend", e => {
compositionEndFired++;
});
test.editContext = editContext;
test.focus();
textInputController.setComposition("foo");
assert_equals(test.innerHTML, "FOO");
assert_equals(compositionStartFired, 1);
textInputController.setComposition("bar");
assert_equals(test.innerHTML, "BAR");
assert_equals(compositionStartFired, 1);
textInputController.insertText("bar");
assert_equals(test.innerHTML, "BAR");
assert_equals(compositionEndFired, 1);
}, 'Testing EditContext Composition Event');
test(function() {
const editContext = new EditContext();
assert_not_equals(editContext, null);
const test = document.getElementById('test');
test.innerHTML = "";
// Add EditContext event listeners
editContext.addEventListener("textupdate", e => {
// Update the text in the div
const buffer = test.innerText;
test.innerHTML = buffer.substr(0, e.updateRangeStart) + e.updateText.toUpperCase() + buffer.substr(e.updateRangeEnd);
});
test.editContext = editContext;
test.focus();
textInputController.setComposition("f");
assert_equals(test.innerHTML, "F");
textInputController.setComposition("foo");
assert_equals(test.innerHTML, "FOO");
textInputController.insertText("foobar");
assert_equals(test.innerHTML, "FOOBAR");
}, 'Testing EditContext Text updates');
test(function() {
const editContext = new EditContext();
assert_not_equals(editContext, null);
const test = document.getElementById('test');
test.innerHTML = "";
// Add EditContext event listeners
editContext.addEventListener("textupdate", e => {
// Update the text in the div
const buffer = test.innerText;
test.innerHTML = buffer.substr(0, e.updateRangeStart) + e.updateText.toUpperCase() + buffer.substr(e.updateRangeEnd);
});
test.editContext = editContext;
test.focus();
textInputController.setComposition("f");
assert_equals(test.innerHTML, "F");
textInputController.setComposition("");
assert_equals(test.innerHTML, "");
textInputController.insertText("foobar");
assert_equals(test.innerHTML, "FOOBAR");
}, 'Testing EditContext Text updates with empty text');
test(function() {
const editContext = new EditContext();
assert_not_equals(editContext, null);
const test = document.getElementById('test');
test.innerHTML = "";
// Add EditContext event listeners
editContext.addEventListener("textupdate", e => {
// Update the text in the div
const buffer = test.innerText;
test.innerHTML = buffer.substr(0, e.updateRangeStart) + e.updateText.toUpperCase() + buffer.substr(e.updateRangeEnd);
});
test.editContext = editContext;
test.focus();
textInputController.setComposition("foo");
assert_equals(test.innerHTML, "FOO");
editContext.updateText(0, 1, "h");
assert_equals(editContext.text, "hoo");
editContext.updateText(0, 3, "bar");
assert_equals(editContext.text, "bar");
}, 'Testing EditContext TextChange');
test(function() {
const editContext = new EditContext();
assert_not_equals(editContext, null);
const test = document.getElementById('test');
test.innerHTML = "";
// Add EditContext event listeners
editContext.addEventListener("textupdate", e => {
// Update the text in the div
const buffer = test.innerText;
test.innerHTML = buffer.substr(0, e.updateRangeStart) + e.updateText.toUpperCase() + buffer.substr(e.updateRangeEnd);
});
test.editContext = editContext;
test.focus();
textInputController.setComposition("foo");
assert_equals(test.innerHTML, "FOO");
textInputController.insertText("bar");
assert_equals(editContext.text, "bar");
assert_equals(editContext.selectionStart, 3);
assert_equals(editContext.selectionEnd, 3);
editContext.updateSelection(0, 0);
assert_equals(editContext.selectionStart, 0);
assert_equals(editContext.selectionEnd, 0);
textInputController.setComposition("foo");
assert_equals(editContext.text, "foobar");
textInputController.insertText("foo");
assert_equals(editContext.selectionStart, 3);
assert_equals(editContext.selectionEnd, 3);
}, 'Testing EditContext Selection Change');
test(function() {
const editContext = new EditContext();
assert_not_equals(editContext, null);
const test = document.getElementById('test');
test.innerHTML = "";
// Add EditContext event listeners
editContext.addEventListener("textupdate", e => {
// Update the text in the div
const buffer = test.innerText;
test.innerHTML = buffer.substr(0, e.updateRangeStart) + e.updateText.toUpperCase() + buffer.substr(e.updateRangeEnd);
});
test.editContext = editContext;
test.focus();
textInputController.setComposition("foo");
assert_equals(test.innerHTML, "FOO");
editContext.updateText(0, 1, "h");
assert_equals(editContext.text, "hoo");
editContext.updateText(0, 3, "bar");
assert_equals(editContext.text, "bar");
textInputController.insertText("bar");
assert_equals(editContext.text, "bar");
editContext.updateSelection(0, 0);
assert_equals(editContext.selectionStart, 0);
assert_equals(editContext.selectionEnd, 0);
textInputController.setComposition("foo");
assert_equals(editContext.text, "foobar");
textInputController.insertText("foo");
assert_equals(editContext.text, "foobar");
}, 'Testing EditContext Text And Selection Change');
test(function() {
const editContext = new EditContext();
assert_not_equals(editContext, null);
const test = document.getElementById('test');
test.innerHTML = "";
// Add EditContext event listeners
editContext.addEventListener("textupdate", e => {
// Update the text in the div
const buffer = test.innerText;
test.innerHTML = buffer.substr(0, e.updateRangeStart) + e.updateText.toUpperCase() + buffer.substr(e.updateRangeEnd);
});
test.editContext = editContext;
test.focus();
textInputController.setComposition("foo");
assert_equals(test.innerHTML, "FOO");
textInputController.insertText("foo");
textInputController.setMarkedTextFromExistingText(0, 3);
textInputController.insertText("bar");
assert_equals(editContext.text, "bar");
textInputController.setMarkedTextFromExistingText(2, 3);
textInputController.insertText("t");
assert_equals(editContext.text, "bat");
}, 'Testing EditContext SetCompositionFromExistingText');
test(function() {
const editContext = new EditContext();
assert_not_equals(editContext, null);
const test = document.getElementById('test');
test.innerHTML = "";
// Add EditContext event listeners
editContext.addEventListener("textupdate", e => {
// Update the text in the div
const buffer = test.innerText;
test.innerHTML = buffer.substr(0, e.updateRangeStart) + e.updateText.toUpperCase() + buffer.substr(e.updateRangeEnd);
});
test.editContext = editContext;
test.focus();
textInputController.setComposition("foo");
assert_equals(test.innerHTML, "FOO");
textInputController.insertText("foo");
assert_equals(editContext.selectionStart, 3);
assert_equals(editContext.selectionEnd, 3);
textInputController.extendSelectionAndDelete(3, 0);
assert_equals(editContext.selectionStart, 0);
assert_equals(editContext.selectionEnd, 0);
textInputController.insertText("bar");
assert_equals(editContext.text, "bar");
assert_equals(editContext.selectionStart, 3);
assert_equals(editContext.selectionEnd, 3);
textInputController.extendSelectionAndDelete(1, 0);
assert_equals(editContext.selectionStart, 2);
assert_equals(editContext.selectionEnd, 2);
assert_equals(editContext.text, "ba");
textInputController.insertText("t");
assert_equals(editContext.text, "bat");
}, 'Testing EditContext ExtendSelectionAndDelete');
test(function() {
const editContext = new EditContext();
assert_not_equals(editContext, null);
const test = document.getElementById('test');
test.innerHTML = "";
// Add EditContext event listeners
editContext.addEventListener("textupdate", e => {
// Update the text in the div
const buffer = test.innerText;
test.innerHTML = buffer.substr(0, e.updateRangeStart) + e.updateText.toUpperCase() + buffer.substr(e.updateRangeEnd);
});
test.editContext = editContext;
test.focus();
textInputController.setComposition("foo");
assert_equals(test.innerHTML, "FOO");
textInputController.unmarkText();
assert_equals(editContext.text, "foo");
textInputController.setComposition("bar");
assert_equals(editContext.text, "foobar");
}, 'Testing EditContext FinishComposingText');
test(function() {
const editContext1 = new EditContext();
assert_not_equals(editContext1, null);
const editContext2 = new EditContext();
assert_not_equals(editContext2, null);
const test = document.getElementById('test');
test.innerHTML = "";
// Add EditContext event listeners
editContext1.addEventListener("textupdate", e => {
// Update the text in the div
const buffer = test.innerText;
test.innerHTML = buffer.substr(0, e.updateRangeStart) + e.updateText.toUpperCase() + buffer.substr(e.updateRangeEnd);
});
editContext2.addEventListener("textupdate", e => {
// Update the text in the div
const buffer = test.innerText;
test.innerHTML = buffer.substr(0, e.updateRangeStart) + e.updateText.toLowerCase() + buffer.substr(e.updateRangeEnd);
});
test.editContext = editContext1;
test.focus();
textInputController.setComposition("foo");
assert_equals(test.innerHTML, "FOO");
test.blur();
textInputController.setComposition("foo2");
assert_equals(test.innerHTML, "FOO");
const test2 = document.getElementById('test2');
test2.editContext = editContext2;
test2.focus();
textInputController.setComposition("BAR");
assert_equals(editContext2.text, "BAR");
assert_equals(test.innerHTML, "barFOO");
assert_equals(editContext1.text, "foo");
}, 'Testing EditContext blur');
test(function() {
const editContext = new EditContext();
assert_not_equals(editContext, null);
editContext.text = "foo";
assert_equals(editContext.text, "foo");
const test = document.getElementById('test');
// Update the layout of the |EditContext|
var viewRect = test.getBoundingClientRect();
viewRect.x = viewRect.left;
viewRect.y = viewRect.top;
var caretRect = test.getBoundingClientRect();
caretRect.x = caretRect.left;
caretRect.y = 2.2 * caretRect.top;
caretRect.width = 1;
editContext.updateSelection(0, 0);
assert_equals(editContext.selectionStart, 0);
assert_equals(editContext.selectionEnd, 0);
editContext.selectionStart = 1;
assert_equals(editContext.selectionStart, 0); // selectionEnd is still 0
editContext.selectionEnd = 1;
assert_equals(editContext.selectionEnd, 1);
editContext.selectionStart = 1;
assert_equals(editContext.selectionStart, 1);
editContext.updateBounds(viewRect, caretRect);
}, 'Testing EditContext update text, selection and layout');
test(function() {
const editContext = new EditContext();
const test = document.getElementById('test');
var rect1 = DOMRect.fromRect({x:0, y:1, width:100, height:200});
var rect2 = DOMRect.fromRect({x:2, y:3, width:300, height:400});
var rectArray = [rect1, rect2];
var rangeStart = 2;
editContext.updateCharacterBounds(rangeStart, rectArray);
assert_equals(editContext.characterBoundsRangeStart, 2);
var actualRectArray = editContext.characterBounds();
assert_equals(actualRectArray.length, 2);
assert_equals(actualRectArray[0].x, 0);
assert_equals(actualRectArray[0].y, 1);
assert_equals(actualRectArray[0].width, 100);
assert_equals(actualRectArray[0].height, 200);
rect2.x=100;
assert_equals(actualRectArray[1].x, 2); // the cached value shouldn't change.
assert_equals(actualRectArray[1].y, 3);
assert_equals(actualRectArray[1].width, 300);
assert_equals(actualRectArray[1].height, 400);
}, 'updateCharacterBounds(), characterBounds(), and characterBoundsRangeStart should work properly');
test(function() {
const editContext = new EditContext();
assert_not_equals(editContext, null);
editContext.text = "foo";
assert_equals(editContext.text, "foo");
assert_throws_dom("IndexSizeError", function() { editContext.updateSelection(10, 0); });
assert_equals(editContext.selectionStart, 0);
assert_equals(editContext.selectionEnd, 0);
assert_throws_dom("IndexSizeError", function() { editContext.updateText(10, 1, "h"); });
assert_equals(editContext.text, "foo");
}, 'Testing EditContext update text and selection with invalid values');
test(function() {
const editContext = new EditContext();
assert_not_equals(editContext, null);
assert_equals(editContext.inputMode, "text"); // default value
editContext.inputMode = "tel";
assert_equals(editContext.inputMode, "tel");
editContext.inputMode = "email";
assert_equals(editContext.inputMode, "email");
editContext.inputMode = "search";
assert_equals(editContext.inputMode, "search");
editContext.inputMode = "decimal";
assert_equals(editContext.inputMode, "decimal");
editContext.inputMode = "numeric";
assert_equals(editContext.inputMode, "numeric");
editContext.inputMode = "url";
assert_equals(editContext.inputMode, "url");
editContext.inputMode = "none";
assert_equals(editContext.inputMode, "none");
editContext.inputMode = "test";
assert_equals(editContext.inputMode, "none");
}, 'Testing EditContext inputMode');
test(function() {
const editContext = new EditContext();
assert_not_equals(editContext, null);
assert_equals(editContext.enterKeyHint, "enter"); // default value
editContext.enterKeyHint = "done";
assert_equals(editContext.enterKeyHint, "done");
editContext.enterKeyHint = "go";
assert_equals(editContext.enterKeyHint, "go");
editContext.enterKeyHint = "next";
assert_equals(editContext.enterKeyHint, "next");
editContext.enterKeyHint = "previous";
assert_equals(editContext.enterKeyHint, "previous");
editContext.enterKeyHint = "search";
assert_equals(editContext.enterKeyHint, "search");
editContext.enterKeyHint = "send";
assert_equals(editContext.enterKeyHint, "send");
editContext.enterKeyHint = "test";
assert_equals(editContext.enterKeyHint, "send");
}, 'Testing EditContext enterKeyHint');
test(function() {
// SetComposition should not crash when event handler removes document
const child = document.createElement("iframe");
document.body.appendChild(child);
const childDocument = child.contentDocument;
const textarea = childDocument.createElement('textarea');
childDocument.body.appendChild(textarea);
textarea.addEventListener("focusin", e => {
const childEditContext = new EditContext();
textarea.editContext = childEditContext;
childEditContext.addEventListener("textupdate", e => {
child.remove();
});
childEditContext.addEventListener("textformatupdate", e => {
});
});
textarea.focus();
child.contentWindow.focus();
child.contentWindow.textInputController.setComposition("bar");
}, 'Testing EditContext Iframe Document Delete');
test(function() {
const editContext1 = new EditContext();
editContext1.addEventListener("textupdate", e => {
});
const test = document.getElementById('test');
test.editContext = editContext1;
test.focus();
gc()
textInputController.setComposition("bar");
}, 'Testing EditContext GC');
</script>
</body>
</html>