Allow multiple entries with the same mimetype in dataTransfer (#150425)

Currently our data transfer implementation only allows a single entry of each mimeType. There can only be a single `image/gif` file for example.

However this doesn't match how the DOM apis work. If you drop multiple gifs into VS Code for example, the DataTransfer you get contains entries for each of the gifs.

This change allows us to also support DataTransfers that have multiple entries with the same mime type. Just like with the DOM, we support constructing these duplicate mime data transfers internally, but do not allow extensions to create them

As part of this change, I've also made a few clean ups:

- Add helpers for creating dataTransfer items
- Clarify when adding a data transfer item should `append` or `replace`
- Adopt some helper functions in a few more places
This commit is contained in:
Matt Bierner
2022-05-25 18:29:28 -07:00
committed by GitHub
parent e262c88fb1
commit 528ee1ae3d
9 changed files with 104 additions and 86 deletions

View File

@@ -40,6 +40,7 @@ import { ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/ed
import type * as vscode from 'vscode';
import * as types from './extHostTypes';
import { once } from 'vs/base/common/functional';
import { VSDataTransfer } from 'vs/base/common/dataTransfer';
export namespace Command {
@@ -1980,14 +1981,13 @@ export namespace DataTransferItem {
export namespace DataTransfer {
export function toDataTransfer(value: extHostProtocol.DataTransferDTO, resolveFileData: (dataItemIndex: number) => Promise<Uint8Array>): types.DataTransfer {
const newDataTransfer = new types.DataTransfer();
value.items.forEach(([type, item], index) => {
newDataTransfer.set(type, DataTransferItem.toDataTransferItem(item, () => resolveFileData(index)));
const init = value.items.map(([type, item], index) => {
return [type, DataTransferItem.toDataTransferItem(item, () => resolveFileData(index))] as const;
});
return newDataTransfer;
return new types.DataTransfer(init);
}
export async function toDataTransferDTO(value: vscode.DataTransfer): Promise<extHostProtocol.DataTransferDTO> {
export async function toDataTransferDTO(value: vscode.DataTransfer | VSDataTransfer): Promise<extHostProtocol.DataTransferDTO> {
const newDTO: extHostProtocol.DataTransferDTO = { items: [] };
const promises: Promise<any>[] = [];

View File

@@ -2451,18 +2451,33 @@ export class DataTransferItem {
@es5ClassCompat
export class DataTransfer {
#items = new Map<string, DataTransferItem>();
#items = new Map<string, DataTransferItem[]>();
constructor(init?: Iterable<readonly [string, DataTransferItem]>) {
for (const [mime, item] of init ?? []) {
const existing = this.#items.get(mime);
if (existing) {
existing.push(item);
} else {
this.#items.set(mime, [item]);
}
}
}
get(mimeType: string): DataTransferItem | undefined {
return this.#items.get(mimeType);
return this.#items.get(mimeType)?.[0];
}
set(mimeType: string, value: DataTransferItem): void {
this.#items.set(mimeType, value);
// This intentionally overwrites all entries for a given mimetype.
// This is similar to how the DOM DataTransfer type works
this.#items.set(mimeType, [value]);
}
forEach(callbackfn: (value: DataTransferItem, key: string) => void): void {
this.#items.forEach(callbackfn);
for (const [mime, items] of this.#items) {
items.forEach(item => callbackfn(item, mime));
}
}
}