提交 5da820a3 编写于 作者: B Benjamin Pasero

restore ability to drop folders or *.vsix into Code

上级 1d8a0023
...@@ -42,17 +42,19 @@ export class DelayedDragHandler { ...@@ -42,17 +42,19 @@ export class DelayedDragHandler {
} }
} }
export function extractResources(e: DragEvent): URI[] { export function extractResources(e: DragEvent, externalOnly?: boolean): URI[] {
const resources: URI[] = []; const resources: URI[] = [];
if (e.dataTransfer.types.length > 0) { if (e.dataTransfer.types.length > 0) {
// Check for in-app DND // Check for in-app DND
const rawData = e.dataTransfer.getData(e.dataTransfer.types[0]); if (!externalOnly) {
if (rawData) { const rawData = e.dataTransfer.getData(e.dataTransfer.types[0]);
try { if (rawData) {
resources.push(URI.parse(rawData)); try {
} catch (error) { resources.push(URI.parse(rawData));
// Invalid URI } catch (error) {
// Invalid URI
}
} }
} }
......
...@@ -40,6 +40,29 @@ ...@@ -40,6 +40,29 @@
margin-top: 7px; /* Center the select box */ margin-top: 7px; /* Center the select box */
} }
#monaco-workbench-drop-overlay {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
z-index: 3000000;
}
.vs #monaco-workbench-drop-overlay {
background-color: rgba(51,153,255, 0.18);
}
.vs-dark #monaco-workbench-drop-overlay {
background-color: rgba(83, 89, 93, 0.5);
}
.hc-black #monaco-workbench-drop-overlay {
background: none !important;
outline: 2px dashed #f38518;
outline-offset: -2px;
}
/* ---------- Light Theme ---------- */ /* ---------- Light Theme ---------- */
.vs .monaco-workbench { background-color: #F3F3F3; } .vs .monaco-workbench { background-color: #F3F3F3; }
......
...@@ -8,7 +8,10 @@ ...@@ -8,7 +8,10 @@
import platform = require('vs/base/common/platform'); import platform = require('vs/base/common/platform');
import URI from 'vs/base/common/uri'; import URI from 'vs/base/common/uri';
import DOM = require('vs/base/browser/dom'); import DOM = require('vs/base/browser/dom');
import workbenchEditorCommon = require('vs/workbench/common/editor'); import DND = require('vs/base/browser/dnd');
import {Builder, $} from 'vs/base/browser/builder';
import {Identifiers} from 'vs/workbench/common/constants';
import {asFileEditorInput} from 'vs/workbench/common/editor';
import {IViewletService} from 'vs/workbench/services/viewlet/common/viewletService'; import {IViewletService} from 'vs/workbench/services/viewlet/common/viewletService';
import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService'; import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService';
import {IStorageService} from 'vs/platform/storage/common/storage'; import {IStorageService} from 'vs/platform/storage/common/storage';
...@@ -17,6 +20,8 @@ import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; ...@@ -17,6 +20,8 @@ import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace';
import {IEditorGroupService} from 'vs/workbench/services/group/common/groupService'; import {IEditorGroupService} from 'vs/workbench/services/group/common/groupService';
import {ipcRenderer as ipc, shell, remote} from 'electron'; import {ipcRenderer as ipc, shell, remote} from 'electron';
import * as fs from 'fs';
import * as path from 'path';
const dialog = remote.dialog; const dialog = remote.dialog;
...@@ -29,6 +34,13 @@ export interface IWindowConfiguration { ...@@ -29,6 +34,13 @@ export interface IWindowConfiguration {
}; };
} }
enum DraggedFileType {
UNKNOWN,
FILE,
EXTENSION,
FOLDER
}
export class ElectronWindow { export class ElectronWindow {
private win: Electron.BrowserWindow; private win: Electron.BrowserWindow;
private windowId: number; private windowId: number;
...@@ -53,7 +65,7 @@ export class ElectronWindow { ...@@ -53,7 +65,7 @@ export class ElectronWindow {
// React to editor input changes (Mac only) // React to editor input changes (Mac only)
if (platform.platform === platform.Platform.Mac) { if (platform.platform === platform.Platform.Mac) {
this.editorGroupService.onEditorsChanged(() => { this.editorGroupService.onEditorsChanged(() => {
let fileInput = workbenchEditorCommon.asFileEditorInput(this.editorService.getActiveEditorInput(), true); let fileInput = asFileEditorInput(this.editorService.getActiveEditorInput(), true);
let representedFilename = ''; let representedFilename = '';
if (fileInput) { if (fileInput) {
representedFilename = fileInput.getResource().fsPath; representedFilename = fileInput.getResource().fsPath;
...@@ -63,11 +75,61 @@ export class ElectronWindow { ...@@ -63,11 +75,61 @@ export class ElectronWindow {
}); });
} }
// Prevent a dropped link from opening within let draggedExternalResources: URI[];
[DOM.EventType.DRAG_OVER, DOM.EventType.DROP].forEach(event => { let dropOverlay: Builder;
function cleanUp(): void {
draggedExternalResources = void 0;
if (dropOverlay) {
dropOverlay.destroy();
dropOverlay = void 0;
}
}
// Detect resources dropped into Code from outside
window.document.body.addEventListener(DOM.EventType.DRAG_OVER, (e: DragEvent) => {
DOM.EventHelper.stop(e);
if (!draggedExternalResources) {
draggedExternalResources = DND.extractResources(e, true /* external only */);
// Show Code wide overlay if we detect a Folder or Extension to be dragged
if (draggedExternalResources.some(r => {
const kind = this.getFileKind(r);
return kind === DraggedFileType.FOLDER || kind === DraggedFileType.EXTENSION;
})) {
dropOverlay = $(window.document.getElementById(Identifiers.WORKBENCH_CONTAINER))
.div({ id: 'monaco-workbench-drop-overlay' })
.on(DOM.EventType.DROP, (e: DragEvent) => {
DOM.EventHelper.stop(e, true);
this.focus(); // make sure this window has focus so that the open call reaches the right window!
ipc.send('vscode:windowOpen', draggedExternalResources.map(r => r.fsPath)); // handled from browser process
cleanUp();
})
.on([DOM.EventType.DRAG_LEAVE, DOM.EventType.DRAG_END], () => {
cleanUp();
});
}
}
});
// Clear our map and overlay on any finish of DND outside the overlay
[DOM.EventType.DROP, DOM.EventType.DRAG_END].forEach(event => {
window.document.body.addEventListener(event, (e: DragEvent) => { window.document.body.addEventListener(event, (e: DragEvent) => {
DOM.EventHelper.stop(e); if (!dropOverlay || e.target !== dropOverlay.getHTMLElement()) {
}); DOM.EventHelper.stop(e); // this prevents opening a real URL inside the shell
cleanUp();
}
}, true /* use capture because components within may preventDefault() when they accept the drop */);
});
// prevent opening a real URL inside the shell
window.document.body.addEventListener(DOM.EventType.DROP, (e: DragEvent) => {
DOM.EventHelper.stop(e);
}); });
// Handle window.open() calls // Handle window.open() calls
...@@ -86,20 +148,19 @@ export class ElectronWindow { ...@@ -86,20 +148,19 @@ export class ElectronWindow {
}; };
} }
public open(pathsToOpen: string[]): void; private getFileKind(resource: URI): DraggedFileType {
public open(fileResource: URI): void; if (path.extname(resource.fsPath) === '.vsix') {
public open(pathToOpen: string): void; return DraggedFileType.EXTENSION;
public open(arg1: any): void { }
let pathsToOpen: string[];
if (Array.isArray(arg1)) { let kind = DraggedFileType.UNKNOWN;
pathsToOpen = arg1; try {
} else if (typeof arg1 === 'string') { kind = fs.statSync(resource.fsPath).isDirectory() ? DraggedFileType.FOLDER : DraggedFileType.FILE;
pathsToOpen = [arg1]; } catch (error) {
} else { // Do not fail in DND handler
pathsToOpen = [(<URI>arg1).fsPath];
} }
ipc.send('vscode:windowOpen', pathsToOpen); // handled from browser process return kind;
} }
public openNew(): void { public openNew(): void {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册