Skip to content

Commit 0181e95

Browse files
author
Benjamin Pasero
committed
Web: allow to drop a local file into editor area to open it (fixes microsoft#83650)
1 parent cbeff45 commit 0181e95

2 files changed

Lines changed: 50 additions & 8 deletions

File tree

src/vs/workbench/browser/parts/editor/editorDropTarget.ts

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
1818
import { RunOnceScheduler } from 'vs/base/common/async';
1919
import { find } from 'vs/base/common/arrays';
2020
import { DataTransfers } from 'vs/base/browser/dnd';
21+
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
22+
import { VSBuffer } from 'vs/base/common/buffer';
23+
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
24+
import { URI } from 'vs/base/common/uri';
25+
import { joinPath } from 'vs/base/common/resources';
2126

2227
interface IDropOperation {
2328
splitDirection?: GroupDirection;
@@ -41,8 +46,10 @@ class DropOverlay extends Themable {
4146
constructor(
4247
private accessor: IEditorGroupsAccessor,
4348
private groupView: IEditorGroupView,
44-
themeService: IThemeService,
45-
private instantiationService: IInstantiationService
49+
@IThemeService themeService: IThemeService,
50+
@IInstantiationService private instantiationService: IInstantiationService,
51+
@IUntitledTextEditorService private untitledTextEditorService: IUntitledTextEditorService,
52+
@IFileDialogService private readonly fileDialogService: IFileDialogService
4653
) {
4754
super(themeService);
4855

@@ -100,10 +107,6 @@ class DropOverlay extends Themable {
100107
this._register(new DragAndDropObserver(this.container, {
101108
onDragEnter: e => undefined,
102109
onDragOver: e => {
103-
if (isWeb && containsDragType(e, DataTransfers.FILES)) {
104-
return; // dropping files into editor is unsupported on web
105-
}
106-
107110
const isDraggingGroup = this.groupTransfer.hasData(DraggedEditorGroupIdentifier.prototype);
108111
const isDraggingEditor = this.editorTransfer.hasData(DraggedEditorIdentifier.prototype);
109112

@@ -281,6 +284,45 @@ class DropOverlay extends Themable {
281284
}
282285
}
283286

287+
// Web: check for file transfer
288+
else if (isWeb && containsDragType(event, DataTransfers.FILES)) {
289+
let targetGroup: IEditorGroupView | undefined = undefined;
290+
291+
const files = event.dataTransfer?.files;
292+
if (files) {
293+
for (let i = 0; i < files.length; i++) {
294+
const file = files.item(i);
295+
if (file) {
296+
const reader = new FileReader();
297+
reader.readAsArrayBuffer(file);
298+
reader.onload = async event => {
299+
const name = file.name;
300+
if (typeof name === 'string' && event.target?.result instanceof ArrayBuffer) {
301+
302+
// Try to come up with a good file path for the untitled
303+
// editor by asking the file dialog service for the default
304+
let proposedFilePath: URI | undefined = undefined;
305+
const defaultFilePath = this.fileDialogService.defaultFilePath();
306+
if (defaultFilePath) {
307+
proposedFilePath = joinPath(defaultFilePath, name);
308+
}
309+
310+
// Open as untitled file with the provided contents
311+
const contents = VSBuffer.wrap(new Uint8Array(event.target.result)).toString();
312+
const untitledEditor = this.untitledTextEditorService.createOrGet(proposedFilePath, undefined, contents);
313+
314+
if (!targetGroup) {
315+
targetGroup = ensureTargetGroup();
316+
}
317+
318+
await targetGroup.openEditor(untitledEditor);
319+
}
320+
};
321+
}
322+
}
323+
}
324+
}
325+
284326
// Check for URI transfer
285327
else {
286328
const dropHandler = this.instantiationService.createInstance(ResourcesDropHandler, { allowWorkspaceOpen: true /* open workspace instead of file if dropped */ });
@@ -532,7 +574,7 @@ export class EditorDropTarget extends Themable {
532574
if (!this.overlay) {
533575
const targetGroupView = this.findTargetGroupView(target);
534576
if (targetGroupView) {
535-
this._overlay = new DropOverlay(this.accessor, targetGroupView, this.themeService, this.instantiationService);
577+
this._overlay = this.instantiationService.createInstance(DropOverlay, this.accessor, targetGroupView);
536578
}
537579
}
538580
}

src/vs/workbench/contrib/files/browser/views/explorerViewer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -860,7 +860,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
860860
}
861861

862862
const resource = joinPath(target.resource, name);
863-
await this.fileService.writeFile(resource, VSBuffer.wrap(new Uint8Array(event.target?.result)));
863+
await this.fileService.writeFile(resource, VSBuffer.wrap(new Uint8Array(event.target.result)));
864864
if (data.files.length === 1) {
865865
await this.editorService.openEditor({ resource, options: { pinned: true } });
866866
}

0 commit comments

Comments
 (0)