A user account is required in order to edit this wiki, but we've had to disable public user registrations due to spam.
To request an account, ask an autoconfirmed user on Chat (such as one of these permanent autoconfirmed members).
Component Model: Difference between revisions
No edit summary |
|||
Line 169: | Line 169: | ||
* API surface: introduce a new <code>isolated</code> attribute to the <code>script</code> attributes. | * API surface: introduce a new <code>isolated</code> attribute to the <code>script</code> attributes. | ||
Needs Implementing | ===Needs Implementing=== | ||
* [[Component_Model_Isolation_Brainstorming | Isolation Primitives]] | * [[Component_Model_Isolation_Brainstorming | Isolation Primitives]] | ||
Revision as of 20:35, 18 August 2011
Here's a good starting point for learning about the component model spec, which is currently under development (also see periodically updating gh-pages).
Introduction
TODO Populate with beautifully crafted words.
Overview
Extensibility
The component model must enable creation of new types of DOM elements by allowing the use of existing DOM elements in Javascript prototype chain. For example, here's how you might create a new sub-type of HTMLElement:
function LayoutManagerPanel() {
HTMLElement.call(this);
}
LayoutManagerPanel.prototype = Object.create(HTMLElement.prototype);
// ...
// 1) Will not be able to add instances of LayoutManagerPanel to document without this call.
// 2) First parameter specifies the tagName of the element being registered and must be a string prefixed with "x-".
Element.register("x-layout-manager-panel", LayoutManagerPanel);
// ...
var panel = new LayoutManagerPanel();
document.body.appendChild(panel);
// or
document.body.innerHTML = "<x-layout-manager-panel></x-layout-manager-panel>";
The resulting panel
instance is a Javascript object that is a valid DOM element, which can be added to the DOM tree. You can then extend this object using standard Javascript prototype inheritance.
Needs implementing
- Make calling constructors of DOM elements possible.
- Implement
Element.register
.
Consistency
Because components are just DOM objects, they inherently share the same traversal and manipulation APIs, as defined by the DOM Core. The authors of components can extend these APIs by adding custom methods and properties on DOM objects, using standard Javascript inheritance:
Widget.prototype = Object.create(HTMLElement.prototype, {
update: {
value: function() { /* ... */ }
},
value: {
get: function() { /* ... */ },
set: function() { /* ... */ }
},
// ...
});
The common API surface and the ability to extend it serves as a natural API boundary for framework authors, enabling interoperability.
Encapsulation
To enable hiding of the implementation details, the component model provides a way to build a DOM tree that is not accessible from the document DOM tree, but is rendered as part of the document. This DOM tree, associated with the component is the shadow DOM. The boundary between the document DOM tree and shadow DOM tree provides complete encapsulation, and ensures that no information about the shadow DOM tree crosses this boundary. Additionally, the boundary serves as a convenient style application lever, giving the component a choice of letting (or not letting) document CSS affect the shadow DOM tree.
Every DOM element instance may only have (or host) one shadow DOM tree. A shadow tree is instantiated by creating an instance of the ShadowRoot
object, which takes a reference to the hosting element as a parameter. Attempting to create more than one instance for the same element throws an exception:
var element = document.createElement("div");
var shadow = new ShadowRoot(element);
var shadow2 = new ShadowRoot(element); // throws an exception.
A ShadowRoot
instance is a Node, and acts as the root of the element's shadow DOM subtree. The ShadowRoot
itself is never rendered, nor has styles. In this regard, it's similar to the DocumentFragment. It has two properties:
applyAuthorSheets
, which is either true (that is, apply author style sheets from the document), or false (don't);shadowHost
, which points to the hosting element.
Needs Implementing
- shadow DOM plumbing, including
ShadowRoot
object
Composability
Being DOM objects, components fit naturally into the document DOM tree and support all of its composition properties. In addition, the content
element allows controlling interaction between shadow and document DOM trees. A content
element specifies places where immediate document tree children of the component are rendered inside the shadow tree. For example, a DockLayoutPanel
component could be used like this in the document DOM tree:
<x-dock-layout-panel>
<h1 class="north">On Gardens</h1>
<ul class="west">
<li>Automatic Gardens</li>
<li>Gardening on minefields</li>
</ul>
<p>I love gardening.</p>
<div class="south">Written by Avid Gardener.</div>
</x-dock-layout-panel>
Provided that its shadow DOM tree looks like this:
<#shadow-root>
<div class="north">
<content includes=".north">
</div>
<div>
<div class="west">
<content includes=".west">
</div>
<div class="east">
<content>
</div>
</div>
<div class="south">
<content includes=".east">
</div>
<#shadow-root>
The document DOM tree children on of
x-dock-layout-panel
will be rendered as if composed from this tree:
<x-dock-layout-panel>
<div class="north">
<h1 class="north">On Gardens</h1>
</div>
<div>
<div class="west">
<ul class="west">
<li>Automatic Gardens</li>
<li>Gardening on minefields</li>
</ul>
</div>
<div class="east">
<p>I love gardening.</p>
</div>
</div>
<div class="south">
<div class="south">Written by Avid Gardener.</div>
</div>
</x-dock-layout-panel>
Needs Implementing
- Support for the
content
element
Desugaring
The component model also explains pretty well how the native HTML elements are built and dispels some of the magic associated with the "DOM object vs. Javascript object" juxtaposition.
Allowing DOM elements to participate in the Javascript inheritance chain makes DOM elements more approachable and easier to work with.
Complex DOM elements that are rendered with more than one CSS box (and aren't specified in terms of CSS, like lists) are just components that have shadow DOM. Coincidentally, this also explains why you can't add shadow DOM subtrees to input
or details
elements -- their ShadowRoot
s are claimed by HTMLInputElement
and HTMLDetailsElement
constructors, respectively.
Isolation
The API surface of the component model lends well to proper isolation. Here's an approach that could be used to provide it (very early brainstorming):
- Isolation is not tied to the component model. Instead, it's a new twist on the method of loading scripts. A script could be loaded as usual or it could be isolated, or loaded into its own context.
- When isolated, a script has its own global and document objects. These objects only reveal some safe limited subset of the actual document objects. Think of it as a WorkerGlobalScope++.
- You can communicate with the main document using
window.postMessage
.
- The isolated document DOM tree is always empty. Attempting to insert into it throws exceptions.
- ... except when you append to elements in shadow DOM. That's right, you can do
Element.register
andnew ShadowRoot
in the isolated document.
- Whenever you register an element, it registers in the main document as well. Creating an instance of a component from an isolated document produces a functional DOM element shell that proxies to the actual element in the isolated document.
- API surface: introduce a new
isolated
attribute to thescript
attributes.
Needs Implementing
Differences From Existing Specs
Templates
Events
Attachment
Styles
<style scoped> is a natural way to limit style sheets to only affect the shadow tree of a component. The component model follows the implementation suggested in this www-style thread. That is, a selector is only matched up to, and including, the scoping element - i.e., the parent element of <style scoped> - but not further. The exceptions are:
- the selector contains the :root pseudo-class (note that this will fail if not used within the first selector sequence), or
- the selector contains the :scope pseudo-class
CSS4: care must be taken that the subject of a selector is the scoping element or a descendant thereof.
[TODO: notes on crossing the boundary from/into the shadow tree]