Manage the active pane at the model level

This commit is contained in:
Nathan Sobo 2014-01-09 17:40:04 -07:00
parent 4026e6ca5c
commit 5e1b2e2696
6 changed files with 84 additions and 24 deletions

View File

@ -50,7 +50,7 @@
"temp": "0.5.0",
"text-buffer": "0.12.0",
"underscore-plus": "0.6.1",
"theorist": "~0.9.0",
"theorist": "~0.10.0",
"delegato": "~0.4.0",
"mixto": "~0.4.0"
},

View File

@ -11,6 +11,36 @@ describe "PaneContainerModel", ->
expect(pane3A.focused).toBe true
containerB = containerA.testSerialization()
[pane1A, pane2A, pane3A] = containerB.getPanes()
expect(pane3A.focusContext).toBe containerB.focusContext
expect(pane3A.focused).toBe true
[pane1B, pane2B, pane3B] = containerB.getPanes()
expect(pane3B.focusContext).toBe containerB.focusContext
expect(pane3B.focused).toBe true
describe "::activePane", ->
[container, pane1, pane2] = []
beforeEach ->
pane1 = new PaneModel
container = new PaneContainerModel(root: pane1)
it "references the first pane if no pane has been focused", ->
expect(container.activePane).toBe pane1
expect(pane1.active).toBe true
it "references the most recently focused pane", ->
pane2 = pane1.splitRight()
expect(container.activePane).toBe pane2
expect(pane1.active).toBe false
expect(pane2.active).toBe true
pane1.focus()
expect(container.activePane).toBe pane1
expect(pane1.active).toBe true
expect(pane2.active).toBe false
it "is reassigned to the next pane if the current active pane is unfocused and destroyed", ->
pane2 = pane1.splitRight()
pane2.blur()
pane2.destroy()
expect(container.activePane).toBe pane1
expect(pane1.active).toBe true
pane1.destroy()
expect(container.activePane).toBe null

View File

@ -88,7 +88,8 @@ describe "PaneModel", ->
describe "::removeItemAtIndex(index)", ->
describe "when the removal of the item causes blur to be called on the pane model", ->
it "remains focused if it was before the item was removed", ->
pane = new PaneModel(items: ["A", "B", "C"], focusContext: new FocusContext)
pane = new PaneModel(items: ["A", "B", "C"])
container = new PaneContainerModel(root: pane)
pane.on 'item-removed', -> pane.blur()
pane.focus()
pane.removeItemAtIndex(0)

View File

@ -12,19 +12,14 @@ class PaneAxisModel extends Model
Serializable.includeInto(this)
Delegator.includeInto(this)
@delegatesMethod 'focusNextPane', toProperty: 'parent'
@delegatesProperty 'focusContext', toProperty: 'container'
@property 'focusContext'
constructor: ({@focusContext, @orientation, children}) ->
constructor: ({@container, @orientation, children}) ->
@children = Sequence.fromArray(children ? [])
@subscribe @$focusContext, (focusContext) =>
child.focusContext = focusContext for child in @children
@subscribe @children.onEach (child) =>
child.parent = this
child.focusContext = @focusContext
child.container = @container
@subscribe child, 'destroyed', => @removeChild(child)
@subscribe @children.onRemoval (child) => @unsubscribe(child)
@ -33,8 +28,8 @@ class PaneAxisModel extends Model
@when @children.$length.becomesLessThan(1), 'destroy'
deserializeParams: (params) ->
{focusContext} = params
params.children = params.children.map (childState) -> atom.deserializers.deserialize(childState, {focusContext})
{container} = params
params.children = params.children.map (childState) -> atom.deserializers.deserialize(childState, {container})
params
serializeParams: ->

View File

@ -2,6 +2,7 @@
Serializable = require 'serializable'
{find} = require 'underscore-plus'
FocusContext = require './focus-context'
PaneModel = require './pane-model'
module.exports =
class PaneContainerModel extends Model
@ -10,18 +11,23 @@ class PaneContainerModel extends Model
@properties
root: null
focusContext: -> new FocusContext
focusContext: null
activePane: null
constructor: ->
super
@focusContext ?= new FocusContext
@subscribe @$root, (root) =>
if root?
root.parent = this
root.focusContext = @focusContext
root.container = this
@activePane ?= root if root instanceof PaneModel
deserializeParams: (params) ->
params.focusContext ?= new FocusContext
params.root = atom.deserializers.deserialize(params.root, focusContext: params.focusContext)
@focusContext ?= params.focusContext ? new FocusContext
params.root = atom.deserializers.deserialize(params.root, container: this)
params
serializeParams: (params) ->
@ -57,3 +63,12 @@ class PaneContainerModel extends Model
true
else
false
makeNextPaneActive: ->
panes = @getPanes()
if panes.length > 1
currentIndex = panes.indexOf(@activePane)
nextIndex = (currentIndex + 1) % panes.length
@activePane = panes[nextIndex]
else
@activePane = null

View File

@ -13,26 +13,38 @@ class PaneModel extends Model
Focusable.includeInto(this)
@properties
container: null
activeItem: null
@behavior 'active', ->
@$container
.flatMapLatest((container) -> container?.$activePane)
.map((activePane) => activePane is this)
.distinctUntilChanged()
constructor: (params) ->
super
@focus() if params?.focused
@items = Sequence.fromArray(params?.items ? [])
@activeItem ?= @items[0]
@subscribe @$container, (container) =>
@focusContext = container?.focusContext
@subscribe @items.onEach (item) =>
if typeof item.on is 'function'
@subscribe item, 'destroyed', => @removeItem(item)
@subscribe @items.onRemoval (item, index) =>
@unsubscribe item
@unsubscribe item if typeof item.on is 'function'
@emit 'item-removed', item, index
@when @items.$length.becomesLessThan(1), 'destroy'
@when @$focused, => @makeActive()
@focus() if params?.focused
serializeParams: ->
items: compact(@items.map((item) -> item.serialize?()))
activeItemUri: @activeItem?.getUri?()
@ -46,6 +58,10 @@ class PaneModel extends Model
getViewClass: -> Pane ?= require './pane'
isActive: -> @active
makeActive: -> @container.activePane = this
getPanes: -> [this]
# Public: Returns all contained views.
@ -144,7 +160,10 @@ class PaneModel extends Model
# Private: Called by model superclass
destroyed: ->
item.destroy?() for item in @items.slice()
@parent.focusNextPane() if @focused
if @focused
@container.focusNextPane()
else if @isActive()
@container.makeNextPaneActive()
# Public: Prompt the user to save the given item.
promptToSaveItem: (item) ->
@ -223,7 +242,7 @@ class PaneModel extends Model
split: (orientation, side, params) ->
if @parent.orientation isnt orientation
@parent.replaceChild(this, new PaneAxisModel({orientation, children: [this]}))
@parent.replaceChild(this, new PaneAxisModel({@container, orientation, children: [this]}))
newPane = new @constructor(params)
switch side