mirror of
https://github.com/atom/atom.git
synced 2026-01-22 21:38:10 -05:00
Merge pull request #3418 from atom/ns-simplify-events
Clean Up Workspace Event Subscription API
This commit is contained in:
@@ -53,7 +53,7 @@ module.exports =
|
||||
|
||||
convert: ->
|
||||
# This assumes the active pane item is an editor
|
||||
editor = atom.workspace.activePaneItem
|
||||
editor = atom.workspace.getActivePaneItem()
|
||||
editor.insertText('Hello, World!')
|
||||
```
|
||||
|
||||
@@ -131,7 +131,7 @@ inserting 'Hello, World!' convert the selected text to ASCII art.
|
||||
```coffeescript
|
||||
convert: ->
|
||||
# This assumes the active pane item is an editor
|
||||
editor = atom.workspace.activePaneItem
|
||||
editor = atom.workspace.getActivePaneItem()
|
||||
selection = editor.getLastSelection()
|
||||
|
||||
figlet = require 'figlet'
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
"coffee-script": "1.7.0",
|
||||
"coffeestack": "0.7.0",
|
||||
"delegato": "^1",
|
||||
"emissary": "^1.2.2",
|
||||
"emissary": "^1.3.1",
|
||||
"event-kit": "0.5.0",
|
||||
"first-mate": "^2.0.5",
|
||||
"fs-plus": "^2.2.6",
|
||||
"fstream": "0.1.24",
|
||||
@@ -109,7 +110,6 @@
|
||||
"welcome": "0.18.0",
|
||||
"whitespace": "0.25.0",
|
||||
"wrap-guide": "0.21.0",
|
||||
|
||||
"language-c": "0.28.0",
|
||||
"language-coffee-script": "0.30.0",
|
||||
"language-css": "0.17.0",
|
||||
|
||||
@@ -27,42 +27,91 @@ describe "PaneContainer", ->
|
||||
|
||||
it "preserves the active pane across serialization, independent of focus", ->
|
||||
pane3A.activate()
|
||||
expect(containerA.activePane).toBe pane3A
|
||||
expect(containerA.getActivePane()).toBe pane3A
|
||||
|
||||
containerB = containerA.testSerialization()
|
||||
[pane1B, pane2B, pane3B] = containerB.getPanes()
|
||||
expect(containerB.activePane).toBe pane3B
|
||||
expect(containerB.getActivePane()).toBe pane3B
|
||||
|
||||
describe "::activePane", ->
|
||||
it "does not allow the root pane to be destroyed", ->
|
||||
container = new PaneContainer
|
||||
container.getRoot().destroy()
|
||||
expect(container.getRoot()).toBeDefined()
|
||||
expect(container.getRoot().isDestroyed()).toBe false
|
||||
|
||||
describe "::getActivePane()", ->
|
||||
[container, pane1, pane2] = []
|
||||
|
||||
beforeEach ->
|
||||
container = new PaneContainer
|
||||
pane1 = container.root
|
||||
pane1 = container.getRoot()
|
||||
|
||||
it "references the first pane if no pane has been made active", ->
|
||||
expect(container.activePane).toBe pane1
|
||||
expect(pane1.active).toBe true
|
||||
it "returns the first pane if no pane has been made active", ->
|
||||
expect(container.getActivePane()).toBe pane1
|
||||
expect(pane1.isActive()).toBe true
|
||||
|
||||
it "references the most pane on which ::activate was most recently called", ->
|
||||
it "returns the most pane on which ::activate() was most recently called", ->
|
||||
pane2 = pane1.splitRight()
|
||||
pane2.activate()
|
||||
expect(container.activePane).toBe pane2
|
||||
expect(pane1.active).toBe false
|
||||
expect(pane2.active).toBe true
|
||||
expect(container.getActivePane()).toBe pane2
|
||||
expect(pane1.isActive()).toBe false
|
||||
expect(pane2.isActive()).toBe true
|
||||
pane1.activate()
|
||||
expect(container.activePane).toBe pane1
|
||||
expect(pane1.active).toBe true
|
||||
expect(pane2.active).toBe false
|
||||
expect(container.getActivePane()).toBe pane1
|
||||
expect(pane1.isActive()).toBe true
|
||||
expect(pane2.isActive()).toBe false
|
||||
|
||||
it "is reassigned to the next pane if the current active pane is destroyed", ->
|
||||
it "returns the next pane if the current active pane is destroyed", ->
|
||||
pane2 = pane1.splitRight()
|
||||
pane2.activate()
|
||||
pane2.destroy()
|
||||
expect(container.activePane).toBe pane1
|
||||
expect(pane1.active).toBe true
|
||||
expect(container.getActivePane()).toBe pane1
|
||||
expect(pane1.isActive()).toBe true
|
||||
|
||||
it "does not allow the root pane to be destroyed", ->
|
||||
pane1.destroy()
|
||||
expect(container.root).toBe pane1
|
||||
expect(pane1.isDestroyed()).toBe false
|
||||
describe "::onDidChangeActivePaneItem()", ->
|
||||
[container, pane1, pane2, observed] = []
|
||||
|
||||
beforeEach ->
|
||||
container = new PaneContainer(root: new Pane(items: [new Object, new Object]))
|
||||
container.getRoot().splitRight(items: [new Object, new Object])
|
||||
[pane1, pane2] = container.getPanes()
|
||||
|
||||
observed = []
|
||||
container.onDidChangeActivePaneItem (item) -> observed.push(item)
|
||||
|
||||
it "invokes observers when the active item of the active pane changes", ->
|
||||
pane2.activateNextItem()
|
||||
pane2.activateNextItem()
|
||||
expect(observed).toEqual [pane2.itemAtIndex(1), pane2.itemAtIndex(0)]
|
||||
|
||||
it "invokes observers when the active pane changes", ->
|
||||
pane1.activate()
|
||||
pane2.activate()
|
||||
expect(observed).toEqual [pane1.itemAtIndex(0), pane2.itemAtIndex(0)]
|
||||
|
||||
describe "::observePanes()", ->
|
||||
it "invokes observers with all current and future panes", ->
|
||||
container = new PaneContainer
|
||||
container.getRoot().splitRight()
|
||||
[pane1, pane2] = container.getPanes()
|
||||
|
||||
observed = []
|
||||
container.observePanes (pane) -> observed.push(pane)
|
||||
|
||||
pane3 = pane2.splitDown()
|
||||
pane4 = pane2.splitRight()
|
||||
|
||||
expect(observed).toEqual [pane1, pane2, pane3, pane4]
|
||||
|
||||
describe "::observePaneItems()", ->
|
||||
it "invokes observers with all current and future pane items", ->
|
||||
container = new PaneContainer(root: new Pane(items: [new Object, new Object]))
|
||||
container.getRoot().splitRight(items: [new Object])
|
||||
[pane1, pane2] = container.getPanes()
|
||||
observed = []
|
||||
container.observePaneItems (pane) -> observed.push(pane)
|
||||
|
||||
pane3 = pane2.splitDown(items: [new Object])
|
||||
pane3.addItems([new Object, new Object])
|
||||
|
||||
expect(observed).toEqual container.getPaneItems()
|
||||
|
||||
@@ -21,39 +21,83 @@ describe "Pane", ->
|
||||
describe "construction", ->
|
||||
it "sets the active item to the first item", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B")])
|
||||
expect(pane.activeItem).toBe pane.items[0]
|
||||
expect(pane.getActiveItem()).toBe pane.itemAtIndex(0)
|
||||
|
||||
it "compacts the items array", ->
|
||||
pane = new Pane(items: [undefined, new Item("A"), null, new Item("B")])
|
||||
expect(pane.items.length).toBe 2
|
||||
expect(pane.activeItem).toBe pane.items[0]
|
||||
expect(pane.getItems().length).toBe 2
|
||||
expect(pane.getActiveItem()).toBe pane.itemAtIndex(0)
|
||||
|
||||
describe "::activate()", ->
|
||||
[container, pane1, pane2] = []
|
||||
|
||||
beforeEach ->
|
||||
container = new PaneContainer(root: new Pane)
|
||||
container.getRoot().splitRight()
|
||||
[pane1, pane2] = container.getPanes()
|
||||
|
||||
it "changes the active pane on the container", ->
|
||||
expect(container.getActivePane()).toBe pane2
|
||||
pane1.activate()
|
||||
expect(container.getActivePane()).toBe pane1
|
||||
pane2.activate()
|
||||
expect(container.getActivePane()).toBe pane2
|
||||
|
||||
it "invokes ::onDidChangeActivePane observers on the container", ->
|
||||
observed = []
|
||||
container.onDidChangeActivePane (activePane) -> observed.push(activePane)
|
||||
|
||||
pane1.activate()
|
||||
pane1.activate()
|
||||
pane2.activate()
|
||||
pane1.activate()
|
||||
expect(observed).toEqual [pane1, pane2, pane1]
|
||||
|
||||
it "invokes ::onDidChangeActive observers on the relevant panes", ->
|
||||
observed = []
|
||||
pane1.onDidChangeActive (active) -> observed.push(active)
|
||||
pane1.activate()
|
||||
pane2.activate()
|
||||
expect(observed).toEqual [true, false]
|
||||
|
||||
it "invokes ::onDidActivate() observers", ->
|
||||
eventCount = 0
|
||||
pane1.onDidActivate -> eventCount++
|
||||
pane1.activate()
|
||||
pane1.activate()
|
||||
pane2.activate()
|
||||
expect(eventCount).toBe 2
|
||||
|
||||
describe "::addItem(item, index)", ->
|
||||
it "adds the item at the given index", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B")])
|
||||
[item1, item2] = pane.items
|
||||
[item1, item2] = pane.getItems()
|
||||
item3 = new Item("C")
|
||||
pane.addItem(item3, 1)
|
||||
expect(pane.items).toEqual [item1, item3, item2]
|
||||
expect(pane.getItems()).toEqual [item1, item3, item2]
|
||||
|
||||
it "adds the item after the active item ", ->
|
||||
it "adds the item after the active item if no index is provided", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
|
||||
[item1, item2, item3] = pane.items
|
||||
[item1, item2, item3] = pane.getItems()
|
||||
pane.activateItem(item2)
|
||||
item4 = new Item("D")
|
||||
pane.addItem(item4)
|
||||
expect(pane.items).toEqual [item1, item2, item4, item3]
|
||||
expect(pane.getItems()).toEqual [item1, item2, item4, item3]
|
||||
|
||||
it "sets the active item after adding the first item", ->
|
||||
pane = new Pane
|
||||
item = new Item("A")
|
||||
events = []
|
||||
pane.on 'item-added', -> events.push('item-added')
|
||||
pane.$activeItem.changes.onValue -> events.push('active-item-changed')
|
||||
|
||||
pane.addItem(item)
|
||||
expect(pane.activeItem).toBe item
|
||||
expect(events).toEqual ['item-added', 'active-item-changed']
|
||||
expect(pane.getActiveItem()).toBe item
|
||||
|
||||
it "invokes ::onDidAddItem() observers", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B")])
|
||||
events = []
|
||||
pane.onDidAddItem (event) -> events.push(event)
|
||||
|
||||
item = new Item("C")
|
||||
pane.addItem(item, 1)
|
||||
expect(events).toEqual [{item, index: 1}]
|
||||
|
||||
describe "::activateItem(item)", ->
|
||||
pane = null
|
||||
@@ -62,83 +106,102 @@ describe "Pane", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B")])
|
||||
|
||||
it "changes the active item to the current item", ->
|
||||
expect(pane.activeItem).toBe pane.items[0]
|
||||
pane.activateItem(pane.items[1])
|
||||
expect(pane.activeItem).toBe pane.items[1]
|
||||
expect(pane.getActiveItem()).toBe pane.itemAtIndex(0)
|
||||
pane.activateItem(pane.itemAtIndex(1))
|
||||
expect(pane.getActiveItem()).toBe pane.itemAtIndex(1)
|
||||
|
||||
it "adds the given item if it isn't present in ::items", ->
|
||||
item = new Item("C")
|
||||
pane.activateItem(item)
|
||||
expect(item in pane.items).toBe true
|
||||
expect(pane.activeItem).toBe item
|
||||
expect(item in pane.getItems()).toBe true
|
||||
expect(pane.getActiveItem()).toBe item
|
||||
|
||||
it "invokes ::onDidChangeActiveItem() observers", ->
|
||||
observed = []
|
||||
pane.onDidChangeActiveItem (item) -> observed.push(item)
|
||||
pane.activateItem(pane.itemAtIndex(1))
|
||||
expect(observed).toEqual [pane.itemAtIndex(1)]
|
||||
|
||||
describe "::activateNextItem() and ::activatePreviousItem()", ->
|
||||
it "sets the active item to the next/previous item, looping around at either end", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
|
||||
[item1, item2, item3] = pane.items
|
||||
[item1, item2, item3] = pane.getItems()
|
||||
|
||||
expect(pane.activeItem).toBe item1
|
||||
expect(pane.getActiveItem()).toBe item1
|
||||
pane.activatePreviousItem()
|
||||
expect(pane.activeItem).toBe item3
|
||||
expect(pane.getActiveItem()).toBe item3
|
||||
pane.activatePreviousItem()
|
||||
expect(pane.activeItem).toBe item2
|
||||
expect(pane.getActiveItem()).toBe item2
|
||||
pane.activateNextItem()
|
||||
expect(pane.activeItem).toBe item3
|
||||
expect(pane.getActiveItem()).toBe item3
|
||||
pane.activateNextItem()
|
||||
expect(pane.activeItem).toBe item1
|
||||
expect(pane.getActiveItem()).toBe item1
|
||||
|
||||
describe "::activateItemAtIndex(index)", ->
|
||||
it "activates the item at the given index", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
|
||||
[item1, item2, item3] = pane.items
|
||||
[item1, item2, item3] = pane.getItems()
|
||||
pane.activateItemAtIndex(2)
|
||||
expect(pane.activeItem).toBe item3
|
||||
expect(pane.getActiveItem()).toBe item3
|
||||
pane.activateItemAtIndex(1)
|
||||
expect(pane.activeItem).toBe item2
|
||||
expect(pane.getActiveItem()).toBe item2
|
||||
pane.activateItemAtIndex(0)
|
||||
expect(pane.activeItem).toBe item1
|
||||
expect(pane.getActiveItem()).toBe item1
|
||||
|
||||
# Doesn't fail with out-of-bounds indices
|
||||
pane.activateItemAtIndex(100)
|
||||
expect(pane.activeItem).toBe item1
|
||||
expect(pane.getActiveItem()).toBe item1
|
||||
pane.activateItemAtIndex(-1)
|
||||
expect(pane.activeItem).toBe item1
|
||||
expect(pane.getActiveItem()).toBe item1
|
||||
|
||||
describe "::destroyItem(item)", ->
|
||||
[pane, item1, item2, item3] = []
|
||||
|
||||
beforeEach ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
|
||||
[item1, item2, item3] = pane.items
|
||||
[item1, item2, item3] = pane.getItems()
|
||||
|
||||
it "removes the item from the items list", ->
|
||||
expect(pane.activeItem).toBe item1
|
||||
it "removes the item from the items list and destroyes it", ->
|
||||
expect(pane.getActiveItem()).toBe item1
|
||||
pane.destroyItem(item2)
|
||||
expect(item2 in pane.items).toBe false
|
||||
expect(pane.activeItem).toBe item1
|
||||
expect(item2 in pane.getItems()).toBe false
|
||||
expect(item2.isDestroyed()).toBe true
|
||||
expect(pane.getActiveItem()).toBe item1
|
||||
|
||||
pane.destroyItem(item1)
|
||||
expect(item1 in pane.items).toBe false
|
||||
expect(item1 in pane.getItems()).toBe false
|
||||
expect(item1.isDestroyed()).toBe true
|
||||
|
||||
it "invokes ::onWillDestroyItem() observers before destroying the item", ->
|
||||
events = []
|
||||
pane.onWillDestroyItem (event) ->
|
||||
expect(item2.isDestroyed()).toBe false
|
||||
events.push(event)
|
||||
|
||||
pane.destroyItem(item2)
|
||||
expect(item2.isDestroyed()).toBe true
|
||||
expect(events).toEqual [{item: item2, index: 1}]
|
||||
|
||||
it "invokes ::onDidRemoveItem() observers", ->
|
||||
events = []
|
||||
pane.onDidRemoveItem (event) -> events.push(event)
|
||||
pane.destroyItem(item2)
|
||||
expect(events).toEqual [{item: item2, index: 1, destroyed: true}]
|
||||
|
||||
describe "when the destroyed item is the active item and is the first item", ->
|
||||
it "activates the next item", ->
|
||||
expect(pane.activeItem).toBe item1
|
||||
expect(pane.getActiveItem()).toBe item1
|
||||
pane.destroyItem(item1)
|
||||
expect(pane.activeItem).toBe item2
|
||||
expect(pane.getActiveItem()).toBe item2
|
||||
|
||||
describe "when the destroyed item is the active item and is not the first item", ->
|
||||
beforeEach ->
|
||||
pane.activateItem(item2)
|
||||
|
||||
it "activates the previous item", ->
|
||||
expect(pane.activeItem).toBe item2
|
||||
expect(pane.getActiveItem()).toBe item2
|
||||
pane.destroyItem(item2)
|
||||
expect(pane.activeItem).toBe item1
|
||||
|
||||
it "emits 'item-removed' with the item, its index, and true indicating the item is being destroyed", ->
|
||||
pane.on 'item-removed', itemRemovedHandler = jasmine.createSpy("itemRemovedHandler")
|
||||
pane.destroyItem(item2)
|
||||
expect(itemRemovedHandler).toHaveBeenCalledWith(item2, 1, true)
|
||||
expect(pane.getActiveItem()).toBe item1
|
||||
|
||||
describe "if the item is modified", ->
|
||||
itemUri = null
|
||||
@@ -157,7 +220,7 @@ describe "Pane", ->
|
||||
pane.destroyItem(item1)
|
||||
|
||||
expect(item1.save).toHaveBeenCalled()
|
||||
expect(item1 in pane.items).toBe false
|
||||
expect(item1 in pane.getItems()).toBe false
|
||||
expect(item1.isDestroyed()).toBe true
|
||||
|
||||
describe "when the item has no uri", ->
|
||||
@@ -170,7 +233,7 @@ describe "Pane", ->
|
||||
|
||||
expect(atom.showSaveDialogSync).toHaveBeenCalled()
|
||||
expect(item1.saveAs).toHaveBeenCalledWith("/selected/path")
|
||||
expect(item1 in pane.items).toBe false
|
||||
expect(item1 in pane.getItems()).toBe false
|
||||
expect(item1.isDestroyed()).toBe true
|
||||
|
||||
describe "if the [Don't Save] option is selected", ->
|
||||
@@ -179,7 +242,7 @@ describe "Pane", ->
|
||||
pane.destroyItem(item1)
|
||||
|
||||
expect(item1.save).not.toHaveBeenCalled()
|
||||
expect(item1 in pane.items).toBe false
|
||||
expect(item1 in pane.getItems()).toBe false
|
||||
expect(item1.isDestroyed()).toBe true
|
||||
|
||||
describe "if the [Cancel] option is selected", ->
|
||||
@@ -188,7 +251,7 @@ describe "Pane", ->
|
||||
pane.destroyItem(item1)
|
||||
|
||||
expect(item1.save).not.toHaveBeenCalled()
|
||||
expect(item1 in pane.items).toBe true
|
||||
expect(item1 in pane.getItems()).toBe true
|
||||
expect(item1.isDestroyed()).toBe false
|
||||
|
||||
describe "when the last item is destroyed", ->
|
||||
@@ -197,7 +260,7 @@ describe "Pane", ->
|
||||
expect(atom.config.get('core.destroyEmptyPanes')).toBe false
|
||||
pane.destroyItem(item) for item in pane.getItems()
|
||||
expect(pane.isDestroyed()).toBe false
|
||||
expect(pane.activeItem).toBeUndefined()
|
||||
expect(pane.getActiveItem()).toBeUndefined()
|
||||
expect(-> pane.saveActiveItem()).not.toThrow()
|
||||
expect(-> pane.saveActiveItemAs()).not.toThrow()
|
||||
|
||||
@@ -210,10 +273,10 @@ describe "Pane", ->
|
||||
describe "::destroyActiveItem()", ->
|
||||
it "destroys the active item", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B")])
|
||||
activeItem = pane.activeItem
|
||||
activeItem = pane.getActiveItem()
|
||||
pane.destroyActiveItem()
|
||||
expect(activeItem.isDestroyed()).toBe true
|
||||
expect(activeItem in pane.items).toBe false
|
||||
expect(activeItem in pane.getItems()).toBe false
|
||||
|
||||
it "does not throw an exception if there are no more items", ->
|
||||
pane = new Pane
|
||||
@@ -222,27 +285,40 @@ describe "Pane", ->
|
||||
describe "::destroyItems()", ->
|
||||
it "destroys all items", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
|
||||
[item1, item2, item3] = pane.items
|
||||
[item1, item2, item3] = pane.getItems()
|
||||
pane.destroyItems()
|
||||
expect(item1.isDestroyed()).toBe true
|
||||
expect(item2.isDestroyed()).toBe true
|
||||
expect(item3.isDestroyed()).toBe true
|
||||
expect(pane.items).toEqual []
|
||||
expect(pane.getItems()).toEqual []
|
||||
|
||||
describe "::observeItems()", ->
|
||||
it "invokes the observer with all current and future items", ->
|
||||
pane = new Pane(items: [new Item, new Item])
|
||||
[item1, item2] = pane.getItems()
|
||||
|
||||
observed = []
|
||||
pane.observeItems (item) -> observed.push(item)
|
||||
|
||||
item3 = new Item
|
||||
pane.addItem(item3)
|
||||
|
||||
expect(observed).toEqual [item1, item2, item3]
|
||||
|
||||
describe "when an item emits a destroyed event", ->
|
||||
it "removes it from the list of items", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
|
||||
[item1, item2, item3] = pane.items
|
||||
pane.items[1].destroy()
|
||||
expect(pane.items).toEqual [item1, item3]
|
||||
[item1, item2, item3] = pane.getItems()
|
||||
pane.itemAtIndex(1).destroy()
|
||||
expect(pane.getItems()).toEqual [item1, item3]
|
||||
|
||||
describe "::destroyInactiveItems()", ->
|
||||
it "destroys all items but the active item", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
|
||||
[item1, item2, item3] = pane.items
|
||||
[item1, item2, item3] = pane.getItems()
|
||||
pane.activateItem(item2)
|
||||
pane.destroyInactiveItems()
|
||||
expect(pane.items).toEqual [item2]
|
||||
expect(pane.getItems()).toEqual [item2]
|
||||
|
||||
describe "::saveActiveItem()", ->
|
||||
pane = null
|
||||
@@ -253,30 +329,30 @@ describe "Pane", ->
|
||||
|
||||
describe "when the active item has a uri", ->
|
||||
beforeEach ->
|
||||
pane.activeItem.uri = "test"
|
||||
pane.getActiveItem().uri = "test"
|
||||
|
||||
describe "when the active item has a save method", ->
|
||||
it "saves the current item", ->
|
||||
pane.activeItem.save = jasmine.createSpy("save")
|
||||
pane.getActiveItem().save = jasmine.createSpy("save")
|
||||
pane.saveActiveItem()
|
||||
expect(pane.activeItem.save).toHaveBeenCalled()
|
||||
expect(pane.getActiveItem().save).toHaveBeenCalled()
|
||||
|
||||
describe "when the current item has no save method", ->
|
||||
it "does nothing", ->
|
||||
expect(pane.activeItem.save).toBeUndefined()
|
||||
expect(pane.getActiveItem().save).toBeUndefined()
|
||||
pane.saveActiveItem()
|
||||
|
||||
describe "when the current item has no uri", ->
|
||||
describe "when the current item has a saveAs method", ->
|
||||
it "opens a save dialog and saves the current item as the selected path", ->
|
||||
pane.activeItem.saveAs = jasmine.createSpy("saveAs")
|
||||
pane.getActiveItem().saveAs = jasmine.createSpy("saveAs")
|
||||
pane.saveActiveItem()
|
||||
expect(atom.showSaveDialogSync).toHaveBeenCalled()
|
||||
expect(pane.activeItem.saveAs).toHaveBeenCalledWith('/selected/path')
|
||||
expect(pane.getActiveItem().saveAs).toHaveBeenCalledWith('/selected/path')
|
||||
|
||||
describe "when the current item has no saveAs method", ->
|
||||
it "does nothing", ->
|
||||
expect(pane.activeItem.saveAs).toBeUndefined()
|
||||
expect(pane.getActiveItem().saveAs).toBeUndefined()
|
||||
pane.saveActiveItem()
|
||||
expect(atom.showSaveDialogSync).not.toHaveBeenCalled()
|
||||
|
||||
@@ -289,22 +365,22 @@ describe "Pane", ->
|
||||
|
||||
describe "when the current item has a saveAs method", ->
|
||||
it "opens the save dialog and calls saveAs on the item with the selected path", ->
|
||||
pane.activeItem.path = __filename
|
||||
pane.activeItem.saveAs = jasmine.createSpy("saveAs")
|
||||
pane.getActiveItem().path = __filename
|
||||
pane.getActiveItem().saveAs = jasmine.createSpy("saveAs")
|
||||
pane.saveActiveItemAs()
|
||||
expect(atom.showSaveDialogSync).toHaveBeenCalledWith(__filename)
|
||||
expect(pane.activeItem.saveAs).toHaveBeenCalledWith('/selected/path')
|
||||
expect(pane.getActiveItem().saveAs).toHaveBeenCalledWith('/selected/path')
|
||||
|
||||
describe "when the current item does not have a saveAs method", ->
|
||||
it "does nothing", ->
|
||||
expect(pane.activeItem.saveAs).toBeUndefined()
|
||||
expect(pane.getActiveItem().saveAs).toBeUndefined()
|
||||
pane.saveActiveItemAs()
|
||||
expect(atom.showSaveDialogSync).not.toHaveBeenCalled()
|
||||
|
||||
describe "::itemForUri(uri)", ->
|
||||
it "returns the item for which a call to .getUri() returns the given uri", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C"), new Item("D")])
|
||||
[item1, item2, item3] = pane.items
|
||||
[item1, item2, item3] = pane.getItems()
|
||||
item1.uri = "a"
|
||||
item2.uri = "b"
|
||||
expect(pane.itemForUri("a")).toBe item1
|
||||
@@ -312,24 +388,32 @@ describe "Pane", ->
|
||||
expect(pane.itemForUri("bogus")).toBeUndefined()
|
||||
|
||||
describe "::moveItem(item, index)", ->
|
||||
it "moves the item to the given index and emits an 'item-moved' event with the item and its new index", ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C"), new Item("D")])
|
||||
[item1, item2, item3, item4] = pane.items
|
||||
pane.on 'item-moved', itemMovedHandler = jasmine.createSpy("itemMovedHandler")
|
||||
[pane, item1, item2, item3, item4] = []
|
||||
|
||||
beforeEach ->
|
||||
pane = new Pane(items: [new Item("A"), new Item("B"), new Item("C"), new Item("D")])
|
||||
[item1, item2, item3, item4] = pane.getItems()
|
||||
|
||||
it "moves the item to the given index and invokes ::onDidMoveItem observers", ->
|
||||
pane.moveItem(item1, 2)
|
||||
expect(pane.getItems()).toEqual [item2, item3, item1, item4]
|
||||
expect(itemMovedHandler).toHaveBeenCalledWith(item1, 2)
|
||||
itemMovedHandler.reset()
|
||||
|
||||
pane.moveItem(item2, 3)
|
||||
expect(pane.getItems()).toEqual [item3, item1, item4, item2]
|
||||
expect(itemMovedHandler).toHaveBeenCalledWith(item2, 3)
|
||||
itemMovedHandler.reset()
|
||||
|
||||
pane.moveItem(item2, 1)
|
||||
expect(pane.getItems()).toEqual [item3, item2, item1, item4]
|
||||
expect(itemMovedHandler).toHaveBeenCalledWith(item2, 1)
|
||||
|
||||
it "invokes ::onDidMoveItem() observers", ->
|
||||
events = []
|
||||
pane.onDidMoveItem (event) -> events.push(event)
|
||||
|
||||
pane.moveItem(item1, 2)
|
||||
pane.moveItem(item2, 3)
|
||||
expect(events).toEqual [
|
||||
{item: item1, oldIndex: 0, newIndex: 2}
|
||||
{item: item2, oldIndex: 0, newIndex: 3}
|
||||
]
|
||||
|
||||
describe "::moveItemToPane(item, pane, index)", ->
|
||||
[container, pane1, pane2] = []
|
||||
@@ -339,13 +423,20 @@ describe "Pane", ->
|
||||
pane1 = new Pane(items: [new Item("A"), new Item("B"), new Item("C")])
|
||||
container = new PaneContainer(root: pane1)
|
||||
pane2 = pane1.splitRight(items: [new Item("D"), new Item("E")])
|
||||
[item1, item2, item3] = pane1.items
|
||||
[item4, item5] = pane2.items
|
||||
[item1, item2, item3] = pane1.getItems()
|
||||
[item4, item5] = pane2.getItems()
|
||||
|
||||
it "moves the item to the given pane at the given index", ->
|
||||
pane1.moveItemToPane(item2, pane2, 1)
|
||||
expect(pane1.items).toEqual [item1, item3]
|
||||
expect(pane2.items).toEqual [item4, item2, item5]
|
||||
expect(pane1.getItems()).toEqual [item1, item3]
|
||||
expect(pane2.getItems()).toEqual [item4, item2, item5]
|
||||
|
||||
it "invokes ::onDidRemoveItem() observers", ->
|
||||
events = []
|
||||
pane1.onDidRemoveItem (event) -> events.push(event)
|
||||
pane1.moveItemToPane(item2, pane2, 1)
|
||||
|
||||
expect(events).toEqual [{item: item2, index: 1, destroyed: false}]
|
||||
|
||||
describe "when the moved item the last item in the source pane", ->
|
||||
beforeEach ->
|
||||
@@ -455,7 +546,7 @@ describe "Pane", ->
|
||||
pane2 = pane1.splitRight()
|
||||
|
||||
it "destroys the pane's destroyable items", ->
|
||||
[item1, item2] = pane1.items
|
||||
[item1, item2] = pane1.getItems()
|
||||
pane1.destroy()
|
||||
expect(item1.isDestroyed()).toBe true
|
||||
expect(item2.isDestroyed()).toBe true
|
||||
@@ -493,12 +584,12 @@ describe "Pane", ->
|
||||
|
||||
it "can serialize and deserialize the pane and all its items", ->
|
||||
newPane = pane.testSerialization()
|
||||
expect(newPane.items).toEqual pane.items
|
||||
expect(newPane.getItems()).toEqual pane.getItems()
|
||||
|
||||
it "restores the active item on deserialization", ->
|
||||
pane.activateItemAtIndex(1)
|
||||
newPane = pane.testSerialization()
|
||||
expect(newPane.activeItem).toEqual newPane.items[1]
|
||||
expect(newPane.getActiveItem()).toEqual newPane.itemAtIndex(1)
|
||||
|
||||
it "does not include items that cannot be deserialized", ->
|
||||
spyOn(console, 'warn')
|
||||
@@ -506,8 +597,8 @@ describe "Pane", ->
|
||||
pane.activateItem(unserializable)
|
||||
|
||||
newPane = pane.testSerialization()
|
||||
expect(newPane.activeItem).toEqual pane.items[0]
|
||||
expect(newPane.items.length).toBe pane.items.length - 1
|
||||
expect(newPane.getActiveItem()).toEqual pane.itemAtIndex(0)
|
||||
expect(newPane.getItems().length).toBe pane.getItems().length - 1
|
||||
|
||||
it "includes the pane's focus state in the serialized state", ->
|
||||
pane.focus()
|
||||
|
||||
@@ -37,7 +37,7 @@ describe "PaneView", ->
|
||||
|
||||
describe "when the active pane item changes", ->
|
||||
it "hides all item views except the active one", ->
|
||||
expect(pane.activeItem).toBe view1
|
||||
expect(pane.getActiveItem()).toBe view1
|
||||
expect(view1.css('display')).not.toBe 'none'
|
||||
|
||||
pane.activateItem(view2)
|
||||
@@ -48,7 +48,7 @@ describe "PaneView", ->
|
||||
itemChangedHandler = jasmine.createSpy("itemChangedHandler")
|
||||
container.on 'pane:active-item-changed', itemChangedHandler
|
||||
|
||||
expect(pane.activeItem).toBe view1
|
||||
expect(pane.getActiveItem()).toBe view1
|
||||
paneModel.activateItem(view2)
|
||||
paneModel.activateItem(view2)
|
||||
|
||||
@@ -149,7 +149,7 @@ describe "PaneView", ->
|
||||
activeItemTitleChangedHandler = jasmine.createSpy("activeItemTitleChangedHandler")
|
||||
pane.on 'pane:active-item-title-changed', activeItemTitleChangedHandler
|
||||
|
||||
expect(pane.activeItem).toBe view1
|
||||
expect(pane.getActiveItem()).toBe view1
|
||||
|
||||
view2.trigger 'title-changed'
|
||||
expect(activeItemTitleChangedHandler).not.toHaveBeenCalled()
|
||||
@@ -246,7 +246,7 @@ describe "PaneView", ->
|
||||
|
||||
it "transfers focus to the active view", ->
|
||||
focusHandler = jasmine.createSpy("focusHandler")
|
||||
pane.activeItem.on 'focus', focusHandler
|
||||
pane.getActiveItem().on 'focus', focusHandler
|
||||
pane.focus()
|
||||
expect(focusHandler).toHaveBeenCalled()
|
||||
|
||||
|
||||
@@ -8,8 +8,12 @@ describe "Workspace", ->
|
||||
atom.workspace = workspace = new Workspace
|
||||
|
||||
describe "::open(uri, options)", ->
|
||||
openEvents = null
|
||||
|
||||
beforeEach ->
|
||||
spyOn(workspace.activePane, 'activate').andCallThrough()
|
||||
openEvents = []
|
||||
workspace.onDidOpen (event) -> openEvents.push(event)
|
||||
spyOn(workspace.getActivePane(), 'activate').andCallThrough()
|
||||
|
||||
describe "when the 'searchAllPanes' option is false (default)", ->
|
||||
describe "when called without a uri", ->
|
||||
@@ -21,18 +25,21 @@ describe "Workspace", ->
|
||||
|
||||
runs ->
|
||||
expect(editor1.getPath()).toBeUndefined()
|
||||
expect(workspace.activePane.items).toEqual [editor1]
|
||||
expect(workspace.activePaneItem).toBe editor1
|
||||
expect(workspace.activePane.activate).toHaveBeenCalled()
|
||||
expect(workspace.getActivePane().items).toEqual [editor1]
|
||||
expect(workspace.getActivePaneItem()).toBe editor1
|
||||
expect(workspace.getActivePane().activate).toHaveBeenCalled()
|
||||
expect(openEvents).toEqual [{uri: undefined, pane: workspace.getActivePane(), item: editor1, index: 0}]
|
||||
openEvents = []
|
||||
|
||||
waitsForPromise ->
|
||||
workspace.open().then (editor) -> editor2 = editor
|
||||
|
||||
runs ->
|
||||
expect(editor2.getPath()).toBeUndefined()
|
||||
expect(workspace.activePane.items).toEqual [editor1, editor2]
|
||||
expect(workspace.activePaneItem).toBe editor2
|
||||
expect(workspace.activePane.activate).toHaveBeenCalled()
|
||||
expect(workspace.getActivePane().items).toEqual [editor1, editor2]
|
||||
expect(workspace.getActivePaneItem()).toBe editor2
|
||||
expect(workspace.getActivePane().activate).toHaveBeenCalled()
|
||||
expect(openEvents).toEqual [{uri: undefined, pane: workspace.getActivePane(), item: editor2, index: 1}]
|
||||
|
||||
describe "when called with a uri", ->
|
||||
describe "when the active pane already has an editor for the given uri", ->
|
||||
@@ -51,8 +58,29 @@ describe "Workspace", ->
|
||||
|
||||
runs ->
|
||||
expect(editor).toBe editor1
|
||||
expect(workspace.activePaneItem).toBe editor
|
||||
expect(workspace.activePane.activate).toHaveBeenCalled()
|
||||
expect(workspace.getActivePaneItem()).toBe editor
|
||||
expect(workspace.getActivePane().activate).toHaveBeenCalled()
|
||||
|
||||
expect(openEvents).toEqual [
|
||||
{
|
||||
uri: atom.project.resolve('a')
|
||||
item: editor1
|
||||
pane: atom.workspace.getActivePane()
|
||||
index: 0
|
||||
}
|
||||
{
|
||||
uri: atom.project.resolve('b')
|
||||
item: editor2
|
||||
pane: atom.workspace.getActivePane()
|
||||
index: 1
|
||||
}
|
||||
{
|
||||
uri: atom.project.resolve('a')
|
||||
item: editor1
|
||||
pane: atom.workspace.getActivePane()
|
||||
index: 0
|
||||
}
|
||||
]
|
||||
|
||||
describe "when the active pane does not have an editor for the given uri", ->
|
||||
it "adds and activates a new editor for the given path on the active pane", ->
|
||||
@@ -62,9 +90,9 @@ describe "Workspace", ->
|
||||
|
||||
runs ->
|
||||
expect(editor.getUri()).toBe atom.project.resolve('a')
|
||||
expect(workspace.activePaneItem).toBe editor
|
||||
expect(workspace.activePane.items).toEqual [editor]
|
||||
expect(workspace.activePane.activate).toHaveBeenCalled()
|
||||
expect(workspace.getActivePaneItem()).toBe editor
|
||||
expect(workspace.getActivePane().items).toEqual [editor]
|
||||
expect(workspace.getActivePane().activate).toHaveBeenCalled()
|
||||
|
||||
describe "when the 'searchAllPanes' option is true", ->
|
||||
describe "when an editor for the given uri is already open on an inactive pane", ->
|
||||
@@ -83,14 +111,14 @@ describe "Workspace", ->
|
||||
workspace.open('b').then (o) -> editor2 = o
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePaneItem).toBe editor2
|
||||
expect(workspace.getActivePaneItem()).toBe editor2
|
||||
|
||||
waitsForPromise ->
|
||||
workspace.open('a', searchAllPanes: true)
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePane).toBe pane1
|
||||
expect(workspace.activePaneItem).toBe editor1
|
||||
expect(workspace.getActivePane()).toBe pane1
|
||||
expect(workspace.getActivePaneItem()).toBe editor1
|
||||
|
||||
describe "when no editor for the given uri is open in any pane", ->
|
||||
it "opens an editor for the given uri in the active pane", ->
|
||||
@@ -99,21 +127,21 @@ describe "Workspace", ->
|
||||
workspace.open('a', searchAllPanes: true).then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePaneItem).toBe editor
|
||||
expect(workspace.getActivePaneItem()).toBe editor
|
||||
|
||||
describe "when the 'split' option is set", ->
|
||||
describe "when the 'split' option is 'left'", ->
|
||||
it "opens the editor in the leftmost pane of the current pane axis", ->
|
||||
pane1 = workspace.activePane
|
||||
pane1 = workspace.getActivePane()
|
||||
pane2 = pane1.splitRight()
|
||||
expect(workspace.activePane).toBe pane2
|
||||
expect(workspace.getActivePane()).toBe pane2
|
||||
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
workspace.open('a', split: 'left').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePane).toBe pane1
|
||||
expect(workspace.getActivePane()).toBe pane1
|
||||
expect(pane1.items).toEqual [editor]
|
||||
expect(pane2.items).toEqual []
|
||||
|
||||
@@ -123,37 +151,37 @@ describe "Workspace", ->
|
||||
workspace.open('a', split: 'left').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePane).toBe pane1
|
||||
expect(workspace.getActivePane()).toBe pane1
|
||||
expect(pane1.items).toEqual [editor]
|
||||
expect(pane2.items).toEqual []
|
||||
|
||||
describe "when a pane axis is the leftmost sibling of the current pane", ->
|
||||
it "opens the new item in the current pane", ->
|
||||
editor = null
|
||||
pane1 = workspace.activePane
|
||||
pane1 = workspace.getActivePane()
|
||||
pane2 = pane1.splitLeft()
|
||||
pane3 = pane2.splitDown()
|
||||
pane1.activate()
|
||||
expect(workspace.activePane).toBe pane1
|
||||
expect(workspace.getActivePane()).toBe pane1
|
||||
|
||||
waitsForPromise ->
|
||||
workspace.open('a', split: 'left').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePane).toBe pane1
|
||||
expect(workspace.getActivePane()).toBe pane1
|
||||
expect(pane1.items).toEqual [editor]
|
||||
|
||||
describe "when the 'split' option is 'right'", ->
|
||||
it "opens the editor in the rightmost pane of the current pane axis", ->
|
||||
editor = null
|
||||
pane1 = workspace.activePane
|
||||
pane1 = workspace.getActivePane()
|
||||
pane2 = null
|
||||
waitsForPromise ->
|
||||
workspace.open('a', split: 'right').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
pane2 = workspace.getPanes().filter((p) -> p != pane1)[0]
|
||||
expect(workspace.activePane).toBe pane2
|
||||
expect(workspace.getActivePane()).toBe pane2
|
||||
expect(pane1.items).toEqual []
|
||||
expect(pane2.items).toEqual [editor]
|
||||
|
||||
@@ -163,18 +191,18 @@ describe "Workspace", ->
|
||||
workspace.open('a', split: 'right').then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePane).toBe pane2
|
||||
expect(workspace.getActivePane()).toBe pane2
|
||||
expect(pane1.items).toEqual []
|
||||
expect(pane2.items).toEqual [editor]
|
||||
|
||||
describe "when a pane axis is the rightmost sibling of the current pane", ->
|
||||
it "opens the new item in a new pane split to the right of the current pane", ->
|
||||
editor = null
|
||||
pane1 = workspace.activePane
|
||||
pane1 = workspace.getActivePane()
|
||||
pane2 = pane1.splitRight()
|
||||
pane3 = pane2.splitDown()
|
||||
pane1.activate()
|
||||
expect(workspace.activePane).toBe pane1
|
||||
expect(workspace.getActivePane()).toBe pane1
|
||||
pane4 = null
|
||||
|
||||
waitsForPromise ->
|
||||
@@ -182,7 +210,7 @@ describe "Workspace", ->
|
||||
|
||||
runs ->
|
||||
pane4 = workspace.getPanes().filter((p) -> p != pane1)[0]
|
||||
expect(workspace.activePane).toBe pane4
|
||||
expect(workspace.getActivePane()).toBe pane4
|
||||
expect(pane4.items).toEqual [editor]
|
||||
expect(workspace.paneContainer.root.children[0]).toBe pane1
|
||||
expect(workspace.paneContainer.root.children[1]).toBe pane4
|
||||
@@ -203,21 +231,21 @@ describe "Workspace", ->
|
||||
workspace.open("bar://baz").then (item) ->
|
||||
expect(item).toEqual { bar: "bar://baz" }
|
||||
|
||||
it "emits an 'editor-created' event", ->
|
||||
it "notifies ::onDidAddTextEditor observers", ->
|
||||
absolutePath = require.resolve('./fixtures/dir/a')
|
||||
newEditorHandler = jasmine.createSpy('newEditorHandler')
|
||||
workspace.on 'editor-created', newEditorHandler
|
||||
workspace.onDidAddTextEditor newEditorHandler
|
||||
|
||||
editor = null
|
||||
waitsForPromise ->
|
||||
workspace.open(absolutePath).then (e) -> editor = e
|
||||
|
||||
runs ->
|
||||
expect(newEditorHandler).toHaveBeenCalledWith editor
|
||||
expect(newEditorHandler.argsForCall[0][0].textEditor).toBe editor
|
||||
|
||||
describe "::reopenItem()", ->
|
||||
it "opens the uri associated with the last closed pane that isn't currently open", ->
|
||||
pane = workspace.activePane
|
||||
pane = workspace.getActivePane()
|
||||
waitsForPromise ->
|
||||
workspace.open('a').then ->
|
||||
workspace.open('b').then ->
|
||||
@@ -226,44 +254,44 @@ describe "Workspace", ->
|
||||
|
||||
runs ->
|
||||
# does not reopen items with no uri
|
||||
expect(workspace.activePaneItem.getUri()).toBeUndefined()
|
||||
expect(workspace.getActivePaneItem().getUri()).toBeUndefined()
|
||||
pane.destroyActiveItem()
|
||||
|
||||
waitsForPromise ->
|
||||
workspace.reopenItem()
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePaneItem.getUri()).not.toBeUndefined()
|
||||
expect(workspace.getActivePaneItem().getUri()).not.toBeUndefined()
|
||||
|
||||
# destroy all items
|
||||
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('file1')
|
||||
expect(workspace.getActivePaneItem().getUri()).toBe atom.project.resolve('file1')
|
||||
pane.destroyActiveItem()
|
||||
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('b')
|
||||
expect(workspace.getActivePaneItem().getUri()).toBe atom.project.resolve('b')
|
||||
pane.destroyActiveItem()
|
||||
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('a')
|
||||
expect(workspace.getActivePaneItem().getUri()).toBe atom.project.resolve('a')
|
||||
pane.destroyActiveItem()
|
||||
|
||||
# reopens items with uris
|
||||
expect(workspace.activePaneItem).toBeUndefined()
|
||||
expect(workspace.getActivePaneItem()).toBeUndefined()
|
||||
|
||||
waitsForPromise ->
|
||||
workspace.reopenItem()
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('a')
|
||||
expect(workspace.getActivePaneItem().getUri()).toBe atom.project.resolve('a')
|
||||
|
||||
# does not reopen items that are already open
|
||||
waitsForPromise ->
|
||||
workspace.open('b')
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('b')
|
||||
expect(workspace.getActivePaneItem().getUri()).toBe atom.project.resolve('b')
|
||||
|
||||
waitsForPromise ->
|
||||
workspace.reopenItem()
|
||||
|
||||
runs ->
|
||||
expect(workspace.activePaneItem.getUri()).toBe atom.project.resolve('file1')
|
||||
expect(workspace.getActivePaneItem().getUri()).toBe atom.project.resolve('file1')
|
||||
|
||||
describe "::increase/decreaseFontSize()", ->
|
||||
it "increases/decreases the font size without going below 1", ->
|
||||
@@ -282,7 +310,22 @@ describe "Workspace", ->
|
||||
describe "::openLicense()", ->
|
||||
it "opens the license as plain-text in a buffer", ->
|
||||
waitsForPromise -> workspace.openLicense()
|
||||
runs -> expect(workspace.activePaneItem.getText()).toMatch /Copyright/
|
||||
runs -> expect(workspace.getActivePaneItem().getText()).toMatch /Copyright/
|
||||
|
||||
describe "::observeTextEditors()", ->
|
||||
it "invokes the observer with current and future text editors", ->
|
||||
observed = []
|
||||
|
||||
waitsForPromise -> workspace.open()
|
||||
waitsForPromise -> workspace.open()
|
||||
waitsForPromise -> workspace.openLicense()
|
||||
|
||||
runs ->
|
||||
workspace.observeTextEditors (editor) -> observed.push(editor)
|
||||
|
||||
waitsForPromise -> workspace.open()
|
||||
|
||||
expect(observed).toEqual workspace.getTextEditors()
|
||||
|
||||
describe "when an editor is destroyed", ->
|
||||
it "removes the editor", ->
|
||||
@@ -292,23 +335,9 @@ describe "Workspace", ->
|
||||
workspace.open("a").then (e) -> editor = e
|
||||
|
||||
runs ->
|
||||
expect(workspace.getEditors()).toHaveLength 1
|
||||
expect(workspace.getTextEditors()).toHaveLength 1
|
||||
editor.destroy()
|
||||
expect(workspace.getEditors()).toHaveLength 0
|
||||
|
||||
describe "when an editor is copied", ->
|
||||
it "emits an 'editor-created' event", ->
|
||||
editor = null
|
||||
handler = jasmine.createSpy('editorCreatedHandler')
|
||||
workspace.on 'editor-created', handler
|
||||
|
||||
waitsForPromise ->
|
||||
workspace.open("a").then (o) -> editor = o
|
||||
|
||||
runs ->
|
||||
expect(handler.callCount).toBe 1
|
||||
editorCopy = editor.copy()
|
||||
expect(handler.callCount).toBe 2
|
||||
expect(workspace.getTextEditors()).toHaveLength 0
|
||||
|
||||
it "stores the active grammars used by all the open editors", ->
|
||||
waitsForPromise ->
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
{CompositeDisposable} = require 'event-kit'
|
||||
{View} = require './space-pen-extensions'
|
||||
PaneView = null
|
||||
|
||||
module.exports =
|
||||
class PaneAxisView extends View
|
||||
initialize: (@model) ->
|
||||
@onChildAdded(child) for child in @model.children
|
||||
@subscribe @model.children, 'changed', @onChildrenChanged
|
||||
@subscriptions = new CompositeDisposable
|
||||
|
||||
@onChildAdded({child, index}) for child, index in @model.getChildren()
|
||||
|
||||
@subscriptions.add @model.onDidAddChild(@onChildAdded)
|
||||
@subscriptions.add @model.onDidRemoveChild(@onChildRemoved)
|
||||
@subscriptions.add @model.onDidReplaceChild(@onChildReplaced)
|
||||
|
||||
afterAttach: ->
|
||||
@container = @closest('.panes').view()
|
||||
@@ -14,19 +20,22 @@ class PaneAxisView extends View
|
||||
viewClass = model.getViewClass()
|
||||
model._view ?= new viewClass(model)
|
||||
|
||||
onChildrenChanged: ({index, removedValues, insertedValues}) =>
|
||||
onChildReplaced: ({index, oldChild, newChild}) =>
|
||||
focusedElement = document.activeElement if @hasFocus()
|
||||
@onChildRemoved(child, index) for child in removedValues
|
||||
@onChildAdded(child, index + i) for child, i in insertedValues
|
||||
@onChildRemoved({child: oldChild, index})
|
||||
@onChildAdded({child: newChild, index})
|
||||
focusedElement?.focus() if document.activeElement is document.body
|
||||
|
||||
onChildAdded: (child, index) =>
|
||||
onChildAdded: ({child, index}) =>
|
||||
view = @viewForModel(child)
|
||||
@insertAt(index, view)
|
||||
|
||||
onChildRemoved: (child) =>
|
||||
onChildRemoved: ({child}) =>
|
||||
view = @viewForModel(child)
|
||||
view.detach()
|
||||
PaneView ?= require './pane-view'
|
||||
if view instanceof PaneView and view.model.isDestroyed()
|
||||
@container?.trigger 'pane:removed', [view]
|
||||
|
||||
beforeRemove: ->
|
||||
@subscriptions.dispose()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{Model, Sequence} = require 'theorist'
|
||||
{Model} = require 'theorist'
|
||||
{Emitter, CompositeDisposable} = require 'event-kit'
|
||||
{flatten} = require 'underscore-plus'
|
||||
Serializable = require 'serializable'
|
||||
|
||||
@@ -10,18 +11,17 @@ class PaneAxis extends Model
|
||||
atom.deserializers.add(this)
|
||||
Serializable.includeInto(this)
|
||||
|
||||
parent: null
|
||||
container: null
|
||||
orientation: null
|
||||
|
||||
constructor: ({@container, @orientation, children}) ->
|
||||
@children = Sequence.fromArray(children ? [])
|
||||
|
||||
@subscribe @children.onEach (child) =>
|
||||
child.parent = this
|
||||
child.container = @container
|
||||
@subscribe child, 'destroyed', => @removeChild(child)
|
||||
|
||||
@subscribe @children.onRemoval (child) => @unsubscribe(child)
|
||||
|
||||
@when @children.$length.becomesLessThan(2), 'reparentLastChild'
|
||||
@when @children.$length.becomesLessThan(1), 'destroy'
|
||||
@emitter = new Emitter
|
||||
@subscriptionsByChild = new WeakMap
|
||||
@subscriptions = new CompositeDisposable
|
||||
@children = []
|
||||
if children?
|
||||
@addChild(child) for child in children
|
||||
|
||||
deserializeParams: (params) ->
|
||||
{container} = params
|
||||
@@ -32,35 +32,93 @@ class PaneAxis extends Model
|
||||
children: @children.map (child) -> child.serialize()
|
||||
orientation: @orientation
|
||||
|
||||
getParent: -> @parent
|
||||
|
||||
setParent: (@parent) -> @parent
|
||||
|
||||
getContainer: -> @container
|
||||
|
||||
setContainer: (@container) -> @container
|
||||
|
||||
getViewClass: ->
|
||||
if @orientation is 'vertical'
|
||||
PaneColumnView ?= require './pane-column-view'
|
||||
else
|
||||
PaneRowView ?= require './pane-row-view'
|
||||
|
||||
getChildren: -> @children.slice()
|
||||
|
||||
getPanes: ->
|
||||
flatten(@children.map (child) -> child.getPanes())
|
||||
|
||||
addChild: (child, index=@children.length) ->
|
||||
@children.splice(index, 0, child)
|
||||
getItems: ->
|
||||
flatten(@children.map (child) -> child.getItems())
|
||||
|
||||
removeChild: (child) ->
|
||||
onDidAddChild: (fn) ->
|
||||
@emitter.on 'did-add-child', fn
|
||||
|
||||
onDidRemoveChild: (fn) ->
|
||||
@emitter.on 'did-remove-child', fn
|
||||
|
||||
onDidReplaceChild: (fn) ->
|
||||
@emitter.on 'did-replace-child', fn
|
||||
|
||||
onDidDestroy: (fn) ->
|
||||
@emitter.on 'did-destroy', fn
|
||||
|
||||
addChild: (child, index=@children.length) ->
|
||||
child.setParent(this)
|
||||
child.setContainer(@container)
|
||||
|
||||
@subscribeToChild(child)
|
||||
|
||||
@children.splice(index, 0, child)
|
||||
@emitter.emit 'did-add-child', {child, index}
|
||||
|
||||
removeChild: (child, replacing=false) ->
|
||||
index = @children.indexOf(child)
|
||||
throw new Error("Removing non-existent child") if index is -1
|
||||
|
||||
@unsubscribeFromChild(child)
|
||||
|
||||
@children.splice(index, 1)
|
||||
@emitter.emit 'did-remove-child', {child, index}
|
||||
@reparentLastChild() if not replacing and @children.length < 2
|
||||
|
||||
replaceChild: (oldChild, newChild) ->
|
||||
@unsubscribeFromChild(oldChild)
|
||||
@subscribeToChild(newChild)
|
||||
|
||||
newChild.setParent(this)
|
||||
newChild.setContainer(@container)
|
||||
|
||||
index = @children.indexOf(oldChild)
|
||||
throw new Error("Replacing non-existent child") if index is -1
|
||||
@children.splice(index, 1, newChild)
|
||||
@emitter.emit 'did-replace-child', {oldChild, newChild, index}
|
||||
|
||||
insertChildBefore: (currentChild, newChild) ->
|
||||
index = @children.indexOf(currentChild)
|
||||
@children.splice(index, 0, newChild)
|
||||
@addChild(newChild, index)
|
||||
|
||||
insertChildAfter: (currentChild, newChild) ->
|
||||
index = @children.indexOf(currentChild)
|
||||
@children.splice(index + 1, 0, newChild)
|
||||
@addChild(newChild, index + 1)
|
||||
|
||||
reparentLastChild: ->
|
||||
@parent.replaceChild(this, @children[0])
|
||||
@destroy()
|
||||
|
||||
subscribeToChild: (child) ->
|
||||
subscription = child.onDidDestroy => @removeChild(child)
|
||||
@subscriptionsByChild.set(child, subscription)
|
||||
@subscriptions.add(subscription)
|
||||
|
||||
unsubscribeFromChild: (child) ->
|
||||
subscription = @subscriptionsByChild.get(child)
|
||||
@subscriptions.remove(subscription)
|
||||
subscription.dispose()
|
||||
|
||||
destroyed: ->
|
||||
@subscriptions.dispose()
|
||||
@emitter.emit 'did-destroy'
|
||||
@emitter.dispose()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{deprecate} = require 'grim'
|
||||
Delegator = require 'delegato'
|
||||
{CompositeDisposable} = require 'event-kit'
|
||||
{$, View} = require './space-pen-extensions'
|
||||
PaneView = require './pane-view'
|
||||
PaneContainer = require './pane-container'
|
||||
@@ -15,13 +16,15 @@ class PaneContainerView extends View
|
||||
@div class: 'panes'
|
||||
|
||||
initialize: (params) ->
|
||||
@subscriptions = new CompositeDisposable
|
||||
|
||||
if params instanceof PaneContainer
|
||||
@model = params
|
||||
else
|
||||
@model = new PaneContainer({root: params?.root?.model})
|
||||
|
||||
@subscribe @model.$root, @onRootChanged
|
||||
@subscribe @model.$activePaneItem.changes, @onActivePaneItemChanged
|
||||
@subscriptions.add @model.observeRoot(@onRootChanged)
|
||||
@subscriptions.add @model.onDidChangeActivePaneItem(@onActivePaneItemChanged)
|
||||
|
||||
viewForModel: (model) ->
|
||||
if model?
|
||||
@@ -88,7 +91,7 @@ class PaneContainerView extends View
|
||||
@viewForModel(@model.activePane)
|
||||
|
||||
getActivePaneItem: ->
|
||||
@model.activePaneItem
|
||||
@model.getActivePaneItem()
|
||||
|
||||
getActiveView: ->
|
||||
@getActivePaneView()?.activeView
|
||||
@@ -153,3 +156,6 @@ class PaneContainerView extends View
|
||||
getPanes: ->
|
||||
deprecate("Use PaneContainerView::getPaneViews() instead")
|
||||
@getPaneViews()
|
||||
|
||||
beforeRemove: ->
|
||||
@subscriptions.dispose()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{find} = require 'underscore-plus'
|
||||
{find, flatten} = require 'underscore-plus'
|
||||
{Model} = require 'theorist'
|
||||
{Emitter, CompositeDisposable} = require 'event-kit'
|
||||
Serializable = require 'serializable'
|
||||
Pane = require './pane'
|
||||
|
||||
@@ -11,10 +12,9 @@ class PaneContainer extends Model
|
||||
@version: 1
|
||||
|
||||
@properties
|
||||
root: -> new Pane
|
||||
activePane: null
|
||||
|
||||
previousRoot: null
|
||||
root: null
|
||||
|
||||
@behavior 'activePaneItem', ->
|
||||
@$activePane
|
||||
@@ -23,9 +23,16 @@ class PaneContainer extends Model
|
||||
|
||||
constructor: (params) ->
|
||||
super
|
||||
@subscribe @$root, @onRootChanged
|
||||
|
||||
@emitter = new Emitter
|
||||
@subscriptions = new CompositeDisposable
|
||||
|
||||
@setRoot(params?.root ? new Pane)
|
||||
@destroyEmptyPanes() if params?.destroyEmptyPanes
|
||||
|
||||
@monitorActivePaneItem()
|
||||
@monitorPaneItems()
|
||||
|
||||
deserializeParams: (params) ->
|
||||
params.root = atom.deserializers.deserialize(params.root, container: this)
|
||||
params.destroyEmptyPanes = atom.config.get('core.destroyEmptyPanes')
|
||||
@@ -36,16 +43,75 @@ class PaneContainer extends Model
|
||||
root: @root?.serialize()
|
||||
activePaneId: @activePane.id
|
||||
|
||||
onDidChangeRoot: (fn) ->
|
||||
@emitter.on 'did-change-root', fn
|
||||
|
||||
observeRoot: (fn) ->
|
||||
fn(@getRoot())
|
||||
@onDidChangeRoot(fn)
|
||||
|
||||
onDidAddPane: (fn) ->
|
||||
@emitter.on 'did-add-pane', fn
|
||||
|
||||
observePanes: (fn) ->
|
||||
fn(pane) for pane in @getPanes()
|
||||
@onDidAddPane ({pane}) -> fn(pane)
|
||||
|
||||
onDidChangeActivePane: (fn) ->
|
||||
@emitter.on 'did-change-active-pane', fn
|
||||
|
||||
observeActivePane: (fn) ->
|
||||
fn(@getActivePane())
|
||||
@onDidChangeActivePane(fn)
|
||||
|
||||
onDidAddPaneItem: (fn) ->
|
||||
@emitter.on 'did-add-pane-item', fn
|
||||
|
||||
observePaneItems: (fn) ->
|
||||
fn(item) for item in @getPaneItems()
|
||||
@onDidAddPaneItem ({item}) -> fn(item)
|
||||
|
||||
onDidChangeActivePaneItem: (fn) ->
|
||||
@emitter.on 'did-change-active-pane-item', fn
|
||||
|
||||
observeActivePaneItem: (fn) ->
|
||||
fn(@getActivePaneItem())
|
||||
@onDidChangeActivePaneItem(fn)
|
||||
|
||||
onDidDestroyPaneItem: (fn) ->
|
||||
@emitter.on 'did-destroy-pane-item', fn
|
||||
|
||||
getRoot: -> @root
|
||||
|
||||
setRoot: (@root) ->
|
||||
@root.setParent(this)
|
||||
@root.setContainer(this)
|
||||
@emitter.emit 'did-change-root', @root
|
||||
if not @getActivePane()? and @root instanceof Pane
|
||||
@setActivePane(@root)
|
||||
|
||||
replaceChild: (oldChild, newChild) ->
|
||||
throw new Error("Replacing non-existent child") if oldChild isnt @root
|
||||
@root = newChild
|
||||
@setRoot(newChild)
|
||||
|
||||
getPanes: ->
|
||||
@root?.getPanes() ? []
|
||||
@getRoot().getPanes()
|
||||
|
||||
getPaneItems: ->
|
||||
@getRoot().getItems()
|
||||
|
||||
getActivePane: ->
|
||||
@activePane
|
||||
|
||||
setActivePane: (activePane) ->
|
||||
if activePane isnt @activePane
|
||||
@activePane = activePane
|
||||
@emitter.emit 'did-change-active-pane', @activePane
|
||||
@activePane
|
||||
|
||||
getActivePaneItem: ->
|
||||
@getActivePane().getActiveItem()
|
||||
|
||||
paneForUri: (uri) ->
|
||||
find @getPanes(), (pane) -> pane.itemForUri(uri)?
|
||||
|
||||
@@ -73,26 +139,37 @@ class PaneContainer extends Model
|
||||
else
|
||||
false
|
||||
|
||||
onRootChanged: (root) =>
|
||||
@unsubscribe(@previousRoot) if @previousRoot?
|
||||
@previousRoot = root
|
||||
|
||||
unless root?
|
||||
@activePane = null
|
||||
return
|
||||
|
||||
root.parent = this
|
||||
root.container = this
|
||||
|
||||
|
||||
@activePane ?= root if root instanceof Pane
|
||||
|
||||
destroyEmptyPanes: ->
|
||||
pane.destroy() for pane in @getPanes() when pane.items.length is 0
|
||||
|
||||
itemDestroyed: (item) ->
|
||||
@emit 'item-destroyed', item
|
||||
paneItemDestroyed: (item) ->
|
||||
@emitter.emit 'did-destroy-pane-item', item
|
||||
|
||||
didAddPane: (pane) ->
|
||||
@emitter.emit 'did-add-pane', pane
|
||||
|
||||
# Called by Model superclass when destroyed
|
||||
destroyed: ->
|
||||
pane.destroy() for pane in @getPanes()
|
||||
@subscriptions.dispose()
|
||||
@emitter.dispose()
|
||||
|
||||
monitorActivePaneItem: ->
|
||||
childSubscription = null
|
||||
@subscriptions.add @observeActivePane (activePane) =>
|
||||
if childSubscription?
|
||||
@subscriptions.remove(childSubscription)
|
||||
childSubscription.dispose()
|
||||
|
||||
childSubscription = activePane.observeActiveItem (activeItem) =>
|
||||
@emitter.emit 'did-change-active-pane-item', activeItem
|
||||
|
||||
@subscriptions.add(childSubscription)
|
||||
|
||||
monitorPaneItems: ->
|
||||
@subscriptions.add @observePanes (pane) =>
|
||||
for item, index in pane.getItems()
|
||||
@emitter.emit 'did-add-pane-item', {item, pane, index}
|
||||
|
||||
pane.onDidAddItem ({item, index}) =>
|
||||
@emitter.emit 'did-add-pane-item', {item, pane, index}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{$, View} = require './space-pen-extensions'
|
||||
Delegator = require 'delegato'
|
||||
{deprecate} = require 'grim'
|
||||
{CompositeDisposable} = require 'event-kit'
|
||||
PropertyAccessors = require 'property-accessors'
|
||||
|
||||
Pane = require './pane'
|
||||
@@ -33,6 +34,8 @@ class PaneView extends View
|
||||
previousActiveItem: null
|
||||
|
||||
initialize: (args...) ->
|
||||
@subscriptions = new CompositeDisposable
|
||||
|
||||
if args[0] instanceof Pane
|
||||
@model = args[0]
|
||||
else
|
||||
@@ -44,13 +47,13 @@ class PaneView extends View
|
||||
@handleEvents()
|
||||
|
||||
handleEvents: ->
|
||||
@subscribe @model.$activeItem, @onActiveItemChanged
|
||||
@subscribe @model, 'item-added', @onItemAdded
|
||||
@subscribe @model, 'item-removed', @onItemRemoved
|
||||
@subscribe @model, 'item-moved', @onItemMoved
|
||||
@subscribe @model, 'before-item-destroyed', @onBeforeItemDestroyed
|
||||
@subscribe @model, 'activated', @onActivated
|
||||
@subscribe @model.$active, @onActiveStatusChanged
|
||||
@subscriptions.add @model.observeActiveItem(@onActiveItemChanged)
|
||||
@subscriptions.add @model.onDidAddItem(@onItemAdded)
|
||||
@subscriptions.add @model.onDidRemoveItem(@onItemRemoved)
|
||||
@subscriptions.add @model.onDidMoveItem(@onItemMoved)
|
||||
@subscriptions.add @model.onWillDestroyItem(@onBeforeItemDestroyed)
|
||||
@subscriptions.add @model.onDidActivate(@onActivated)
|
||||
@subscriptions.add @model.observeActive(@onActiveStatusChanged)
|
||||
|
||||
@subscribe this, 'focusin', => @model.focus()
|
||||
@subscribe this, 'focusout', => @model.blur()
|
||||
@@ -160,10 +163,10 @@ class PaneView extends View
|
||||
|
||||
@trigger 'pane:active-item-changed', [item]
|
||||
|
||||
onItemAdded: (item, index) =>
|
||||
onItemAdded: ({item, index}) =>
|
||||
@trigger 'pane:item-added', [item, index]
|
||||
|
||||
onItemRemoved: (item, index, destroyed) =>
|
||||
onItemRemoved: ({item, index, destroyed}) =>
|
||||
if item instanceof $
|
||||
viewToRemove = item
|
||||
else if viewToRemove = @viewsByItem.get(item)
|
||||
@@ -177,7 +180,7 @@ class PaneView extends View
|
||||
|
||||
@trigger 'pane:item-removed', [item, index]
|
||||
|
||||
onItemMoved: (item, newIndex) =>
|
||||
onItemMoved: ({item, newIndex}) =>
|
||||
@trigger 'pane:item-moved', [item, newIndex]
|
||||
|
||||
onBeforeItemDestroyed: (item) =>
|
||||
@@ -219,6 +222,7 @@ class PaneView extends View
|
||||
@closest('.panes').view()
|
||||
|
||||
beforeRemove: ->
|
||||
@subscriptions.dispose()
|
||||
@model.destroy() unless @model.isDestroyed()
|
||||
|
||||
remove: (selector, keepData) ->
|
||||
|
||||
446
src/pane.coffee
446
src/pane.coffee
@@ -1,47 +1,16 @@
|
||||
{find, compact, extend, last} = require 'underscore-plus'
|
||||
{Model, Sequence} = require 'theorist'
|
||||
{Model} = require 'theorist'
|
||||
{Emitter} = require 'event-kit'
|
||||
Serializable = require 'serializable'
|
||||
Grim = require 'grim'
|
||||
PaneAxis = require './pane-axis'
|
||||
Editor = require './editor'
|
||||
PaneView = null
|
||||
|
||||
# Extended: A container for multiple items, one of which is *active* at a given
|
||||
# time. With the default packages, a tab is displayed for each item and the
|
||||
# active item's view is displayed.
|
||||
#
|
||||
# ## Events
|
||||
# ### activated
|
||||
#
|
||||
# Extended: Emit when this pane as been activated
|
||||
#
|
||||
# ### item-added
|
||||
#
|
||||
# Extended: Emit when an item was added to the pane
|
||||
#
|
||||
# * `item` The pane item that has been added
|
||||
# * `index` {Number} Index in the pane
|
||||
#
|
||||
# ### before-item-destroyed
|
||||
#
|
||||
# Extended: Emit before the item is destroyed
|
||||
#
|
||||
# * `item` The pane item that will be destoryed
|
||||
#
|
||||
# ### item-removed
|
||||
#
|
||||
# Extended: Emit when the item was removed from the pane
|
||||
#
|
||||
# * `item` The pane item that was removed
|
||||
# * `index` {Number} Index in the pane
|
||||
# * `destroying` {Boolean} `true` when the item is being removed because of destruction
|
||||
#
|
||||
# ### item-moved
|
||||
#
|
||||
# Extended: Emit when an item was moved within the pane
|
||||
#
|
||||
# * `item` The pane item that was moved
|
||||
# * `newIndex` {Number} Index that the item was moved to
|
||||
#
|
||||
# Extended: A container for presenting content in the center of the workspace.
|
||||
# Panes can contain multiple items, one of which is *active* at a given time.
|
||||
# The view corresponding to the active item is displayed in the interface. In
|
||||
# the default configuration, tabs are also displayed for each item.
|
||||
module.exports =
|
||||
class Pane extends Model
|
||||
atom.deserializers.add(this)
|
||||
@@ -64,15 +33,11 @@ class Pane extends Model
|
||||
constructor: (params) ->
|
||||
super
|
||||
|
||||
@items = Sequence.fromArray(compact(params?.items ? []))
|
||||
@activeItem ?= @items[0]
|
||||
@emitter = new Emitter
|
||||
@items = []
|
||||
|
||||
@subscribe @items.onEach (item) =>
|
||||
if typeof item.on is 'function'
|
||||
@subscribe item, 'destroyed', => @removeItem(item, true)
|
||||
|
||||
@subscribe @items.onRemoval (item, index) =>
|
||||
@unsubscribe item if typeof item.on is 'function'
|
||||
@addItems(compact(params?.items ? []))
|
||||
@setActiveItem(@items[0]) unless @getActiveItem()?
|
||||
|
||||
# Called by the Serializable mixin during serialization.
|
||||
serializeParams: ->
|
||||
@@ -91,7 +56,174 @@ class Pane extends Model
|
||||
# Called by the view layer to construct a view for this model.
|
||||
getViewClass: -> PaneView ?= require './pane-view'
|
||||
|
||||
isActive: -> @active
|
||||
getParent: -> @parent
|
||||
|
||||
setParent: (@parent) -> @parent
|
||||
|
||||
getContainer: -> @container
|
||||
|
||||
setContainer: (container) ->
|
||||
container.didAddPane({pane: this}) unless container is @container
|
||||
@container = container
|
||||
|
||||
###
|
||||
Section: Event Subscription
|
||||
###
|
||||
|
||||
# Public: Invoke the given callback when the pane is activated.
|
||||
#
|
||||
# The given callback will be invoked whenever {::activate} is called on the
|
||||
# pane, even if it is already active at the time.
|
||||
#
|
||||
# * `callback` {Function} to be called when the pane is activated.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
onDidActivate: (callback) ->
|
||||
@emitter.on 'did-activate', callback
|
||||
|
||||
# Public: Invoke the given callback when the pane is destroyed.
|
||||
#
|
||||
# * `callback` {Function} to be called when the pane is destroyed.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
onDidDestroy: (callback) ->
|
||||
@emitter.on 'did-destroy', callback
|
||||
|
||||
# Public: Invoke the given callback when the value of the {::isActive}
|
||||
# property changes.
|
||||
#
|
||||
# * `callback` {Function} to be called when the value of the {::isActive}
|
||||
# property changes.
|
||||
# * `active` {Boolean} indicating whether the pane is active.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
onDidChangeActive: (callback) ->
|
||||
@container.onDidChangeActivePane (activePane) =>
|
||||
callback(this is activePane)
|
||||
|
||||
# Public: Invoke the given callback with the current and future values of the
|
||||
# {::isActive} property.
|
||||
#
|
||||
# * `callback` {Function} to be called with the current and future values of
|
||||
# the {::isActive} property.
|
||||
# * `active` {Boolean} indicating whether the pane is active.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
observeActive: (callback) ->
|
||||
callback(@isActive())
|
||||
@onDidChangeActive(callback)
|
||||
|
||||
# Public: Invoke the given callback when an item is added to the pane.
|
||||
#
|
||||
# * `callback` {Function} to be called with when items are added.
|
||||
# * `event` {Object} with the following keys:
|
||||
# * `item` The added pane item.
|
||||
# * `index` {Number} indicating where the item is located.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
onDidAddItem: (callback) ->
|
||||
@emitter.on 'did-add-item', callback
|
||||
|
||||
# Public: Invoke the given callback when an item is removed from the pane.
|
||||
#
|
||||
# * `callback` {Function} to be called with when items are removed.
|
||||
# * `event` {Object} with the following keys:
|
||||
# * `item` The removed pane item.
|
||||
# * `index` {Number} indicating where the item was located.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
onDidRemoveItem: (callback) ->
|
||||
@emitter.on 'did-remove-item', callback
|
||||
|
||||
# Public: Invoke the given callback when an item is moved within the pane.
|
||||
#
|
||||
# * `callback` {Function} to be called with when items are moved.
|
||||
# * `event` {Object} with the following keys:
|
||||
# * `item` The removed pane item.
|
||||
# * `oldIndex` {Number} indicating where the item was located.
|
||||
# * `newIndex` {Number} indicating where the item is now located.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
onDidMoveItem: (callback) ->
|
||||
@emitter.on 'did-move-item', callback
|
||||
|
||||
# Public: Invoke the given callback with all current and future items.
|
||||
#
|
||||
# * `callback` {Function} to be called with current and future items.
|
||||
# * `item` An item that is present in {::getItems} at the time of
|
||||
# subscription or that is added at some later time.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
observeItems: (callback) ->
|
||||
callback(item) for item in @getItems()
|
||||
@onDidAddItem ({item}) -> callback(item)
|
||||
|
||||
# Public: Invoke the given callback when the value of {::getActiveItem}
|
||||
# changes.
|
||||
#
|
||||
# * `callback` {Function} to be called with when the active item changes.
|
||||
# * `activeItem` The current active item.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
onDidChangeActiveItem: (callback) ->
|
||||
@emitter.on 'did-change-active-item', callback
|
||||
|
||||
# Public: Invoke the given callback with the current and future values of
|
||||
# {::getActiveItem}.
|
||||
#
|
||||
# * `callback` {Function} to be called with the current and future active
|
||||
# items.
|
||||
# * `activeItem` The current active item.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
observeActiveItem: (callback) ->
|
||||
callback(@getActiveItem())
|
||||
@onDidChangeActiveItem(callback)
|
||||
|
||||
# Public: Invoke the given callback before items are destroyed.
|
||||
#
|
||||
# * `callback` {Function} to be called before items are destroyed.
|
||||
# * `event` {Object} with the following keys:
|
||||
# * `item` The item that will be destroyed.
|
||||
# * `index` The location of the item.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to
|
||||
# unsubscribe.
|
||||
onWillDestroyItem: (callback) ->
|
||||
@emitter.on 'will-destroy-item', callback
|
||||
|
||||
on: (eventName) ->
|
||||
switch eventName
|
||||
when 'activated'
|
||||
Grim.deprecate("Use Pane::onDidActivate instead")
|
||||
when 'destroyed'
|
||||
Grim.deprecate("Use Pane::onDidDestroy instead")
|
||||
when 'item-added'
|
||||
Grim.deprecate("Use Pane::onDidAddItem instead")
|
||||
when 'item-removed'
|
||||
Grim.deprecate("Use Pane::onDidRemoveItem instead")
|
||||
when 'item-moved'
|
||||
Grim.deprecate("Use Pane::onDidMoveItem instead")
|
||||
when 'before-item-destroyed'
|
||||
Grim.deprecate("Use Pane::onWillDestroyItem instead")
|
||||
else
|
||||
Grim.deprecate("Subscribing via ::on is deprecated. Use documented event subscription methods instead.")
|
||||
super
|
||||
|
||||
behavior: (behaviorName) ->
|
||||
switch behaviorName
|
||||
when 'active'
|
||||
Grim.deprecate("The $active behavior property is deprecated. Use ::observeActive or ::onDidChangeActive instead.")
|
||||
when 'container'
|
||||
Grim.deprecate("The $container behavior property is deprecated.")
|
||||
when 'activeItem'
|
||||
Grim.deprecate("The $activeItem behavior property is deprecated. Use ::observeActiveItem or ::onDidChangeActiveItem instead.")
|
||||
when 'focused'
|
||||
Grim.deprecate("The $focused behavior property is deprecated.")
|
||||
else
|
||||
Grim.deprecate("Pane::behavior is deprecated. Use event subscription methods instead.")
|
||||
|
||||
super
|
||||
|
||||
# Called by the view layer to indicate that the pane has gained focus.
|
||||
focus: ->
|
||||
@@ -103,14 +235,12 @@ class Pane extends Model
|
||||
@focused = false
|
||||
true # if this is called from an event handler, don't cancel it
|
||||
|
||||
# Public: Makes this pane the *active* pane, causing it to gain focus
|
||||
# immediately.
|
||||
activate: ->
|
||||
@container?.activePane = this
|
||||
@emit 'activated'
|
||||
|
||||
getPanes: -> [this]
|
||||
|
||||
###
|
||||
Section: Items
|
||||
###
|
||||
|
||||
# Public: Get the items in this pane.
|
||||
#
|
||||
# Returns an {Array} of items.
|
||||
@@ -120,15 +250,23 @@ class Pane extends Model
|
||||
# Public: Get the active pane item in this pane.
|
||||
#
|
||||
# Returns a pane item.
|
||||
getActiveItem: ->
|
||||
getActiveItem: -> @activeItem
|
||||
|
||||
setActiveItem: (activeItem) ->
|
||||
unless activeItem is @activeItem
|
||||
@activeItem = activeItem
|
||||
@emitter.emit 'did-change-active-item', @activeItem
|
||||
@activeItem
|
||||
|
||||
# Public: Returns an {Editor} if the pane item is an {Editor}, or null
|
||||
# otherwise.
|
||||
# Return an {Editor} if the pane item is an {Editor}, or null otherwise.
|
||||
getActiveEditor: ->
|
||||
@activeItem if @activeItem instanceof Editor
|
||||
|
||||
# Public: Returns the item at the specified index.
|
||||
# Public: Return the item at the given index.
|
||||
#
|
||||
# * `index` {Number}
|
||||
#
|
||||
# Returns an item or `null` if no item exists at the given index.
|
||||
itemAtIndex: (index) ->
|
||||
@items[index]
|
||||
|
||||
@@ -148,86 +286,115 @@ class Pane extends Model
|
||||
else
|
||||
@activateItemAtIndex(@items.length - 1)
|
||||
|
||||
# Returns the index of the current active item.
|
||||
# Public: Get the index of the active item.
|
||||
#
|
||||
# Returns a {Number}.
|
||||
getActiveItemIndex: ->
|
||||
@items.indexOf(@activeItem)
|
||||
|
||||
# Makes the item at the given index active.
|
||||
# Public: Activate the item at the given index.
|
||||
#
|
||||
# * `index` {Number}
|
||||
activateItemAtIndex: (index) ->
|
||||
@activateItem(@itemAtIndex(index))
|
||||
|
||||
# Makes the given item active, adding the item if necessary.
|
||||
# Public: Make the given item *active*, causing it to be displayed by
|
||||
# the pane's view.
|
||||
activateItem: (item) ->
|
||||
if item?
|
||||
@addItem(item)
|
||||
@activeItem = item
|
||||
@setActiveItem(item)
|
||||
|
||||
# Public: Adds the item to the pane.
|
||||
# Public: Add the given item to the pane.
|
||||
#
|
||||
# * `item` The item to add. It can be a model with an associated view or a view.
|
||||
# * `index` (optional) {Number} at which to add the item. If omitted, the item is
|
||||
# added after the current active item.
|
||||
# * `item` The item to add. It can be a model with an associated view or a
|
||||
# view.
|
||||
# * `index` (optional) {Number} indicating the index at which to add the item.
|
||||
# If omitted, the item is added after the current active item.
|
||||
#
|
||||
# Returns the added item
|
||||
# Returns the added item.
|
||||
addItem: (item, index=@getActiveItemIndex() + 1) ->
|
||||
return if item in @items
|
||||
|
||||
if typeof item.on is 'function'
|
||||
@subscribe item, 'destroyed', => @removeItem(item, true)
|
||||
|
||||
@items.splice(index, 0, item)
|
||||
@emit 'item-added', item, index
|
||||
@activeItem ?= item
|
||||
@emitter.emit 'did-add-item', {item, index}
|
||||
@setActiveItem(item) unless @getActiveItem()?
|
||||
item
|
||||
|
||||
# Public: Adds the given items to the pane.
|
||||
# Public: Add the given items to the pane.
|
||||
#
|
||||
# * `items` An {Array} of items to add. Items can be models with associated
|
||||
# views or views. Any items that are already present in items will
|
||||
# not be added.
|
||||
# * `index` (optional) {Number} index at which to add the item. If omitted, the item is
|
||||
# added after the current active item.
|
||||
# * `items` An {Array} of items to add. Items can be views or models with
|
||||
# associated views. Any objects that are already present in the pane's
|
||||
# current items will not be added again.
|
||||
# * `index` (optional) {Number} index at which to add the items. If omitted,
|
||||
# the item is # added after the current active item.
|
||||
#
|
||||
# Returns an {Array} of the added items
|
||||
# Returns an {Array} of added items.
|
||||
addItems: (items, index=@getActiveItemIndex() + 1) ->
|
||||
items = items.filter (item) => not (item in @items)
|
||||
@addItem(item, index + i) for item, i in items
|
||||
items
|
||||
|
||||
removeItem: (item, destroying) ->
|
||||
removeItem: (item, destroyed=false) ->
|
||||
index = @items.indexOf(item)
|
||||
return if index is -1
|
||||
|
||||
if typeof item.on is 'function'
|
||||
@unsubscribe item
|
||||
|
||||
if item is @activeItem
|
||||
if @items.length is 1
|
||||
@activeItem = undefined
|
||||
@setActiveItem(undefined)
|
||||
else if index is 0
|
||||
@activateNextItem()
|
||||
else
|
||||
@activatePreviousItem()
|
||||
@items.splice(index, 1)
|
||||
@emit 'item-removed', item, index, destroying
|
||||
@container?.itemDestroyed(item) if destroying
|
||||
@emit 'item-removed', item, index, destroyed
|
||||
@emitter.emit 'did-remove-item', {item, index, destroyed}
|
||||
@container?.paneItemDestroyed(item) if destroyed
|
||||
@destroy() if @items.length is 0 and atom.config.get('core.destroyEmptyPanes')
|
||||
|
||||
# Public: Moves the given item to the specified index.
|
||||
# Public: Move the given item to the given index.
|
||||
#
|
||||
# * `item` The item to move.
|
||||
# * `index` {Number} indicating the index to which to move the item.
|
||||
moveItem: (item, newIndex) ->
|
||||
oldIndex = @items.indexOf(item)
|
||||
@items.splice(oldIndex, 1)
|
||||
@items.splice(newIndex, 0, item)
|
||||
@emit 'item-moved', item, newIndex
|
||||
@emitter.emit 'did-move-item', {item, oldIndex, newIndex}
|
||||
|
||||
# Public: Moves the given item to the given index at another pane.
|
||||
# Public: Move the given item to the given index on another pane.
|
||||
#
|
||||
# * `item` The item to move.
|
||||
# * `pane` {Pane} to which to move the item.
|
||||
# * `index` {Number} indicating the index to which to move the item in the
|
||||
# given pane.
|
||||
moveItemToPane: (item, pane, index) ->
|
||||
pane.addItem(item, index)
|
||||
@removeItem(item)
|
||||
|
||||
# Public: Destroys the currently active item and make the next item active.
|
||||
# Public: Destroy the active item and activate the next item.
|
||||
destroyActiveItem: ->
|
||||
@destroyItem(@activeItem)
|
||||
false
|
||||
|
||||
# Public: Destroys the given item. If it is the active item, activate the next
|
||||
# one. If this is the last item, also destroys the pane.
|
||||
# Public: Destroy the given item.
|
||||
#
|
||||
# If the item is active, the next item will be activated. If the item is the
|
||||
# last item, the pane will be destroyed if the `core.destroyEmptyPanes` config
|
||||
# setting is `true`.
|
||||
destroyItem: (item) ->
|
||||
if item?
|
||||
index = @items.indexOf(item)
|
||||
if index isnt -1
|
||||
@emit 'before-item-destroyed', item
|
||||
@emitter.emit 'will-destroy-item', {item, index}
|
||||
if @promptToSaveItem(item)
|
||||
@removeItem(item, true)
|
||||
item.destroy?()
|
||||
@@ -235,27 +402,14 @@ class Pane extends Model
|
||||
else
|
||||
false
|
||||
|
||||
# Public: Destroys all items and destroys the pane.
|
||||
# Public: Destroy all items.
|
||||
destroyItems: ->
|
||||
@destroyItem(item) for item in @getItems()
|
||||
|
||||
# Public: Destroys all items but the active one.
|
||||
# Public: Destroy all items except for the active item.
|
||||
destroyInactiveItems: ->
|
||||
@destroyItem(item) for item in @getItems() when item isnt @activeItem
|
||||
|
||||
destroy: ->
|
||||
if @container?.isAlive() and @container.getPanes().length is 1
|
||||
@destroyItems()
|
||||
else
|
||||
super
|
||||
|
||||
# Called by model superclass.
|
||||
destroyed: ->
|
||||
@container.activateNextPane() if @isActive()
|
||||
item.destroy?() for item in @items.slice()
|
||||
|
||||
# Public: Prompts the user to save the given item if it can be saved and is
|
||||
# currently unsaved.
|
||||
promptToSaveItem: (item) ->
|
||||
return true unless item.shouldPromptToSave?()
|
||||
|
||||
@@ -270,18 +424,23 @@ class Pane extends Model
|
||||
when 1 then false
|
||||
when 2 then true
|
||||
|
||||
# Public: Saves the active item.
|
||||
saveActiveItem: ->
|
||||
@saveItem(@activeItem)
|
||||
# Public: Save the active item.
|
||||
saveActiveItem: (nextAction) ->
|
||||
@saveItem(@getActiveItem(), nextAction)
|
||||
|
||||
# Public: Saves the active item at a prompted-for location.
|
||||
saveActiveItemAs: ->
|
||||
@saveItemAs(@activeItem)
|
||||
# Public: Prompt the user for a location and save the active item with the
|
||||
# path they select.
|
||||
#
|
||||
# * `nextAction` (optional) {Function} which will be called after the item is
|
||||
# successfully saved.
|
||||
saveActiveItemAs: (nextAction) ->
|
||||
@saveItemAs(@getActiveItem(), nextAction)
|
||||
|
||||
# Public: Saves the specified item.
|
||||
# Public: Save the given item.
|
||||
#
|
||||
# * `item` The item to save.
|
||||
# * `nextAction` (optional) {Function} which will be called after the item is saved.
|
||||
# * `nextAction` (optional) {Function} which will be called after the item is
|
||||
# successfully saved.
|
||||
saveItem: (item, nextAction) ->
|
||||
if item?.getUri?()
|
||||
item.save?()
|
||||
@@ -289,10 +448,12 @@ class Pane extends Model
|
||||
else
|
||||
@saveItemAs(item, nextAction)
|
||||
|
||||
# Public: Saves the given item at a prompted-for location.
|
||||
# Public: Prompt the user for a location and save the active item with the
|
||||
# path they select.
|
||||
#
|
||||
# * `item` The item to save.
|
||||
# * `nextAction` (optional) {Function} which will be called after the item is saved.
|
||||
# * `nextAction` (optional) {Function} which will be called after the item is
|
||||
# successfully saved.
|
||||
saveItemAs: (item, nextAction) ->
|
||||
return unless item?.saveAs?
|
||||
|
||||
@@ -302,17 +463,20 @@ class Pane extends Model
|
||||
item.saveAs(newItemPath)
|
||||
nextAction?()
|
||||
|
||||
# Public: Saves all items.
|
||||
# Public: Save all items.
|
||||
saveItems: ->
|
||||
@saveItem(item) for item in @getItems()
|
||||
|
||||
# Public: Returns the first item that matches the given URI or undefined if
|
||||
# Public: Return the first item that matches the given URI or undefined if
|
||||
# none exists.
|
||||
#
|
||||
# * `uri` {String} containing a URI.
|
||||
itemForUri: (uri) ->
|
||||
find @items, (item) -> item.getUri?() is uri
|
||||
|
||||
# Public: Activates the first item that matches the given URI. Returns a
|
||||
# boolean indicating whether a matching item was found.
|
||||
# Public: Activate the first item that matches the given URI.
|
||||
#
|
||||
# Returns a {Boolean} indicating whether an item matching the URI was found.
|
||||
activateItemForUri: (uri) ->
|
||||
if item = @itemForUri(uri)
|
||||
@activateItem(item)
|
||||
@@ -324,19 +488,55 @@ class Pane extends Model
|
||||
if @activeItem?
|
||||
@activeItem.copy?() ? atom.deserializers.deserialize(@activeItem.serialize())
|
||||
|
||||
# Public: Creates a new pane to the left of the receiver.
|
||||
###
|
||||
Section: Lifecycle
|
||||
###
|
||||
|
||||
# Public: Determine whether the pane is active.
|
||||
#
|
||||
# * `params` {Object} with keys
|
||||
# * `items` (optional) {Array} of items with which to construct the new pane.
|
||||
# Returns a {Boolean}.
|
||||
isActive: ->
|
||||
@container?.getActivePane() is this
|
||||
|
||||
# Public: Makes this pane the *active* pane, causing it to gain focus.
|
||||
activate: ->
|
||||
@container?.setActivePane(this)
|
||||
@emit 'activated'
|
||||
@emitter.emit 'did-activate'
|
||||
|
||||
# Public: Close the pane and destroy all its items.
|
||||
#
|
||||
# If this is the last pane, all the items will be destroyed but the pane
|
||||
# itself will not be destroyed.
|
||||
destroy: ->
|
||||
if @container?.isAlive() and @container.getPanes().length is 1
|
||||
@destroyItems()
|
||||
else
|
||||
super
|
||||
|
||||
# Called by model superclass.
|
||||
destroyed: ->
|
||||
@container.activateNextPane() if @isActive()
|
||||
@emitter.emit 'did-destroy'
|
||||
item.destroy?() for item in @items.slice()
|
||||
|
||||
###
|
||||
Section: Splitting
|
||||
###
|
||||
|
||||
# Public: Create a new pane to the left of this pane.
|
||||
#
|
||||
# * `params` (optional) {Object} with the following keys:
|
||||
# * `items` (optional) {Array} of items to add to the new pane.
|
||||
#
|
||||
# Returns the new {Pane}.
|
||||
splitLeft: (params) ->
|
||||
@split('horizontal', 'before', params)
|
||||
|
||||
# Public: Creates a new pane to the right of the receiver.
|
||||
# Public: Create a new pane to the right of this pane.
|
||||
#
|
||||
# * `params` {Object} with keys:
|
||||
# * `items` (optional) {Array} of items with which to construct the new pane.
|
||||
# * `params` (optional) {Object} with the following keys:
|
||||
# * `items` (optional) {Array} of items to add to the new pane.
|
||||
#
|
||||
# Returns the new {Pane}.
|
||||
splitRight: (params) ->
|
||||
@@ -344,8 +544,8 @@ class Pane extends Model
|
||||
|
||||
# Public: Creates a new pane above the receiver.
|
||||
#
|
||||
# * `params` {Object} with keys:
|
||||
# * `items` (optional) {Array} of items with which to construct the new pane.
|
||||
# * `params` (optional) {Object} with the following keys:
|
||||
# * `items` (optional) {Array} of items to add to the new pane.
|
||||
#
|
||||
# Returns the new {Pane}.
|
||||
splitUp: (params) ->
|
||||
@@ -353,8 +553,8 @@ class Pane extends Model
|
||||
|
||||
# Public: Creates a new pane below the receiver.
|
||||
#
|
||||
# * `params` {Object} with keys:
|
||||
# * `items` (optional) {Array} of items with which to construct the new pane.
|
||||
# * `params` (optional) {Object} with the following keys:
|
||||
# * `items` (optional) {Array} of items to add to the new pane.
|
||||
#
|
||||
# Returns the new {Pane}.
|
||||
splitDown: (params) ->
|
||||
|
||||
@@ -84,7 +84,7 @@ class WorkspaceView extends View
|
||||
@panes.replaceWith(panes)
|
||||
@panes = panes
|
||||
|
||||
@subscribe @model, 'uri-opened', => @trigger 'uri-opened'
|
||||
@subscribe @model.onDidOpen => @trigger 'uri-opened'
|
||||
|
||||
@subscribe scrollbarStyle, (style) =>
|
||||
@removeClass('scrollbars-visible-always scrollbars-visible-when-scrolling')
|
||||
@@ -409,4 +409,4 @@ class WorkspaceView extends View
|
||||
# Deprecated: Call {Workspace::getActivePaneItem} instead.
|
||||
getActivePaneItem: ->
|
||||
deprecate("Use Workspace::getActivePaneItem instead")
|
||||
@model.activePaneItem
|
||||
@model.getActivePaneItem()
|
||||
|
||||
@@ -5,6 +5,7 @@ _ = require 'underscore-plus'
|
||||
Q = require 'q'
|
||||
Serializable = require 'serializable'
|
||||
Delegator = require 'delegato'
|
||||
{Emitter} = require 'event-kit'
|
||||
Editor = require './editor'
|
||||
PaneContainer = require './pane-container'
|
||||
Pane = require './pane'
|
||||
@@ -16,17 +17,6 @@ Pane = require './pane'
|
||||
# editors, and manipulate panes. To add panels, you'll need to use the
|
||||
# {WorkspaceView} class for now until we establish APIs at the model layer.
|
||||
#
|
||||
# ## Events
|
||||
#
|
||||
# ### uri-opened
|
||||
#
|
||||
# Extended: Emit when something has been opened. This can be anything, from an
|
||||
# editor to the settings view. You can get the new item via {::getActivePaneItem}
|
||||
#
|
||||
# ### editor-created
|
||||
#
|
||||
# Extended: Emit when an editor is created (a file opened).
|
||||
#
|
||||
# * `editor` {Editor} the new editor
|
||||
#
|
||||
module.exports =
|
||||
@@ -44,9 +34,11 @@ class Workspace extends Model
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
@emitter = new Emitter
|
||||
@openers = []
|
||||
|
||||
@subscribe @paneContainer, 'item-destroyed', @onPaneItemDestroyed
|
||||
@paneContainer.onDidDestroyPaneItem(@onPaneItemDestroyed)
|
||||
|
||||
@registerOpener (filePath) =>
|
||||
switch filePath
|
||||
when 'atom://.atom/stylesheet'
|
||||
@@ -83,34 +75,130 @@ class Workspace extends Model
|
||||
for scopeName in includedGrammarScopes ? []
|
||||
addGrammar(atom.syntax.grammarForScopeName(scopeName))
|
||||
|
||||
addGrammar(editor.getGrammar()) for editor in @getEditors()
|
||||
addGrammar(editor.getGrammar()) for editor in @getTextEditors()
|
||||
_.uniq(packageNames)
|
||||
|
||||
editorAdded: (editor) ->
|
||||
@emit 'editor-created', editor
|
||||
|
||||
# Public: Register a function to be called for every current and future
|
||||
# {Editor} in the workspace.
|
||||
###
|
||||
Section: Event Subscription
|
||||
###
|
||||
|
||||
# Extended: Invoke the given callback when a pane is added to the workspace.
|
||||
#
|
||||
# * `callback` A {Function} with an {Editor} as its only argument.
|
||||
# * `callback` {Function} to be called panes are added.
|
||||
# * `event` {Object} with the following keys:
|
||||
# * `pane` The added pane.
|
||||
#
|
||||
# Returns a subscription object with an `.off` method that you can call to
|
||||
# unregister the callback.
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
onDidAddPane: (callback) -> @paneContainer.onDidAddPane(callback)
|
||||
|
||||
# Extended: Invoke the given callback with all current and future panes in the
|
||||
# workspace.
|
||||
#
|
||||
# * `callback` {Function} to be called with current and future panes.
|
||||
# * `pane` A {Pane} that is present in {::getPanes} at the time of
|
||||
# subscription or that is added at some later time.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
observePanes: (callback) -> @paneContainer.observePanes(callback)
|
||||
|
||||
# Extended: Invoke the given callback when a pane item is added to the
|
||||
# workspace.
|
||||
#
|
||||
# * `callback` {Function} to be called panes are added.
|
||||
# * `event` {Object} with the following keys:
|
||||
# * `item` The added pane item.
|
||||
# * `pane` {Pane} containing the added item.
|
||||
# * `index` {Number} indicating the index of the added item in its pane.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
onDidAddPaneItem: (callback) -> @paneContainer.onDidAddPaneItem(callback)
|
||||
|
||||
# Extended: Invoke the given callback with all current and future panes items in
|
||||
# the workspace.
|
||||
#
|
||||
# * `callback` {Function} to be called with current and future pane items.
|
||||
# * `item` An item that is present in {::getPaneItems} at the time of
|
||||
# subscription or that is added at some later time.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
observePaneItems: (callback) -> @paneContainer.observePaneItems(callback)
|
||||
|
||||
# Extended: Invoke the given callback when a text editor is added to the
|
||||
# workspace.
|
||||
#
|
||||
# * `callback` {Function} to be called panes are added.
|
||||
# * `event` {Object} with the following keys:
|
||||
# * `textEditor` {Editor} that was added.
|
||||
# * `pane` {Pane} containing the added text editor.
|
||||
# * `index` {Number} indicating the index of the added text editor in its
|
||||
# pane.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
onDidAddTextEditor: (callback) ->
|
||||
@onDidAddPaneItem ({item, pane, index}) ->
|
||||
callback({textEditor: item, pane, index}) if item instanceof Editor
|
||||
|
||||
# Essential: Invoke the given callback with all current and future text
|
||||
# editors in the workspace.
|
||||
#
|
||||
# * `callback` {Function} to be called with current and future text editors.
|
||||
# * `editor` An {Editor} that is present in {::getTextEditors} at the time
|
||||
# of subscription or that is added at some later time.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
observeTextEditors: (callback) ->
|
||||
callback(textEditor) for textEditor in @getTextEditors()
|
||||
@onDidAddTextEditor ({textEditor}) -> callback(textEditor)
|
||||
|
||||
# Essential: Invoke the given callback whenever an item is opened. Unlike
|
||||
# ::onDidAddPaneItem, observers will be notified for items that are already
|
||||
# present in the workspace when they are reopened.
|
||||
#
|
||||
# * `callback` {Function} to be called whenever an item is opened.
|
||||
# * `event` {Object} with the following keys:
|
||||
# * `uri` {String} representing the opened URI. Could be `undefined`.
|
||||
# * `item` The opened item.
|
||||
# * `pane` The pane in which the item was opened.
|
||||
# * `index` The index of the opened item on its pane.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
onDidOpen: (callback) ->
|
||||
@emitter.on 'did-open', callback
|
||||
|
||||
eachEditor: (callback) ->
|
||||
deprecate("Use Workspace::observeTextEditors instead")
|
||||
|
||||
callback(editor) for editor in @getEditors()
|
||||
@subscribe this, 'editor-created', (editor) -> callback(editor)
|
||||
|
||||
# Public: Get all current editors in the workspace.
|
||||
#
|
||||
# Returns an {Array} of {Editor}s.
|
||||
getEditors: ->
|
||||
deprecate("Use Workspace::getTextEditors instead")
|
||||
|
||||
editors = []
|
||||
for pane in @paneContainer.getPanes()
|
||||
editors.push(item) for item in pane.getItems() when item instanceof Editor
|
||||
|
||||
editors
|
||||
|
||||
# Public: Open a given a URI in Atom asynchronously.
|
||||
on: (eventName) ->
|
||||
switch eventName
|
||||
when 'editor-created'
|
||||
deprecate("Use Workspace::onDidAddTextEditor or Workspace::observeTextEditors instead.")
|
||||
when 'uri-opened'
|
||||
deprecate("Use Workspace::onDidAddPaneItem instead.")
|
||||
else
|
||||
deprecate("Subscribing via ::on is deprecated. Use documented event subscription methods instead.")
|
||||
|
||||
super
|
||||
|
||||
###
|
||||
Section: Opening
|
||||
###
|
||||
|
||||
# Essential: Open a given a URI in Atom asynchronously.
|
||||
#
|
||||
# * `uri` A {String} containing a URI.
|
||||
# * `options` (optional) {Object}
|
||||
@@ -137,11 +225,11 @@ class Workspace extends Model
|
||||
pane = @paneContainer.paneForUri(uri) if searchAllPanes
|
||||
pane ?= switch split
|
||||
when 'left'
|
||||
@activePane.findLeftmostSibling()
|
||||
@getActivePane().findLeftmostSibling()
|
||||
when 'right'
|
||||
@activePane.findOrCreateRightmostSibling()
|
||||
@getActivePane().findOrCreateRightmostSibling()
|
||||
else
|
||||
@activePane
|
||||
@getActivePane()
|
||||
|
||||
@openUriInPane(uri, pane, options)
|
||||
|
||||
@@ -195,12 +283,14 @@ class Workspace extends Model
|
||||
@itemOpened(item)
|
||||
pane.activateItem(item)
|
||||
pane.activate() if changeFocus
|
||||
index = pane.getActiveItemIndex()
|
||||
@emit "uri-opened"
|
||||
@emitter.emit 'did-open', {uri, pane, item, index}
|
||||
item
|
||||
.catch (error) ->
|
||||
console.error(error.stack ? error)
|
||||
|
||||
# Public: Asynchronously reopens the last-closed item's URI if it hasn't already been
|
||||
# Extended: Asynchronously reopens the last-closed item's URI if it hasn't already been
|
||||
# reopened.
|
||||
#
|
||||
# Returns a promise that is resolved when the item is opened
|
||||
@@ -216,7 +306,7 @@ class Workspace extends Model
|
||||
if uri = @destroyedItemUris.pop()
|
||||
@openSync(uri)
|
||||
|
||||
# Public: Register an opener for a uri.
|
||||
# Extended: Register an opener for a uri.
|
||||
#
|
||||
# An {Editor} will be used if no openers return a value.
|
||||
#
|
||||
@@ -232,52 +322,52 @@ class Workspace extends Model
|
||||
registerOpener: (opener) ->
|
||||
@openers.push(opener)
|
||||
|
||||
# Public: Unregister an opener registered with {::registerOpener}.
|
||||
# Extended: Unregister an opener registered with {::registerOpener}.
|
||||
unregisterOpener: (opener) ->
|
||||
_.remove(@openers, opener)
|
||||
|
||||
getOpeners: ->
|
||||
@openers
|
||||
|
||||
# Public: Get the active {Pane}.
|
||||
###
|
||||
Section: Pane Items
|
||||
###
|
||||
|
||||
# Essential: Get all pane items in the workspace.
|
||||
#
|
||||
# Returns a {Pane}.
|
||||
getActivePane: ->
|
||||
@paneContainer.activePane
|
||||
# Returns an {Array} of items.
|
||||
getPaneItems: ->
|
||||
@paneContainer.getPaneItems()
|
||||
|
||||
# Public: Get all {Pane}s.
|
||||
#
|
||||
# Returns an {Array} of {Pane}s.
|
||||
getPanes: ->
|
||||
@paneContainer.getPanes()
|
||||
|
||||
# Public: Save all pane items.
|
||||
saveAll: ->
|
||||
@paneContainer.saveAll()
|
||||
|
||||
# Public: Make the next pane active.
|
||||
activateNextPane: ->
|
||||
@paneContainer.activateNextPane()
|
||||
|
||||
# Public: Make the previous pane active.
|
||||
activatePreviousPane: ->
|
||||
@paneContainer.activatePreviousPane()
|
||||
|
||||
# Public: Get the first pane {Pane} with an item for the given URI.
|
||||
#
|
||||
# * `uri` {String} uri
|
||||
#
|
||||
# Returns a {Pane} or `undefined` if no pane exists for the given URI.
|
||||
paneForUri: (uri) ->
|
||||
@paneContainer.paneForUri(uri)
|
||||
|
||||
# Public: Get the active {Pane}'s active item.
|
||||
# Essential: Get the active {Pane}'s active item.
|
||||
#
|
||||
# Returns an pane item {Object}.
|
||||
getActivePaneItem: ->
|
||||
@paneContainer.getActivePane().getActiveItem()
|
||||
@paneContainer.getActivePaneItem()
|
||||
|
||||
# Public: Save the active pane item.
|
||||
# Essential: Get all text editors in the workspace.
|
||||
#
|
||||
# Returns an {Array} of {Editor}s.
|
||||
getTextEditors: ->
|
||||
@getPaneItems().filter (item) -> item instanceof Editor
|
||||
|
||||
# Essential: Get the active item if it is an {Editor}.
|
||||
#
|
||||
# Returns an {Editor} or `undefined` if the current active item is not an
|
||||
# {Editor}.
|
||||
getActiveTextEditor: ->
|
||||
activeItem = @getActiveItem()
|
||||
activeItem if activeItem instanceof Editor
|
||||
|
||||
# Deprecated:
|
||||
getActiveEditor: ->
|
||||
@activePane?.getActiveEditor()
|
||||
|
||||
# Extended: Save all pane items.
|
||||
saveAll: ->
|
||||
@paneContainer.saveAll()
|
||||
|
||||
# Save the active pane item.
|
||||
#
|
||||
# If the active pane item currently has a URI according to the item's
|
||||
# `.getUri` method, calls `.save` on the item. Otherwise
|
||||
@@ -286,7 +376,7 @@ class Workspace extends Model
|
||||
saveActivePaneItem: ->
|
||||
@activePane?.saveActiveItem()
|
||||
|
||||
# Public: Prompt the user for a path and save the active pane item to it.
|
||||
# Prompt the user for a path and save the active pane item to it.
|
||||
#
|
||||
# Opens a native dialog where the user selects a path on disk, then calls
|
||||
# `.saveAs` on the item with the selected path. This method does nothing if
|
||||
@@ -294,34 +384,59 @@ class Workspace extends Model
|
||||
saveActivePaneItemAs: ->
|
||||
@activePane?.saveActiveItemAs()
|
||||
|
||||
# Public: Destroy (close) the active pane item.
|
||||
# Destroy (close) the active pane item.
|
||||
#
|
||||
# Removes the active pane item and calls the `.destroy` method on it if one is
|
||||
# defined.
|
||||
destroyActivePaneItem: ->
|
||||
@activePane?.destroyActiveItem()
|
||||
|
||||
# Public: Destroy (close) the active pane.
|
||||
###
|
||||
Section: Panes
|
||||
###
|
||||
|
||||
# Extended: Get all panes in the workspace.
|
||||
#
|
||||
# Returns an {Array} of {Pane}s.
|
||||
getPanes: ->
|
||||
@paneContainer.getPanes()
|
||||
|
||||
# Extended: Get the active {Pane}.
|
||||
#
|
||||
# Returns a {Pane}.
|
||||
getActivePane: ->
|
||||
@paneContainer.getActivePane()
|
||||
|
||||
# Extended: Make the next pane active.
|
||||
activateNextPane: ->
|
||||
@paneContainer.activateNextPane()
|
||||
|
||||
# Extended: Make the previous pane active.
|
||||
activatePreviousPane: ->
|
||||
@paneContainer.activatePreviousPane()
|
||||
|
||||
# Extended: Get the first pane {Pane} with an item for the given URI.
|
||||
#
|
||||
# * `uri` {String} uri
|
||||
#
|
||||
# Returns a {Pane} or `undefined` if no pane exists for the given URI.
|
||||
paneForUri: (uri) ->
|
||||
@paneContainer.paneForUri(uri)
|
||||
|
||||
# Destroy (close) the active pane.
|
||||
destroyActivePane: ->
|
||||
@activePane?.destroy()
|
||||
|
||||
# Public: Get the active item if it is an {Editor}.
|
||||
#
|
||||
# Returns an {Editor} or `undefined` if the current active item is not an
|
||||
# {Editor}.
|
||||
getActiveEditor: ->
|
||||
@activePane?.getActiveEditor()
|
||||
|
||||
# Public: Increase the editor font size by 1px.
|
||||
# Increase the editor font size by 1px.
|
||||
increaseFontSize: ->
|
||||
atom.config.set("editor.fontSize", atom.config.get("editor.fontSize") + 1)
|
||||
|
||||
# Public: Decrease the editor font size by 1px.
|
||||
# Decrease the editor font size by 1px.
|
||||
decreaseFontSize: ->
|
||||
fontSize = atom.config.get("editor.fontSize")
|
||||
atom.config.set("editor.fontSize", fontSize - 1) if fontSize > 1
|
||||
|
||||
# Public: Restore to a default editor font size.
|
||||
# Restore to a default editor font size.
|
||||
resetFontSize: ->
|
||||
atom.config.restoreDefault("editor.fontSize")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user