From ee4116536d66e982fbd6eefffd0cb90908730685 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 27 Oct 2014 17:15:45 -0700 Subject: [PATCH] Move the ViewRegistry to atom.views --- benchmark/benchmark-suite.coffee | 2 +- spec/atom-spec.coffee | 2 +- spec/package-manager-spec.coffee | 2 +- spec/pane-container-view-spec.coffee | 12 +-- spec/pane-view-spec.coffee | 6 +- spec/theme-manager-spec.coffee | 2 +- spec/workspace-view-spec.coffee | 6 +- src/atom.coffee | 7 +- src/view-registry.coffee | 73 ++++++++++++++++ src/workspace-element.coffee | 2 +- src/workspace-view.coffee | 2 +- src/workspace.coffee | 121 +++++---------------------- 12 files changed, 116 insertions(+), 121 deletions(-) diff --git a/benchmark/benchmark-suite.coffee b/benchmark/benchmark-suite.coffee index 207c056df..f4eb62cd8 100644 --- a/benchmark/benchmark-suite.coffee +++ b/benchmark/benchmark-suite.coffee @@ -7,7 +7,7 @@ describe "editorView.", -> beforeEach -> atom.workspaceViewParentSelector = '#jasmine-content' - atom.workspaceView = atom.workspace.getView(atom.workspace).__spacePenView + atom.workspaceView = atom.views.getView(atom.workspace).__spacePenView atom.workspaceView.attachToDom() atom.workspaceView.width(1024) diff --git a/spec/atom-spec.coffee b/spec/atom-spec.coffee index 31fc9b220..615e510f7 100644 --- a/spec/atom-spec.coffee +++ b/spec/atom-spec.coffee @@ -6,7 +6,7 @@ ThemeManager = require '../src/theme-manager' describe "the `atom` global", -> beforeEach -> - atom.workspaceView = atom.workspace.getView(atom.workspace).__spacePenView + atom.workspaceView = atom.views.getView(atom.workspace).__spacePenView describe 'window sizing methods', -> describe '::getPosition and ::setPosition', -> diff --git a/spec/package-manager-spec.coffee b/spec/package-manager-spec.coffee index ab393c623..2cacbfb1d 100644 --- a/spec/package-manager-spec.coffee +++ b/spec/package-manager-spec.coffee @@ -3,7 +3,7 @@ Package = require '../src/package' describe "PackageManager", -> beforeEach -> - atom.workspaceView = atom.workspace.getView(atom.workspace).__spacePenView + atom.workspaceView = atom.views.getView(atom.workspace).__spacePenView describe "::loadPackage(name)", -> it "continues if the package has an invalid package.json", -> diff --git a/spec/pane-container-view-spec.coffee b/spec/pane-container-view-spec.coffee index 61f44521c..b0989cfaf 100644 --- a/spec/pane-container-view-spec.coffee +++ b/spec/pane-container-view-spec.coffee @@ -19,7 +19,7 @@ describe "PaneContainerView", -> save: -> @saved = true isEqual: (other) -> @name is other?.name - container = atom.workspace.getView(atom.workspace.paneContainer).__spacePenView + container = atom.views.getView(atom.workspace.paneContainer).__spacePenView pane1 = container.getRoot() pane1.activateItem(new TestView('1')) pane2 = pane1.splitRight(new TestView('2')) @@ -73,7 +73,7 @@ describe "PaneContainerView", -> describe "serialization", -> it "can be serialized and deserialized, and correctly adjusts dimensions of deserialized panes after attach", -> - newContainer = atom.workspace.getView(container.model.testSerialization()).__spacePenView + newContainer = atom.views.getView(container.model.testSerialization()).__spacePenView expect(newContainer.find('atom-pane-axis.horizontal > :contains(1)')).toExist() expect(newContainer.find('atom-pane-axis.horizontal > atom-pane-axis.vertical > :contains(2)')).toExist() expect(newContainer.find('atom-pane-axis.horizontal > atom-pane-axis.vertical > :contains(3)')).toExist() @@ -89,14 +89,14 @@ describe "PaneContainerView", -> describe "if the 'core.destroyEmptyPanes' config option is false (the default)", -> it "leaves the empty panes intact", -> - newContainer = atom.workspace.getView(container.model.testSerialization()).__spacePenView + newContainer = atom.views.getView(container.model.testSerialization()).__spacePenView expect(newContainer.find('atom-pane-axis.horizontal > :contains(1)')).toExist() expect(newContainer.find('atom-pane-axis.horizontal > atom-pane-axis.vertical > atom-pane').length).toBe 2 describe "if the 'core.destroyEmptyPanes' config option is true", -> it "removes empty panes on deserialization", -> atom.config.set('core.destroyEmptyPanes', true) - newContainer = atom.workspace.getView(container.model.testSerialization()).__spacePenView + newContainer = atom.views.getView(container.model.testSerialization()).__spacePenView expect(newContainer.find('atom-pane-axis.horizontal, atom-pane-axis.vertical')).not.toExist() expect(newContainer.find('> :contains(1)')).toExist() @@ -109,7 +109,7 @@ describe "PaneContainerView", -> item2b = new TestView('2b') item3a = new TestView('3a') - container = atom.workspace.getView(new PaneContainer).__spacePenView + container = atom.views.getView(new PaneContainer).__spacePenView pane1 = container.getRoot() pane1.activateItem(item1a) container.attachToDom() @@ -259,7 +259,7 @@ describe "PaneContainerView", -> # |7|8|9| # ------- - container = atom.workspace.getView(new PaneContainer).__spacePenView + container = atom.views.getView(new PaneContainer).__spacePenView pane1 = container.getRoot() pane1.activateItem(new TestView('1')) pane4 = pane1.splitDown(new TestView('4')) diff --git a/spec/pane-view-spec.coffee b/spec/pane-view-spec.coffee index 12ee29b6f..7c98a3086 100644 --- a/spec/pane-view-spec.coffee +++ b/spec/pane-view-spec.coffee @@ -24,7 +24,7 @@ describe "PaneView", -> beforeEach -> deserializerDisposable = atom.deserializers.add(TestView) - container = atom.workspace.getView(new PaneContainer).__spacePenView + container = atom.views.getView(new PaneContainer).__spacePenView containerModel = container.model view1 = new TestView(id: 'view-1', text: 'View 1') view2 = new TestView(id: 'view-2', text: 'View 2') @@ -311,13 +311,13 @@ describe "PaneView", -> container.attachToDom() pane.focus() - container2 = atom.workspace.getView(container.model.testSerialization()).__spacePenView + container2 = atom.views.getView(container.model.testSerialization()).__spacePenView pane2 = container2.getRoot() container2.attachToDom() expect(pane2).toMatchSelector(':has(:focus)') $(document.activeElement).blur() - container3 = atom.workspace.getView(container.model.testSerialization()).__spacePenView + container3 = atom.views.getView(container.model.testSerialization()).__spacePenView pane3 = container3.getRoot() container3.attachToDom() expect(pane3).not.toMatchSelector(':has(:focus)') diff --git a/spec/theme-manager-spec.coffee b/spec/theme-manager-spec.coffee index 5ce9f614a..b03984534 100644 --- a/spec/theme-manager-spec.coffee +++ b/spec/theme-manager-spec.coffee @@ -208,7 +208,7 @@ describe "ThemeManager", -> describe "base stylesheet loading", -> beforeEach -> - atom.workspaceView = atom.workspace.getView(atom.workspace).__spacePenView + atom.workspaceView = atom.views.getView(atom.workspace).__spacePenView atom.workspaceView.append $('') atom.workspaceView.attachToDom() diff --git a/spec/workspace-view-spec.coffee b/spec/workspace-view-spec.coffee index d37281cc0..ff0eff660 100644 --- a/spec/workspace-view-spec.coffee +++ b/spec/workspace-view-spec.coffee @@ -13,7 +13,7 @@ describe "WorkspaceView", -> atom.project.setPaths([atom.project.resolve('dir')]) pathToOpen = atom.project.resolve('a') atom.workspace = new Workspace - atom.workspaceView = atom.workspace.getView(atom.workspace).__spacePenView + atom.workspaceView = atom.views.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 = atom.workspace.getView(atom.workspace).__spacePenView + atom.workspaceView = atom.views.getView(atom.workspace).__spacePenView atom.workspaceView.attachToDom() describe "when the serialized WorkspaceView has an unsaved buffer", -> @@ -274,7 +274,7 @@ describe "WorkspaceView", -> describe 'panel containers', -> workspaceElement = null beforeEach -> - workspaceElement = atom.workspace.getView(atom.workspace) + workspaceElement = atom.views.getView(atom.workspace) it 'inserts panel container elements in the correct places in the DOM', -> leftContainer = workspaceElement.querySelector('atom-panel-container[location="left"]') diff --git a/src/atom.coffee b/src/atom.coffee index 31580d2c9..a69323a60 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -140,6 +140,9 @@ class Atom extends Model # Public: A {DeserializerManager} instance deserializers: null + # Public: A {ViewRegistry} instance + views: null + # Public: A {Workspace} instance workspace: null @@ -182,6 +185,7 @@ class Atom extends Model Config = require './config' KeymapManager = require './keymap-extensions' + ViewRegistry = require './view-registry' CommandRegistry = require './command-registry' PackageManager = require './package-manager' Clipboard = require './clipboard' @@ -209,6 +213,7 @@ class Atom extends Model @keymaps = new KeymapManager({configDirPath, resourcePath}) @keymap = @keymaps # Deprecated @commands = new CommandRegistry + @views = new ViewRegistry @packages = new PackageManager({devMode, configDirPath, resourcePath, safeMode}) @styles = new StyleManager document.head.appendChild(new StylesElement) @@ -597,7 +602,7 @@ class Atom extends Model startTime = Date.now() @workspace = Workspace.deserialize(@state.workspace) ? new Workspace - @workspaceView = @workspace.getView(@workspace).__spacePenView + @workspaceView = @views.getView(@workspace).__spacePenView @deserializeTimings.workspace = Date.now() - startTime @keymaps.defaultTarget = @workspaceView[0] diff --git a/src/view-registry.coffee b/src/view-registry.coffee index 2893cf8de..d95ae77cc 100644 --- a/src/view-registry.coffee +++ b/src/view-registry.coffee @@ -1,17 +1,90 @@ {Disposable} = require 'event-kit' {jQuery} = require './space-pen-extensions' +# Essential module.exports = class ViewRegistry constructor: -> @views = new WeakMap @providers = [] + # 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. + # + # ## Examples + # + # 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.views.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) -> @providers.push(providerSpec) new Disposable => @providers = @providers.filter (provider) -> provider isnt providerSpec + # 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.views.getView(textEditor) + # ``` + # + # ### Getting A Pane View + # ```coffee + # pane = atom.workspace.getActivePane() + # paneView = atom.views.getView(pane) + # ``` + # + # ### Getting The Workspace View + # + # ```coffee + # workspaceView = atom.views.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) -> return unless object? diff --git a/src/workspace-element.coffee b/src/workspace-element.coffee index 031f8af45..73a9438af 100644 --- a/src/workspace-element.coffee +++ b/src/workspace-element.coffee @@ -64,7 +64,7 @@ class WorkspaceElement extends HTMLElement getModel: -> @model setModel: (@model) -> - @paneContainer = @model.getView(@model.paneContainer) + @paneContainer = atom.views.getView(@model.paneContainer) @verticalAxis.appendChild(@paneContainer) @addEventListener 'focus', @handleFocus.bind(this) diff --git a/src/workspace-view.coffee b/src/workspace-view.coffee index 28ee66b2f..06a39e9a5 100644 --- a/src/workspace-view.coffee +++ b/src/workspace-view.coffee @@ -59,7 +59,7 @@ class WorkspaceView extends View constructor: (@element) -> unless @element? - return atom.workspace.getView(atom.workspace).__spacePenView + return atom.views.getView(atom.workspace).__spacePenView super @deprecateViewEvents() diff --git a/src/workspace.coffee b/src/workspace.coffee index 5b640b61b..e4fa0ffb9 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -45,15 +45,15 @@ class Workspace extends Model @emitter = new Emitter @openers = [] - @viewRegistry ?= new ViewRegistry - @paneContainer ?= new PaneContainer({@viewRegistry}) + viewRegistry = atom.views + @paneContainer ?= new PaneContainer({viewRegistry}) @paneContainer.onDidDestroyPaneItem(@onPaneItemDestroyed) @panelContainers = - top: new PanelContainer({@viewRegistry, location: 'top'}) - left: new PanelContainer({@viewRegistry, location: 'left'}) - right: new PanelContainer({@viewRegistry, location: 'right'}) - bottom: new PanelContainer({@viewRegistry, location: 'bottom'}) + top: new PanelContainer({viewRegistry, location: 'top'}) + left: new PanelContainer({viewRegistry, location: 'left'}) + right: new PanelContainer({viewRegistry, location: 'right'}) + bottom: new PanelContainer({viewRegistry, location: 'bottom'}) @subscribeToActiveItem() @@ -68,15 +68,15 @@ class Workspace extends Model when 'atom://.atom/init-script' @open(atom.getUserInitScriptPath()) - @addViewProvider + atom.views.addViewProvider modelConstructor: Workspace viewConstructor: WorkspaceElement - @addViewProvider + atom.views.addViewProvider modelConstructor: PanelContainer viewConstructor: PanelContainerElement - @addViewProvider + atom.views.addViewProvider modelConstructor: Panel viewConstructor: PanelElement @@ -85,8 +85,7 @@ 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.viewRegistry = atom.views params.paneContainer = PaneContainer.deserialize(params.paneContainer) params @@ -605,8 +604,8 @@ class Workspace extends Model # # * `options` {Object} # * `item` Your panel content. It can be DOM element, a jQuery element, or - # a model with a view registered via {::addViewProvider}. We recommend the - # latter. See {::addViewProvider} for more information. + # a model with a view registered via {ViewRegistry::addViewProvider}. We recommend the + # latter. See {ViewRegistry::addViewProvider} for more information. # * `visible` (optional) {Boolean} false if you want the panel to initially be hidden # (default: true) # * `priority` (optional) {Number} Determines stacking order. Lower priority items are @@ -620,8 +619,8 @@ class Workspace extends Model # # * `options` {Object} # * `item` Your panel content. It can be DOM element, a jQuery element, or - # a model with a view registered via {::addViewProvider}. We recommend the - # latter. See {::addViewProvider} for more information. + # a model with a view registered via {ViewRegistry::addViewProvider}. We recommend the + # latter. See {ViewRegistry::addViewProvider} for more information. # * `visible` (optional) {Boolean} false if you want the panel to initially be hidden # (default: true) # * `priority` (optional) {Number} Determines stacking order. Lower priority items are @@ -635,8 +634,8 @@ class Workspace extends Model # # * `options` {Object} # * `item` Your panel content. It can be DOM element, a jQuery element, or - # a model with a view registered via {::addViewProvider}. We recommend the - # latter. See {::addViewProvider} for more information. + # a model with a view registered via {ViewRegistry::addViewProvider}. We recommend the + # latter. See {ViewRegistry::addViewProvider} for more information. # * `visible` (optional) {Boolean} false if you want the panel to initially be hidden # (default: true) # * `priority` (optional) {Number} Determines stacking order. Lower priority items are @@ -650,8 +649,8 @@ class Workspace extends Model # # * `options` {Object} # * `item` Your panel content. It can be DOM element, a jQuery element, or - # a model with a view registered via {::addViewProvider}. We recommend the - # latter. See {::addViewProvider} for more information. + # a model with a view registered via {ViewRegistry::addViewProvider}. We recommend the + # latter. See {ViewRegistry::addViewProvider} for more information. # * `visible` (optional) {Boolean} false if you want the panel to initially be hidden # (default: true) # * `priority` (optional) {Number} Determines stacking order. Lower priority items are @@ -663,87 +662,5 @@ class Workspace extends Model addPanel: (location, options) -> options ?= {} - options.viewRegistry = @viewRegistry + options.viewRegistry = atom.views @panelContainers[location].addPanel(new Panel(options)) - - ### - 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. - # - # ## Examples - # - # 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)