Start converting tabs package to work with new panes / pane-items

This commit is contained in:
Nathan Sobo
2013-02-25 17:41:00 -07:00
committed by probablycorey
parent 5240d9989f
commit 0c24843e52
6 changed files with 145 additions and 223 deletions

View File

@@ -1,4 +1,5 @@
$ = require 'jquery'
_ = require 'underscore'
SortableList = require 'sortable-list'
TabView = require './tab-view'
@@ -9,14 +10,16 @@ class TabBarView extends SortableList
initialize: (@pane) ->
super
@addTabForItem(item) for item in @pane.getItems()
@pane.on 'pane:item-added', (e, item, index) => @addTabForItem(item, index)
@pane.on 'pane:item-removed', (e, item) => @removeTabForItem(item)
@pane.on 'pane:active-item-changed', => @updateActiveTab()
@updateActiveTab()
# @addTabForEditSession(editSession) for editSession in @editor.editSessions
#
# @setActiveTab(@editor.getActiveEditSessionIndex())
# @editor.on 'editor:active-edit-session-changed', (e, editSession, index) => @setActiveTab(index)
# @editor.on 'editor:edit-session-added', (e, editSession) => @addTabForEditSession(editSession)
# @editor.on 'editor:edit-session-removed', (e, editSession, index) => @removeTabAtIndex(index)
# @editor.on 'editor:edit-session-order-changed', (e, editSession, fromIndex, toIndex) =>
@@ -29,26 +32,45 @@ class TabBarView extends SortableList
# fromTab.insertBefore(toTab)
@on 'click', '.tab', (e) =>
@editor.setActiveEditSessionIndex($(e.target).closest('.tab').index())
@editor.focus()
tab = $(e.target).closest('.tab').view()
@pane.showItem(tab.item)
@pane.focus()
@on 'click', '.tab .close-icon', (e) =>
index = $(e.target).closest('.tab').index()
@editor.destroyEditSessionIndex(index)
tab = $(e.target).closest('.tab').view()
@pane.removeItem(tab.item)
false
@pane.prepend(this)
addTabForItem: (item) ->
addTabForItem: (item, index) ->
tabView = new TabView(item, @pane)
@append(tabView)
@setActiveTabView(tabView) if item is @pane.currentItem
followingTab = @tabAtIndex(index) if index?
if followingTab
tabView.insertBefore(followingTab)
else
@append(tabView)
setActiveTabView: (tabView) ->
removeTabForItem: (item) ->
@tabForItem(item).remove()
getTabs: ->
@children('.tab').toArray().map (elt) -> $(elt).view()
tabAtIndex: (index) ->
@children(".tab:eq(#{index})").view()
tabForItem: (item) ->
_.detect @getTabs(), (tab) -> tab.item is item
setActiveTab: (tabView) ->
unless tabView.hasClass('active')
@find(".tab.active").removeClass('active')
tabView.addClass('active')
updateActiveTab: ->
@setActiveTab(@tabForItem(@pane.activeItem))
removeTabAtIndex: (index) ->
@find(".tab:eq(#{index})").remove()

View File

@@ -1,100 +1,44 @@
$ = require 'jquery'
SortableList = require 'sortable-list'
Tab = require './tab'
{View} = require 'space-pen'
fs = require 'fs'
module.exports =
class TabView extends SortableList
@activate: ->
rootView.eachEditor (editor) =>
@prependToEditorPane(editor) if editor.attached
@prependToEditorPane: (editor) ->
if pane = editor.pane()
pane.prepend(new TabView(editor))
class TabView extends View
@content: ->
@ul class: "tabs #{@viewClass()}"
@li class: 'tab sortable', =>
@span class: 'title', outlet: 'title'
@span class: 'close-icon'
initialize: (@editor) ->
super
initialize: (@item, @pane) ->
@title.text(@item.getTitle())
@addTabForEditSession(editSession) for editSession in @editor.editSessions
@setActiveTab(@editor.getActiveEditSessionIndex())
@editor.on 'editor:active-edit-session-changed', (e, editSession, index) => @setActiveTab(index)
@editor.on 'editor:edit-session-added', (e, editSession) => @addTabForEditSession(editSession)
@editor.on 'editor:edit-session-removed', (e, editSession, index) => @removeTabAtIndex(index)
@editor.on 'editor:edit-session-order-changed', (e, editSession, fromIndex, toIndex) =>
fromTab = @find(".tab:eq(#{fromIndex})")
toTab = @find(".tab:eq(#{toIndex})")
fromTab.detach()
if fromIndex < toIndex
fromTab.insertAfter(toTab)
else
fromTab.insertBefore(toTab)
# @buffer = @editSession.buffer
# @subscribe @buffer, 'path-changed', => @updateFileName()
# @subscribe @buffer, 'contents-modified', => @updateModifiedStatus()
# @subscribe @buffer, 'saved', => @updateModifiedStatus()
# @subscribe @buffer, 'git-status-changed', => @updateModifiedStatus()
# @subscribe @editor, 'editor:edit-session-added', => @updateFileName()
# @subscribe @editor, 'editor:edit-session-removed', => @updateFileName()
# @updateFileName()
# @updateModifiedStatus()
@on 'click', '.tab', (e) =>
@editor.setActiveEditSessionIndex($(e.target).closest('.tab').index())
@editor.focus()
@on 'click', '.tab .close-icon', (e) =>
index = $(e.target).closest('.tab').index()
@editor.destroyEditSessionIndex(index)
false
addTabForEditSession: (editSession) ->
@append(new Tab(editSession, @editor))
setActiveTab: (index) ->
@find(".tab.active").removeClass('active')
@find(".tab:eq(#{index})").addClass('active')
removeTabAtIndex: (index) ->
@find(".tab:eq(#{index})").remove()
containsEditSession: (editor, editSession) ->
for session in editor.editSessions
return true if editSession.getPath() is session.getPath()
shouldAllowDrag: (event) ->
panes = rootView.find('.pane')
!(panes.length == 1 && panes.find('.sortable').length == 1)
onDragStart: (event) =>
super
pane = $(event.target).closest('.pane')
paneIndex = rootView.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'
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(".#{TabView.viewClass()} .sortable:eq(#{previousDraggedTabIndex})")
if draggedTab.is(droppedNearTab)
fromEditor.focus()
return
if fromPaneIndex == toPaneIndex
droppedNearTab = @getSortableElement(event)
fromIndex = draggedTab.index()
toIndex = droppedNearTab.index()
toIndex++ if fromIndex > toIndex
fromEditor.moveEditSessionToIndex(fromIndex, toIndex)
fromEditor.focus()
updateModifiedStatus: ->
if @buffer.isModified()
@toggleClass('file-modified') unless @isModified
@isModified = true
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()
@removeClass('file-modified') if @isModified
@isModified = false
updateFileName: ->
fileNameText = @editSession.buffer.getBaseName()
if fileNameText?
duplicates = @editor.getEditSessions().filter (session) -> fileNameText is session.buffer.getBaseName()
if duplicates.length > 1
directory = fs.base(fs.directory(@editSession.getPath()))
fileNameText = "#{fileNameText} - #{directory}" if directory
else
fileNameText = 'untitled'
@fileName.text(fileNameText)
@fileName.attr('title', @editSession.getPath())

View File

@@ -1,40 +0,0 @@
{View} = require 'space-pen'
fs = require 'fs'
module.exports =
class Tab extends View
@content: (editSession) ->
@li class: 'tab sortable', =>
@span class: 'file-name', outlet: 'fileName'
@span class: 'close-icon'
initialize: (@editSession, @editor) ->
@buffer = @editSession.buffer
@subscribe @buffer, 'path-changed', => @updateFileName()
@subscribe @buffer, 'contents-modified', => @updateModifiedStatus()
@subscribe @buffer, 'saved', => @updateModifiedStatus()
@subscribe @editor, 'editor:edit-session-added', => @updateFileName()
@subscribe @editor, 'editor:edit-session-removed', => @updateFileName()
@updateFileName()
@updateModifiedStatus()
updateModifiedStatus: ->
if @buffer.isModified()
@toggleClass('file-modified') unless @isModified
@isModified = true
else
@removeClass('file-modified') if @isModified
@isModified = false
updateFileName: ->
fileNameText = @editSession.buffer.getBaseName()
if fileNameText?
duplicates = @editor.getEditSessions().filter (session) -> fileNameText is session.buffer.getBaseName()
if duplicates.length > 1
directory = fs.base(fs.directory(@editSession.getPath()))
fileNameText = "#{fileNameText} - #{directory}" if directory
else
fileNameText = 'untitled'
@fileName.text(fileNameText)
@fileName.attr('title', @editSession.getPath())

View File

@@ -0,0 +1,5 @@
TabBarView = require './tab-bar-view'
module.exports =
activate: ->
rootView.eachPane (pane) => new TabBarView(pane)

View File

@@ -1 +1 @@
'main': 'lib/tab-view'
'main': 'lib/tabs'

View File

@@ -1,93 +1,99 @@
$ = require 'jquery'
_ = require 'underscore'
RootView = require 'root-view'
Pane = require 'pane'
PaneContainer = require 'pane-container'
TabBarView = require 'tabs/lib/tab-bar-view'
fs = require 'fs'
{View} = require 'space-pen'
describe "TabView", ->
[editor, buffer, tabs] = []
describe "Tabs package main", ->
beforeEach ->
window.rootView = new RootView
rootView.open('sample.js')
rootView.open('sample.txt')
rootView.simulateDomAttachment()
window.loadPackage("tabs")
editor = rootView.getActiveEditor()
tabs = rootView.find('.tabs').view()
describe "@activate", ->
it "appends a status bear to all existing and new editors", ->
describe ".activate()", ->
it "appends a tab bar all existing and new panes", ->
expect(rootView.panes.find('.pane').length).toBe 1
expect(rootView.panes.find('.pane > .tabs').length).toBe 1
editor.splitRight()
rootView.getActivePane().splitRight()
expect(rootView.find('.pane').length).toBe 2
expect(rootView.panes.find('.pane > .tabs').length).toBe 2
describe ".initialize()", ->
it "creates a tab for each edit session on the editor to which the tab-strip belongs", ->
expect(editor.editSessions.length).toBe 2
expect(tabs.find('.tab').length).toBe 2
fdescribe "TabBarView", ->
[item1, item2, editSession1, editSession2, pane, tabBar] = []
expect(tabs.find('.tab:eq(0) .file-name').text()).toBe editor.editSessions[0].buffer.getBaseName()
expect(tabs.find('.tab:eq(1) .file-name').text()).toBe editor.editSessions[1].buffer.getBaseName()
class TestView extends View
@content: (title) -> @div title
initialize: (@title) ->
getTitle: -> @title
it "highlights the tab for the current active edit session", ->
expect(editor.getActiveEditSessionIndex()).toBe 1
expect(tabs.find('.tab:eq(1)')).toHaveClass 'active'
beforeEach ->
item1 = new TestView('Item 1')
item2 = new TestView('Item 2')
editSession1 = project.buildEditSession('sample.js')
paneContainer = new PaneContainer
pane = new Pane(item1, editSession1, item2)
pane.showItem(item2)
paneContainer.append(pane)
tabBar = new TabBarView(pane)
it "sets the title on each tab to be the full path of the edit session", ->
expect(tabs.find('.tab:eq(0) .file-name').attr('title')).toBe editor.editSessions[0].getPath()
expect(tabs.find('.tab:eq(1) .file-name').attr('title')).toBe editor.editSessions[1].getPath()
describe ".initialize(pane)", ->
it "creates a tab for each item on the tab bar's parent pane", ->
expect(pane.getItems().length).toBe 3
expect(tabBar.find('.tab').length).toBe 3
describe "when the active edit session changes", ->
it "highlights the tab for the newly-active edit session", ->
editor.setActiveEditSessionIndex(0)
expect(tabs.find('.active').length).toBe 1
expect(tabs.find('.tab:eq(0)')).toHaveClass 'active'
expect(tabBar.find('.tab:eq(0) .title').text()).toBe item1.getTitle()
expect(tabBar.find('.tab:eq(1) .title').text()).toBe editSession1.getTitle()
expect(tabBar.find('.tab:eq(2) .title').text()).toBe item2.getTitle()
editor.setActiveEditSessionIndex(1)
expect(tabs.find('.active').length).toBe 1
expect(tabs.find('.tab:eq(1)')).toHaveClass 'active'
it "highlights the tab for the active pane item", ->
expect(tabBar.find('.tab:eq(2)')).toHaveClass 'active'
describe "when a new edit session is created", ->
it "adds a tab for the new edit session", ->
rootView.open('two-hundred.txt')
expect(tabs.find('.tab').length).toBe 3
expect(tabs.find('.tab:eq(2) .file-name').text()).toBe 'two-hundred.txt'
describe "when the active pane item changes", ->
it "highlights the tab for the new active pane item", ->
pane.showItem(item1)
expect(tabBar.find('.active').length).toBe 1
expect(tabBar.find('.tab:eq(0)')).toHaveClass 'active'
describe "when the edit session's buffer has an undefined path", ->
it "makes the tab text 'untitled'", ->
rootView.open()
expect(tabs.find('.tab').length).toBe 3
expect(tabs.find('.tab:eq(2) .file-name').text()).toBe 'untitled'
pane.showItem(item2)
expect(tabBar.find('.active').length).toBe 1
expect(tabBar.find('.tab:eq(2)')).toHaveClass 'active'
it "removes the tab's title", ->
rootView.open()
expect(tabs.find('.tab').length).toBe 3
expect(tabs.find('.tab:eq(2) .file-name').attr('title')).toBeUndefined()
describe "when a new item is added to the pane", ->
ffit "adds a tab for the new item at the same index as the item in the pane", ->
pane.showItem(item1)
item3 = new TestView('Item 3')
pane.showItem(item3)
expect(tabBar.find('.tab').length).toBe 4
expect(tabBar.tabAtIndex(1).find('.title')).toHaveText 'Item 3'
describe "when an edit session is removed", ->
it "removes the tab for the removed edit session", ->
editor.setActiveEditSessionIndex(0)
editor.destroyActiveEditSession()
expect(tabs.find('.tab').length).toBe 1
expect(tabs.find('.tab:eq(0) .file-name').text()).toBe 'sample.txt'
describe "when an item is removed from the pane", ->
it "removes the item's tab from the tab bar", ->
pane.removeItem(item2)
expect(tabBar.getTabs().length).toBe 2
expect(tabBar.find('.tab:contains(Item 2)')).not.toExist()
describe "when a tab is clicked", ->
it "activates the associated edit session", ->
expect(editor.getActiveEditSessionIndex()).toBe 1
tabs.find('.tab:eq(0)').click()
expect(editor.getActiveEditSessionIndex()).toBe 0
tabs.find('.tab:eq(1)').click()
expect(editor.getActiveEditSessionIndex()).toBe 1
it "shows the associated item on the pane and focuses the pane", ->
spyOn(pane, 'focus')
it "focuses the associated editor", ->
rootView.attachToDom()
expect(editor).toMatchSelector ":has(:focus)"
editor.splitRight()
expect(editor).not.toMatchSelector ":has(:focus)"
tabs.find('.tab:eq(0)').click()
expect(editor).toMatchSelector ":has(:focus)"
tabBar.tabAtIndex(0).click()
expect(pane.activeItem).toBe pane.getItems()[0]
tabBar.tabAtIndex(2).click()
expect(pane.activeItem).toBe pane.getItems()[2]
expect(pane.focus.callCount).toBe 2
describe "when a tab's close icon is clicked", ->
it "removes the tab's item from the pane", ->
tabBar.tabForItem(item1).find('.close-icon').click()
expect(pane.getItems().length).toBe 2
expect(pane.getItems().indexOf(item1)).toBe -1
expect(tabBar.getTabs().length).toBe 2
expect(tabBar.find('.tab:contains(Item 1)')).not.toExist()
describe "when a file name associated with a tab changes", ->
[buffer, oldPath, newPath] = []
@@ -110,21 +116,6 @@ describe "TabView", ->
waitsFor "file to be renamed", ->
tabFileName.text() == "renamed-file.txt"
describe "when the close icon is clicked", ->
it "closes the selected non-active edit session", ->
activeSession = editor.activeEditSession
expect(editor.getActiveEditSessionIndex()).toBe 1
tabs.find('.tab .close-icon:eq(0)').click()
expect(editor.getActiveEditSessionIndex()).toBe 0
expect(editor.activeEditSession).toBe activeSession
it "closes the selected active edit session", ->
firstSession = editor.getEditSessions()[0]
expect(editor.getActiveEditSessionIndex()).toBe 1
tabs.find('.tab .close-icon:eq(1)').click()
expect(editor.getActiveEditSessionIndex()).toBe 0
expect(editor.activeEditSession).toBe firstSession
describe "when two tabs have the same file name", ->
[tempPath] = []