Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

<!doctype html>
<title>Test dnd for shadow-crossing selection</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
<style>
</style>
<div>
<span id="outer1">Outer1</span>
<div id="host">
<template shadowrootmode="open">
<span>Inner1</span>
<span>Inner2</span>
<span id="inner3">Inner3</span>
</template>
</div>
<span id="outer2">Outer2</span>
<div id="host2">
<template shadowrootmode="open">
<span id="inner4">Inner4</span>
</template>
</div>
</div>
<input id="dropZone" />
<script>
const selection = window.getSelection();
async function waitForEvent(event) {
return new Promise(r => {
addEventListener(event, function(e) {
r(e.target);
}, { once : true});
});
}
async function waitForDropEvent() {
return new Promise(r => {
addEventListener("drop", function(e) {
r(event.dataTransfer.getData('text/html'));
}, { once : true});
});
}
async function run(startNode, startOffset, endNode, endOffset, expectedValue, expectedTarget, expectedHTML, assertionMessage) {
selection.setBaseAndExtent(startNode, startOffset, endNode, endOffset);
const waitForDragStart = waitForEvent("dragstart");
const waitForDragEnd = waitForEvent("dragend");
const waitForDrop = waitForDropEvent();
await synthesizePlainDragAndDrop({
srcSelection: selection,
destElement: dropZone
});
const dragStartTarget = await waitForDragStart;
const dragEndTarget = await waitForDragEnd;
const htmlData = await waitForDrop;
is(dropZone.value, expectedValue, assertionMessage);
is(dragStartTarget, dragEndTarget, "dragstart and dragend should have the same target");
is(dragStartTarget, expectedTarget, "dragstart target should be the same as expectedTarget");
is(htmlData.replace(/\r\n?/g, "\n"), expectedHTML, "dragged html should match")
selection.empty();
dropZone.value = '';
}
add_task(async function runTests() {
await SpecialPowers.pushPrefEnv({
set: [
["dom.shadowdom.selection_across_boundary.enabled", true],
["ui.dragThresholdX", 4], // bug 1873142
["ui.dragThresholdY", 4], // bug 1873142
],
});
// synthesizePlainDragAndDrop would use the focused node to initiate DnD, so
// the expectedTarget is provided based this.
// light to shadow
let sel = [outer1.firstChild, 2, host.shadowRoot.getElementById("inner3").firstChild, 5];
await run(
...sel,
"ter1 Inner1 Inner2 Inner",
host, // expectedTarget - focused node is inside the shadow dom, hence the host is the target to preserve encapsulation.
"<span id=\"outer1\">ter1</span>\n <div id=\"host\">\n <span>Inner1</span>\n <span>Inner2</span>\n <span id=\"inner3\">Inner</span></div>",
"start is in light DOM and end is in shadow DOM");
// light to light
sel = [outer1.firstChild, 2, outer2.firstChild, 6];
await run(
...sel,
"ter1 Inner1 Inner2 Inner3 Outer2",
outer2.firstChild, // expectedTarget - focused node is outer2.firstChild
"<span id=\"outer1\">ter1</span>\n <div id=\"host\">\n <span>Inner1</span>\n <span>Inner2</span>\n <span id=\"inner3\">Inner3</span>\n </div>\n <span id=\"outer2\">Outer2</span>",
"start is in light DOM and end is in light DOM"
);
// shadow to light
sel = [host.shadowRoot.getElementById("inner3").firstChild, 2, outer2.firstChild, 6];
await run(
...sel,
"ner3 Outer2",
outer2.firstChild, // expectedTarget - focused node is outer2.firstChild
"<div id=\"host\"><span id=\"inner3\">ner3</span>\n </div>\n <span id=\"outer2\">Outer2</span>",
"start is in shadow DOM and end is in light DOM"
);
// shadow to shadow
sel = [host.shadowRoot.getElementById("inner3").firstChild, 2, host2.shadowRoot.getElementById("inner4").firstChild, 6];
await run(
...sel,
"ner3 Outer2 Inner4 ",
host2, // expectedTarget - focused node is inside the shadow dom, hence the host is the target to preserve encapsulation.
"<div id=\"host\"><span id=\"inner3\">ner3</span>\n </div>\n <span id=\"outer2\">Outer2</span>\n <div id=\"host2\">\n <span id=\"inner4\">Inner4</span>\n </div>",
"start is in shadow DOM and end is in shadow DOM"
);
});
</script>