| <html> |
| <head> |
| <script> |
| |
| var logDiv; |
| |
| function log(msg, success) |
| { |
| logDiv.appendChild(document.createElement('div')).textContent = msg + ': ' + (success ? 'PASS' : 'FAIL'); |
| } |
| |
| function moveOver(element) |
| { |
| if (!window.eventSender) |
| return; |
| |
| var x = element.offsetLeft + element.offsetWidth / 2; |
| var y = element.offsetTop + element.offsetHeight / 2; |
| eventSender.mouseMoveTo(x, y); |
| } |
| |
| function moveOverLeftQuarterOf(element) |
| { |
| if (!window.eventSender) |
| return; |
| |
| var x = element.offsetLeft + element.offsetWidth / 4; |
| var y = element.offsetTop + element.offsetHeight / 2; |
| eventSender.mouseMoveTo(x, y); |
| } |
| |
| function moveOverRightQuarterOf(element) |
| { |
| if (!window.eventSender) |
| return; |
| |
| var x = element.offsetLeft + element.offsetWidth * 3 / 4; |
| var y = element.offsetTop + element.offsetHeight / 2; |
| eventSender.mouseMoveTo(x, y); |
| } |
| |
| function clickOn(element) |
| { |
| moveOver(element); |
| eventSender.mouseDown(); |
| eventSender.mouseUp(); |
| } |
| |
| function clickOnLeftQuarterOf(element) |
| { |
| if (!window.eventSender) |
| return; |
| |
| moveOverLeftQuarterOf(element); |
| eventSender.mouseDown(); |
| eventSender.mouseUp(); |
| } |
| |
| function leapForward() |
| { |
| if (!window.eventSender) |
| return; |
| |
| eventSender.leapForward(1000); |
| } |
| |
| var tests = { |
| mutationEventPropagation: function() |
| { |
| var textarea = document.body.appendChild(document.createElement('textarea')); |
| var mutationEventFired; |
| textarea.addEventListener('DOMSubtreeModified', function(e) |
| { |
| mutationEventFired = true; |
| }, false); |
| textarea.value = 'test'; |
| // Trigger style recalc and sadly, the actual mutation of the textarea shadow DOM. |
| textarea.offsetHeight; |
| log('Mutation events should not propagate out of the shadow DOM', !mutationEventFired); |
| textarea.parentNode.removeChild(textarea); |
| }, |
| selectstartEventPropagation: function() |
| { |
| var textInput = document.body.appendChild(document.createElement('input')); |
| var selectstartEventFired = false; |
| document.selectstart = function() |
| { |
| selectstartEventFired = true; |
| } |
| clickOn(textInput); |
| log('The selectstart event should not propagate out of the shadow DOM', !selectstartEventFired); |
| textInput.parentNode.removeChild(textInput); |
| document.selectstart = null; |
| }, |
| mouseOverAndOutPropagation: function() |
| { |
| var count = 0; |
| var fileInput = document.body.appendChild(document.createElement('input')); |
| fileInput.setAttribute('type', 'file'); |
| var countEventDispatch = function() |
| { |
| count++; |
| } |
| moveOverLeftQuarterOf(fileInput); |
| |
| document.body.addEventListener('mouseover', countEventDispatch, false); |
| document.body.addEventListener('mouseout', countEventDispatch, false); |
| |
| moveOverRightQuarterOf(fileInput); |
| |
| log("The mouseover/mouseout event between two elements inside the same shadow subtree should not propagate out of the shadow DOM", count == 0); |
| |
| document.body.removeEventListener('mouseover', countEventDispatch, false); |
| document.body.removeEventListener('mouseout', countEventDispatch, false); |
| fileInput.parentNode.removeChild(fileInput); |
| }, |
| relatedTargetAsHost: function() |
| { |
| var count = 0; |
| var relatedTarget = document.createElement('div'); |
| relatedTarget.style.cssText = 'width: 50px; height: 50px; padding-left: 50px;'; |
| document.body.appendChild(relatedTarget); |
| var target = document.createElement('div'); |
| target.style.cssText = 'width: 50px; height: 50px'; |
| relatedTarget.attachShadow({mode: 'open'}).appendChild(target); |
| moveOverLeftQuarterOf(relatedTarget); |
| var countEventDispatch = function() |
| { |
| count++; |
| } |
| relatedTarget.addEventListener('mouseover', countEventDispatch, false) |
| moveOverRightQuarterOf(relatedTarget); |
| |
| log("The mouseover event in a shadow subtree, where related target is the tree host should not escape out of shadow DOM", count == 0); |
| |
| relatedTarget.removeEventListener('mouseover', countEventDispatch, false); |
| document.body.removeChild(relatedTarget); |
| }, |
| targetAsHost: function() |
| { |
| var count = 0; |
| var target = document.createElement('div'); |
| target.style.cssText = 'width: 50px; height: 50px; padding-left: 50px;'; |
| document.body.appendChild(target); |
| var relatedTarget = document.createElement('div'); |
| relatedTarget.style.cssText = 'width: 50px; height: 50px'; |
| target.attachShadow({mode: 'open'}).appendChild(relatedTarget); |
| moveOverRightQuarterOf(target); |
| var countEventDispatch = function(evt) |
| { |
| count++; |
| } |
| target.addEventListener('mouseover', countEventDispatch, false) |
| moveOverLeftQuarterOf(target); |
| |
| log("Events with relatedTarget should not escape out of shadow subtree when its host is the target", count == 0); |
| |
| target.removeEventListener('mouseout', countEventDispatch, false); |
| document.body.removeChild(target); |
| }, |
| mouseOverOnHost: function() |
| { |
| var count = 0; |
| var input = document.body.appendChild(document.createElement('input')); |
| var countEventDispatch = function() |
| { |
| count++; |
| } |
| |
| moveOver(document.body); |
| input.addEventListener('mouseover', countEventDispatch, false); |
| moveOver(input); |
| |
| log("The mouseover/mouseout event on a shadow subtree host should propagate out of the shadow DOM", count == 1); |
| |
| document.body.removeEventListener('mouseover', countEventDispatch, false); |
| input.parentNode.removeChild(input); |
| }, |
| labelSyntheticClick: function() |
| { |
| var count = 0; |
| var label = document.body.appendChild(document.createElement('label')); |
| var searchInput = label.appendChild(document.createElement('input')); |
| searchInput.setAttribute('type', 'search'); |
| searchInput.setAttribute('id', 'baz'); |
| label.setAttribute('for', 'baz'); |
| searchInput.addEventListener('click', function(e) |
| { |
| count++; |
| }, false); |
| clickOn(searchInput); |
| log("Label should look beyond shadow boundary to detect if it encloses its associated element", count == 1); |
| label.parentNode.removeChild(label); |
| }, |
| /* This subtest started crashing after r89007: |
| * https://bugs.webkit.org/show_bug.cgi?id=62788 |
| * I'm disabling this test for now while I ask for help understanding the problem. |
| defaultEventRetargeting: function() |
| { |
| var count = 0; |
| var fileInput = document.body.appendChild(document.createElement('input')); |
| fileInput.setAttribute('type', 'file'); |
| var counter = function() |
| { |
| count++; |
| } |
| document.body.addEventListener('DOMActivate', counter, false); |
| clickOnLeftQuarterOf(fileInput); |
| log("Events for default event handler should not be retargeted", count == 1); |
| document.body.removeEventListener('DOMActivate', counter, false); |
| fileInput.parentNode.removeChild(fileInput); |
| }, |
| */ |
| relatedTargetRetargeting: function() |
| { |
| var count = 0; |
| var textInput = document.body.appendChild(document.createElement('input')); |
| var counter = function(evt) |
| { |
| if (evt.relatedTarget && !evt.relatedTarget.parentNode) |
| count++; |
| } |
| moveOver(textInput); |
| document.body.addEventListener("mouseover", counter, false); |
| moveOver(document.body); |
| document.body.removeEventListener("mouseover", counter, false); |
| log("Event's relatedTarget should be retargeted", count == 0); |
| textInput.parentNode.removeChild(textInput); |
| }, |
| eventInProgress: function() |
| { |
| var textInput = document.body.appendChild(document.createElement('input')); |
| textInput.addEventListener('click', function(e) |
| { |
| log('Other events should be retargeted', e.target == textInput); |
| }, false); |
| clickOn(textInput); |
| textInput.parentNode.removeChild(textInput); |
| }, |
| finalEventObject: function() |
| { |
| var textInput = document.body.appendChild(document.createElement('input')); |
| var storedEvent; |
| textInput.addEventListener('click', function(e) |
| { |
| storedEvent = e; |
| }, false); |
| clickOn(textInput); |
| log('After event dispatch, the event object should not reveal shadow DOM', storedEvent && storedEvent.target == textInput); |
| textInput.parentNode.removeChild(textInput); |
| }, |
| focusEventPropagation: function() |
| { |
| var searchInput = document.body.appendChild(document.createElement('input')); |
| searchInput.setAttribute('type', 'search'); |
| var count = 0; |
| searchInput.addEventListener('focus', function(evt) |
| { |
| count++; |
| }); |
| clickOn(searchInput); |
| leapForward(); |
| clickOn(searchInput); |
| log('Focusing same shadow DOM element repeatedly should not trigger multiple focus/blur events', count == 1); |
| searchInput.parentNode.removeChild(searchInput); |
| } |
| }; |
| |
| function runTest() |
| { |
| if (window.testRunner) |
| testRunner.dumpAsText(); |
| |
| logDiv = document.getElementById('log'); |
| for(var testName in tests) { |
| tests[testName](); |
| } |
| } |
| |
| </script> |
| </head> |
| <body onload="runTest()"> |
| <p>Tests to ensure that shadow DOM boundary is not crossed during event propagation. Can only run within DRT. |
| <p>See <a href="https://bugs.webkit.org/show_bug.cgi?id=46015">bug 46015</a> for details. |
| <div id="log"></div> |
| </body> |
| </html> |