Skip to content

Commit

Permalink
fix eclipse-theia#6000: only apply drag and drop of view container pa…
Browse files Browse the repository at this point in the history
…rts to parts

A view container part widget also can handle drag and drop events, in this case they should be ignored by a view container.

Signed-off-by: Anton Kosyakov <[email protected]>

resolve auto-reresh failed when d&d in the root folder

Signed-off-by: kpge <[email protected]>
  • Loading branch information
akosyakov committed Aug 23, 2019
1 parent fd0e6a3 commit 566ebda
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 65 deletions.
119 changes: 56 additions & 63 deletions packages/core/src/browser/view-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ export class ViewContainer extends BaseWidget implements StatefulWidget, Applica
this.fireDidChangeTrackableWidgets();
}
}),
this.registerDND(newPart),
newPart.onVisibilityChanged(() => {
this.updateTitle();
this.updateCurrentPart();
Expand All @@ -296,7 +297,6 @@ export class ViewContainer extends BaseWidget implements StatefulWidget, Applica
this.containerLayout.updateCollapsed(newPart, this.enableAnimation);
this.updateCurrentPart();
}),
newPart.onMoveBefore(toMoveId => this.moveBefore(toMoveId, newPart.id)),
newPart.onContextMenu(event => {
if (event.button === 2) {
event.preventDefault();
Expand Down Expand Up @@ -554,6 +554,61 @@ export class ViewContainer extends BaseWidget implements StatefulWidget, Applica
this.lastVisibleState = undefined;
}

protected draggingPart: ViewContainerPart | undefined;

protected registerDND(part: ViewContainerPart): Disposable {
part['header'].draggable = true;
const style = (event: DragEvent) => {
if (!this.draggingPart) {
return;
}
event.preventDefault();
const enclosingPartNode = ViewContainerPart.closestPart(event.target);
if (enclosingPartNode && enclosingPartNode !== this.draggingPart.node) {
enclosingPartNode.classList.add('drop-target');
}
};
const unstyle = (event: DragEvent) => {
if (!this.draggingPart) {
return;
}
event.preventDefault();
const enclosingPartNode = ViewContainerPart.closestPart(event.target);
if (enclosingPartNode) {
enclosingPartNode.classList.remove('drop-target');
}
};
return new DisposableCollection(
addEventListener(part['header'], 'dragstart', event => {
const { dataTransfer } = event;
if (dataTransfer) {
this.draggingPart = part;
dataTransfer.effectAllowed = 'move';
dataTransfer.setData('view-container-dnd', part.id);
const dragImage = document.createElement('div');
dragImage.classList.add('theia-view-container-drag-image');
dragImage.innerText = part.wrapped.title.label;
document.body.appendChild(dragImage);
dataTransfer.setDragImage(dragImage, -10, -10);
setTimeout(() => document.body.removeChild(dragImage), 0);
}
}, false),
addEventListener(part.node, 'dragend', () => this.draggingPart = undefined, false),
addEventListener(part.node, 'dragover', style, false),
addEventListener(part.node, 'dragleave', unstyle, false),
addEventListener(part.node, 'drop', event => {
const { dataTransfer } = event;
if (dataTransfer) {
const moveId = dataTransfer.getData('view-container-dnd');
if (moveId && moveId !== part.id) {
this.moveBefore(moveId, part.id);
}
unstyle(event);
}
}, false)
);
}

}

export namespace ViewContainer {
Expand Down Expand Up @@ -602,7 +657,6 @@ export class ViewContainerPart extends BaseWidget {
protected readonly header: HTMLElement;
protected readonly body: HTMLElement;
protected readonly collapsedEmitter = new Emitter<boolean>();
protected readonly moveBeforeEmitter = new Emitter<string>();
protected readonly contextMenuEmitter = new Emitter<MouseEvent>();
protected readonly onVisibilityChangedEmitter = new Emitter<boolean>();
readonly onVisibilityChanged = this.onVisibilityChangedEmitter.event;
Expand All @@ -612,12 +666,6 @@ export class ViewContainerPart extends BaseWidget {
readonly onDidFocus = this.onDidFocusEmitter.event;

protected _collapsed: boolean;
/**
* Self cannot be a drop target. When the drag event starts, we disable the current part as a possible drop target.
*
* This is a workaround for not being able to sniff into the `event.dataTransfer.getData` value when `dragover` due to security reasons.
*/
private canBeDropTarget = true;

uncollapsedSize: number | undefined;
animatedSize: number | undefined;
Expand Down Expand Up @@ -650,11 +698,9 @@ export class ViewContainerPart extends BaseWidget {
this.toDispose.pushAll([
disposable,
this.collapsedEmitter,
this.moveBeforeEmitter,
this.contextMenuEmitter,
this.onVisibilityChangedEmitter,
this.onTitleChangedEmitter,
this.registerDND(),
this.registerContextMenu(),
this.onDidFocusEmitter,
// focus event does not bubble, capture it
Expand Down Expand Up @@ -715,10 +761,6 @@ export class ViewContainerPart extends BaseWidget {
return this.collapsedEmitter.event;
}

get onMoveBefore(): Event<string> {
return this.moveBeforeEmitter.event;
}

get onContextMenu(): Event<MouseEvent> {
return this.contextMenuEmitter.event;
}
Expand Down Expand Up @@ -767,55 +809,6 @@ export class ViewContainerPart extends BaseWidget {
);
}

protected registerDND(): Disposable {
this.header.draggable = true;
const style = (event: DragEvent) => {
event.preventDefault();
const part = ViewContainerPart.closestPart(event.target);
if (part instanceof HTMLElement) {
if (this.canBeDropTarget) {
part.classList.add('drop-target');
}
}
};
const unstyle = (event: DragEvent) => {
event.preventDefault();
const part = ViewContainerPart.closestPart(event.target);
if (part instanceof HTMLElement) {
part.classList.remove('drop-target');
}
};
return new DisposableCollection(
addEventListener(this.header, 'dragstart', event => {
const { dataTransfer } = event;
if (dataTransfer) {
this.canBeDropTarget = false;
dataTransfer.effectAllowed = 'move';
dataTransfer.setData('view-container-dnd', this.id);
const dragImage = document.createElement('div');
dragImage.classList.add('theia-view-container-drag-image');
dragImage.innerText = this.wrapped.title.label;
document.body.appendChild(dragImage);
dataTransfer.setDragImage(dragImage, -10, -10);
setTimeout(() => document.body.removeChild(dragImage), 0);
}
}, false),
addEventListener(this.node, 'dragend', () => this.canBeDropTarget = true, false),
addEventListener(this.node, 'dragover', style, false),
addEventListener(this.node, 'dragleave', unstyle, false),
addEventListener(this.node, 'drop', event => {
const { dataTransfer } = event;
if (dataTransfer) {
const moveId = dataTransfer.getData('view-container-dnd');
if (moveId && moveId !== this.id) {
this.moveBeforeEmitter.fire(moveId);
}
unstyle(event);
}
}, false)
);
}

protected createContent(): { header: HTMLElement, body: HTMLElement, disposable: Disposable } {
const disposable = new DisposableCollection();
const { header, disposable: headerDisposable } = this.createHeader();
Expand Down
4 changes: 2 additions & 2 deletions packages/filesystem/src/browser/file-tree/file-tree-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ export class FileTreeModel extends TreeModelImpl implements LocationService {
return;
}
this.refreshAffectedNodes([
move.sourceUri.parent,
move.targetUri.parent
move.sourceUri,
move.targetUri
]);
}

Expand Down

0 comments on commit 566ebda

Please sign in to comment.