mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-09-20 23:48:05 +03:00
4b0d22917b
The behavior of flexbox is actually slightly different in that it divides space evenly among the immediate children of a row or column rather than accounting for all splits. But it's actually not that big a deal.
645 lines
26 KiB
CoffeeScript
645 lines
26 KiB
CoffeeScript
PaneContainer = require '../src/pane-container'
|
|
Pane = require '../src/pane'
|
|
{fs, $, View} = require 'atom'
|
|
path = require 'path'
|
|
temp = require 'temp'
|
|
|
|
describe "Pane", ->
|
|
[container, view1, view2, editor1, editor2, pane] = []
|
|
|
|
class TestView extends View
|
|
@deserialize: ({id, text}) -> new TestView({id, text})
|
|
@content: ({id, text}) -> @div class: 'test-view', id: id, tabindex: -1, text
|
|
initialize: ({@id, @text}) ->
|
|
serialize: -> { deserializer: 'TestView', @id, @text }
|
|
getUri: -> @id
|
|
isEqual: (other) -> other? and @id == other.id and @text == other.text
|
|
|
|
beforeEach ->
|
|
atom.deserializers.add(TestView)
|
|
container = new PaneContainer
|
|
view1 = new TestView(id: 'view-1', text: 'View 1')
|
|
view2 = new TestView(id: 'view-2', text: 'View 2')
|
|
editor1 = atom.project.openSync('sample.js')
|
|
editor2 = atom.project.openSync('sample.txt')
|
|
pane = new Pane(view1, editor1, view2, editor2)
|
|
container.setRoot(pane)
|
|
|
|
afterEach ->
|
|
atom.deserializers.remove(TestView)
|
|
|
|
describe "::initialize(items...)", ->
|
|
it "displays the first item in the pane", ->
|
|
expect(pane.itemViews.find('#view-1')).toExist()
|
|
|
|
describe "::showItem(item)", ->
|
|
it "hides all item views except the one being shown and sets the activeItem", ->
|
|
expect(pane.activeItem).toBe view1
|
|
pane.showItem(view2)
|
|
expect(view1.css('display')).toBe 'none'
|
|
expect(view2.css('display')).not.toBe 'none'
|
|
expect(pane.activeItem).toBe view2
|
|
|
|
it "triggers 'pane:active-item-changed' if the item isn't already the activeItem", ->
|
|
pane.makeActive()
|
|
itemChangedHandler = jasmine.createSpy("itemChangedHandler")
|
|
container.on 'pane:active-item-changed', itemChangedHandler
|
|
|
|
expect(pane.activeItem).toBe view1
|
|
pane.showItem(view2)
|
|
pane.showItem(view2)
|
|
expect(itemChangedHandler.callCount).toBe 1
|
|
expect(itemChangedHandler.argsForCall[0][1]).toBe view2
|
|
itemChangedHandler.reset()
|
|
|
|
pane.showItem(editor1)
|
|
expect(itemChangedHandler).toHaveBeenCalled()
|
|
expect(itemChangedHandler.argsForCall[0][1]).toBe editor1
|
|
itemChangedHandler.reset()
|
|
|
|
describe "if the pane's active view is focused before calling showItem", ->
|
|
it "focuses the new active view", ->
|
|
container.attachToDom()
|
|
pane.focus()
|
|
expect(pane.activeView).not.toBe view2
|
|
expect(pane.activeView).toMatchSelector ':focus'
|
|
pane.showItem(view2)
|
|
expect(view2).toMatchSelector ':focus'
|
|
|
|
describe "when the given item isn't yet in the items list on the pane", ->
|
|
view3 = null
|
|
beforeEach ->
|
|
view3 = new TestView(id: 'view-3', text: "View 3")
|
|
pane.showItem(editor1)
|
|
expect(pane.getActiveItemIndex()).toBe 1
|
|
|
|
it "adds it to the items list after the active item", ->
|
|
pane.showItem(view3)
|
|
expect(pane.getItems()).toEqual [view1, editor1, view3, view2, editor2]
|
|
expect(pane.activeItem).toBe view3
|
|
expect(pane.getActiveItemIndex()).toBe 2
|
|
|
|
it "triggers the 'item-added' event with the item and its index before the 'active-item-changed' event", ->
|
|
events = []
|
|
container.on 'pane:item-added', (e, item, index) -> events.push(['pane:item-added', item, index])
|
|
container.on 'pane:active-item-changed', (e, item) -> events.push(['pane:active-item-changed', item])
|
|
pane.showItem(view3)
|
|
expect(events).toEqual [['pane:item-added', view3, 2], ['pane:active-item-changed', view3]]
|
|
|
|
describe "when showing a model item", ->
|
|
describe "when no view has yet been appended for that item", ->
|
|
it "appends and shows a view to display the item based on its `.getViewClass` method", ->
|
|
pane.showItem(editor1)
|
|
editorView = pane.activeView
|
|
expect(editorView.css('display')).not.toBe 'none'
|
|
expect(editorView.editor).toBe editor1
|
|
|
|
describe "when a valid view has already been appended for another item", ->
|
|
it "multiple views are created for multiple items", ->
|
|
pane.showItem(editor1)
|
|
pane.showItem(editor2)
|
|
expect(pane.itemViews.find('.editor').length).toBe 2
|
|
editorView = pane.activeView
|
|
expect(editorView.css('display')).not.toBe 'none'
|
|
expect(editorView.editor).toBe editor2
|
|
|
|
it "creates a new view with the item", ->
|
|
initialViewCount = pane.itemViews.find('.test-view').length
|
|
|
|
model1 =
|
|
id: 'test-model-1'
|
|
text: 'Test Model 1'
|
|
serialize: -> {@id, @text}
|
|
getViewClass: -> TestView
|
|
|
|
model2 =
|
|
id: 'test-model-2'
|
|
text: 'Test Model 2'
|
|
serialize: -> {@id, @text}
|
|
getViewClass: -> TestView
|
|
|
|
pane.showItem(model1)
|
|
pane.showItem(model2)
|
|
expect(pane.itemViews.find('.test-view').length).toBe initialViewCount + 2
|
|
|
|
pane.showPreviousItem()
|
|
expect(pane.itemViews.find('.test-view').length).toBe initialViewCount + 2
|
|
|
|
pane.removeItem(model2)
|
|
expect(pane.itemViews.find('.test-view').length).toBe initialViewCount + 1
|
|
|
|
pane.removeItem(model1)
|
|
expect(pane.itemViews.find('.test-view').length).toBe initialViewCount
|
|
|
|
describe "when showing a view item", ->
|
|
it "appends it to the itemViews div if it hasn't already been appended and shows it", ->
|
|
expect(pane.itemViews.find('#view-2')).not.toExist()
|
|
pane.showItem(view2)
|
|
expect(pane.itemViews.find('#view-2')).toExist()
|
|
expect(pane.activeView).toBe view2
|
|
|
|
describe "::destroyItem(item)", ->
|
|
describe "if the item is not modified", ->
|
|
it "removes the item and tries to call destroy on it", ->
|
|
pane.destroyItem(editor2)
|
|
expect(pane.getItems().indexOf(editor2)).toBe -1
|
|
expect(editor2.isDestroyed()).toBe true
|
|
|
|
describe "if the item is modified", ->
|
|
beforeEach ->
|
|
jasmine.unspy(editor2, 'shouldPromptToSave')
|
|
spyOn(editor2, 'save')
|
|
spyOn(editor2, 'saveAs')
|
|
|
|
editor2.insertText('a')
|
|
expect(editor2.isModified()).toBeTruthy()
|
|
|
|
describe "if the [Save] option is selected", ->
|
|
describe "when the item has a uri", ->
|
|
it "saves the item before removing and destroying it", ->
|
|
spyOn(atom, 'confirm').andReturn(0)
|
|
pane.destroyItem(editor2)
|
|
|
|
expect(editor2.save).toHaveBeenCalled()
|
|
expect(pane.getItems().indexOf(editor2)).toBe -1
|
|
expect(editor2.isDestroyed()).toBe true
|
|
|
|
describe "when the item has no uri", ->
|
|
it "presents a save-as dialog, then saves the item with the given uri before removing and destroying it", ->
|
|
editor2.buffer.setPath(undefined)
|
|
|
|
spyOn(atom, 'showSaveDialogSync').andReturn("/selected/path")
|
|
spyOn(atom, 'confirm').andReturn(0)
|
|
pane.destroyItem(editor2)
|
|
|
|
expect(atom.showSaveDialogSync).toHaveBeenCalled()
|
|
|
|
expect(editor2.saveAs).toHaveBeenCalledWith("/selected/path")
|
|
expect(pane.getItems().indexOf(editor2)).toBe -1
|
|
expect(editor2.isDestroyed()).toBe true
|
|
|
|
describe "if the [Don't Save] option is selected", ->
|
|
it "removes and destroys the item without saving it", ->
|
|
spyOn(atom, 'confirm').andReturn(2)
|
|
pane.destroyItem(editor2)
|
|
|
|
expect(editor2.save).not.toHaveBeenCalled()
|
|
expect(pane.getItems().indexOf(editor2)).toBe -1
|
|
expect(editor2.isDestroyed()).toBe true
|
|
|
|
describe "if the [Cancel] option is selected", ->
|
|
it "does not save, remove, or destroy the item", ->
|
|
spyOn(atom, 'confirm').andReturn(1)
|
|
pane.destroyItem(editor2)
|
|
|
|
expect(editor2.save).not.toHaveBeenCalled()
|
|
expect(pane.getItems().indexOf(editor2)).not.toBe -1
|
|
expect(editor2.isDestroyed()).toBe false
|
|
|
|
describe "::removeItem(item)", ->
|
|
it "removes the item from the items list and shows the next item if it was showing", ->
|
|
pane.removeItem(view1)
|
|
expect(pane.getItems()).toEqual [editor1, view2, editor2]
|
|
expect(pane.activeItem).toBe editor1
|
|
|
|
pane.showItem(editor2)
|
|
pane.removeItem(editor2)
|
|
expect(pane.getItems()).toEqual [editor1, view2]
|
|
expect(pane.activeItem).toBe editor1
|
|
|
|
it "triggers 'pane:item-removed' with the item and its former index", ->
|
|
itemRemovedHandler = jasmine.createSpy("itemRemovedHandler")
|
|
pane.on 'pane:item-removed', itemRemovedHandler
|
|
pane.removeItem(editor1)
|
|
expect(itemRemovedHandler).toHaveBeenCalled()
|
|
expect(itemRemovedHandler.argsForCall[0][1..2]).toEqual [editor1, 1]
|
|
|
|
describe "when removing the last item", ->
|
|
it "removes the pane", ->
|
|
pane.removeItem(item) for item in pane.getItems()
|
|
expect(pane.hasParent()).toBeFalsy()
|
|
|
|
describe "when the pane is focused", ->
|
|
it "shifts focus to the next pane", ->
|
|
expect(container.getRoot()).toBe pane
|
|
container.attachToDom()
|
|
pane2 = pane.splitRight(new TestView(id: 'view-3', text: 'View 3'))
|
|
pane.focus()
|
|
expect(pane).toMatchSelector(':has(:focus)')
|
|
pane.removeItem(item) for item in pane.getItems()
|
|
expect(pane2).toMatchSelector ':has(:focus)'
|
|
|
|
describe "when the item is a view", ->
|
|
it "removes the item from the 'item-views' div", ->
|
|
expect(view1.parent()).toMatchSelector pane.itemViews
|
|
pane.removeItem(view1)
|
|
expect(view1.parent()).not.toMatchSelector pane.itemViews
|
|
|
|
describe "when the item is a model", ->
|
|
it "removes the associated view only when all items that require it have been removed", ->
|
|
pane.showItem(editor1)
|
|
pane.showItem(editor2)
|
|
pane.removeItem(editor2)
|
|
expect(pane.itemViews.find('.editor')).toExist()
|
|
pane.removeItem(editor1)
|
|
expect(pane.itemViews.find('.editor')).not.toExist()
|
|
|
|
describe "::moveItem(item, index)", ->
|
|
it "moves the item to the given index and emits a 'pane:item-moved' event with the item and the new index", ->
|
|
itemMovedHandler = jasmine.createSpy("itemMovedHandler")
|
|
pane.on 'pane:item-moved', itemMovedHandler
|
|
|
|
pane.moveItem(view1, 2)
|
|
expect(pane.getItems()).toEqual [editor1, view2, view1, editor2]
|
|
expect(itemMovedHandler).toHaveBeenCalled()
|
|
expect(itemMovedHandler.argsForCall[0][1..2]).toEqual [view1, 2]
|
|
itemMovedHandler.reset()
|
|
|
|
pane.moveItem(editor1, 3)
|
|
expect(pane.getItems()).toEqual [view2, view1, editor2, editor1]
|
|
expect(itemMovedHandler).toHaveBeenCalled()
|
|
expect(itemMovedHandler.argsForCall[0][1..2]).toEqual [editor1, 3]
|
|
itemMovedHandler.reset()
|
|
|
|
pane.moveItem(editor1, 1)
|
|
expect(pane.getItems()).toEqual [view2, editor1, view1, editor2]
|
|
expect(itemMovedHandler).toHaveBeenCalled()
|
|
expect(itemMovedHandler.argsForCall[0][1..2]).toEqual [editor1, 1]
|
|
itemMovedHandler.reset()
|
|
|
|
describe "::moveItemToPane(item, pane, index)", ->
|
|
[pane2, view3] = []
|
|
|
|
beforeEach ->
|
|
view3 = new TestView(id: 'view-3', text: "View 3")
|
|
pane2 = pane.splitRight(view3)
|
|
|
|
it "moves the item to the given pane at the given index", ->
|
|
pane.moveItemToPane(view1, pane2, 1)
|
|
expect(pane.getItems()).toEqual [editor1, view2, editor2]
|
|
expect(pane2.getItems()).toEqual [view3, view1]
|
|
|
|
describe "when it is the last item on the source pane", ->
|
|
it "removes the source pane, but does not destroy the item", ->
|
|
pane.removeItem(view1)
|
|
pane.removeItem(view2)
|
|
pane.removeItem(editor2)
|
|
|
|
expect(pane.getItems()).toEqual [editor1]
|
|
pane.moveItemToPane(editor1, pane2, 1)
|
|
|
|
expect(pane.hasParent()).toBeFalsy()
|
|
expect(pane2.getItems()).toEqual [view3, editor1]
|
|
expect(editor1.isDestroyed()).toBe false
|
|
|
|
describe "when the item is a jQuery object", ->
|
|
it "preserves data by detaching instead of removing", ->
|
|
view1.data('preservative', 1234)
|
|
pane.moveItemToPane(view1, pane2, 1)
|
|
pane2.showItemAtIndex(1)
|
|
expect(pane2.activeView.data('preservative')).toBe 1234
|
|
|
|
describe "pane:close", ->
|
|
it "destroys all items and removes the pane", ->
|
|
pane.showItem(editor1)
|
|
pane.trigger 'pane:close'
|
|
expect(pane.hasParent()).toBeFalsy()
|
|
expect(editor2.isDestroyed()).toBe true
|
|
expect(editor1.isDestroyed()).toBe true
|
|
|
|
describe "pane:close-other-items", ->
|
|
it "destroys all items except the current", ->
|
|
pane.showItem(editor1)
|
|
pane.trigger 'pane:close-other-items'
|
|
expect(editor2.isDestroyed()).toBe true
|
|
expect(pane.getItems()).toEqual [editor1]
|
|
|
|
describe "::saveActiveItem()", ->
|
|
describe "when the current item has a uri", ->
|
|
describe "when the current item has a save method", ->
|
|
it "saves the current item", ->
|
|
spyOn(editor2, 'save')
|
|
pane.showItem(editor2)
|
|
pane.saveActiveItem()
|
|
expect(editor2.save).toHaveBeenCalled()
|
|
|
|
describe "when the current item has no save method", ->
|
|
it "does nothing", ->
|
|
pane.activeItem.getUri = -> 'you are eye'
|
|
expect(pane.activeItem.save).toBeUndefined()
|
|
pane.saveActiveItem()
|
|
|
|
describe "when the current item has no uri", ->
|
|
beforeEach ->
|
|
spyOn(atom, 'showSaveDialogSync').andReturn('/selected/path')
|
|
|
|
describe "when the current item has a saveAs method", ->
|
|
it "opens a save dialog and saves the current item as the selected path", ->
|
|
newEditor = atom.project.openSync()
|
|
spyOn(newEditor, 'saveAs')
|
|
pane.showItem(newEditor)
|
|
|
|
pane.saveActiveItem()
|
|
|
|
expect(atom.showSaveDialogSync).toHaveBeenCalled()
|
|
expect(newEditor.saveAs).toHaveBeenCalledWith('/selected/path')
|
|
|
|
describe "when the current item has no saveAs method", ->
|
|
it "does nothing", ->
|
|
expect(pane.activeItem.saveAs).toBeUndefined()
|
|
pane.saveActiveItem()
|
|
expect(atom.showSaveDialogSync).not.toHaveBeenCalled()
|
|
|
|
describe "::saveActiveItemAs()", ->
|
|
beforeEach ->
|
|
spyOn(atom, 'showSaveDialogSync').andReturn('/selected/path')
|
|
|
|
describe "when the current item has a saveAs method", ->
|
|
it "opens the save dialog and calls saveAs on the item with the selected path", ->
|
|
spyOn(editor2, 'saveAs')
|
|
pane.showItem(editor2)
|
|
|
|
pane.saveActiveItemAs()
|
|
|
|
expect(atom.showSaveDialogSync).toHaveBeenCalledWith(path.dirname(editor2.getPath()))
|
|
expect(editor2.saveAs).toHaveBeenCalledWith('/selected/path')
|
|
|
|
describe "when the current item does not have a saveAs method", ->
|
|
it "does nothing", ->
|
|
expect(pane.activeItem.saveAs).toBeUndefined()
|
|
pane.saveActiveItemAs()
|
|
expect(atom.showSaveDialogSync).not.toHaveBeenCalled()
|
|
|
|
describe "pane:show-next-item and pane:show-previous-item", ->
|
|
it "advances forward/backward through the pane's items, looping around at either end", ->
|
|
expect(pane.activeItem).toBe view1
|
|
pane.trigger 'pane:show-previous-item'
|
|
expect(pane.activeItem).toBe editor2
|
|
pane.trigger 'pane:show-previous-item'
|
|
expect(pane.activeItem).toBe view2
|
|
pane.trigger 'pane:show-next-item'
|
|
expect(pane.activeItem).toBe editor2
|
|
pane.trigger 'pane:show-next-item'
|
|
expect(pane.activeItem).toBe view1
|
|
|
|
describe "pane:show-item-N events", ->
|
|
it "shows the (n-1)th item if it exists", ->
|
|
pane.trigger 'pane:show-item-2'
|
|
expect(pane.activeItem).toBe pane.itemAtIndex(1)
|
|
pane.trigger 'pane:show-item-1'
|
|
expect(pane.activeItem).toBe pane.itemAtIndex(0)
|
|
pane.trigger 'pane:show-item-9' # don't fail on out-of-bounds indices
|
|
expect(pane.activeItem).toBe pane.itemAtIndex(0)
|
|
|
|
describe "when the title of the active item changes", ->
|
|
it "emits pane:active-item-title-changed", ->
|
|
activeItemTitleChangedHandler = jasmine.createSpy("activeItemTitleChangedHandler")
|
|
pane.on 'pane:active-item-title-changed', activeItemTitleChangedHandler
|
|
|
|
expect(pane.activeItem).toBe view1
|
|
|
|
view2.trigger 'title-changed'
|
|
expect(activeItemTitleChangedHandler).not.toHaveBeenCalled()
|
|
|
|
view1.trigger 'title-changed'
|
|
expect(activeItemTitleChangedHandler).toHaveBeenCalled()
|
|
activeItemTitleChangedHandler.reset()
|
|
|
|
pane.showItem(view2)
|
|
view2.trigger 'title-changed'
|
|
expect(activeItemTitleChangedHandler).toHaveBeenCalled()
|
|
|
|
describe "when an unmodifed buffer's path is deleted", ->
|
|
it "removes the pane item", ->
|
|
filePath = temp.openSync('atom').path
|
|
editor = atom.project.openSync(filePath)
|
|
pane.showItem(editor)
|
|
expect(pane.items).toHaveLength(5)
|
|
|
|
fs.removeSync(filePath)
|
|
waitsFor ->
|
|
pane.items.length == 4
|
|
|
|
describe "::remove()", ->
|
|
it "destroys all the pane's items", ->
|
|
pane.remove()
|
|
expect(editor1.isDestroyed()).toBe true
|
|
expect(editor2.isDestroyed()).toBe true
|
|
|
|
it "triggers a 'pane:removed' event with the pane", ->
|
|
removedHandler = jasmine.createSpy("removedHandler")
|
|
container.on 'pane:removed', removedHandler
|
|
pane.remove()
|
|
expect(removedHandler).toHaveBeenCalled()
|
|
expect(removedHandler.argsForCall[0][1]).toBe pane
|
|
|
|
describe "when there are other panes", ->
|
|
[paneToLeft, paneToRight] = []
|
|
|
|
beforeEach ->
|
|
pane.showItem(editor1)
|
|
paneToLeft = pane.splitLeft(pane.copyActiveItem())
|
|
paneToRight = pane.splitRight(pane.copyActiveItem())
|
|
container.attachToDom()
|
|
|
|
describe "when the removed pane is focused", ->
|
|
it "activates and focuses the next pane", ->
|
|
pane.focus()
|
|
pane.remove()
|
|
expect(paneToLeft.isActive()).toBeFalsy()
|
|
expect(paneToRight.isActive()).toBeTruthy()
|
|
expect(paneToRight).toMatchSelector ':has(:focus)'
|
|
|
|
describe "when the removed pane is active but not focused", ->
|
|
it "activates the next pane, but does not focus it", ->
|
|
$(document.activeElement).blur()
|
|
expect(pane).not.toMatchSelector ':has(:focus)'
|
|
pane.makeActive()
|
|
pane.remove()
|
|
expect(paneToLeft.isActive()).toBeFalsy()
|
|
expect(paneToRight.isActive()).toBeTruthy()
|
|
expect(paneToRight).not.toMatchSelector ':has(:focus)'
|
|
|
|
describe "when the removed pane is not active", ->
|
|
it "does not affect the active pane or the focus", ->
|
|
paneToLeft.focus()
|
|
expect(paneToLeft.isActive()).toBeTruthy()
|
|
expect(paneToRight.isActive()).toBeFalsy()
|
|
|
|
pane.remove()
|
|
expect(paneToLeft.isActive()).toBeTruthy()
|
|
expect(paneToRight.isActive()).toBeFalsy()
|
|
expect(paneToLeft).toMatchSelector ':has(:focus)'
|
|
|
|
describe "when it is the last pane", ->
|
|
beforeEach ->
|
|
expect(container.getPanes().length).toBe 1
|
|
atom.workspaceView = focus: jasmine.createSpy("workspaceView.focus")
|
|
|
|
describe "when the removed pane is focused", ->
|
|
it "calls focus on workspaceView so we don't lose focus", ->
|
|
container.attachToDom()
|
|
pane.focus()
|
|
pane.remove()
|
|
expect(atom.workspaceView.focus).toHaveBeenCalled()
|
|
|
|
describe "when the removed pane is not focused", ->
|
|
it "does not call focus on root view", ->
|
|
expect(pane).not.toMatchSelector ':has(:focus)'
|
|
pane.remove()
|
|
expect(atom.workspaceView.focus).not.toHaveBeenCalled()
|
|
|
|
describe "::getNextPane()", ->
|
|
it "returns the next pane if one exists, wrapping around from the last pane to the first", ->
|
|
pane.showItem(editor1)
|
|
expect(pane.getNextPane()).toBeUndefined
|
|
pane2 = pane.splitRight(pane.copyActiveItem())
|
|
expect(pane.getNextPane()).toBe pane2
|
|
expect(pane2.getNextPane()).toBe pane
|
|
|
|
describe "when the pane is focused", ->
|
|
beforeEach ->
|
|
container.attachToDom()
|
|
|
|
it "focuses the active item view", ->
|
|
focusHandler = jasmine.createSpy("focusHandler")
|
|
pane.activeItem.on 'focus', focusHandler
|
|
pane.focus()
|
|
expect(focusHandler).toHaveBeenCalled()
|
|
|
|
it "triggers 'pane:became-active' if it was not previously active", ->
|
|
pane2 = pane.splitRight(view2) # Make pane inactive
|
|
|
|
becameActiveHandler = jasmine.createSpy("becameActiveHandler")
|
|
pane.on 'pane:became-active', becameActiveHandler
|
|
expect(pane.isActive()).toBeFalsy()
|
|
pane.focusin()
|
|
expect(pane.isActive()).toBeTruthy()
|
|
pane.focusin()
|
|
|
|
expect(becameActiveHandler.callCount).toBe 1
|
|
|
|
it "triggers 'pane:became-inactive' when it was previously active", ->
|
|
pane2 = pane.splitRight(view2) # Make pane inactive
|
|
|
|
becameInactiveHandler = jasmine.createSpy("becameInactiveHandler")
|
|
pane.on 'pane:became-inactive', becameInactiveHandler
|
|
|
|
expect(pane.isActive()).toBeFalsy()
|
|
pane.focusin()
|
|
expect(pane.isActive()).toBeTruthy()
|
|
pane.splitRight(pane.copyActiveItem())
|
|
expect(pane.isActive()).toBeFalsy()
|
|
|
|
expect(becameInactiveHandler.callCount).toBe 1
|
|
|
|
describe "split methods", ->
|
|
[pane1, view3, view4] = []
|
|
beforeEach ->
|
|
pane1 = pane
|
|
pane.showItem(editor1)
|
|
view3 = new TestView(id: 'view-3', text: 'View 3')
|
|
view4 = new TestView(id: 'view-4', text: 'View 4')
|
|
|
|
describe "splitRight(items...)", ->
|
|
it "builds a row if needed, then appends a new pane after itself", ->
|
|
# creates the new pane with a copy of the active item if none are given
|
|
pane2 = pane1.splitRight(pane1.copyActiveItem())
|
|
expect(container.find('.pane-row .pane').toArray()).toEqual [pane1[0], pane2[0]]
|
|
expect(pane2.items).toEqual [editor1]
|
|
expect(pane2.activeItem).not.toBe editor1 # it's a copy
|
|
|
|
pane3 = pane2.splitRight(view3, view4)
|
|
expect(pane3.getItems()).toEqual [view3, view4]
|
|
expect(container.find('.pane-row .pane').toArray()).toEqual [pane[0], pane2[0], pane3[0]]
|
|
|
|
it "builds a row if needed, then appends a new pane after itself ", ->
|
|
# creates the new pane with a copy of the active item if none are given
|
|
pane2 = pane1.splitRight()
|
|
expect(container.find('.pane-row .pane').toArray()).toEqual [pane1[0], pane2[0]]
|
|
expect(pane2.items).toEqual []
|
|
expect(pane2.activeItem).toBeUndefined()
|
|
|
|
pane3 = pane2.splitRight()
|
|
expect(container.find('.pane-row .pane').toArray()).toEqual [pane1[0], pane2[0], pane3[0]]
|
|
expect(pane3.items).toEqual []
|
|
expect(pane3.activeItem).toBeUndefined()
|
|
|
|
describe "splitLeft(items...)", ->
|
|
it "builds a row if needed, then appends a new pane before itself", ->
|
|
# creates the new pane with a copy of the active item if none are given
|
|
pane2 = pane.splitLeft(pane1.copyActiveItem())
|
|
expect(container.find('.pane-row .pane').toArray()).toEqual [pane2[0], pane[0]]
|
|
expect(pane2.items).toEqual [editor1]
|
|
expect(pane2.activeItem).not.toBe editor1 # it's a copy
|
|
|
|
pane3 = pane2.splitLeft(view3, view4)
|
|
expect(pane3.getItems()).toEqual [view3, view4]
|
|
expect(container.find('.pane-row .pane').toArray()).toEqual [pane3[0], pane2[0], pane[0]]
|
|
|
|
describe "splitDown(items...)", ->
|
|
it "builds a column if needed, then appends a new pane after itself", ->
|
|
# creates the new pane with a copy of the active item if none are given
|
|
pane2 = pane.splitDown(pane1.copyActiveItem())
|
|
expect(container.find('.pane-column .pane').toArray()).toEqual [pane[0], pane2[0]]
|
|
expect(pane2.items).toEqual [editor1]
|
|
expect(pane2.activeItem).not.toBe editor1 # it's a copy
|
|
|
|
pane3 = pane2.splitDown(view3, view4)
|
|
expect(pane3.getItems()).toEqual [view3, view4]
|
|
expect(container.find('.pane-column .pane').toArray()).toEqual [pane[0], pane2[0], pane3[0]]
|
|
|
|
describe "splitUp(items...)", ->
|
|
it "builds a column if needed, then appends a new pane before itself", ->
|
|
# creates the new pane with a copy of the active item if none are given
|
|
pane2 = pane.splitUp(pane1.copyActiveItem())
|
|
expect(container.find('.pane-column .pane').toArray()).toEqual [pane2[0], pane[0]]
|
|
expect(pane2.items).toEqual [editor1]
|
|
expect(pane2.activeItem).not.toBe editor1 # it's a copy
|
|
|
|
pane3 = pane2.splitUp(view3, view4)
|
|
expect(pane3.getItems()).toEqual [view3, view4]
|
|
expect(container.find('.pane-column .pane').toArray()).toEqual [pane3[0], pane2[0], pane[0]]
|
|
|
|
describe "::itemForUri(uri)", ->
|
|
it "returns the item for which a call to .getUri() returns the given uri", ->
|
|
expect(pane.itemForUri(editor1.getUri())).toBe editor1
|
|
expect(pane.itemForUri(editor2.getUri())).toBe editor2
|
|
|
|
describe "serialization", ->
|
|
it "can serialize and deserialize the pane and all its items", ->
|
|
newPane = pane.testSerialization()
|
|
expect(newPane.getItems()).toEqual [view1, editor1, view2, editor2]
|
|
|
|
it "restores the active item on deserialization", ->
|
|
pane.showItem(editor2)
|
|
newPane = pane.testSerialization()
|
|
expect(newPane.activeItem).toEqual editor2
|
|
|
|
it "does not show items that cannot be deserialized", ->
|
|
spyOn(console, 'warn')
|
|
|
|
class Unserializable
|
|
getViewClass: -> TestView
|
|
|
|
pane.showItem(new Unserializable)
|
|
|
|
newPane = pane.testSerialization()
|
|
expect(newPane.activeItem).toEqual pane.items[0]
|
|
expect(newPane.items.length).toBe pane.items.length - 1
|
|
|
|
it "focuses the pane after attach only if had focus when serialized", ->
|
|
container.attachToDom()
|
|
pane.focus()
|
|
|
|
container2 = container.testSerialization()
|
|
pane2 = container2.getRoot()
|
|
container2.attachToDom()
|
|
expect(pane2).toMatchSelector(':has(:focus)')
|
|
|
|
$(document.activeElement).blur()
|
|
container3 = container.testSerialization()
|
|
pane3 = container3.getRoot()
|
|
container3.attachToDom()
|
|
expect(pane3).not.toMatchSelector(':has(:focus)')
|