From 0238061fa2adf3e25017c1cc2ecb24feb1928876 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 26 Feb 2013 19:07:19 -0700 Subject: [PATCH] Make tab drag & drop work with new panes system --- src/app/pane.coffee | 4 + src/packages/tabs/lib/tab-bar-view.coffee | 43 +++--- src/packages/tabs/spec/tabs-spec.coffee | 153 +++++++++++++--------- 3 files changed, 111 insertions(+), 89 deletions(-) diff --git a/src/app/pane.coffee b/src/app/pane.coffee index ad2521f3d..ba4488c6d 100644 --- a/src/app/pane.coffee +++ b/src/app/pane.coffee @@ -114,6 +114,10 @@ class Pane extends View @items.splice(newIndex, 0, item) @trigger 'pane:item-moved', [item, newIndex] + moveItemToPane: (item, pane, index) -> + @removeItem(item) + pane.addItem(item, index) + itemForPath: (path) -> _.detect @items, (item) -> item.getPath?() is path diff --git a/src/packages/tabs/lib/tab-bar-view.coffee b/src/packages/tabs/lib/tab-bar-view.coffee index 4aed71f65..aa4fb47f7 100644 --- a/src/packages/tabs/lib/tab-bar-view.coffee +++ b/src/packages/tabs/lib/tab-bar-view.coffee @@ -10,6 +10,8 @@ class TabBarView extends SortableList initialize: (@pane) -> super + + @paneContainer = @pane.getContainer() @addTabForItem(item) for item in @pane.getItems() @pane.on 'pane:item-added', (e, item, index) => @addTabForItem(item, index) @@ -91,39 +93,26 @@ class TabBarView extends SortableList onDragStart: (event) => super - pane = $(event.target).closest('.pane') - paneIndex = rootView.indexOfPane(pane) + paneIndex = @paneContainer.indexOfPane(pane) event.originalEvent.dataTransfer.setData 'from-pane-index', paneIndex onDrop: (event) => super - droppedNearTab = @getSortableElement(event) - transfer = event.originalEvent.dataTransfer - previousDraggedTabIndex = transfer.getData 'sortable-index' + dataTransfer = event.originalEvent.dataTransfer + fromIndex = parseInt(dataTransfer.getData('sortable-index')) + fromPaneIndex = parseInt(dataTransfer.getData('from-pane-index')) + fromPane = @paneContainer.paneAtIndex(fromPaneIndex) + toIndex = @getSortableElement(event).index() + toPane = $(event.target).closest('.pane').view() + draggedTab = fromPane.find(".tabs .sortable:eq(#{fromIndex})").view() + item = draggedTab.item - fromPaneIndex = ~~transfer.getData 'from-pane-index' - toPaneIndex = rootView.indexOfPane($(event.target).closest('.pane')) - fromPane = $(rootView.find('.pane')[fromPaneIndex]) - fromEditor = fromPane.find('.editor').view() - draggedTab = fromPane.find(".#{TabBarView.viewClass()} .sortable:eq(#{previousDraggedTabIndex})") - - if draggedTab.is(droppedNearTab) - fromEditor.focus() - return - - if fromPaneIndex == toPaneIndex - droppedNearTab = @getSortableElement(event) - fromIndex = draggedTab.index() - toIndex = droppedNearTab.index() + if toPane is fromPane toIndex++ if fromIndex > toIndex - fromEditor.moveEditSessionToIndex(fromIndex, toIndex) - fromEditor.focus() + toPane.moveItem(item, toIndex) else - toEditor = rootView.find(".pane:eq(#{toPaneIndex}) > .editor").view() - if @containsEditSession(toEditor, fromEditor.editSessions[draggedTab.index()]) - fromEditor.focus() - else - fromEditor.moveEditSessionToEditor(draggedTab.index(), toEditor, droppedNearTab.index() + 1) - toEditor.focus() + fromPane.moveItemToPane(item, toPane, toIndex) + toPane.showItem(item) + toPane.focus() diff --git a/src/packages/tabs/spec/tabs-spec.coffee b/src/packages/tabs/spec/tabs-spec.coffee index 5f528bad5..7a70d19f9 100644 --- a/src/packages/tabs/spec/tabs-spec.coffee +++ b/src/packages/tabs/spec/tabs-spec.coffee @@ -21,16 +21,19 @@ describe "Tabs package main", -> expect(rootView.find('.pane').length).toBe 2 expect(rootView.panes.find('.pane > .tabs').length).toBe 2 -fdescribe "TabBarView", -> +describe "TabBarView", -> [item1, item2, editSession1, pane, tabBar] = [] class TestView extends View + @deserialize: ({title, longTitle}) -> new TestView(title, longTitle) @content: (title) -> @div title - initialize: (@title) -> + initialize: (@title, @longTitle) -> getTitle: -> @title getLongTitle: -> @longTitle + serialize: -> { deserializer: 'TestView', @title, @longTitle } beforeEach -> + registerDeserializer(TestView) item1 = new TestView('Item 1') item2 = new TestView('Item 2') editSession1 = project.buildEditSession('sample.js') @@ -40,6 +43,9 @@ fdescribe "TabBarView", -> paneContainer.append(pane) tabBar = new TabBarView(pane) + afterEach -> + unregisterDeserializer(TestView) + describe ".initialize(pane)", -> it "creates a tab for each item on the tab bar's parent pane", -> expect(pane.getItems().length).toBe 3 @@ -131,75 +137,98 @@ fdescribe "TabBarView", -> expect(tabBar.getTabs().map (tab) -> tab.text()).toEqual ["sample.js", "Item 2", "Item 1"] describe "dragging and dropping tabs", -> - describe "when the tab is dropped onto itself", -> - it "doesn't move the edit session and focuses the editor", -> - expect(tabs.find('.tab:eq(1) .file-name').text()).toBe "sample.txt" + buildDragEvents = (dragged, dropTarget) -> + dataTransfer = + data: {} + setData: (key, value) -> @data[key] = value + getData: (key) -> @data[key] - sortableElement = [tabs.find('.tab:eq(0)')] - spyOn(tabs, 'getSortableElement').andCallFake -> sortableElement[0] - event = $.Event() - event.target = tabs[0] - event.originalEvent = - dataTransfer: - data: {} - setData: (key, value) -> @data[key] = value - getData: (key) -> @data[key] + dragStartEvent = $.Event() + dragStartEvent.target = dragged[0] + dragStartEvent.originalEvent = { dataTransfer } - editor.hiddenInput.focusout() - tabs.onDragStart(event) - tabs.onDrop(event) + dropEvent = $.Event() + dropEvent.target = dropTarget[0] + dropEvent.originalEvent = { dataTransfer } - expect(tabs.find('.tab:eq(0) .file-name').text()).toBe "sample.js" - expect(tabs.find('.tab:eq(1) .file-name').text()).toBe "sample.txt" - expect(editor.isFocused).toBeTruthy() + [dragStartEvent, dropEvent] - describe "when a tab is dragged from and dropped onto the same editor", -> - it "moves the edit session, updates the order of the tabs, and focuses the editor", -> - expect(tabs.find('.tab:eq(0) .file-name').text()).toBe "sample.js" - expect(tabs.find('.tab:eq(1) .file-name').text()).toBe "sample.txt" + describe "when a tab is dragged within the same pane", -> + describe "when it is dropped on tab that's later in the list", -> + it "moves the tab and its item, shows the tab's item, and focuses the pane", -> + expect(tabBar.getTabs().map (tab) -> tab.text()).toEqual ["Item 1", "sample.js", "Item 2"] + expect(pane.getItems()).toEqual [item1, editSession1, item2] + expect(pane.activeItem).toBe item2 + spyOn(pane, 'focus') - sortableElement = [tabs.find('.tab:eq(0)')] - spyOn(tabs, 'getSortableElement').andCallFake -> sortableElement[0] - event = $.Event() - event.target = tabs[0] - event.originalEvent = - dataTransfer: - data: {} - setData: (key, value) -> @data[key] = value - getData: (key) -> @data[key] + [dragStartEvent, dropEvent] = buildDragEvents(tabBar.tabAtIndex(0), tabBar.tabAtIndex(1)) + tabBar.onDragStart(dragStartEvent) + tabBar.onDrop(dropEvent) - editor.hiddenInput.focusout() - tabs.onDragStart(event) - sortableElement = [tabs.find('.tab:eq(1)')] - tabs.onDrop(event) + expect(tabBar.getTabs().map (tab) -> tab.text()).toEqual ["sample.js", "Item 1", "Item 2"] + expect(pane.getItems()).toEqual [editSession1, item1, item2] + expect(pane.activeItem).toBe item1 + expect(pane.focus).toHaveBeenCalled() - expect(tabs.find('.tab:eq(0) .file-name').text()).toBe "sample.txt" - expect(tabs.find('.tab:eq(1) .file-name').text()).toBe "sample.js" - expect(editor.isFocused).toBeTruthy() + describe "when it is dropped on a tab that's earlier in the list", -> + it "moves the tab and its item, shows the tab's item, and focuses the pane", -> + expect(tabBar.getTabs().map (tab) -> tab.text()).toEqual ["Item 1", "sample.js", "Item 2"] + expect(pane.getItems()).toEqual [item1, editSession1, item2] + expect(pane.activeItem).toBe item2 + spyOn(pane, 'focus') - describe "when a tab is dragged from one editor and dropped onto another editor", -> - it "moves the edit session, updates the order of the tabs, and focuses the destination editor", -> - leftTabs = tabs - rightEditor = editor.splitRight() - rightTabs = rootView.find('.tabs:last').view() + [dragStartEvent, dropEvent] = buildDragEvents(tabBar.tabAtIndex(2), tabBar.tabAtIndex(0)) + tabBar.onDragStart(dragStartEvent) + tabBar.onDrop(dropEvent) - sortableElement = [leftTabs.find('.tab:eq(0)')] - spyOn(tabs, 'getSortableElement').andCallFake -> sortableElement[0] - event = $.Event() - event.target = leftTabs - event.originalEvent = - dataTransfer: - data: {} - setData: (key, value) -> @data[key] = value - getData: (key) -> @data[key] + expect(tabBar.getTabs().map (tab) -> tab.text()).toEqual ["Item 1", "Item 2", "sample.js"] + expect(pane.getItems()).toEqual [item1, item2, editSession1] + expect(pane.activeItem).toBe item2 + expect(pane.focus).toHaveBeenCalled() - rightEditor.hiddenInput.focusout() - tabs.onDragStart(event) + describe "when it is dropped on itself", -> + it "doesn't move the tab or item, but does make it the active item and focuses the pane", -> + expect(tabBar.getTabs().map (tab) -> tab.text()).toEqual ["Item 1", "sample.js", "Item 2"] + expect(pane.getItems()).toEqual [item1, editSession1, item2] + expect(pane.activeItem).toBe item2 + spyOn(pane, 'focus') - event.target = rightTabs - sortableElement = [rightTabs.find('.tab:eq(0)')] - tabs.onDrop(event) + [dragStartEvent, dropEvent] = buildDragEvents(tabBar.tabAtIndex(0), tabBar.tabAtIndex(0)) + tabBar.onDragStart(dragStartEvent) + tabBar.onDrop(dropEvent) - expect(rightTabs.find('.tab:eq(0) .file-name').text()).toBe "sample.txt" - expect(rightTabs.find('.tab:eq(1) .file-name').text()).toBe "sample.js" - expect(rightEditor.isFocused).toBeTruthy() + expect(tabBar.getTabs().map (tab) -> tab.text()).toEqual ["Item 1", "sample.js", "Item 2"] + expect(pane.getItems()).toEqual [item1, editSession1, item2] + expect(pane.activeItem).toBe item1 + expect(pane.focus).toHaveBeenCalled() + + describe "when a tab is dragged to a different pane", -> + [pane2, tabBar2, item2b] = [] + + beforeEach -> + pane2 = pane.splitRight() + [item2b] = pane2.getItems() + tabBar2 = new TabBarView(pane2) + + it "removes the tab and item from their original pane and moves them to the target pane", -> + expect(tabBar.getTabs().map (tab) -> tab.text()).toEqual ["Item 1", "sample.js", "Item 2"] + expect(pane.getItems()).toEqual [item1, editSession1, item2] + expect(pane.activeItem).toBe item2 + + expect(tabBar2.getTabs().map (tab) -> tab.text()).toEqual ["Item 2"] + expect(pane2.getItems()).toEqual [item2b] + expect(pane2.activeItem).toBe item2b + spyOn(pane2, 'focus') + + [dragStartEvent, dropEvent] = buildDragEvents(tabBar.tabAtIndex(0), tabBar2.tabAtIndex(0)) + tabBar.onDragStart(dragStartEvent) + tabBar.onDrop(dropEvent) + + expect(tabBar.getTabs().map (tab) -> tab.text()).toEqual ["sample.js", "Item 2"] + expect(pane.getItems()).toEqual [editSession1, item2] + expect(pane.activeItem).toBe item2 + + expect(tabBar2.getTabs().map (tab) -> tab.text()).toEqual ["Item 2", "Item 1"] + expect(pane2.getItems()).toEqual [item2b, item1] + expect(pane2.activeItem).toBe item1 + expect(pane2.focus).toHaveBeenCalled()