| OLD | NEW |
| (Empty) |
| 1 <!DOCTYPE html> | |
| 2 <script src="../../../resources/js-test.js"></script> | |
| 3 <script src="resources/shadow-dom.js"></script> | |
| 4 <style> | |
| 5 div { | |
| 6 background-color: white; | |
| 7 } | |
| 8 | |
| 9 div#shadow-host:focus { | |
| 10 background-color: green; | |
| 11 } | |
| 12 </style> | |
| 13 <script> | |
| 14 function backgroundColorOf(selector) { | |
| 15 return window.getComputedStyle(getNodeInTreeOfTrees(selector)).backgroundCol
or; | |
| 16 } | |
| 17 | |
| 18 function backgroundColorShouldBe(selector, expected) { | |
| 19 shouldBeEqualToString('backgroundColorOf(\'' + selector + '\')', expected); | |
| 20 } | |
| 21 | |
| 22 function testWithoutTabStop() | |
| 23 { | |
| 24 debug('testing without tabstop for crbug/479050'); | |
| 25 | |
| 26 // Setting up the DOM tree | |
| 27 var sandbox = document.querySelector('#sandbox'); | |
| 28 sandbox.innerHTML = ''; | |
| 29 sandbox.appendChild( | |
| 30 createDOM('div', {}, | |
| 31 createDOM('input', {'id': 'outer-input1'}), | |
| 32 createDOM('div', {'id': 'shadow-host', 'tabindex': '-1'}, | |
| 33 createShadowRoot( | |
| 34 createDOM('input', {'id': 'inner-input'}))), | |
| 35 createDOM('input', {'id': 'outer-input2'}))); | |
| 36 sandbox.offsetTop; | |
| 37 | |
| 38 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 39 | |
| 40 var host = getNodeInTreeOfTrees('shadow-host'); | |
| 41 var innerInput = getNodeInTreeOfTrees('shadow-host/inner-input'); | |
| 42 var outerInput1 = getNodeInTreeOfTrees('outer-input1'); | |
| 43 var outerInput2 = getNodeInTreeOfTrees('outer-input2'); | |
| 44 | |
| 45 outerInput1.focus(); | |
| 46 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 47 | |
| 48 innerInput.focus(); | |
| 49 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 50 | |
| 51 outerInput2.focus(); | |
| 52 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 53 } | |
| 54 | |
| 55 function testSingleShadow() { | |
| 56 debug('testing single shadow DOM tree'); | |
| 57 | |
| 58 // Setting up the DOM tree | |
| 59 var sandbox = document.querySelector('#sandbox'); | |
| 60 sandbox.innerHTML = ''; | |
| 61 sandbox.appendChild( | |
| 62 createDOM('div', {}, | |
| 63 createDOM('input', {'id': 'outer-input'}), | |
| 64 createDOM('div', {'id': 'shadow-host'}, | |
| 65 createShadowRoot( | |
| 66 createDOM('div', {'id': 'inner-div'}, | |
| 67 document.createTextNode('Blink')), | |
| 68 createDOM('input', {'id': 'inner-input'}))))); | |
| 69 sandbox.offsetTop; | |
| 70 | |
| 71 var host = getNodeInTreeOfTrees('shadow-host'); | |
| 72 var input = getNodeInTreeOfTrees('shadow-host/inner-input'); | |
| 73 var outerInput = document.querySelector('#outer-input'); | |
| 74 | |
| 75 // First check the original behavior. | |
| 76 // By default, shadow host should not reflect the focus status inside shadow
tree. | |
| 77 outerInput.focus(); | |
| 78 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 79 host.tabIndex = 0; | |
| 80 host.focus(); | |
| 81 backgroundColorShouldBe('shadow-host', 'rgb(0, 128, 0)'); | |
| 82 input.focus(); | |
| 83 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 84 | |
| 85 // The following 4 cases cover tabIndex(0 or none)/tabStop(true or false) co
mbination. | |
| 86 // Only when tabindex>=0 and tabStop=false should change the appearance. | |
| 87 host.tabIndex = 0; | |
| 88 host.tabStop = false; | |
| 89 input.focus(); | |
| 90 backgroundColorShouldBe('shadow-host', 'rgb(0, 128, 0)'); | |
| 91 | |
| 92 host.tabStop = true; | |
| 93 input.focus(); | |
| 94 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 95 | |
| 96 host.removeAttribute('tabindex'); | |
| 97 input.focus(); | |
| 98 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 99 | |
| 100 host.tabStop = false; | |
| 101 input.focus(); | |
| 102 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 103 | |
| 104 // Focus outside the shadow tree should not affect. | |
| 105 outerInput.focus(); | |
| 106 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 107 } | |
| 108 | |
| 109 function testShadowTreeOfTrees() { | |
| 110 debug('testing shadow tree of trees'); | |
| 111 | |
| 112 // Setting up the DOM tree | |
| 113 var sandbox = document.querySelector('#sandbox'); | |
| 114 sandbox.innerHTML = ''; | |
| 115 sandbox.appendChild( | |
| 116 createDOM('div', {}, | |
| 117 createDOM('input', {'id': 'outer-input'}), | |
| 118 createDOM('div', {'id': 'shadow-host'}, | |
| 119 createShadowRoot( | |
| 120 createDOM('style', {}, | |
| 121 document.createTextNode('div { background-color: yellow;
} div#inner-shadow-host:focus { background-color: blue; }')), | |
| 122 createDOM('div', {'id': 'inner-div'}, | |
| 123 document.createTextNode('Blink')), | |
| 124 createDOM('input', {'id': 'inner-input'}), | |
| 125 createDOM('div', {'id': 'inner-shadow-host'}, | |
| 126 createShadowRoot( | |
| 127 createDOM('div', {'id': 'inner-div2'}, | |
| 128 document.createTextNode('Blink')), | |
| 129 createDOM('input', {'id': 'inner-input2'}))))))); | |
| 130 sandbox.offsetTop; | |
| 131 | |
| 132 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 133 backgroundColorShouldBe('shadow-host/inner-shadow-host', 'rgb(255, 255, 0)')
; | |
| 134 | |
| 135 var host = getNodeInTreeOfTrees('shadow-host'); | |
| 136 var innerHost = getNodeInTreeOfTrees('shadow-host/inner-shadow-host'); | |
| 137 var input = getNodeInTreeOfTrees('shadow-host/inner-input'); | |
| 138 var input2 = getNodeInTreeOfTrees('shadow-host/inner-shadow-host/inner-input
2'); | |
| 139 var outerInput = document.querySelector('#outer-input'); | |
| 140 | |
| 141 // The default behavior. | |
| 142 input2.focus(); | |
| 143 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 144 backgroundColorShouldBe('shadow-host/inner-shadow-host', 'rgb(255, 255, 0)')
; | |
| 145 | |
| 146 | |
| 147 // Only first-level shadow host should be affected. | |
| 148 host.tabIndex = 0; | |
| 149 host.tabStop = false; | |
| 150 | |
| 151 input2.focus(); | |
| 152 backgroundColorShouldBe('shadow-host', 'rgb(0, 128, 0)'); | |
| 153 backgroundColorShouldBe('shadow-host/inner-shadow-host', 'rgb(255, 255, 0)')
; | |
| 154 | |
| 155 // Both first-level and second-level shadow hosts should be affected. | |
| 156 innerHost.tabIndex = 0; | |
| 157 innerHost.tabStop = false; | |
| 158 backgroundColorShouldBe('shadow-host', 'rgb(0, 128, 0)'); | |
| 159 backgroundColorShouldBe('shadow-host/inner-shadow-host', 'rgb(0, 0, 255)'); | |
| 160 | |
| 161 // The :focus should propagate only upwards, not downwards. | |
| 162 input.focus(); | |
| 163 backgroundColorShouldBe('shadow-host', 'rgb(0, 128, 0)'); | |
| 164 backgroundColorShouldBe('shadow-host/inner-shadow-host', 'rgb(255, 255, 0)')
; | |
| 165 | |
| 166 // Focus outside the shadow tree should not affect. | |
| 167 outerInput.focus(); | |
| 168 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 169 backgroundColorShouldBe('shadow-host/inner-shadow-host', 'rgb(255, 255, 0)')
; | |
| 170 } | |
| 171 | |
| 172 function testDistributedNodes() { | |
| 173 debug('testing distributed nodes'); | |
| 174 | |
| 175 // Setting up the DOM tree | |
| 176 var sandbox = document.querySelector('#sandbox'); | |
| 177 sandbox.innerHTML = ''; | |
| 178 sandbox.appendChild( | |
| 179 createDOM('div', {}, | |
| 180 createDOM('input', {'id': 'outer-input'}), | |
| 181 createDOM('div', {'id': 'shadow-host'}, | |
| 182 createDOM('input', {'id': 'light-input'}), | |
| 183 createShadowRoot( | |
| 184 createDOM('content', {}), | |
| 185 createDOM('div', {'id': 'inner-div'}, | |
| 186 document.createTextNode('Blink')), | |
| 187 createDOM('input', {'id': 'older-input'})), | |
| 188 createShadowRoot( | |
| 189 createDOM('shadow', {}), | |
| 190 createDOM('div', {'id': 'inner-div2'}, | |
| 191 document.createTextNode('Blink')), | |
| 192 createDOM('input', {'id': 'younger-input'}))))); | |
| 193 sandbox.offsetTop; | |
| 194 | |
| 195 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 196 | |
| 197 var host = getNodeInTreeOfTrees('shadow-host'); | |
| 198 var outerInput = getNodeInTreeOfTrees('outer-input'); | |
| 199 var lightInput = getNodeInTreeOfTrees('light-input'); | |
| 200 var olderInput = getNodeInTreeOfTrees('shadow-host/older-input'); | |
| 201 var youngerInput = getNodeInTreeOfTrees('shadow-host//younger-input'); | |
| 202 | |
| 203 lightInput.focus(); | |
| 204 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 205 | |
| 206 host.tabIndex = 0; | |
| 207 host.tabStop = false; | |
| 208 | |
| 209 outerInput.focus(); | |
| 210 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 211 lightInput.focus(); | |
| 212 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 213 | |
| 214 outerInput.focus(); | |
| 215 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 216 olderInput.focus(); | |
| 217 backgroundColorShouldBe('shadow-host', 'rgb(0, 128, 0)'); | |
| 218 | |
| 219 outerInput.focus(); | |
| 220 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 221 youngerInput.focus(); | |
| 222 backgroundColorShouldBe('shadow-host', 'rgb(0, 128, 0)'); | |
| 223 } | |
| 224 | |
| 225 function testNestedDistribution() { | |
| 226 debug('testing nested distribution'); | |
| 227 | |
| 228 // Setting up the DOM tree | |
| 229 var sandbox = document.querySelector('#sandbox'); | |
| 230 sandbox.innerHTML = ''; | |
| 231 sandbox.appendChild( | |
| 232 createDOM('div', {}, | |
| 233 createDOM('input', {'id': 'outer-input'}), | |
| 234 createDOM('div', {'id': 'shadow-host'}, | |
| 235 createDOM('input', {'id': 'input1'}), | |
| 236 createShadowRoot( | |
| 237 createDOM('style', {}, | |
| 238 document.createTextNode('div { background-color: yellow;
} div#inner-shadow-host:focus { background-color: blue; }')), | |
| 239 createDOM('input', {'id': 'input2'}), | |
| 240 createDOM('div', {'id': 'inner-shadow-host'}, | |
| 241 createDOM('content', {}), // #input1 goes here | |
| 242 createShadowRoot( | |
| 243 createDOM('content', {}), // #input1 redistributed
here, #input2 goes here. | |
| 244 createDOM('input', {'id': 'input3'}))))))); | |
| 245 sandbox.offsetTop; | |
| 246 | |
| 247 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 248 | |
| 249 var topShadowHost = getNodeInTreeOfTrees('shadow-host'); | |
| 250 var innerShadowHost = getNodeInTreeOfTrees('shadow-host/inner-shadow-host'); | |
| 251 var outerInput = getNodeInTreeOfTrees('outer-input'); | |
| 252 var input1 = getNodeInTreeOfTrees('input1'); | |
| 253 var input2 = getNodeInTreeOfTrees('shadow-host/input2'); | |
| 254 var input3 = getNodeInTreeOfTrees('shadow-host/inner-shadow-host/input3'); | |
| 255 | |
| 256 debug('#input1, #input2 are (re)distributed in the same treescope as #input3
, but :focus on shadow host only matches when a focused element is under its sha
dow tree.'); | |
| 257 | |
| 258 debug('Case 1: top and inner shadow do not delegate focus.'); | |
| 259 outerInput.focus(); | |
| 260 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 261 backgroundColorShouldBe('shadow-host/inner-shadow-host', 'rgb(255, 255, 0)')
; | |
| 262 | |
| 263 input1.focus(); | |
| 264 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 265 backgroundColorShouldBe('shadow-host/inner-shadow-host', 'rgb(255, 255, 0)')
; | |
| 266 | |
| 267 input2.focus(); | |
| 268 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 269 backgroundColorShouldBe('shadow-host/inner-shadow-host', 'rgb(255, 255, 0)')
; | |
| 270 | |
| 271 input3.focus(); | |
| 272 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 273 backgroundColorShouldBe('shadow-host/inner-shadow-host', 'rgb(255, 255, 0)')
; | |
| 274 | |
| 275 debug('Case 2: top shadow delegates, but inner shadow does not.'); | |
| 276 topShadowHost.tabIndex = 0; | |
| 277 topShadowHost.tabStop = false; | |
| 278 innerShadowHost.tabStop = true; | |
| 279 | |
| 280 outerInput.focus(); | |
| 281 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 282 backgroundColorShouldBe('shadow-host/inner-shadow-host', 'rgb(255, 255, 0)')
; | |
| 283 | |
| 284 input1.focus(); | |
| 285 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 286 backgroundColorShouldBe('shadow-host/inner-shadow-host', 'rgb(255, 255, 0)')
; | |
| 287 | |
| 288 input2.focus(); | |
| 289 backgroundColorShouldBe('shadow-host', 'rgb(0, 128, 0)'); | |
| 290 backgroundColorShouldBe('shadow-host/inner-shadow-host', 'rgb(255, 255, 0)')
; | |
| 291 | |
| 292 input3.focus(); | |
| 293 backgroundColorShouldBe('shadow-host', 'rgb(0, 128, 0)'); | |
| 294 backgroundColorShouldBe('shadow-host/inner-shadow-host', 'rgb(255, 255, 0)')
; | |
| 295 | |
| 296 debug('Case 3: top shadow does not delegate, but inner shadow does.'); | |
| 297 topShadowHost.removeAttribute('tabindex'); | |
| 298 topShadowHost.removeAttribute('tabstop'); | |
| 299 innerShadowHost.tabIndex = 0; | |
| 300 innerShadowHost.tabStop = false; | |
| 301 | |
| 302 outerInput.focus(); | |
| 303 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 304 backgroundColorShouldBe('shadow-host/inner-shadow-host', 'rgb(255, 255, 0)')
; | |
| 305 | |
| 306 input1.focus(); | |
| 307 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 308 backgroundColorShouldBe('shadow-host/inner-shadow-host', 'rgb(255, 255, 0)')
; | |
| 309 | |
| 310 input2.focus(); | |
| 311 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 312 backgroundColorShouldBe('shadow-host/inner-shadow-host', 'rgb(255, 255, 0)')
; | |
| 313 | |
| 314 input3.focus(); | |
| 315 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 316 backgroundColorShouldBe('shadow-host/inner-shadow-host', 'rgb(0, 0, 255)'); | |
| 317 | |
| 318 debug('Case 4: both shadow hosts delagate focus.'); | |
| 319 topShadowHost.tabIndex = 0; | |
| 320 topShadowHost.tabStop = false; | |
| 321 innerShadowHost.tabIndex = 0; | |
| 322 innerShadowHost.tabStop = false; | |
| 323 | |
| 324 outerInput.focus(); | |
| 325 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 326 backgroundColorShouldBe('shadow-host/inner-shadow-host', 'rgb(255, 255, 0)')
; | |
| 327 | |
| 328 input1.focus(); | |
| 329 backgroundColorShouldBe('shadow-host', 'rgb(255, 255, 255)'); | |
| 330 backgroundColorShouldBe('shadow-host/inner-shadow-host', 'rgb(255, 255, 0)')
; | |
| 331 | |
| 332 input2.focus(); | |
| 333 backgroundColorShouldBe('shadow-host', 'rgb(0, 128, 0)'); | |
| 334 backgroundColorShouldBe('shadow-host/inner-shadow-host', 'rgb(255, 255, 0)')
; | |
| 335 | |
| 336 input3.focus(); | |
| 337 backgroundColorShouldBe('shadow-host', 'rgb(0, 128, 0)'); | |
| 338 backgroundColorShouldBe('shadow-host/inner-shadow-host', 'rgb(0, 0, 255)'); | |
| 339 } | |
| 340 | |
| 341 function init() { | |
| 342 if (!window.eventSender) | |
| 343 testFailed('No eventSender'); | |
| 344 | |
| 345 testWithoutTabStop(); | |
| 346 testSingleShadow(); | |
| 347 testShadowTreeOfTrees(); | |
| 348 testDistributedNodes(); | |
| 349 testNestedDistribution(); | |
| 350 } | |
| 351 | |
| 352 window.onload = init; | |
| 353 </script> | |
| 354 <body> | |
| 355 <div id="sandbox"></div> | |
| 356 </body> | |
| OLD | NEW |