<!DOCTYPE html>
<html>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<style>
body, html {
    width: 100%;
    height: 100%;
    margin: 0;
}
</style>
<body>
    <div style="font-size: 40px;" id="source">Copy this text!</div>
    <p>To manually test, copy the above text. The output below dumps DataTransfer state following each operation,</p>
    <p>described directly above the output text for each step. The DataTransfer state should be consistent with the</p>
    <p>operation performed at each step.</p>
    <pre style="height: 100%; width: 100%;" id="output"></pre>
</body>
<script>
function write(message) {
    output.textContent += `${message}\n`;
}

function representationForFile(file) {
    return file ? {
        name: file.name,
        bytes: file.size,
        type: file.type
    } : null;
}

function updateOutputText(description, event) {
    const dataInfo = {};
    for (const type of event.clipboardData.types)
        dataInfo[type] = event.clipboardData.getData(type);
    const itemsInfo = [];
    for (const item of event.clipboardData.items) {
        itemsInfo.push({
            type: item.type,
            kind: item.kind,
            file: representationForFile(item.getAsFile())
        });
    }
    write(`\n${description}\n${JSON.stringify({
        data: dataInfo,
        items: itemsInfo,
        files: Array.from(event.clipboardData.files).map(representationForFile)
    }, null, "    ")}`);
}

function removeAt(itemList, index) {
    const removedItem = itemList[index];
    itemList.remove(index);
    return removedItem;
}

source.addEventListener("copy", event => {
    const fileList = event.clipboardData.files;
    event.clipboardData.items.add("hello world", "text/plain");
    updateOutputText("1. After adding a string", event);

    const buffer = new ArrayBuffer(64);
    const array = new Int8Array(buffer);
    array.fill(15);
    event.clipboardData.items.add(new File([ buffer ], "foo", { type: "custom" }));
    updateOutputText("2. After adding a file of custom type", event);

    event.clipboardData.items.add(new File([
        new Blob(["This part is from a JavaScript Blob"], { type : "text/plain" }),
        "This part is just from a plain string"
    ], "first.txt", { type: "text/plain" }));
    updateOutputText("3. After adding the first plain text file", event);

    removedItem = removeAt(event.clipboardData.items, 2);
    updateOutputText("4. After removing the last file", event);
    write(`removedItem.getAsFile() should be null: ${removedItem.getAsFile()}`);

    event.clipboardData.items.add("<a>goodbye world</a>", "text/html");
    updateOutputText("5. After adding an HTML string", event);

    event.clipboardData.items.add(new File([ "This is just a plain string" ], "second.txt", { type: "text/plain" }));
    updateOutputText("6. After adding another plain text file", event);

    removedItem = removeAt(event.clipboardData.items, 1);
    updateOutputText("7. After removing the custom file", event);
    write(`removedItem.getAsFile() should be null: ${removedItem.getAsFile()}`);

    removedItem = removeAt(event.clipboardData.items, 1);
    updateOutputText("8. After removing the HTML string", event);
    write(`removedItem.getAsFile() should be null: ${removedItem.getAsFile()}`);

    removedItem = removeAt(event.clipboardData.items, 1);
    updateOutputText("9. After removing the second text file", event);
    write(`removedItem.getAsFile() should be null: ${removedItem.getAsFile()}`);

    removedItem = removeAt(event.clipboardData.items, 0);
    updateOutputText("10. After removing the plain text string", event);
    write(`removedItem.getAsFile() should be null: ${removedItem.getAsFile()}`);
    write(`The DataTransfer's FileList should be the same object: ${fileList == event.clipboardData.files}`);

    event.preventDefault();
});

getSelection().setBaseAndExtent(source, 0, source, 1);

if (window.testRunner && window.internals) {
    internals.settings.setCustomPasteboardDataEnabled(true);
    testRunner.dumpAsText();
    document.execCommand("Copy");
}
</script>
</html>
