diff --git a/lib/tree-view.coffee b/lib/tree-view.coffee index 5abf3031..440ff4b3 100644 --- a/lib/tree-view.coffee +++ b/lib/tree-view.coffee @@ -738,12 +738,17 @@ class TreeView extends View onMouseDown: (e) -> e.stopPropagation() - # return early if we're opening a contextual menu (right click) during multi-select mode - if @multiSelectEnabled() and - e.currentTarget.classList.contains('selected') and - # mouse right click or ctrl click as right click on darwin platforms - (e.button is 2 or e.ctrlKey and process.platform is 'darwin') - return + if @multiSelectEnabled() and e.currentTarget.classList.contains('selected') + # return early if we're opening a contextual menu (right click) during multi-select mode + if (e.button is 2 or e.ctrlKey and process.platform is 'darwin') + return + # return early unless we're deselecting an entry (metaKey on OSX, ctrl/metaKey on linux/windows) + if process.platform is 'darwin' + if not e.metaKey + return + else if process.platform isnt 'darwin' + if not (e.ctrlKey or e.metaKey) + return entryToSelect = e.currentTarget @@ -835,26 +840,33 @@ class TreeView extends View onDragStart: (e) -> e.stopPropagation() - target = $(e.currentTarget).find(".name") - initialPath = target.data("path") + initialPaths = [] + targets = [] - style = getStyleObject(target[0]) - - fileNameElement = target.clone() - .css(style) + eventTarget = $(e.currentTarget).find('.name') + dragImage = $('
    ', {class: 'entries list-tree'}) .css( position: 'absolute' top: 0 left: 0 ) - fileNameElement.appendTo(document.body) - e.originalEvent.dataTransfer.effectAllowed = "move" - e.originalEvent.dataTransfer.setDragImage(fileNameElement[0], 0, 0) - e.originalEvent.dataTransfer.setData("initialPath", initialPath) + for entry in @getSelectedEntries() + entryPath = $(entry).find('.name').data('path') + unless path.dirname(entryPath) in initialPaths + initialPaths.push(entryPath) + image = $(entry).clone() + image.find('.entry').addBack('.entry').removeClass('selected') + dragImage.append(image) + + dragImage.appendTo(document.body) + + e.originalEvent.dataTransfer.effectAllowed = 'move' + e.originalEvent.dataTransfer.setDragImage(dragImage[0], 0, 0) + e.originalEvent.dataTransfer.setData('initialPaths', initialPaths) window.requestAnimationFrame -> - fileNameElement.remove() + dragImage.remove() # Handle entry dragover event; reset default dragover actions onDragOver: (e) -> @@ -874,11 +886,13 @@ class TreeView extends View newDirectoryPath = $(entry).find(".name").data("path") return false unless newDirectoryPath - initialPath = e.originalEvent.dataTransfer.getData("initialPath") + initialPaths = e.originalEvent.dataTransfer.getData("initialPaths") - if initialPath + if initialPaths # Drop event from Atom - @moveEntry(initialPath, newDirectoryPath) + # iterate backwards so files in a dir are moved before the dir itself + for initialPath in initialPaths.split(',') by -1 + @moveEntry(initialPath, newDirectoryPath) else # Drop event from OS for file in e.originalEvent.dataTransfer.files diff --git a/spec/event-helpers.coffee b/spec/event-helpers.coffee index 9ebb803e..618700e2 100644 --- a/spec/event-helpers.coffee +++ b/spec/event-helpers.coffee @@ -7,6 +7,9 @@ module.exports.buildInternalDragEvents = (dragged, enterTarget, dropTarget) -> getData: (key) -> @data[key] setDragImage: (@image) -> return + for entry in dragged + $(entry).addClass('selected') + dragStartEvent = $.Event() dragStartEvent.target = dragged dragStartEvent.currentTarget = dragged @@ -39,4 +42,4 @@ module.exports.buildExternalDropEvent = (filePaths, dropTarget) -> for filePath in filePaths dropEvent.originalEvent.dataTransfer.files.push({path: filePath}) - dropEvent \ No newline at end of file + dropEvent diff --git a/spec/tree-view-spec.coffee b/spec/tree-view-spec.coffee index f8c25ef3..69c9e6d0 100644 --- a/spec/tree-view-spec.coffee +++ b/spec/tree-view-spec.coffee @@ -3080,8 +3080,10 @@ describe "TreeView", -> deltaFile = gammaDir[0].entries.children[2] [dragStartEvent, dragEnterEvent, dropEvent] = - eventHelpers.buildInternalDragEvents(deltaFile, alphaDir.find('.header')[0]) + eventHelpers.buildInternalDragEvents([deltaFile], alphaDir.find('.header')[0]) + treeView.onDragStart(dragStartEvent) + expect(deltaFile).toHaveClass('selected') treeView.onDragEnter(dragEnterEvent) expect(alphaDir).toHaveClass('selected') @@ -3104,7 +3106,7 @@ describe "TreeView", -> deltaFile = gammaDir[0].entries.children[2] [dragStartEvent, dragEnterEvent, dropEvent] = - eventHelpers.buildInternalDragEvents(deltaFile, alphaDir.find('.header')[0], alphaDir[0]) + eventHelpers.buildInternalDragEvents([deltaFile], alphaDir.find('.header')[0], alphaDir[0]) runs -> treeView.onDragStart(dragStartEvent) @@ -3117,6 +3119,65 @@ describe "TreeView", -> runs -> expect($(treeView.roots[0].entries).find('.directory:contains(alpha):first .entry').length).toBe 3 + describe "when dropping multiple FileViews onto a DirectoryView's header", -> + it "should move the files to the hovered directory", -> + # Dragging delta.txt onto alphaDir + alphaDir = $(treeView.roots[0].entries).find('.directory:contains(alpha):first') + alphaDir[0].expand() + + gammaDir = $(treeView.roots[0].entries).find('.directory:contains(gamma):first') + gammaDir[0].expand() + gammaFiles = [].slice.call(gammaDir[0].entries.children, 1, 3) + + [dragStartEvent, dragEnterEvent, dropEvent] = + eventHelpers.buildInternalDragEvents([gammaFiles], alphaDir.find('.header')[0], alphaDir[0]) + + runs -> + treeView.onDragStart(dragStartEvent) + treeView.onDrop(dropEvent) + expect(alphaDir[0].children.length).toBe 2 + + waitsFor "directory view contents to refresh", -> + $(treeView.roots[0].entries).find('.directory:contains(alpha):first .entry').length > 2 + + runs -> + expect($(treeView.roots[0].entries).find('.directory:contains(alpha):first .entry').length).toBe 4 + + describe "when dropping a DirectoryView and FileViews onto a DirectoryView's header", -> + it "should move the files and directory to the hovered directory", -> + # Dragging alpha.txt and alphaDir into thetaDir + rootDir = $(treeView.roots[0]) + + alphaFile = rootDir[0].entries.children[2] + alphaDir = $(treeView.roots[0].entries).find('.directory:contains(alpha):first') + alphaDir[0].expand() + + gammaDir = $(treeView.roots[0].entries).find('.directory:contains(gamma):first') + gammaDir[0].expand() + thetaDir = $(gammaDir[0].entries).find('.directory:contains(theta):first') + + dragged = [alphaFile, alphaDir[0]] + + [dragStartEvent, dragEnterEvent, dropEvent] = + eventHelpers.buildInternalDragEvents(dragged, thetaDir.find('.header')[0], thetaDir[0]) + + runs -> + treeView.onDragStart(dragStartEvent) + treeView.onDrop(dropEvent) + expect(thetaDir[0].children.length).toBe 2 + + waitsFor "directory view contents to refresh", -> + $(treeView.roots[0].entries).find('.directory:contains(theta):first .entry').length > 2 + + runs -> + thetaDir = $(gammaDir[0].entries).find('.directory:contains(theta):first') + thetaDir[0].expand() + expect(thetaDir.find('.entry').length).toBe 2 + # alpha dir still has all its entries + alphaDir = $(thetaDir[0].entries).find('.directory:contains(alpha):first') + alphaDir[0].expand() + expect(alphaDir.find('.entry').length).toBe 2 + describe "when dropping a DirectoryView onto a DirectoryView's header", -> it "should move the directory to the hovered directory", -> # Dragging thetaDir onto alphaDir @@ -3128,7 +3189,7 @@ describe "TreeView", -> thetaDir = gammaDir[0].entries.children[0] [dragStartEvent, dragEnterEvent, dropEvent] = - eventHelpers.buildInternalDragEvents(thetaDir, alphaDir.find('.header')[0], alphaDir[0]) + eventHelpers.buildInternalDragEvents([thetaDir], alphaDir.find('.header')[0], alphaDir[0]) runs -> treeView.onDragStart(dragStartEvent)