| <!DOCTYPE html> |
| <html> |
| <head> |
| <script src="../../../resources/js-test.js"></script> |
| <script src="resources/shadow-dom.js"></script> |
| </head> |
| <body> |
| <p>This tests that pressing Tab key should traverse into shadow DOM subtrees, and pressing Shift-Tab should reverse the order.</p> |
| <pre id="console"></pre> |
| <script> |
| |
| function prepareDOMTree(parent) |
| { |
| parent.appendChild( |
| // FIXME: Use more descriptive ids for each elements. |
| createDOM('div', {'id': 'top-div'}, |
| createDOM('input', {'id': 'input-A-1', 'tabindex': 1}), |
| createDOM('input', {'id': 'input-B-1', 'tabindex': 1}), |
| createDOM('div'), // Should not be selected. |
| createDOM('input', {'id': 'input-A-0', 'tabindex': 0}), |
| createDOM('div', {'id': 'host-A', 'tabindex': -1}, |
| createShadowRoot( |
| createDOM('input', {'id': 'input-1', 'tabindex': 1}), |
| createDOM('div', {'tabindex': 2, 'style': 'visibility:hidden;'}, |
| createShadowRoot()), |
| createDOM('input', {'tabindex': 3, 'type': 'date', 'disabled': ''}), |
| createDOM('select', {'tabindex': 4, 'multiple': '', 'disabled': ''}), |
| createDOM('div', {'id': 'nested-host', 'tabindex': 30}, |
| createShadowRoot( |
| createDOM('input', {'tabindex': -1}), |
| createDOM('input', {'id': 'input-15', 'tabindex': 15}), |
| createDOM('input', {'id': 'input-25', 'tabindex': 25}))), |
| createDOM('input', {'id': 'input-20', 'tabindex': 20}))), |
| createDOM('input', {'id': 'input-C-1', 'tabindex': 1}), |
| createDOM('input', {'id': 'input-B-0', 'tabindex': 0}), |
| createDOM('div', {'id': 'host-B', 'tabindex': 1}, |
| createShadowRoot( |
| createDOM('input', {'id': 'older-input-A-0', 'tabindex': 0}), |
| createDOM('input', {'id': 'older-input-A-1', 'tabindex': 1}), |
| createDOM('content', {'select': '#light-child-selected-0, #light-child-selected-1'}), |
| createDOM('input', {'id': 'older-input-B-0', 'tabindex': 0}), |
| createDOM('input', {'id': 'older-input-B-1', 'tabindex': 1})), |
| createShadowRoot( |
| createDOM('input', {'id': 'younger-input-A-0', 'tabindex': 0}), |
| createDOM('input', {'id': 'younger-input-A-1', 'tabindex': 1}), // The first node in the focusScope |
| createDOM('shadow', {}), |
| createDOM('input', {'id': 'younger-input-B-0', 'tabindex': 0}), // The last node in the focusScope |
| createDOM('input', {'id': 'younger-input-B-1', 'tabindex': 1})), |
| createDOM('input', {'id': 'light-child-selected-0', 'tabindex': 0}), |
| createDOM('input', {'id': 'light-child-selected-1', 'tabindex': 1}), |
| createDOM('input', {'id': 'light-child-non-selected-1', 'tabindex': 1})), |
| createDOM('input', {'id': 'input-D-1', 'tabindex': 1}), |
| createDOM('input', {'id': 'input-C-0', 'tabindex': 0}), |
| createDOM('div', {'id': 'host-C', 'tabindex': -1}, |
| createShadowRoot( |
| createDOM('input', {'tabindex': -1}))), |
| createDOM('input', {'id': 'input-D-0', 'tabindex': 0}), |
| createDOM('div', {}, |
| createDOM('div', {'id': 'host-D', 'tabindex': 0}, |
| createShadowRoot())), |
| createDOM('input', {'id': 'input-E-0', 'tabindex': 0}))); |
| parent.offsetLeft; |
| } |
| |
| function test() { |
| if (!window.eventSender) { |
| testFailed(''); |
| return; |
| } |
| |
| prepareDOMTree(document.body); |
| |
| // FIXME: Output inserted comments in this array to expected.txt for readability of the result. |
| var elementsInFocusNavigationOrder = [ |
| 'input-A-1', 'input-B-1', |
| // Traverse elements which have tabindex=1. |
| // Should skip every elements, even though they have the same tabindex, in the non-focusable shadow host (id=host-A) |
| // since a non-focusable shadow host should act as if they were assinged to tabindex=0 so it was skipped in this turn. |
| 'input-C-1', |
| |
| // Traverse a focusable shadow host. |
| 'host-B', |
| |
| // Enter the focus scope of the youngest shadow root in the shadow host and travese the first focusable node in the shadow DOM navigation. |
| 'host-B//younger-input-A-1', |
| 'host-B//younger-input-B-1', |
| 'host-B//younger-input-A-0', |
| |
| // Visits a shadow insertion point. Entering the focus scope of the older shadow root. |
| 'host-B/older-input-A-1', |
| 'host-B/older-input-B-1', |
| 'host-B/older-input-A-0', |
| 'host-B/older-input-B-0', |
| |
| // Exits the focus scope of the older sahdow root. Visits the next focusable element which follows the shadow insertion point. |
| 'host-B//younger-input-B-0', |
| |
| // Exits the focus scope of the youngest sahdow root. |
| 'light-child-selected-1', |
| |
| // 'light-child-non-selected-1' should be skipped since it doesn't participate in the flat tree. |
| 'input-D-1', |
| |
| // All elements with tabindex=1 had been traversed in the outermost scope. |
| // So traverse elements with tabindex=0 in next. |
| 'input-A-0', |
| |
| // // A non-focusable shadow host (id=host-A) will be "replaced" with its shadow DOM navigation. |
| 'host-A/input-1', |
| 'host-A/input-20', |
| 'host-A/nested-host', |
| |
| // Enter a nested focus scope inside of a shadow host (id=nested-host). |
| 'host-A/nested-host/input-15', |
| 'host-A/nested-host/input-25', |
| |
| // Exit a nested shadow host. |
| 'input-B-0', |
| |
| 'light-child-selected-0', |
| |
| 'input-C-0', |
| |
| // A non-focusable shadow host (id=host-C), which does not have focusable elements, should be skipped entirely. |
| 'input-D-0', |
| 'host-D', |
| 'input-E-0', |
| |
| // Wraps to the first element in the outermost focus scope. |
| 'input-A-1', |
| ]; |
| |
| testFocusNavigationForward(elementsInFocusNavigationOrder); |
| elementsInFocusNavigationOrder.reverse(); |
| testFocusNavigationBackward(elementsInFocusNavigationOrder); |
| |
| debug('Test finished.'); |
| } |
| |
| test(); |
| |
| </script> |
| </body> |
| </html> |