Specs: Drop the concept of late-bound elements. An element can never be upgraded.

This has the following implications:

 - There's no createElement() function any more. If you want to create
   an element from script, you have to use its constructor.

 - There's no async element registration. The parser will block until
   all the imports are imported when you use a tag name of a custom
   element that hasn't been registered yet, in case one of the imports
   defines it.

 - If you try to construct a non-registered element in markup, it
   turns into an <error> element.

 - <div>, <span>, and <error> are new built-in elements.

R=esprehn@chromium.org

Review URL: https://codereview.chromium.org/695423004
This commit is contained in:
Hixie 2014-11-03 16:52:47 -08:00
parent ef24228598
commit 00a2de6490
5 changed files with 96 additions and 41 deletions

View File

@ -1,9 +1,9 @@
#!mojo mojo:sky
<sky>
<div><!-- remove this element once Document can have multiple element children -->
<style>
h1 { font-size: 2em; margin: 1em; }
p { margin: 0.5em 1em; color: #bcd8f5; font-weight: 900; }
.h1 { font-size: 2em; margin: 1em; }
.p { margin: 0.5em 1em; color: #bcd8f5; font-weight: 900; }
</style>
<h1>about:blank</h1>
<p>Welcome to Sky!</p>
</sky>
<div class="h1">about:blank</div>
<div class="p">Welcome to Sky!</div>
</div>

View File

@ -142,18 +142,25 @@ module 'sky:core' {
Array<Element> findAll(ParentNode root); // O(N*F()) where N is the number of descendants
}
// Built-in Elements
// BUILT-IN ELEMENTS
class ImportElement : Element {
constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants
constructor (ChildArguments... nodes); // shorthand
constructor (Dictionary attributes); // shorthand
constructor (); // shorthand
constructor attribute String tagName; // O(1) // "import"
constructor attribute Boolean shadow; // O(1) // false
}
class TemplateElement : Element {
constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants
constructor (ChildArguments... nodes); // shorthand
constructor (Dictionary attributes); // shorthand
constructor (); // shorthand
constructor attribute String tagName; // O(1) // "template"
constructor attribute Boolean shadow; // O(1) // false
readonly attribute DocumentFragment content; // O(1)
}
class ScriptElement : Element {
@ -161,18 +168,25 @@ module 'sky:core' {
constructor (ChildArguments... nodes); // shorthand
constructor (Dictionary attributes); // shorthand
constructor (); // shorthand
constructor attribute String tagName; // O(1) // "script"
constructor attribute Boolean shadow; // O(1) // false
}
class StyleElement : Element {
constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants
constructor (ChildArguments... nodes); // shorthand
constructor (Dictionary attributes); // shorthand
constructor (); // shorthand
constructor attribute String tagName; // O(1) // "style"
constructor attribute Boolean shadow; // O(1) // false
}
class ContentElement : Element {
constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants
constructor (ChildArguments... nodes); // shorthand
constructor (Dictionary attributes); // shorthand
constructor (); // shorthand
constructor attribute String tagName; // O(1) // "content"
constructor attribute Boolean shadow; // O(1) // false
Array<Node> getDistributedNodes(); // O(N) in distributed nodes
}
class ImgElement : Element {
@ -180,34 +194,70 @@ module 'sky:core' {
constructor (ChildArguments... nodes); // shorthand
constructor (Dictionary attributes); // shorthand
constructor (); // shorthand
constructor attribute String tagName; // O(1) // "img"
constructor attribute Boolean shadow; // O(1) // false
}
class DivElement : Element {
constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants
constructor (ChildArguments... nodes); // shorthand
constructor (Dictionary attributes); // shorthand
constructor (); // shorthand
constructor attribute String tagName; // O(1) // "div"
constructor attribute Boolean shadow; // O(1) // false
}
class SpanElement : Element {
constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants
constructor (ChildArguments... nodes); // shorthand
constructor (Dictionary attributes); // shorthand
constructor (); // shorthand
constructor attribute String tagName; // O(1) // "span"
constructor attribute Boolean shadow; // O(1) // false
}
class IframeElement : Element {
constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants
constructor (ChildArguments... nodes); // shorthand
constructor (Dictionary attributes); // shorthand
constructor (); // shorthand
constructor attribute String tagName; // O(1) // "iframe"
constructor attribute Boolean shadow; // O(1) // false
}
class TElement : Element {
constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants
constructor (ChildArguments... nodes); // shorthand
constructor (Dictionary attributes); // shorthand
constructor (); // shorthand
constructor attribute String tagName; // O(1) // "t"
constructor attribute Boolean shadow; // O(1) // false
}
class AElement : Element {
constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants
constructor (ChildArguments... nodes); // shorthand
constructor (Dictionary attributes); // shorthand
constructor (); // shorthand
constructor attribute String tagName; // O(1) // "a"
constructor attribute Boolean shadow; // O(1) // false
}
class TitleElement : Element {
constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants
constructor (ChildArguments... nodes); // shorthand
constructor (Dictionary attributes); // shorthand
constructor (); // shorthand
constructor attribute String tagName; // O(1) // "title"
constructor attribute Boolean shadow; // O(1) // false
}
class ErrorElement : Element {
constructor (Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants
constructor (ChildArguments... nodes); // shorthand
constructor (Dictionary attributes); // shorthand
constructor (); // shorthand
constructor attribute String tagName; // O(1) // "error"
constructor attribute Boolean shadow; // O(1) // false
}
// MODULES
dictionary ElementRegistration {
String tagName;
Boolean shadow = false;
@ -224,20 +274,13 @@ module 'sky:core' {
constructor attribute Boolean shadow;
}
// MODULES
abstract class AbstractModule : EventTarget {
readonly attribute Document document; // O(1) // the Documentof the module or application
Promise<any> import(String url); // O(Yikes) // returns the module's exports
readonly attribute String url;
// createElement() lets you create elements that will be upgraded later when you register the element
Element createElement(String tagName, Dictionary attributes, ChildArguments... nodes); // O(M+N), M = number of attributes, N = number of nodes plus all their descendants
Element createElement(String tagName, Dictionary attributes); // shorthand
Element createElement(String tagName, ChildArguments... nodes); // shorthand
Element createElement(String tagName); // shorthand
ElementConstructor registerElement(ElementRegistration options); // O(N) in number of outstanding elements with that tag name to be upgraded
ElementConstructor registerElement(ElementRegistration options); // O(1)
// if you call registerElement() with an object that was created by
// registerElement(), it just returns the object after registering it,
// rather than creating a new constructor

View File

@ -144,6 +144,11 @@ Sky Markup: Elements
The Sky language consists of very few elements, since it is expected
that everything of note would be provided by frameworks.
The following elements are implicitly registered by default, even if
you haven't imported anything. You can get to their constructors if
you import sky:core (basically, sky:core is always imported by defaul;
it's the runtime library). None of these elements have shadow trees.
``<import src="foo.sky">``
- Downloads and imports foo.sky in the background.
@ -176,6 +181,12 @@ that everything of note would be provided by frameworks.
- Sky fetches the bits for foo.bin, looks for a decoder for those
bits, and renders the bits that the decoder returns.
``<div>``
- Element that does nothing.
``<span>``
- Element that does nothing.
``<iframe src="foo.bin">``
- Sky tells mojo to open an application for foo.bin, and hands that
application a view so that the application can render appropriately.
@ -195,6 +206,9 @@ that everything of note would be provided by frameworks.
is mutated, theTitleElement.ownerScope.ownerDocument.title is set
to the element's contents.)
``<error>``
- Represents a parse error.
Sky Markup: Global Attributes
=============================

View File

@ -18,27 +18,18 @@ document's list of outstanding dependencies grows. When an imported
module completes, it is removed from the document's list of
outstanding dependencies.
Before executing any ```script``` elements, the parser waits until the
list of outstanding dependencies is empty. After the parser has
finished parsing, the document waits until its list of outstanding
dependencies is empty before the module it represents is marked
complete.
Before executing script or inserting an element that is not already
registered, the parser waits until the list of outstanding
dependencies is empty. After the parser has finished parsing, the
document waits until its list of outstanding dependencies is empty
before the module it represents is marked complete.
Module API
----------
Within a script in a module, the ```module``` identifier is bound to
the ```Module``` object that represents the module:
```javascript
interface Module : EventTarget {
constructor (Application application, Document document); // O(1)
attribute any exports; // O(1) // defaults to the module's document
readonly attribute Document document; // O(1) // the module's document
readonly attribute Application application; // O(1)
}
```
the [```Module``` object](apis.md) that represents the module.
### Exporting values ###

View File

@ -798,11 +798,16 @@ _document_:
the token.
3. Append _node_ to the top node in the _stack of open nodes_.
- If _token_ is a start tag token,
1. Create an element _node_ with tag name and attributes given by
the token.
2. Append _node_ to the top node in the _stack of open nodes_.
3. Push _node_ onto the top of the _stack of open nodes_.
4. If _node_ is a ``template`` element, then:
1. If the tag name isn't a registered tag name, then yield until
_imported modules_ contains no entries with unresolved
promises.
2. If the tag name is registered, create an element _node_ with
tag name and attributes given by the token. Otherwise, create
an element with the tag name "error" and the attributes given
by the token.
3. Append _node_ to the top node in the _stack of open nodes_.
4. Push _node_ onto the top of the _stack of open nodes_.
5. If _node_ is a ``template`` element, then:
1. Let _fragment_ be the ``DocumentFragment`` object that the
``template`` element uses as its template contents container.
2. Push _fragment_ onto the top of the _stack of open nodes_.
@ -814,14 +819,16 @@ _document_:
has an ``as`` attribute, associate the entry with that
name.
- If _token_ is an end tag token:
1. Let _node_ be the topmost node in the _stack of open nodes_
whose tag name is the same as the token's tag name, if any. If
there isn't one, skip this token.
2. If there's a ``template`` element in the _stack of open
1. If the tag name is registered, let _tag name_ be that tag
name. Otherwise, let _tag name_ be "error".
2. Let _node_ be the topmost node in the _stack of open nodes_
whose tag name is _tag name_, if any. If there isn't one, skip
this token.
3. If there's a ``template`` element in the _stack of open
nodes_ above _node_, then skip this token.
3. Pop nodes from the _stack of open nodes_ until _node_ has been
4. Pop nodes from the _stack of open nodes_ until _node_ has been
popped.
4. If _node_'s tag name is ``script``, then yield until _imported
5. If _node_'s tag name is ``script``, then yield until _imported
modules_ contains no entries with unresolved promises, then
execute the script given by the element's contents, using the
associated names as appropriate.