Files
atom/spec/app/pane-spec.coffee
Kevin Sawicki 09b7fe72eb Detach instead of remove when moved item is the view
Moving an item that extended the jQuery object between panes
was previously wiping out all jQuery data since remove() was being
called on the view item instead of detach().
2013-04-08 18:22:58 -07:00

709 lines
29 KiB
CoffeeScript

PaneContainer = require 'pane-container'
Pane = require 'pane'
{$$} = require 'space-pen'
$ = require 'jquery'
describe "Pane", ->
[container, view1, view2, editSession1, editSession2, pane] = []
beforeEach ->
container = new PaneContainer
view1 = $$ -> @div id: 'view-1', tabindex: -1, 'View 1'
view2 = $$ -> @div id: 'view-2', tabindex: -1, 'View 2'
editSession1 = project.buildEditSession('sample.js')
editSession2 = project.buildEditSession('sample.txt')
pane = new Pane(view1, editSession1, view2, editSession2)
container.append(pane)
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')).toBe ''
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(editSession1)
expect(itemChangedHandler).toHaveBeenCalled()
expect(itemChangedHandler.argsForCall[0][1]).toBe editSession1
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 = $$ -> @div id: 'view-3', "View 3"
pane.showItem(editSession1)
expect(pane.getActiveItemIndex()).toBe 1
it "adds it to the items list after the active item", ->
pane.showItem(view3)
expect(pane.getItems()).toEqual [view1, editSession1, view3, view2, editSession2]
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(editSession1)
editor = pane.activeView
expect(editor.css('display')).toBe ''
expect(editor.activeEditSession).toBe editSession1
describe "when a valid view has already been appended for another item", ->
it "recycles the existing view by assigning the selected item to it", ->
pane.showItem(editSession1)
pane.showItem(editSession2)
expect(pane.itemViews.find('.editor').length).toBe 1
editor = pane.activeView
expect(editor.css('display')).toBe ''
expect(editor.activeEditSession).toBe editSession2
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(editSession2)
expect(pane.getItems().indexOf(editSession2)).toBe -1
expect(editSession2.destroyed).toBeTruthy()
describe "if the item is modified", ->
beforeEach ->
spyOn(atom, 'confirm')
spyOn(atom, 'showSaveDialog')
spyOn(editSession2, 'save')
spyOn(editSession2, 'saveAs')
atom.confirm.selectOption = (buttonText) ->
for arg, i in @argsForCall[0] when arg is buttonText
@argsForCall[0][i + 1]?()
editSession2.insertText('a')
expect(editSession2.isModified()).toBeTruthy()
pane.destroyItem(editSession2)
it "presents a dialog with the option to save the item first", ->
expect(atom.confirm).toHaveBeenCalled()
expect(pane.getItems().indexOf(editSession2)).not.toBe -1
expect(editSession2.destroyed).toBeFalsy()
describe "if the [Save] option is selected", ->
describe "when the item has a uri", ->
it "saves the item before removing and destroying it", ->
atom.confirm.selectOption('Save')
expect(editSession2.save).toHaveBeenCalled()
expect(pane.getItems().indexOf(editSession2)).toBe -1
expect(editSession2.destroyed).toBeTruthy()
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", ->
editSession2.buffer.setPath(undefined)
atom.confirm.selectOption('Save')
expect(atom.showSaveDialog).toHaveBeenCalled()
atom.showSaveDialog.argsForCall[0][0]("/selected/path")
expect(editSession2.saveAs).toHaveBeenCalledWith("/selected/path")
expect(pane.getItems().indexOf(editSession2)).toBe -1
expect(editSession2.destroyed).toBeTruthy()
describe "if the [Don't Save] option is selected", ->
it "removes and destroys the item without saving it", ->
atom.confirm.selectOption("Don't Save")
expect(editSession2.save).not.toHaveBeenCalled()
expect(pane.getItems().indexOf(editSession2)).toBe -1
expect(editSession2.destroyed).toBeTruthy()
describe "if the [Cancel] option is selected", ->
it "does not save, remove, or destroy the item", ->
atom.confirm.selectOption("Cancel")
expect(editSession2.save).not.toHaveBeenCalled()
expect(pane.getItems().indexOf(editSession2)).not.toBe -1
expect(editSession2.destroyed).toBeFalsy()
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 [editSession1, view2, editSession2]
expect(pane.activeItem).toBe editSession1
pane.showItem(editSession2)
pane.removeItem(editSession2)
expect(pane.getItems()).toEqual [editSession1, view2]
expect(pane.activeItem).toBe editSession1
it "triggers 'pane:item-removed' with the item and its former index", ->
itemRemovedHandler = jasmine.createSpy("itemRemovedHandler")
pane.on 'pane:item-removed', itemRemovedHandler
pane.removeItem(editSession1)
expect(itemRemovedHandler).toHaveBeenCalled()
expect(itemRemovedHandler.argsForCall[0][1..2]).toEqual [editSession1, 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", ->
container.attachToDom()
pane2 = pane.splitRight($$ -> @div class: 'view-3', tabindex: -1, '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(editSession2)
pane.removeItem(editSession2)
expect(pane.itemViews.find('.editor')).toExist()
pane.removeItem(editSession1)
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 [editSession1, view2, view1, editSession2]
expect(itemMovedHandler).toHaveBeenCalled()
expect(itemMovedHandler.argsForCall[0][1..2]).toEqual [view1, 2]
itemMovedHandler.reset()
pane.moveItem(editSession1, 3)
expect(pane.getItems()).toEqual [view2, view1, editSession2, editSession1]
expect(itemMovedHandler).toHaveBeenCalled()
expect(itemMovedHandler.argsForCall[0][1..2]).toEqual [editSession1, 3]
itemMovedHandler.reset()
pane.moveItem(editSession1, 1)
expect(pane.getItems()).toEqual [view2, editSession1, view1, editSession2]
expect(itemMovedHandler).toHaveBeenCalled()
expect(itemMovedHandler.argsForCall[0][1..2]).toEqual [editSession1, 1]
itemMovedHandler.reset()
describe ".moveItemToPane(item, pane, index)", ->
[pane2, view3] = []
beforeEach ->
view3 = $$ -> @div id: 'view-3', "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 [editSession1, view2, editSession2]
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(editSession2)
expect(pane.getItems()).toEqual [editSession1]
pane.moveItemToPane(editSession1, pane2, 1)
expect(pane.hasParent()).toBeFalsy()
expect(pane2.getItems()).toEqual [view3, editSession1]
expect(editSession1.destroyed).toBeFalsy()
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 "core:close", ->
it "destroys the active item and does not bubble the event", ->
containerCloseHandler = jasmine.createSpy("containerCloseHandler")
container.on 'core:close', containerCloseHandler
pane.showItem(editSession1)
initialItemCount = pane.getItems().length
pane.trigger 'core:close'
expect(pane.getItems().length).toBe initialItemCount - 1
expect(editSession1.destroyed).toBeTruthy()
expect(containerCloseHandler).not.toHaveBeenCalled()
describe "pane:close", ->
it "destroys all items and removes the pane", ->
pane.showItem(editSession1)
pane.trigger 'pane:close'
expect(pane.hasParent()).toBeFalsy()
expect(editSession2.destroyed).toBeTruthy()
expect(editSession1.destroyed).toBeTruthy()
describe "pane:close-other-items", ->
it "destroys all items except the current", ->
pane.showItem(editSession1)
pane.trigger 'pane:close-other-items'
expect(editSession2.destroyed).toBeTruthy()
expect(pane.getItems()).toEqual [editSession1]
describe "core:save", ->
describe "when the current item has a uri", ->
describe "when the current item has a save method", ->
it "saves the current item", ->
spyOn(editSession2, 'save')
pane.showItem(editSession2)
pane.trigger 'core:save'
expect(editSession2.save).toHaveBeenCalled()
describe "when the current item has no save method", ->
it "does nothing", ->
expect(pane.activeItem.save).toBeUndefined()
pane.trigger 'core:save'
describe "when the current item has no uri", ->
beforeEach ->
spyOn(atom, 'showSaveDialog')
describe "when the current item has a saveAs method", ->
it "opens a save dialog and saves the current item as the selected path", ->
spyOn(editSession2, 'saveAs')
editSession2.buffer.setPath(undefined)
pane.showItem(editSession2)
pane.trigger 'core:save'
expect(atom.showSaveDialog).toHaveBeenCalled()
atom.showSaveDialog.argsForCall[0][0]('/selected/path')
expect(editSession2.saveAs).toHaveBeenCalledWith('/selected/path')
describe "when the current item has no saveAs method", ->
it "does nothing", ->
expect(pane.activeItem.saveAs).toBeUndefined()
pane.trigger 'core:save'
expect(atom.showSaveDialog).not.toHaveBeenCalled()
describe "core:save-as", ->
beforeEach ->
spyOn(atom, 'showSaveDialog')
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(editSession2, 'saveAs')
pane.showItem(editSession2)
pane.trigger 'core:save-as'
expect(atom.showSaveDialog).toHaveBeenCalled()
atom.showSaveDialog.argsForCall[0][0]('/selected/path')
expect(editSession2.saveAs).toHaveBeenCalledWith('/selected/path')
describe "when the current item does not have a saveAs method", ->
it "does nothing", ->
expect(pane.activeItem.saveAs).toBeUndefined()
pane.trigger 'core:save-as'
expect(atom.showSaveDialog).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 editSession2
pane.trigger 'pane:show-previous-item'
expect(pane.activeItem).toBe view2
pane.trigger 'pane:show-next-item'
expect(pane.activeItem).toBe editSession2
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 ".remove()", ->
it "destroys all the pane's items", ->
pane.remove()
expect(editSession1.destroyed).toBeTruthy()
expect(editSession2.destroyed).toBeTruthy()
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(editSession1)
paneToLeft = pane.splitLeft()
paneToRight = pane.splitRight()
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
window.rootView = focus: jasmine.createSpy("rootView.focus")
describe "when the removed pane is focused", ->
it "calls focus on rootView so we don't lose focus", ->
container.attachToDom()
pane.focus()
pane.remove()
expect(rootView.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(rootView.focus).not.toHaveBeenCalled()
describe ".getNextPane()", ->
it "returns the next pane if one exists, wrapping around from the last pane to the first", ->
pane.showItem(editSession1)
expect(pane.getNextPane()).toBeUndefined
pane2 = pane.splitRight()
expect(pane.getNextPane()).toBe pane2
expect(pane2.getNextPane()).toBe pane
describe "when the pane is focused", ->
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", ->
becameActiveHandler = jasmine.createSpy("becameActiveHandler")
container.on 'pane:became-active', becameActiveHandler
expect(pane.isActive()).toBeFalsy()
pane.focusin()
expect(pane.isActive()).toBeTruthy()
pane.focusin()
expect(becameActiveHandler.callCount).toBe 1
describe "split methods", ->
[pane1, view3, view4] = []
beforeEach ->
pane1 = pane
pane.showItem(editSession1)
view3 = $$ -> @div id: 'view-3', 'View 3'
view4 = $$ -> @div id: 'view-4', '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()
expect(container.find('.row .pane').toArray()).toEqual [pane1[0], pane2[0]]
expect(pane2.items).toEqual [editSession1]
expect(pane2.activeItem).not.toBe editSession1 # it's a copy
pane3 = pane2.splitRight(view3, view4)
expect(pane3.getItems()).toEqual [view3, view4]
expect(container.find('.row .pane').toArray()).toEqual [pane[0], pane2[0], pane3[0]]
describe "splitRight(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()
expect(container.find('.row .pane').toArray()).toEqual [pane2[0], pane[0]]
expect(pane2.items).toEqual [editSession1]
expect(pane2.activeItem).not.toBe editSession1 # it's a copy
pane3 = pane2.splitLeft(view3, view4)
expect(pane3.getItems()).toEqual [view3, view4]
expect(container.find('.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()
expect(container.find('.column .pane').toArray()).toEqual [pane[0], pane2[0]]
expect(pane2.items).toEqual [editSession1]
expect(pane2.activeItem).not.toBe editSession1 # it's a copy
pane3 = pane2.splitDown(view3, view4)
expect(pane3.getItems()).toEqual [view3, view4]
expect(container.find('.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()
expect(container.find('.column .pane').toArray()).toEqual [pane2[0], pane[0]]
expect(pane2.items).toEqual [editSession1]
expect(pane2.activeItem).not.toBe editSession1 # it's a copy
pane3 = pane2.splitUp(view3, view4)
expect(pane3.getItems()).toEqual [view3, view4]
expect(container.find('.column .pane').toArray()).toEqual [pane3[0], pane2[0], pane[0]]
it "lays out nested panes by equally dividing their containing row / column", ->
container.width(520).height(240).attachToDom()
pane1.showItem($("1"))
pane1
.splitLeft($("2"))
.splitUp($("3"))
.splitLeft($("4"))
.splitDown($("5"))
row1 = container.children(':eq(0)')
expect(row1.children().length).toBe 2
column1 = row1.children(':eq(0)').view()
pane1 = row1.children(':eq(1)').view()
expect(column1.outerWidth()).toBe Math.round(2/3 * container.width())
expect(column1.outerHeight()).toBe container.height()
expect(pane1.outerWidth()).toBe Math.round(1/3 * container.width())
expect(pane1.outerHeight()).toBe container.height()
expect(Math.round(pane1.position().left)).toBe column1.outerWidth()
expect(column1.children().length).toBe 2
row2 = column1.children(':eq(0)').view()
pane2 = column1.children(':eq(1)').view()
expect(row2.outerWidth()).toBe column1.outerWidth()
expect(row2.height()).toBe 2/3 * container.height()
expect(pane2.outerWidth()).toBe column1.outerWidth()
expect(pane2.outerHeight()).toBe 1/3 * container.height()
expect(Math.round(pane2.position().top)).toBe row2.height()
expect(row2.children().length).toBe 2
column3 = row2.children(':eq(0)').view()
pane3 = row2.children(':eq(1)').view()
expect(column3.outerWidth()).toBe Math.round(1/3 * container.width())
expect(column3.outerHeight()).toBe row2.outerHeight()
# the built in rounding seems to be rounding x.5 down, but we need to go up. this sucks.
expect(Math.round(pane3.trueWidth())).toBe Math.round(1/3 * container.width())
expect(pane3.height()).toBe row2.outerHeight()
expect(Math.round(pane3.position().left)).toBe column3.width()
expect(column3.children().length).toBe 2
pane4 = column3.children(':eq(0)').view()
pane5 = column3.children(':eq(1)').view()
expect(pane4.outerWidth()).toBe column3.width()
expect(pane4.outerHeight()).toBe 1/3 * container.height()
expect(pane5.outerWidth()).toBe column3.width()
expect(Math.round(pane5.position().top)).toBe pane4.outerHeight()
expect(pane5.outerHeight()).toBe 1/3 * container.height()
pane5.remove()
expect(column3.parent()).not.toExist()
expect(pane2.outerHeight()).toBe Math.floor(1/2 * container.height())
expect(pane3.outerHeight()).toBe Math.floor(1/2 * container.height())
expect(pane4.outerHeight()).toBe Math.floor(1/2 * container.height())
pane4.remove()
expect(row2.parent()).not.toExist()
expect(pane1.outerWidth()).toBe Math.floor(1/2 * container.width())
expect(pane2.outerWidth()).toBe Math.floor(1/2 * container.width())
expect(pane3.outerWidth()).toBe Math.floor(1/2 * container.width())
pane3.remove()
expect(column1.parent()).not.toExist()
expect(pane2.outerHeight()).toBe container.height()
pane2.remove()
expect(row1.parent()).not.toExist()
expect(container.children().length).toBe 1
expect(container.children('.pane').length).toBe 1
expect(pane1.outerWidth()).toBe container.width()
describe "autosave", ->
[initialActiveItem, initialActiveItemUri] = []
beforeEach ->
initialActiveItem = pane.activeItem
initialActiveItemUri = null
pane.activeItem.getUri = -> initialActiveItemUri
pane.activeItem.save = jasmine.createSpy("activeItem.save")
spyOn(pane, 'saveItem').andCallThrough()
describe "when the active view loses focus", ->
it "saves the item if core.autosave is true and the item has a uri", ->
pane.activeView.trigger 'focusout'
expect(pane.saveItem).not.toHaveBeenCalled()
expect(pane.activeItem.save).not.toHaveBeenCalled()
config.set('core.autosave', true)
pane.activeView.trigger 'focusout'
expect(pane.saveItem).not.toHaveBeenCalled()
expect(pane.activeItem.save).not.toHaveBeenCalled()
initialActiveItemUri = '/tmp/hi'
pane.activeView.trigger 'focusout'
expect(pane.activeItem.save).toHaveBeenCalled()
describe "when an item becomes inactive", ->
it "saves the item if core.autosave is true and the item has a uri", ->
expect(view2).not.toBe pane.activeItem
expect(pane.saveItem).not.toHaveBeenCalled()
expect(initialActiveItem.save).not.toHaveBeenCalled()
pane.showItem(view2)
pane.showItem(initialActiveItem)
config.set('core.autosave', true)
pane.showItem(view2)
expect(pane.saveItem).not.toHaveBeenCalled()
expect(initialActiveItem.save).not.toHaveBeenCalled()
pane.showItem(initialActiveItem)
initialActiveItemUri = '/tmp/hi'
pane.showItem(view2)
expect(initialActiveItem.save).toHaveBeenCalled()
describe "when an item is destroyed", ->
it "saves the item if core.autosave is true and the item has a uri", ->
# doesn't have to be the active item
expect(view2).not.toBe pane.activeItem
pane.showItem(view2)
pane.destroyItem(editSession1)
expect(pane.saveItem).not.toHaveBeenCalled()
config.set("core.autosave", true)
view2.getUri = -> undefined
view2.save = ->
pane.destroyItem(view2)
expect(pane.saveItem).not.toHaveBeenCalled()
initialActiveItemUri = '/tmp/hi'
pane.destroyItem(initialActiveItem)
expect(initialActiveItem.save).toHaveBeenCalled()
describe ".itemForUri(uri)", ->
it "returns the item for which a call to .getUri() returns the given uri", ->
expect(pane.itemForUri(editSession1.getUri())).toBe editSession1
expect(pane.itemForUri(editSession2.getUri())).toBe editSession2
describe "serialization", ->
it "can serialize and deserialize the pane and all its serializable items", ->
newPane = deserialize(pane.serialize())
expect(newPane.getItems()).toEqual [editSession1, editSession2]
it "restores the active item on deserialization if it serializable", ->
pane.showItem(editSession2)
newPane = deserialize(pane.serialize())
expect(newPane.activeItem).toEqual editSession2
it "defaults to the first item on deserialization if the active item was not serializable", ->
expect(view2.serialize?()).toBeFalsy()
pane.showItem(view2)
newPane = deserialize(pane.serialize())
expect(newPane.activeItem).toEqual editSession1
it "focuses the pane after attach only if had focus when serialized", ->
container.attachToDom()
pane.focus()
state = pane.serialize()
pane.remove()
newPane = deserialize(state)
container.append(newPane)
expect(newPane).toMatchSelector(':has(:focus)')
$(document.activeElement).blur()
state = newPane.serialize()
newPane.remove()
newerPane = deserialize(state)
expect(newerPane).not.toMatchSelector(':has(:focus)')