| <!DOCTYPE html> |
| <script src='../resources/testharness.js'></script> |
| <script src='../resources/testharnessreport.js'></script> |
| <script src='resources/shadow-dom.js'></script> |
| |
| <template id='ShadowTemplate'> |
| <ul> |
| <li tabindex='0' id='one'>One</li> |
| <li tabindex='0' id='two'>Two</li> |
| <li id='three'>Three</li> |
| </ul> |
| </template> |
| <template id='NoFocusableShadowTemplate'> |
| <ul> |
| <li id='one'>One</li> |
| <li id='two'>Two</li> |
| <li id='three'>Three</li> |
| </ul> |
| </template> |
| <body> |
| <input id='input0'> |
| <x-shadow id='xshadow0'></x-shadow> |
| <x-shadow id='xshadow1' tabindex='0'></x-shadow> |
| <x-shadow id='xshadow2' tabindex='0' delegatesFocus></x-shadow> |
| <x-shadow-nofocus id='xshadow3'></x-shadow-nofocus> |
| <x-shadow-nofocus id='xshadow4' tabindex='0'></x-shadow-nofocus> |
| <x-shadow-nofocus id='xshadow5' tabindex='0' delegatesFocus></x-shadow-nofocus> |
| </body> |
| <script> |
| 'use strict'; |
| |
| function registerShadow(templateId, tagName) { |
| const template = document.getElementById(templateId); |
| |
| customElements.define(tagName, class extends HTMLElement { |
| connectedCallback() { |
| const delegatesFocus = this.hasAttribute('delegatesFocus'); |
| this.attachShadow({mode: 'open', delegatesFocus: delegatesFocus}) |
| .appendChild(document.importNode(template.content, true)); |
| } |
| }); |
| } |
| |
| registerShadow('ShadowTemplate', 'x-shadow'); |
| registerShadow('NoFocusableShadowTemplate', 'x-shadow-nofocus'); |
| |
| test(() => { |
| xshadow0.focus(); |
| assert_equals(document.activeElement.tagName, 'BODY'); |
| assert_equals(xshadow0.shadowRoot.activeElement, null); |
| }, 'xshadow0 is not focusable without tabindex.'); |
| |
| test(() => { |
| xshadow1.focus(); |
| assert_equals(document.activeElement.id, 'xshadow1'); |
| assert_equals(xshadow1.shadowRoot.activeElement, null); |
| }, 'xshadow1 becomes focusable with tabindex.'); |
| |
| test(() => { |
| xshadow2.focus(); |
| assert_equals(document.activeElement.id, 'xshadow2'); |
| assert_equals(xshadow2.shadowRoot.activeElement.id, 'one'); |
| }, 'on focus(), focusable xshadow2 with delegatesFocus=true delegates focus into its inner element.'); |
| |
| test(() => { |
| xshadow2.shadowRoot.querySelector('#two').focus(); |
| assert_equals(document.activeElement.id, 'xshadow2'); |
| assert_equals(xshadow2.shadowRoot.activeElement.id, 'two'); |
| }, 'if an element within shadow is focused, focusing on shadow host should not slide focus to its inner element.'); |
| |
| test(() => { |
| xshadow2.focus(); |
| assert_equals(document.activeElement.id, 'xshadow2'); |
| assert_equals(xshadow2.shadowRoot.activeElement.id, 'two'); |
| }, 'xshadow2.focus() shouldn\'t move focus to #one when its inner element is already focused.'); |
| |
| test(() => { |
| // Focus outside shadow DOMs. |
| input0.focus(); |
| |
| // within shadow root. This is different from mouse click behavior. |
| xshadow1.shadowRoot.querySelector('#three').focus(); |
| assert_equals(document.activeElement.id, 'input0'); |
| xshadow2.shadowRoot.querySelector('#three').focus(); |
| assert_equals(document.activeElement.id, 'input0'); |
| }, 'focus() inside shadow DOM should not focus its shadow host, nor focusable siblings.'); |
| |
| test(() => { |
| xshadow3.focus(); |
| assert_equals(document.activeElement.id, 'input0'); |
| }, 'If any element including shadow host is not focusable, focus doesn\'t change.'); |
| |
| test(() => { |
| xshadow4.focus(); |
| assert_equals(document.activeElement.id, 'xshadow4'); |
| xshadow5.focus(); |
| assert_equals(document.activeElement.id, 'xshadow5'); |
| }, 'If no element is focusable within shadow root, but the shadow host is focusable, then the host gets focus regardless of delegatesFocus.'); |
| </script> |