mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-09-21 07:58:04 +03:00
Merge pull request #3587 from atom/ns-workspace-view-providers
Add view provider API to Workspace
This commit is contained in:
commit
3dbaa0679b
@ -7,7 +7,7 @@ describe "editorView.", ->
|
||||
|
||||
beforeEach ->
|
||||
atom.workspaceViewParentSelector = '#jasmine-content'
|
||||
atom.workspaceView = new WorkspaceView
|
||||
atom.workspaceView = atom.workspace.getView(atom.workspace).__spacePenView
|
||||
atom.workspaceView.attachToDom()
|
||||
|
||||
atom.workspaceView.width(1024)
|
||||
|
@ -75,7 +75,7 @@
|
||||
"autocomplete": "0.32.0",
|
||||
"autoflow": "0.18.0",
|
||||
"autosave": "0.17.0",
|
||||
"background-tips": "0.16.0",
|
||||
"background-tips": "0.17.0",
|
||||
"bookmarks": "0.28.0",
|
||||
"bracket-matcher": "0.58.0",
|
||||
"command-palette": "0.25.0",
|
||||
|
@ -6,7 +6,7 @@ ThemeManager = require '../src/theme-manager'
|
||||
|
||||
describe "the `atom` global", ->
|
||||
beforeEach ->
|
||||
atom.workspaceView = new WorkspaceView
|
||||
atom.workspaceView = atom.workspace.getView(atom.workspace).__spacePenView
|
||||
|
||||
describe 'window sizing methods', ->
|
||||
describe '::getPosition and ::setPosition', ->
|
||||
|
@ -99,6 +99,13 @@ describe "Pane", ->
|
||||
pane.addItem(item, 1)
|
||||
expect(events).toEqual [{item, index: 1}]
|
||||
|
||||
it "throws an exception if the item is already present on a pane", ->
|
||||
item = new Item("A")
|
||||
pane1 = new Pane(items: [item])
|
||||
container = new PaneContainer(root: pane1)
|
||||
pane2 = pane1.splitRight()
|
||||
expect(-> pane2.addItem(item)).toThrow()
|
||||
|
||||
describe "::activateItem(item)", ->
|
||||
pane = null
|
||||
|
||||
|
@ -7,7 +7,7 @@ path = require 'path'
|
||||
temp = require 'temp'
|
||||
|
||||
describe "PaneView", ->
|
||||
[container, view1, view2, editor1, editor2, pane, paneModel] = []
|
||||
[container, containerModel, view1, view2, editor1, editor2, pane, paneModel] = []
|
||||
|
||||
class TestView extends View
|
||||
@deserialize: ({id, text}) -> new TestView({id, text})
|
||||
@ -25,6 +25,7 @@ describe "PaneView", ->
|
||||
beforeEach ->
|
||||
atom.deserializers.add(TestView)
|
||||
container = new PaneContainerView
|
||||
containerModel = container.model
|
||||
view1 = new TestView(id: 'view-1', text: 'View 1')
|
||||
view2 = new TestView(id: 'view-2', text: 'View 2')
|
||||
waitsForPromise ->
|
||||
@ -216,7 +217,7 @@ describe "PaneView", ->
|
||||
|
||||
beforeEach ->
|
||||
pane2Model = paneModel.splitRight() # Can't destroy the last pane, so we add another
|
||||
pane2 = pane2Model._view
|
||||
pane2 = containerModel.getView(pane2Model).__spacePenView
|
||||
|
||||
it "triggers a 'pane:removed' event with the pane", ->
|
||||
removedHandler = jasmine.createSpy("removedHandler")
|
||||
@ -249,7 +250,7 @@ describe "PaneView", ->
|
||||
|
||||
beforeEach ->
|
||||
pane2Model = paneModel.splitRight(items: [pane.copyActiveItem()])
|
||||
pane2 = pane2Model._view
|
||||
pane2 = containerModel.getView(pane2Model).__spacePenView
|
||||
expect(pane2Model.isActive()).toBe true
|
||||
|
||||
it "adds or removes the .active class as appropriate", ->
|
||||
@ -296,7 +297,8 @@ describe "PaneView", ->
|
||||
pane2Model = pane1Model.splitRight(items: [pane1Model.copyActiveItem()])
|
||||
pane3Model = pane2Model.splitDown(items: [pane2Model.copyActiveItem()])
|
||||
pane2 = pane2Model._view
|
||||
pane3 = pane3Model._view
|
||||
pane2 = containerModel.getView(pane2Model).__spacePenView
|
||||
pane3 = containerModel.getView(pane3Model).__spacePenView
|
||||
|
||||
expect(container.find('> .pane-row > .pane').toArray()).toEqual [pane1[0]]
|
||||
expect(container.find('> .pane-row > .pane-column > .pane').toArray()).toEqual [pane2[0], pane3[0]]
|
||||
|
@ -209,7 +209,7 @@ describe "ThemeManager", ->
|
||||
|
||||
describe "base stylesheet loading", ->
|
||||
beforeEach ->
|
||||
atom.workspaceView = new WorkspaceView
|
||||
atom.workspaceView = atom.workspace.getView(atom.workspace).__spacePenView
|
||||
atom.workspaceView.append $$ -> @div class: 'editor'
|
||||
atom.workspaceView.attachToDom()
|
||||
|
||||
|
107
spec/view-registry-spec.coffee
Normal file
107
spec/view-registry-spec.coffee
Normal file
@ -0,0 +1,107 @@
|
||||
ViewRegistry = require '../src/view-registry'
|
||||
{View} = require '../src/space-pen-extensions'
|
||||
|
||||
describe "ViewRegistry", ->
|
||||
registry = null
|
||||
|
||||
beforeEach ->
|
||||
registry = new ViewRegistry
|
||||
|
||||
describe "::getView(object)", ->
|
||||
describe "when passed a DOM node", ->
|
||||
it "returns the given DOM node", ->
|
||||
node = document.createElement('div')
|
||||
expect(registry.getView(node)).toBe node
|
||||
|
||||
describe "when passed a SpacePen view", ->
|
||||
it "returns the root node of the view with a __spacePenView property pointing at the SpacePen view", ->
|
||||
class TestView extends View
|
||||
@content: -> @div "Hello"
|
||||
|
||||
view = new TestView
|
||||
node = registry.getView(view)
|
||||
expect(node.textContent).toBe "Hello"
|
||||
expect(node.__spacePenView).toBe view
|
||||
|
||||
describe "when passed a model object", ->
|
||||
describe "when a view provider is registered matching the object's constructor", ->
|
||||
describe "when the provider has a viewConstructor property", ->
|
||||
it "constructs a view element and assigns the model on it", ->
|
||||
class TestModel
|
||||
|
||||
class TestModelSubclass extends TestModel
|
||||
|
||||
class TestView
|
||||
setModel: (@model) ->
|
||||
|
||||
model = new TestModel
|
||||
|
||||
registry.addViewProvider
|
||||
modelConstructor: TestModel
|
||||
viewConstructor: TestView
|
||||
|
||||
view = registry.getView(model)
|
||||
expect(view instanceof TestView).toBe true
|
||||
expect(view.model).toBe model
|
||||
|
||||
subclassModel = new TestModelSubclass
|
||||
view2 = registry.getView(subclassModel)
|
||||
expect(view2 instanceof TestView).toBe true
|
||||
expect(view2.model).toBe subclassModel
|
||||
|
||||
describe "when the provider has a createView method", ->
|
||||
it "constructs a view element by calling the createView method with the model", ->
|
||||
class TestModel
|
||||
class TestView
|
||||
setModel: (@model) ->
|
||||
|
||||
registry.addViewProvider
|
||||
modelConstructor: TestModel
|
||||
createView: (model) ->
|
||||
view = new TestView
|
||||
view.setModel(model)
|
||||
view
|
||||
|
||||
model = new TestModel
|
||||
view = registry.getView(model)
|
||||
expect(view instanceof TestView).toBe true
|
||||
expect(view.model).toBe model
|
||||
|
||||
describe "when no view provider is registered for the object's constructor", ->
|
||||
describe "when the object has a .getViewClass() method", ->
|
||||
it "builds an instance of the view class with the model, then returns its root node with a __spacePenView property pointing at the view", ->
|
||||
class TestView extends View
|
||||
@content: (model) -> @div model.name
|
||||
initialize: (@model) ->
|
||||
|
||||
class TestModel
|
||||
constructor: (@name) ->
|
||||
getViewClass: -> TestView
|
||||
|
||||
model = new TestModel("hello")
|
||||
node = registry.getView(model)
|
||||
|
||||
expect(node.textContent).toBe "hello"
|
||||
view = node.__spacePenView
|
||||
expect(view instanceof TestView).toBe true
|
||||
expect(view.model).toBe model
|
||||
|
||||
# returns the same DOM node for repeated calls
|
||||
expect(registry.getView(model)).toBe node
|
||||
|
||||
describe "when the object has no .getViewClass() method", ->
|
||||
it "throws an exception", ->
|
||||
expect(-> registry.getView(new Object)).toThrow()
|
||||
|
||||
describe "::addViewProvider(providerSpec)", ->
|
||||
it "returns a disposable that can be used to remove the provider", ->
|
||||
class TestModel
|
||||
class TestView
|
||||
setModel: (@model) ->
|
||||
disposable = registry.addViewProvider
|
||||
modelConstructor: TestModel
|
||||
viewConstructor: TestView
|
||||
|
||||
expect(registry.getView(new TestModel) instanceof TestView).toBe true
|
||||
disposable.dispose()
|
||||
expect(-> registry.getView(new TestModel)).toThrow()
|
@ -1,4 +1,5 @@
|
||||
Workspace = require '../src/workspace'
|
||||
{View} = require '../src/space-pen-extensions'
|
||||
|
||||
describe "Workspace", ->
|
||||
workspace = null
|
||||
|
@ -13,7 +13,7 @@ describe "WorkspaceView", ->
|
||||
atom.project.setPath(atom.project.resolve('dir'))
|
||||
pathToOpen = atom.project.resolve('a')
|
||||
atom.workspace = new Workspace
|
||||
atom.workspaceView = new WorkspaceView(atom.workspace)
|
||||
atom.workspaceView = atom.workspace.getView(atom.workspace).__spacePenView
|
||||
atom.workspaceView.enableKeymap()
|
||||
atom.workspaceView.focus()
|
||||
|
||||
@ -29,7 +29,7 @@ describe "WorkspaceView", ->
|
||||
atom.workspaceView.remove()
|
||||
atom.project = atom.deserializers.deserialize(projectState)
|
||||
atom.workspace = Workspace.deserialize(workspaceState)
|
||||
atom.workspaceView = new WorkspaceView(atom.workspace)
|
||||
atom.workspaceView = atom.workspace.getView(atom.workspace).__spacePenView
|
||||
atom.workspaceView.attachToDom()
|
||||
|
||||
describe "when the serialized WorkspaceView has an unsaved buffer", ->
|
||||
@ -61,7 +61,7 @@ describe "WorkspaceView", ->
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('b').then (editor) ->
|
||||
pane2.activateItem(editor)
|
||||
pane2.activateItem(editor.copy())
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.open('../sample.js').then (editor) ->
|
||||
@ -185,7 +185,8 @@ describe "WorkspaceView", ->
|
||||
|
||||
describe "when the root view is deserialized", ->
|
||||
it "updates the title to contain the project's path", ->
|
||||
workspaceView2 = new WorkspaceView(atom.workspace.testSerialization())
|
||||
workspace2 = atom.workspace.testSerialization()
|
||||
workspaceView2 = workspace2.getView(workspace2).__spacePenView
|
||||
item = atom.workspace.getActivePaneItem()
|
||||
expect(workspaceView2.title).toBe "#{item.getTitle()} - #{atom.project.getPath()}"
|
||||
workspaceView2.remove()
|
||||
|
@ -582,7 +582,7 @@ class Atom extends Model
|
||||
|
||||
startTime = Date.now()
|
||||
@workspace = Workspace.deserialize(@state.workspace) ? new Workspace
|
||||
@workspaceView = new WorkspaceView(@workspace)
|
||||
@workspaceView = @workspace.getView(@workspace).__spacePenView
|
||||
@deserializeTimings.workspace = Date.now() - startTime
|
||||
|
||||
@keymaps.defaultTarget = @workspaceView[0]
|
||||
|
15
src/item-registry.coffee
Normal file
15
src/item-registry.coffee
Normal file
@ -0,0 +1,15 @@
|
||||
module.exports =
|
||||
class ItemRegistry
|
||||
constructor: ->
|
||||
@items = new WeakSet
|
||||
|
||||
addItem: (item) ->
|
||||
if @hasItem(item)
|
||||
throw new Error("The workspace can only contain one instance of item #{item}")
|
||||
@items.add(item)
|
||||
|
||||
removeItem: (item) ->
|
||||
@items.delete(item)
|
||||
|
||||
hasItem: (item) ->
|
||||
@items.has(item)
|
@ -16,10 +16,6 @@ class PaneAxisView extends View
|
||||
afterAttach: ->
|
||||
@container = @closest('.panes').view()
|
||||
|
||||
viewForModel: (model) ->
|
||||
viewClass = model.getViewClass()
|
||||
model._view ?= new viewClass(model)
|
||||
|
||||
onChildReplaced: ({index, oldChild, newChild}) =>
|
||||
focusedElement = document.activeElement if @hasFocus()
|
||||
@onChildRemoved({child: oldChild, index})
|
||||
@ -27,11 +23,11 @@ class PaneAxisView extends View
|
||||
focusedElement?.focus() if document.activeElement is document.body
|
||||
|
||||
onChildAdded: ({child, index}) =>
|
||||
view = @viewForModel(child)
|
||||
view = @model.getView(child).__spacePenView
|
||||
@insertAt(index, view)
|
||||
|
||||
onChildRemoved: ({child}) =>
|
||||
view = @viewForModel(child)
|
||||
view = @model.getView(child).__spacePenView
|
||||
view.detach()
|
||||
PaneView ?= require './pane-view'
|
||||
if view instanceof PaneView and view.model.isDestroyed()
|
||||
|
@ -46,6 +46,9 @@ class PaneAxis extends Model
|
||||
else
|
||||
PaneRowView ?= require './pane-row-view'
|
||||
|
||||
getView: (object) ->
|
||||
@container.getView(object)
|
||||
|
||||
getChildren: -> @children.slice()
|
||||
|
||||
getPanes: ->
|
||||
|
@ -26,11 +26,6 @@ class PaneContainerView extends View
|
||||
@subscriptions.add @model.observeRoot(@onRootChanged)
|
||||
@subscriptions.add @model.onDidChangeActivePaneItem(@onActivePaneItemChanged)
|
||||
|
||||
viewForModel: (model) ->
|
||||
if model?
|
||||
viewClass = model.getViewClass()
|
||||
model._view ?= new viewClass(model)
|
||||
|
||||
getRoot: ->
|
||||
@children().first().view()
|
||||
|
||||
@ -42,7 +37,7 @@ class PaneContainerView extends View
|
||||
@trigger 'pane:removed', [oldRoot]
|
||||
oldRoot?.detach()
|
||||
if root?
|
||||
view = @viewForModel(root)
|
||||
view = @model.getView(root).__spacePenView
|
||||
@append(view)
|
||||
focusedElement?.focus()
|
||||
else
|
||||
@ -88,7 +83,7 @@ class PaneContainerView extends View
|
||||
@getActivePaneView()
|
||||
|
||||
getActivePaneView: ->
|
||||
@viewForModel(@model.activePane)
|
||||
@model.getView(@model.getActivePane()).__spacePenView
|
||||
|
||||
getActivePaneItem: ->
|
||||
@model.getActivePaneItem()
|
||||
@ -97,7 +92,7 @@ class PaneContainerView extends View
|
||||
@getActivePaneView()?.activeView
|
||||
|
||||
paneForUri: (uri) ->
|
||||
@viewForModel(@model.paneForUri(uri))
|
||||
@model.getView(@model.paneForUri(uri)).__spacePenView
|
||||
|
||||
focusNextPaneView: ->
|
||||
@model.activateNextPane()
|
||||
|
@ -3,6 +3,9 @@
|
||||
{Emitter, CompositeDisposable} = require 'event-kit'
|
||||
Serializable = require 'serializable'
|
||||
Pane = require './pane'
|
||||
ViewRegistry = require './view-registry'
|
||||
ItemRegistry = require './item-registry'
|
||||
PaneContainerView = null
|
||||
|
||||
module.exports =
|
||||
class PaneContainer extends Model
|
||||
@ -27,6 +30,8 @@ class PaneContainer extends Model
|
||||
@emitter = new Emitter
|
||||
@subscriptions = new CompositeDisposable
|
||||
|
||||
@viewRegistry = params?.viewRegistry ? new ViewRegistry
|
||||
@itemRegistry = new ItemRegistry
|
||||
@setRoot(params?.root ? new Pane)
|
||||
@destroyEmptyPanes() if params?.destroyEmptyPanes
|
||||
|
||||
@ -43,6 +48,12 @@ class PaneContainer extends Model
|
||||
root: @root?.serialize()
|
||||
activePaneId: @activePane.id
|
||||
|
||||
getViewClass: ->
|
||||
PaneContainerView ?= require './pane-container-view'
|
||||
|
||||
getView: (object) ->
|
||||
@viewRegistry.getView(object)
|
||||
|
||||
onDidChangeRoot: (fn) ->
|
||||
@emitter.on 'did-change-root', fn
|
||||
|
||||
@ -169,7 +180,17 @@ class PaneContainer extends Model
|
||||
monitorPaneItems: ->
|
||||
@subscriptions.add @observePanes (pane) =>
|
||||
for item, index in pane.getItems()
|
||||
@emitter.emit 'did-add-pane-item', {item, pane, index}
|
||||
@addedPaneItem(item, pane, index)
|
||||
|
||||
pane.onDidAddItem ({item, index}) =>
|
||||
@addedPaneItem(item, pane, index)
|
||||
|
||||
pane.onDidRemoveItem ({item}) =>
|
||||
@removedPaneItem(item)
|
||||
|
||||
addedPaneItem: (item, pane, index) ->
|
||||
@itemRegistry.addItem(item)
|
||||
@emitter.emit 'did-add-pane-item', {item, pane, index}
|
||||
|
||||
removedPaneItem: (item) ->
|
||||
@itemRegistry.removeItem(item)
|
||||
|
@ -33,17 +33,9 @@ class PaneView extends View
|
||||
|
||||
previousActiveItem: null
|
||||
|
||||
initialize: (args...) ->
|
||||
initialize: (@model) ->
|
||||
@subscriptions = new CompositeDisposable
|
||||
|
||||
if args[0] instanceof Pane
|
||||
@model = args[0]
|
||||
else
|
||||
@model = new Pane(items: args)
|
||||
@model._view = this
|
||||
|
||||
@onItemAdded(item) for item in @items
|
||||
@viewsByItem = new WeakMap()
|
||||
@handleEvents()
|
||||
|
||||
handleEvents: ->
|
||||
@ -175,7 +167,7 @@ class PaneView extends View
|
||||
item.on('modified-status-changed', @activeItemModifiedChanged)
|
||||
@activeItemDisposables.add(disposable) if disposable?.dispose?
|
||||
|
||||
view = @viewForItem(item)
|
||||
view = @model.getView(item).__spacePenView
|
||||
otherView.hide() for otherView in @itemViews.children().not(view).views()
|
||||
@itemViews.append(view) unless view.parent().is(@itemViews)
|
||||
view.show() if @attached
|
||||
@ -189,8 +181,8 @@ class PaneView extends View
|
||||
onItemRemoved: ({item, index, destroyed}) =>
|
||||
if item instanceof $
|
||||
viewToRemove = item
|
||||
else if viewToRemove = @viewsByItem.get(item)
|
||||
@viewsByItem.delete(item)
|
||||
else
|
||||
viewToRemove = @model.getView(item).__spacePenView
|
||||
|
||||
if viewToRemove?
|
||||
if destroyed
|
||||
@ -213,27 +205,15 @@ class PaneView extends View
|
||||
activeItemModifiedChanged: =>
|
||||
@trigger 'pane:active-item-modified-status-changed'
|
||||
|
||||
viewForItem: (item) ->
|
||||
return unless item?
|
||||
if item instanceof $
|
||||
item
|
||||
else if view = @viewsByItem.get(item)
|
||||
view
|
||||
else
|
||||
viewClass = item.getViewClass()
|
||||
view = new viewClass(item)
|
||||
@viewsByItem.set(item, view)
|
||||
view
|
||||
@::accessor 'activeView', -> @model.getView(@activeItem)?.__spacePenView
|
||||
|
||||
@::accessor 'activeView', -> @viewForItem(@activeItem)
|
||||
splitLeft: (items...) -> @model.getView(@model.splitLeft({items})).__spacePenView
|
||||
|
||||
splitLeft: (items...) -> @model.splitLeft({items})._view
|
||||
splitRight: (items...) -> @model.getView(@model.splitRight({items})).__spacePenView
|
||||
|
||||
splitRight: (items...) -> @model.splitRight({items})._view
|
||||
splitUp: (items...) -> @model.getView(@model.splitUp({items})).__spacePenView
|
||||
|
||||
splitUp: (items...) -> @model.splitUp({items})._view
|
||||
|
||||
splitDown: (items...) -> @model.splitDown({items})._view
|
||||
splitDown: (items...) -> @model.getView(@model.splitDown({items})).__spacePenView
|
||||
|
||||
# Public: Get the container view housing this pane.
|
||||
#
|
||||
|
@ -56,6 +56,9 @@ class Pane extends Model
|
||||
# Called by the view layer to construct a view for this model.
|
||||
getViewClass: -> PaneView ?= require './pane-view'
|
||||
|
||||
getView: (object) ->
|
||||
@container.getView(object)
|
||||
|
||||
getParent: -> @parent
|
||||
|
||||
setParent: (@parent) -> @parent
|
||||
@ -377,8 +380,8 @@ class Pane extends Model
|
||||
# * `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)
|
||||
pane.addItem(item, index)
|
||||
|
||||
# Public: Destroy the active item and activate the next item.
|
||||
destroyActiveItem: ->
|
||||
|
45
src/view-registry.coffee
Normal file
45
src/view-registry.coffee
Normal file
@ -0,0 +1,45 @@
|
||||
{Disposable} = require 'event-kit'
|
||||
{jQuery} = require './space-pen-extensions'
|
||||
|
||||
module.exports =
|
||||
class ViewRegistry
|
||||
constructor: ->
|
||||
@views = new WeakMap
|
||||
@providers = []
|
||||
|
||||
addViewProvider: (providerSpec) ->
|
||||
@providers.push(providerSpec)
|
||||
new Disposable =>
|
||||
@providers = @providers.filter (provider) -> provider isnt providerSpec
|
||||
|
||||
getView: (object) ->
|
||||
return unless object?
|
||||
|
||||
if view = @views.get(object)
|
||||
view
|
||||
else
|
||||
view = @createView(object)
|
||||
@views.set(object, view)
|
||||
view
|
||||
|
||||
createView: (object) ->
|
||||
if object instanceof HTMLElement
|
||||
object
|
||||
else if object instanceof jQuery
|
||||
object[0].__spacePenView ?= object
|
||||
object[0]
|
||||
else if provider = @findProvider(object)
|
||||
element = provider.createView?(object)
|
||||
unless element?
|
||||
element = new provider.viewConstructor
|
||||
element.setModel(object)
|
||||
element
|
||||
else if viewConstructor = object?.getViewClass?()
|
||||
view = new viewConstructor(object)
|
||||
view[0].__spacePenView ?= view
|
||||
view[0]
|
||||
else
|
||||
throw new Error("Can't create a view for #{object.constructor.name} instance. Please register a view provider.")
|
||||
|
||||
findProvider: (object) ->
|
||||
@providers.find ({modelConstructor}) -> object instanceof modelConstructor
|
@ -87,7 +87,7 @@ class WorkspaceView extends View
|
||||
@element.getModel = -> model
|
||||
atom.commands.setRootNode(@[0])
|
||||
|
||||
panes = new PaneContainerView(@model.paneContainer)
|
||||
panes = @model.getView(@model.paneContainer).__spacePenView
|
||||
@panes.replaceWith(panes)
|
||||
@panes = panes
|
||||
|
||||
|
@ -9,6 +9,8 @@ Delegator = require 'delegato'
|
||||
Editor = require './editor'
|
||||
PaneContainer = require './pane-container'
|
||||
Pane = require './pane'
|
||||
ViewRegistry = require './view-registry'
|
||||
WorkspaceView = null
|
||||
|
||||
# Essential: Represents the state of the user interface for the entire window.
|
||||
# An instance of this class is available via the `atom.workspace` global.
|
||||
@ -27,7 +29,7 @@ class Workspace extends Model
|
||||
@delegatesProperty 'activePane', 'activePaneItem', toProperty: 'paneContainer'
|
||||
|
||||
@properties
|
||||
paneContainer: -> new PaneContainer
|
||||
paneContainer: null
|
||||
fullScreen: false
|
||||
destroyedItemUris: -> []
|
||||
|
||||
@ -37,6 +39,8 @@ class Workspace extends Model
|
||||
@emitter = new Emitter
|
||||
@openers = []
|
||||
|
||||
@viewRegistry ?= new ViewRegistry
|
||||
@paneContainer ?= new PaneContainer({@viewRegistry})
|
||||
@paneContainer.onDidDestroyPaneItem(@onPaneItemDestroyed)
|
||||
|
||||
@registerOpener (filePath) =>
|
||||
@ -55,6 +59,8 @@ class Workspace extends Model
|
||||
for packageName in params.packagesWithActiveGrammars ? []
|
||||
atom.packages.getLoadedPackage(packageName)?.loadGrammarsSync()
|
||||
|
||||
params.viewRegistry = new ViewRegistry
|
||||
params.paneContainer.viewRegistry = params.viewRegistry
|
||||
params.paneContainer = PaneContainer.deserialize(params.paneContainer)
|
||||
params
|
||||
|
||||
@ -64,6 +70,9 @@ class Workspace extends Model
|
||||
fullScreen: atom.isFullScreen()
|
||||
packagesWithActiveGrammars: @getPackageNamesWithActiveGrammars()
|
||||
|
||||
getViewClass: ->
|
||||
WorkspaceView ?= require './workspace-view'
|
||||
|
||||
getPackageNamesWithActiveGrammars: ->
|
||||
packageNames = []
|
||||
addGrammar = ({includedGrammarScopes, packageName}={}) ->
|
||||
@ -488,3 +497,85 @@ class Workspace extends Model
|
||||
# Called by Model superclass when destroyed
|
||||
destroyed: ->
|
||||
@paneContainer.destroy()
|
||||
|
||||
###
|
||||
Section: View Management
|
||||
###
|
||||
|
||||
# Essential: Get the view associated with an object in the workspace.
|
||||
#
|
||||
# If you're just *using* the workspace, you shouldn't need to access the view
|
||||
# layer, but view layer access may be necessary if you want to perform DOM
|
||||
# manipulation that isn't supported via the model API.
|
||||
#
|
||||
# ## Examples
|
||||
#
|
||||
# ### Getting An Editor View
|
||||
# ```coffee
|
||||
# textEditor = atom.workspace.getActiveTextEditor()
|
||||
# textEditorView = atom.workspace.getView(textEditor)
|
||||
# ```
|
||||
#
|
||||
# ### Getting A Pane View
|
||||
# ```coffee
|
||||
# pane = atom.workspace.getActivePane()
|
||||
# paneView = atom.workspace.getView(pane)
|
||||
# ```
|
||||
#
|
||||
# ### Getting The Workspace View
|
||||
#
|
||||
# ```coffee
|
||||
# workspaceView = atom.workspace.getView(atom.workspace)
|
||||
# ```
|
||||
#
|
||||
# * `object` The object for which you want to retrieve a view. This can be a
|
||||
# pane item, a pane, or the workspace itself.
|
||||
#
|
||||
# Returns a DOM element.
|
||||
getView: (object) ->
|
||||
@viewRegistry.getView(object)
|
||||
|
||||
# Essential: Add a provider that will be used to construct views in the
|
||||
# workspace's view layer based on model objects in its model layer.
|
||||
#
|
||||
# If you're adding your own kind of pane item, a good strategy for all but the
|
||||
# simplest items is to separate the model and the view. The model handles
|
||||
# application logic and is the primary point of API interaction. The view
|
||||
# just handles presentation.
|
||||
#
|
||||
# Use view providers to inform the workspace how your model objects should be
|
||||
# presented in the DOM. A view provider must always return a DOM node, which
|
||||
# makes [HTML 5 custom elements](http://www.html5rocks.com/en/tutorials/webcomponents/customelements/)
|
||||
# an ideal tool for implementing views in Atom.
|
||||
#
|
||||
# ## Example
|
||||
#
|
||||
# Text editors are divided into a model and a view layer, so when you interact
|
||||
# with methods like `atom.workspace.getActiveTextEditor()` you're only going
|
||||
# to get the model object. We display text editors on screen by teaching the
|
||||
# workspace what view constructor it should use to represent them:
|
||||
#
|
||||
# ```coffee
|
||||
# atom.workspace.addViewProvider
|
||||
# modelConstructor: TextEditor
|
||||
# viewConstructor: TextEditorElement
|
||||
# ```
|
||||
#
|
||||
# * `providerSpec` {Object} containing the following keys:
|
||||
# * `modelConstructor` Constructor {Function} for your model.
|
||||
# * `viewConstructor` (Optional) Constructor {Function} for your view. It
|
||||
# should be a subclass of `HTMLElement` (that is, your view should be a
|
||||
# DOM node) and have a `::setModel()` method which will be called
|
||||
# immediately after construction. If you don't supply this property, you
|
||||
# must supply the `createView` property with a function that never returns
|
||||
# `undefined`.
|
||||
# * `createView` (Optional) Factory {Function} that must return a subclass
|
||||
# of `HTMLElement` or `undefined`. If this property is not present or the
|
||||
# function returns `undefined`, the view provider will fall back to the
|
||||
# `viewConstructor` property. If you don't provide this property, you must
|
||||
# provider a `viewConstructor` property.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to remove the
|
||||
# added provider.
|
||||
addViewProvider: (providerSpec) ->
|
||||
@viewRegistry.addViewProvider(providerSpec)
|
||||
|
Loading…
Reference in New Issue
Block a user