<!DOCTYPE html>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<div id="main" role="main">
<div id="contenteditable-textbox" role="textbox" contenteditable="true">
<div id="contenteditable-line1">Line 1</div>
<textarea id="contenteditable-line2" rows="1" cols="40">Line 2</textarea>
</div>
<div id="contenteditable-div" contenteditable>
<p id="paragraph1">Line 1<br>
Line 2</p>
<p id="paragraph2">Line 3</p>
</div>
<div id="contenteditable-div-2" contenteditable role="textbox"
style="max-width: 5px; overflow-wrap: normal;">
Line 1<br>
Line 2
</div>
</div>
<script>
test(function()
{
let mainAccessible = accessibilityController.accessibleElementById("main");
assert_equals(mainAccessible.selectionAnchorObject, null);
assert_equals(mainAccessible.selectionAnchorOffset, -1);
assert_equals(mainAccessible.selectionFocusObject, null);
assert_equals(mainAccessible.selectionFocusOffset, -1);
}, "Initially there should be no selection under the main object.");
test(function()
{
let rootAccessible = accessibilityController.rootElement;
assert_equals(rootAccessible.selectionAnchorObject, null);
assert_equals(rootAccessible.selectionAnchorOffset, -1);
assert_equals(rootAccessible.selectionFocusObject, null);
assert_equals(rootAccessible.selectionFocusOffset, -1);
}, "Initially there should be no selection on the root object.");
test(function()
{
let textbox = document.getElementById("contenteditable-textbox");
textbox.focus();
let textboxAccessible = accessibilityController.accessibleElementById("contenteditable-textbox");
let line1Accessible = accessibilityController.accessibleElementById("contenteditable-line1");
let line1TextAccessible = line1Accessible.childAtIndex(0);
assert_equals(textboxAccessible.selectionAnchorObject, line1TextAccessible);
assert_equals(textboxAccessible.selectionAnchorOffset, 0);
assert_equals(textboxAccessible.selectionFocusObject, line1TextAccessible);
assert_equals(textboxAccessible.selectionFocusOffset, 0);
}, "Moving the focus to an ARIA textbox should place the caret at its beginning.");
test(function()
{
let selection = window.getSelection();
let selectionRange = document.createRange();
let textboxAccessible = accessibilityController.accessibleElementById("contenteditable-textbox");
let mainAccessible = accessibilityController.accessibleElementById("main");
let rootAccessible = accessibilityController.rootElement;
let line1 = document.getElementById("contenteditable-line1");
let line1Accessible = accessibilityController.accessibleElementById("contenteditable-line1");
let line1TextAccessible = line1Accessible.childAtIndex(0);
selectionRange.setStart(line1.firstChild, 1);
selectionRange.setEnd(line1.firstChild, 1);
selection.removeAllRanges();
selection.addRange(selectionRange);
assert_equals(textboxAccessible.selectionAnchorObject, line1TextAccessible);
assert_equals(textboxAccessible.selectionAnchorOffset, 1);
assert_equals(textboxAccessible.selectionFocusObject, line1TextAccessible);
assert_equals(textboxAccessible.selectionFocusOffset, 1);
assert_equals(mainAccessible.selectionAnchorObject, line1TextAccessible);
assert_equals(mainAccessible.selectionAnchorOffset, 1);
assert_equals(mainAccessible.selectionFocusObject, line1TextAccessible);
assert_equals(mainAccessible.selectionFocusOffset, 1);
assert_equals(rootAccessible.selectionAnchorObject, line1TextAccessible);
assert_equals(rootAccessible.selectionAnchorOffset, 1);
assert_equals(rootAccessible.selectionFocusObject, line1TextAccessible);
assert_equals(rootAccessible.selectionFocusOffset, 1);
}, "Setting a new caret position in the ARIA textbox should be reflected in the accessibility APIs.");
test(function()
{
let selection = window.getSelection();
let textboxAccessible = accessibilityController.accessibleElementById("contenteditable-textbox");
let mainAccessible = accessibilityController.accessibleElementById("main");
let rootAccessible = accessibilityController.rootElement;
selection.removeAllRanges();
assert_equals(textboxAccessible.selectionAnchorObject, null);
assert_equals(textboxAccessible.selectionAnchorOffset, -1);
assert_equals(textboxAccessible.selectionFocusObject, null);
assert_equals(textboxAccessible.selectionFocusOffset, -1);
assert_equals(mainAccessible.selectionAnchorObject, null);
assert_equals(mainAccessible.selectionAnchorOffset, -1);
assert_equals(mainAccessible.selectionFocusObject, null);
assert_equals(mainAccessible.selectionFocusOffset, -1);
assert_equals(rootAccessible.selectionAnchorObject, null);
assert_equals(rootAccessible.selectionAnchorOffset, -1);
assert_equals(rootAccessible.selectionFocusObject, null);
assert_equals(rootAccessible.selectionFocusOffset, -1);
}, "Removing the selection should remove the caret completely.");
test(function()
{
let selection = window.getSelection();
let textboxAccessible = accessibilityController.accessibleElementById("contenteditable-textbox");
let mainAccessible = accessibilityController.accessibleElementById("main");
let rootAccessible = accessibilityController.rootElement;
let line1Accessible = accessibilityController.accessibleElementById("contenteditable-line1");
let line1TextAccessible = line1Accessible.childAtIndex(0);
line1TextAccessible.setSelectedTextRange(2, 0);
assert_equals(textboxAccessible.selectionAnchorObject, line1TextAccessible);
assert_equals(textboxAccessible.selectionAnchorOffset, 2);
assert_equals(textboxAccessible.selectionFocusObject, line1TextAccessible);
assert_equals(textboxAccessible.selectionFocusOffset, 2);
assert_equals(mainAccessible.selectionAnchorObject, line1TextAccessible);
assert_equals(mainAccessible.selectionAnchorOffset, 2);
assert_equals(mainAccessible.selectionFocusObject, line1TextAccessible);
assert_equals(mainAccessible.selectionFocusOffset, 2);
assert_equals(rootAccessible.selectionAnchorObject, line1TextAccessible);
assert_equals(rootAccessible.selectionAnchorOffset, 2);
assert_equals(rootAccessible.selectionFocusObject, line1TextAccessible);
assert_equals(rootAccessible.selectionFocusOffset, 2);
}, "Positioning the caret using the accessibility API instead of the DOM should work.");
test(function()
{
let line2Accessible = accessibilityController.accessibleElementById("contenteditable-line2");
let textboxAccessible = accessibilityController.accessibleElementById("contenteditable-textbox");
let mainAccessible = accessibilityController.accessibleElementById("main");
let line2 = document.getElementById("contenteditable-line2");
line2.focus();
assert_equals(line2Accessible.selectionAnchorObject, line2Accessible);
assert_equals(line2Accessible.selectionAnchorOffset, 0);
assert_equals(line2Accessible.selectionFocusObject, line2Accessible);
assert_equals(line2Accessible.selectionFocusOffset, 0);
assert_equals(textboxAccessible.selectionAnchorObject, line2Accessible);
assert_equals(textboxAccessible.selectionAnchorOffset, 0);
assert_equals(textboxAccessible.selectionFocusObject, line2Accessible);
assert_equals(textboxAccessible.selectionFocusOffset, 0);
assert_equals(mainAccessible.selectionAnchorObject, line2Accessible);
assert_equals(mainAccessible.selectionAnchorOffset, 0);
assert_equals(mainAccessible.selectionFocusObject, line2Accessible);
assert_equals(mainAccessible.selectionFocusOffset, 0);
}, "Moving the focus into a textarea should remove the caret from the ARIA textbox.");
test(function()
{
document.getElementById("contenteditable-line2").focus();
let rootAccessible = accessibilityController.rootElement;
let line2Accessible = accessibilityController.focusedElement;
assert_equals(rootAccessible.selectionAnchorObject, line2Accessible);
assert_equals(rootAccessible.selectionAnchorOffset, 0);
assert_equals(rootAccessible.selectionFocusObject, line2Accessible);
assert_equals(rootAccessible.selectionFocusOffset, 0);
assert_equals(line2Accessible.selectionAnchorObject, line2Accessible);
assert_equals(line2Accessible.selectionAnchorOffset, 0);
assert_equals(line2Accessible.selectionFocusObject, line2Accessible);
assert_equals(line2Accessible.selectionFocusOffset, 0);
}, "Standard text fields start with the caret at the beginning of their contents.");
test(function()
{
let line2 = document.getElementById("contenteditable-line2");
line2.focus();
let line2Accessible = accessibilityController.focusedElement;
line2.setSelectionRange(3, 3);
assert_equals(line2Accessible.selectionAnchorObject, line2Accessible);
assert_equals(line2Accessible.selectionAnchorOffset, 3);
assert_equals(line2Accessible.selectionFocusObject, line2Accessible);
assert_equals(line2Accessible.selectionFocusOffset, 3);
}, "Setting a new caret position in the textarea should be exposed in the accessibility APIs.");
test(function()
{
let textboxAccessible = accessibilityController.accessibleElementById("contenteditable-textbox");
let mainAccessible = accessibilityController.accessibleElementById("main");
let rootAccessible = accessibilityController.rootElement;
document.getElementById("contenteditable-line2").focus();
let line2Accessible = accessibilityController.focusedElement;
assert_equals(textboxAccessible.selectionAnchorObject, line2Accessible);
assert_equals(textboxAccessible.selectionAnchorOffset, 3);
assert_equals(textboxAccessible.selectionFocusObject, line2Accessible);
assert_equals(textboxAccessible.selectionFocusOffset, 3);
assert_equals(mainAccessible.selectionAnchorObject, line2Accessible);
assert_equals(mainAccessible.selectionAnchorOffset, 3);
assert_equals(mainAccessible.selectionFocusObject, line2Accessible);
assert_equals(mainAccessible.selectionFocusOffset, 3);
assert_equals(rootAccessible.selectionAnchorObject, line2Accessible);
assert_equals(rootAccessible.selectionAnchorOffset, 3);
assert_equals(rootAccessible.selectionFocusObject, line2Accessible);
assert_equals(rootAccessible.selectionFocusOffset, 3);
}, "Offsets in text fields should be reported from the beginning of the field and not from the top of the container.");
test(function()
{
var line1Accessible = accessibilityController.accessibleElementById("contenteditable-line1");
var line2Accessible = accessibilityController.accessibleElementById("contenteditable-line2");
assert_equals(line1Accessible.selectionAnchorObject, line2Accessible);
assert_equals(line1Accessible.selectionAnchorOffset, 3);
assert_equals(line1Accessible.selectionFocusObject, line2Accessible);
assert_equals(line1Accessible.selectionFocusOffset, 3);
assert_equals(line2Accessible.selectionAnchorObject, line2Accessible);
assert_equals(line2Accessible.selectionAnchorOffset, 3);
assert_equals(line2Accessible.selectionFocusObject, line2Accessible);
assert_equals(line2Accessible.selectionFocusOffset, 3);
}, "The caret position should be retrievable from any object.");
test(function()
{
const selection = window.getSelection();
const selectionRange = document.createRange();
const mainAccessible = accessibilityController.accessibleElementById("main");
const rootAccessible = accessibilityController.rootElement;
const contenteditable = document.getElementById("contenteditable-div");
contenteditable.focus();
// The offset from the newline character between the two lines of the
// first paragraph to the first character of its second line.
// (Needed for skipping wide space.)
const line2StartOffset = 13;
const line1 = document.getElementById("paragraph1").firstChild;
const line2 = document.getElementById("paragraph1").lastChild;
const line3 = document.getElementById("paragraph2").firstChild;
const contenteditableLines = [ line1, line2, line3 ];
const contenteditableAccessible = accessibilityController.accessibleElementById("contenteditable-div");
const paragraph1Accessible = accessibilityController.accessibleElementById("paragraph1");
const paragraph2Accessible = accessibilityController.accessibleElementById("paragraph2");
const line1Accessible = paragraph1Accessible.childAtIndex(0);
const line2Accessible = paragraph1Accessible.childAtIndex(2);
const line3Accessible = paragraph2Accessible.childAtIndex(0);
const expectations = [
line1Accessible, line2Accessible, line3Accessible
];
for (let lineNumber = 0; lineNumber < 3; ++lineNumber) {
for (let characterOffset = 0; characterOffset < 7; ++characterOffset) {
// Any widespace in the DOM should be stripped out in the
// accessibility tree.
let selectionOffset = characterOffset;
if (lineNumber == 1)
selectionOffset += line2StartOffset;
selectionRange.setStart(contenteditableLines[lineNumber], selectionOffset);
selectionRange.setEnd(contenteditableLines[lineNumber], selectionOffset);
selection.removeAllRanges();
selection.addRange(selectionRange);
assert_equals(contenteditableAccessible.selectionAnchorObject, expectations[lineNumber]);
assert_equals(contenteditableAccessible.selectionAnchorOffset, characterOffset);
assert_equals(contenteditableAccessible.selectionFocusObject, expectations[lineNumber]);
assert_equals(contenteditableAccessible.selectionFocusOffset, characterOffset);
assert_equals(mainAccessible.selectionAnchorObject, expectations[lineNumber]);
assert_equals(mainAccessible.selectionAnchorOffset, characterOffset);
assert_equals(mainAccessible.selectionFocusObject, expectations[lineNumber]);
assert_equals(mainAccessible.selectionFocusOffset, characterOffset);
assert_equals(rootAccessible.selectionAnchorObject, expectations[lineNumber]);
assert_equals(rootAccessible.selectionAnchorOffset, characterOffset);
assert_equals(rootAccessible.selectionFocusObject, expectations[lineNumber]);
assert_equals(rootAccessible.selectionFocusOffset, characterOffset);
}
}
}, "Test moving the caret across two paragraphs by re-creating the selection.");
test(function()
{
const selection = window.getSelection();
const selectionRange = document.createRange();
const mainAccessible = accessibilityController.accessibleElementById("main");
const rootAccessible = accessibilityController.rootElement;
const contenteditable = document.getElementById("contenteditable-div");
contenteditable.focus();
const line1 = document.getElementById("paragraph1").firstChild;
selectionRange.setStart(line1, 0);
selectionRange.setEnd(line1, 0);
selection.removeAllRanges();
selection.addRange(selectionRange);
const contenteditableAccessible = accessibilityController.accessibleElementById("contenteditable-div");
const paragraph1Accessible = accessibilityController.accessibleElementById("paragraph1");
const paragraph2Accessible = accessibilityController.accessibleElementById("paragraph2");
const line1Accessible = paragraph1Accessible.childAtIndex(0);
const line2Accessible = paragraph1Accessible.childAtIndex(2);
const line3Accessible = paragraph2Accessible.childAtIndex(0);
const expectations = [
line1Accessible, line2Accessible, line3Accessible
];
for (let lineNumber = 0; lineNumber < 3; ++lineNumber) {
for (let characterOffset = 0; characterOffset < 7; ++characterOffset) {
assert_equals(contenteditableAccessible.selectionAnchorObject, expectations[lineNumber]);
assert_equals(contenteditableAccessible.selectionAnchorOffset, characterOffset);
assert_equals(contenteditableAccessible.selectionFocusObject, expectations[lineNumber]);
assert_equals(contenteditableAccessible.selectionFocusOffset, characterOffset);
assert_equals(mainAccessible.selectionAnchorObject, expectations[lineNumber]);
assert_equals(mainAccessible.selectionAnchorOffset, characterOffset);
assert_equals(mainAccessible.selectionFocusObject, expectations[lineNumber]);
assert_equals(mainAccessible.selectionFocusOffset, characterOffset);
assert_equals(rootAccessible.selectionAnchorObject, expectations[lineNumber]);
assert_equals(rootAccessible.selectionAnchorOffset, characterOffset);
assert_equals(rootAccessible.selectionFocusObject, expectations[lineNumber]);
assert_equals(rootAccessible.selectionFocusOffset, characterOffset);
selection.modify('move', 'forward', 'character');
}
}
}, "Test moving the caret across two paragraphs by modifying the existing selection.");
test(function()
{
const selection = window.getSelection();
const selectionRange = document.createRange();
const mainAccessible = accessibilityController.accessibleElementById("main");
const rootAccessible = accessibilityController.rootElement;
const contenteditable = document.getElementById('contenteditable-div-2');
contenteditable.focus();
selectionRange.setStart(contenteditable, 0);
selectionRange.setEnd(contenteditable, 0);
selection.removeAllRanges();
selection.addRange(selectionRange);
const contenteditableAccessible = accessibilityController.accessibleElementById('contenteditable-div-2');
const line1Accessible = contenteditableAccessible.childAtIndex(0);
const line2Accessible = contenteditableAccessible.childAtIndex(2);
const expectations = [ line1Accessible, line2Accessible ];
for (let lineNumber = 0; lineNumber < 2; ++lineNumber) {
for (let characterOffset = 0; characterOffset < 7; ++characterOffset) {
assert_equals(contenteditableAccessible.selectionAnchorObject, expectations[lineNumber]);
assert_equals(contenteditableAccessible.selectionAnchorOffset, characterOffset);
assert_equals(contenteditableAccessible.selectionFocusObject, expectations[lineNumber]);
assert_equals(contenteditableAccessible.selectionFocusOffset, characterOffset);
assert_equals(mainAccessible.selectionAnchorObject, expectations[lineNumber]);
assert_equals(mainAccessible.selectionAnchorOffset, characterOffset);
assert_equals(mainAccessible.selectionFocusObject, expectations[lineNumber]);
assert_equals(mainAccessible.selectionFocusOffset, characterOffset);
assert_equals(rootAccessible.selectionAnchorObject, expectations[lineNumber]);
assert_equals(rootAccessible.selectionAnchorOffset, characterOffset);
assert_equals(rootAccessible.selectionFocusObject, expectations[lineNumber]);
assert_equals(rootAccessible.selectionFocusOffset, characterOffset);
selection.modify('move', 'forward', 'character');
}
}
}, "Test moving the caret across two lines that wrap by modifying the existing selection.");
</script>