From 7e2ea8aff15bd53962dee3d060c463b76e7265ce Mon Sep 17 00:00:00 2001 From: probablycorey Date: Mon, 1 Apr 2013 16:46:57 -0700 Subject: [PATCH] Allow tabs to be moved to the beginning and end of the tab bar Closes #409 (409, puts grease on the run! http://www.dailymotion.com/video/xxsbbb_formula-409-1990-puts-grease-on-the-run-commercial-2_tv#.UVocOZbF30Y) --- src/app/sortable-list.coffee | 46 +++++++++++++---------- src/packages/tabs/lib/tab-bar-view.coffee | 6 +-- src/packages/tabs/spec/tabs-spec.coffee | 14 +++++++ src/packages/tabs/stylesheets/tabs.less | 30 +++++++++++---- 4 files changed, 66 insertions(+), 30 deletions(-) diff --git a/src/app/sortable-list.coffee b/src/app/sortable-list.coffee index ebdc675a1..ffc2ced5a 100644 --- a/src/app/sortable-list.coffee +++ b/src/app/sortable-list.coffee @@ -7,38 +7,40 @@ class SortableList extends View initialize: -> @on 'dragstart', '.sortable', @onDragStart - @on 'dragend', '.sortable', @onDragEnd - @on 'dragover', '.sortable', @onDragOver - @on 'dragenter', '.sortable', @onDragEnter - @on 'dragleave', '.sortable', @onDragLeave - @on 'drop', '.sortable', @onDrop + @on 'dragend', '.sortable', @onDragEnd + @on 'dragover', @onDragOver + @on 'drop', @onDrop onDragStart: (event) => unless @shouldAllowDrag(event) event.preventDefault() return - el = @getSortableElement(event) + el = $(event.target).closest('.sortable') el.addClass 'is-dragging' event.originalEvent.dataTransfer.setData 'sortable-index', el.index() onDragEnd: (event) => - @getSortableElement(event).removeClass 'is-dragging' - - onDragEnter: (event) => - event.preventDefault() + @find(".is-dragging").removeClass 'is-dragging' onDragOver: (event) => event.preventDefault() - @getSortableElement(event).addClass 'is-drop-target' + currentDropTargetIndex = @find(".is-drop-target").index() + newDropTargetIndex = @getDropTargetIndex(event) - onDragLeave: (event) => - @getSortableElement(event).removeClass 'is-drop-target' + if newDropTargetIndex != currentDropTargetIndex + @children().removeClass 'is-drop-target drop-target-is-after' + sortableObjects = @find(".sortable") + if newDropTargetIndex < sortableObjects.length + sortableObjects.eq(newDropTargetIndex).addClass 'is-drop-target' + else + sortableObjects.eq(newDropTargetIndex - 1).addClass 'drop-target-is-after' onDrop: (event) => return false if !@shouldAllowDrop(event) event.stopPropagation() - @find('.is-drop-target').removeClass 'is-drop-target' + @children('.is-drop-target').removeClass 'is-drop-target' + @children('.drop-target-is-after').removeClass 'drop-target-is-after' shouldAllowDrag: (event) -> true @@ -46,9 +48,15 @@ class SortableList extends View shouldAllowDrop: (event) -> true - getDroppedElement: (event) -> - index = event.originalEvent.dataTransfer.getData('sortable-index') - @find(".sortable:eq(#{index})") + getDropTargetIndex: (event) -> + el = $(event.target).closest('.sortable') + el = $(event.target).find('.sortable').last() if el.length == 0 - getSortableElement: (event) -> - $(event.target).closest('.sortable') + elementCenter = el.offset().left + el.width() / 2 + + if event.originalEvent.pageX < elementCenter + el.index() + else if el.next().length > 0 + el.next().index() + else + el.index() + 1 diff --git a/src/packages/tabs/lib/tab-bar-view.coffee b/src/packages/tabs/lib/tab-bar-view.coffee index 68f41df86..59b0e7dc7 100644 --- a/src/packages/tabs/lib/tab-bar-view.coffee +++ b/src/packages/tabs/lib/tab-bar-view.coffee @@ -86,15 +86,15 @@ class TabBarView extends SortableList fromIndex = parseInt(dataTransfer.getData('sortable-index')) fromPaneIndex = parseInt(dataTransfer.getData('from-pane-index')) fromPane = @paneContainer.paneAtIndex(fromPaneIndex) - toIndex = @getSortableElement(event).index() + toIndex = @getDropTargetIndex(event) toPane = $(event.target).closest('.pane').view() draggedTab = fromPane.find(".tabs .sortable:eq(#{fromIndex})").view() item = draggedTab.item if toPane is fromPane - toIndex++ if fromIndex > toIndex + toIndex-- if fromIndex < toIndex toPane.moveItem(item, toIndex) else - fromPane.moveItemToPane(item, toPane, toIndex) + 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 820f3f9eb..a366126d9 100644 --- a/src/packages/tabs/spec/tabs-spec.coffee +++ b/src/packages/tabs/spec/tabs-spec.coffee @@ -235,6 +235,20 @@ describe "TabBarView", -> expect(pane.activeItem).toBe item1 expect(pane.focus).toHaveBeenCalled() + describe "when it is dropped on the tab bar", -> + it "moves the tab and its item to the end", -> + 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') + + [dragStartEvent, dropEvent] = buildDragEvents(tabBar.tabAtIndex(0), tabBar) + tabBar.onDragStart(dragStartEvent) + tabBar.onDrop(dropEvent) + + expect(tabBar.getTabs().map (tab) -> tab.text()).toEqual ["sample.js", "Item 2", "Item 1"] + expect(pane.getItems()).toEqual [editSession1, item2, item1] + describe "when a tab is dragged to a different pane", -> [pane2, tabBar2, item2b] = [] diff --git a/src/packages/tabs/stylesheets/tabs.less b/src/packages/tabs/stylesheets/tabs.less index bb262bba1..120503c5d 100644 --- a/src/packages/tabs/stylesheets/tabs.less +++ b/src/packages/tabs/stylesheets/tabs.less @@ -83,11 +83,10 @@ } -.tab.is-drop-target:after { +.tab.is-drop-target:before, .tab.drop-target-is-after:after { + content: ""; position: absolute; top: 0; - right: -2px; - content: ""; z-index: 999; display: inline-block; width: 2px; @@ -96,15 +95,30 @@ background: #0098ff; } -.tab.is-drop-target:before { +.tab.is-drop-target:after, .tab.drop-target-is-after:before { content: ""; position: absolute; + top: 30px; + z-index: 9999; width: 4px; height: 4px; background: #0098ff; - right: -4px; - top: 30px; border-radius: 4px; - z-index: 9999; border: 1px solid transparent; -} \ No newline at end of file +} + +.tab.is-drop-target:before { + left: -2px; +} + +.tab.is-drop-target:after { + left: -4px; +} + +.tab.drop-target-is-after:before { + right: -4px; +} + +.tab.drop-target-is-after:after { + right: -2px; +}