atom/atom — pull request #4353 by nathansobo (2014-12-01 00:49:03+00:00)
Title: Separate view creation from association

## Concerns About Current View Registry

Originally, the view registry had three main responsibilities:

* A centralized place to register view providers, which describe how element constructors associate with constructors.
* A factory that can create a view for a given model based on the above providers.
* A 1:1 mapping from models to views that persists for the lifetime of each model.

After working with the system and talking with @maxbrunsfeld, I'm very concerned about the pitfalls associated with maintaining a *global* 1:1 mapping between models and views. Currently, the only way to create a new view is via `getView`, which returns an existing view if one already exists. If a user called this method thinking they were creating a new view, but one already existed, they could potentially move the existing DOM node from its previous location on the DOM. Beyond that: are we confident enough that we'll want a 1:1 correspondence between models and views *everywhere* that we want to force those semantics globally if anyone wants to use our factory?

## Proposed Changes

In response to these concerns, this PR separates the view *factory* functionality from the view *registry* functionality, meaning you can use the factory to create a view without buying into the 1:1 map. The factory remains global at `atom.views` and has two methods, `::createView` and `::addViewProvider`. The *registry* is moved inside of WorkspaceElement and is proxied via `WorkspaceElement::getView`.

If a user wants to get a reference to a particular model's existing view *in the workspace*, then they should call `::getView` on the workspace element. If they want to create a *new view*, then they can use `.createView` on the global factory. This radically reduces the amount of global state we're tracking, making `atom.views` a more reasonable global service. It also discourages people from referencing the view from the model layer since `::getView` can only be accessed if you already have a reference to the view layer.

## Open Questions

### Accessing the Workspace Element?

Prior to this PR, it's possible to get a reference to the workspace element with `atom.views.getView(atom.workspace)`. It wasn't a particularly attractive incantation as it was, but at least it was possible. There's now no longer any way to get access to the workspace element short of direct DOM querying:

```coffee
workpaceElement = document.querySelector('atom-workspace')
```

It actually reads clearer than accessing it via `atom.views`, but it still feels awkward for some reason to have to pull this off the DOM with a query. One idea is that we could add a `document.workspace` property as a shorthand for querying the selector. We could even automatically create the workspace element when that property is referenced for the first time in specs.

It seems very much inline with existing shorthand properties such as `document.body` and `document.head`, and since the user would be going through `document` it would emphasize that you are entering DOM territory when you call this. The downside is that we would be adding a non-standard property to the `document` object.

Another option is `atom.workspaceElement`. Or we just force people to query for it.

### Clarify The Global Name?

I kinda want to change `atom.views` to `atom.viewFactory`. That will yet more deprecation warnings for APIs that we've made public as part of the effort, but I think long-term clarity could be worth the short-term incremental pain.