<!DOCTYPE html>
<script src='../resources/testharness.js'></script>
<script src='../resources/testharnessreport.js'></script>
<script src='resources/shadow-dom.js'></script>
<script src='resources/focus-utils.js'></script>
<input id='defaultFocus'>
<div id='sandbox'></div>
<script>
'use strict';
function prepareDOMTree(parent, delegatesFocus) {
parent.innerHTML = '';
let host = document.createElement('div');
host.id = 'shadowHost';
host.setAttribute('tabindex', '0');
var root = host.attachShadow({mode: 'open', delegatesFocus: delegatesFocus});
root.innerHTML = '<div id="innerDiv">Blink</div><input id="inputA"><input id="inputB">';
parent.appendChild(host);
}
var host;
var innerDiv;
var inputA;
var inputB;
// TODO(https://crbug.com/1350218): Replace this with test_diver.click() and
// move test to WPT
function clickOn(el) {
eventSender.mouseMoveTo(el.offsetLeft + 8, el.offsetTop + 8);
eventSender.mouseDown();
eventSender.mouseUp();
}
function resetFocus() {
document.querySelector('#defaultFocus').focus();
}
function assert_innermost_active_element(path) {
assert_true(isInnermostActiveElement(path), 'innermost active element should be ' + path);
}
test(() => {
prepareDOMTree(sandbox, false);
resetFocus();
let host = getNodeInComposedTree('shadowHost');
let innerDiv = getNodeInComposedTree('shadowHost/innerDiv');
let inputA = getNodeInComposedTree('shadowHost/inputA');
let inputB = getNodeInComposedTree('shadowHost/inputB');
clickOn(innerDiv);
assert_innermost_active_element('shadowHost');
inputA.focus();
assert_innermost_active_element('shadowHost/inputA');
clickOn(innerDiv);
assert_innermost_active_element('shadowHost');
inputB.focus();
assert_innermost_active_element('shadowHost/inputB');
clickOn(innerDiv);
assert_innermost_active_element('shadowHost');
}, 'click on inner div should focus shadow host (with delegatesFocus = false).');
test(() => {
prepareDOMTree(sandbox, true);
resetFocus();
let host = getNodeInComposedTree('shadowHost');
let innerDiv = getNodeInComposedTree('shadowHost/innerDiv');
let inputA = getNodeInComposedTree('shadowHost/inputA');
let inputB = getNodeInComposedTree('shadowHost/inputB');
inputA.value = 'wonderful'; // len = 9
inputB.value = 'beautiful';
clickOn(innerDiv);
assert_innermost_active_element('shadowHost/inputA');
// If focus slides from shadow host, all the content will be selected.
assert_equals(inputA.selectionStart, 0);
assert_equals(inputA.selectionEnd, 9);
// Clicking on non-focusable area inside shadow should not change the focus state.
clickOn(innerDiv);
assert_innermost_active_element('shadowHost/inputA');
assert_equals(inputA.selectionStart, 0);
assert_equals(inputA.selectionEnd, 9);
// Clicking on focusable directly will cause the element to be focused.
clickOn(inputA);
assert_innermost_active_element('shadowHost/inputA');
inputA.setSelectionRange(1, 1);
clickOn(innerDiv);
assert_innermost_active_element('shadowHost/inputA');
assert_equals(inputA.selectionStart, 1, 'inputA selection start should be preserved.');
assert_equals(inputA.selectionEnd, 1, 'inputA selection end should be preserved.');
clickOn(inputB);
assert_innermost_active_element('shadowHost/inputB');
inputA.setSelectionRange(1, 1);
clickOn(innerDiv);
assert_innermost_active_element('shadowHost/inputB');
assert_equals(inputB.selectionStart, 1, 'inputB selection start should be preserved.');
assert_equals(inputB.selectionEnd, 1, 'inputB selection end should be preserved.');
}, 'click on inner div should focus inner focusable (with delegatesFocus = true).');
</script>