提交 e5500c19 编写于 作者: H Hixie

Specs: update elements.md to define List-based APIs in terms of Node-based...

Specs: update elements.md to define List-based APIs in terms of Node-based APIs, and finish dartification of modules.md (and do Document->Root there)

Review URL: https://codereview.chromium.org/926733002
上级 5b9e4a9f
......@@ -17,19 +17,64 @@ abstract class Node extends EventTarget {
external Root get owner; // O(1)
external ParentNode get parentNode; // O(1)
external Element get parentElement; // O(1) // if parentNode isn't an element, returns null
Element get parentElement => {
if (parentNode is Element)
return parentNode as Element;
return null;
}
external Node get previousSibling; // O(1)
Element get previousElementSibling => {
var result = previousSibling;
while (result != null && result is! Element)
result = result.previousSibling;
return result as Element;
}
external Node get nextSibling; // O(1)
Element get nextElementSibling => {
var result = nextSibling;
while (result != null && result is! Element)
result = result.nextSibling;
return result as Element;
}
external void _insertBefore(Node node); // O(N) in number of descendants
// node must be Text or Element, parentNode must be non-null
void insertBefore(List nodes) {
List.forEach((node) {
if (node is String)
node = new Text(node);
_insertBefore(node);
});
}
void _insertAfter(Node node); // O(N) in number of arguments plus all their descendants
// node must be Text or Element, parentNode must be non-null
void insertAfter(List nodes) {
var lastNode = this;
List.forEach((node) {
if (node is String)
node = new Text(node);
lastNode._insertAfter(node);
lastNode = node;
});
}
// the following all throw if parentNode is null
external void insertBefore(List nodes); // O(N) in number of arguments plus all their descendants
external void insertAfter(List nodes); // O(N) in number of arguments plus all their descendants
// TODO(ianh): rename insertBefore() and insertAfter() since the Web has an insertBefore() that means
// something else. What's a good name, though?
external void replaceWith(List nodes); // O(N) in number of descendants plus arguments plus all their descendants
// nodes must be String, Text, or Element
void replaceWith(List nodes) {
if (nextSibling != null) {
var anchor = nextSibling;
remove(); // parentNode can't be null here, so this won't throw
anchor.insertBefore(nodes);
} else {
var anchor = parentNode;
remove(); // throws if parentNode is null
anchor.append(nodes);
}
}
external void remove(); // O(N) in number of descendants
// parentNode must be non-null
// called when parentNode changes
// this is why insertBefore(), append(), et al, are O(N) -- the whole affected subtree is walked
......@@ -70,18 +115,63 @@ abstract class Node extends EventTarget {
abstract class ParentNode extends Node {
external Node get firstChild; // O(1)
Element get firstElementChild => {
var result = firstChild;
while (result != null && result is! Element)
result = result.nextSibling;
return result as Element;
}
external Node get lastChild; // O(1)
Element get lastElementChild => {
var result = lastChild;
while (result != null && result is! Element)
result = result.previousSibling;
return result as Element;
}
// Returns a new List every time.
external List<Node> getChildren(); // O(N) in number of child nodes
external List<Element> getChildElements(); // O(N) in number of child nodes
// TODO(ianh): might not be necessary if we have the parser drop unnecessary whitespace text nodes
external void append(List nodes); // O(N) in number of arguments plus all their descendants
external void appendChild(Node child); // O(N) in number of descandants
external void prepend(List nodes); // O(N) in number of arguments plus all their descendants
external void replaceChildrenWith(List nodes); // O(N) in number of descendants plus arguments plus all their descendants
// nodes must be String, Text, or Element
List<Element> getChildElements() {
// that the following works without a cast is absurd
return getChildren().where((node) => node is Element).toList();
}
external void _appendChild(Node node); // O(N) in number of descendants
// node must be Text or Element
void appendChild(Node node) {
if (node is String)
node = new Text(node);
_appendChild(node);
}
void append(List nodes) {
nodes.forEach(appendChild);
}
external void _prependChild(Node node); // O(N) in number of descendants
// node must be Text or Element
void prependChild(Node node) {
if (node is String)
node = new Text(node);
_prependChild(node);
}
void prepend(List nodes) {
// note: not implemented in terms of _prependChild()
if (firstChild != null)
firstChild.insertBefore(nodes);
else
append(nodes);
}
external void removeChildren(); // O(N) in number of descendants
void setChild(Node node) {
removeChildren();
appendChild(node);
}
void setChildren(List nodes) {
removeChildren();
append(nodes);
}
}
class Attr {
......@@ -107,7 +197,7 @@ abstract class Element extends ParentNode with Node {
external Element({Map<String, String> attributes: null,
List children: null,
Module hostModule: null}); // O(M+N), M = number of attributes, N = number of children nodes plus all their descendants
// initialises the internal attributes table
// initialises the internal attributes table, which is a ordered list
// appends the given children nodes
// children must be String, Text, or Element
// if this.needsShadow, creates a shadow tree
......@@ -129,9 +219,8 @@ abstract class Element extends ParentNode with Node {
external List<Attr> getAttributes(); // O(N) in number of attributes
get bool needsShadow => false; // O(1)
external Root get shadowRoot; // O(1)
external final Root shadowRoot; // O(1)
// returns the shadow root
// TODO(ianh): Should this be mutable? It would help explain how it gets set...
void endTagParsedCallback() { }
void attributeChangeCallback(String name, String oldValue, String newValue) { }
......
......@@ -24,6 +24,13 @@ 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.
The ``as`` attribute on the ``import`` element binds a name to the
imported module:
```html
<import src="path/to/chocolate.sky" as="chocolate" />
```
Module API
----------
......@@ -52,7 +59,8 @@ relative order as those elements were first seen by the parser.
When a library imports a module, it actually imports all the libraries
that were declared by that module except the aforementioned element
tree library.
tree library. If the ``as`` attribute is present on the ``import``
element, all the libraries are bound to the same name.
At the end of the ``<script>`` block's source, if it parsed correctly
and completely, the conceptual equivalent of the following code is
......@@ -78,24 +86,23 @@ exposed in MirrorSystem.getName(libraryMirror.qualifiedName) etc
The ``Module`` class is defined in ``sky:core`` as follows:
```dart
abstract class AbstractModule extends EventTarget {
AbstractModule({this.document, this.url});
final Document document; // O(1)
// the Document of the module or application
AbstractModule({this.url, this.elements});
final String url;
@nonnull external Future<@nonnull Module> import(String url); // O(Yikes)
final Root elements; // O(1)
// the Root node of the module or application's element tree
external Future<Module> import(String url); // O(Yikes)
// load and return the URL at the given Module
// if it's already loaded, the future will resolve immediately
// if loading fails, the future will have an error
@nonnull List</*@nonnull*/ Module> getImports(); // O(N)
List<Module> getImports(); // O(N)
// returns the Module objects of all the imported modules
external registerElement(@nonnull String tagname, @nonnull Type elementClass); // O(1)
external registerElement(String tagname, Type elementClass); // O(1)
// registers a tag name with the parser
// only useful during parse time
// verify that tagname isn't null or empty
......@@ -107,44 +114,17 @@ abstract class AbstractModule extends EventTarget {
// (mention the tag name but not the classes, so that it's not observable that this currently happens out of order)
}
class Module : AbstractModule {
constructor (Application application, Document document, String url); // O(1)
readonly attribute Application application; // O(1)
class Module extends AbstractModule {
Module({String url, Root elements, this.application}) :
super(url: url, elements: elements); // O(1)
final Application application; // O(1)
}
class Application : AbstractModule {
constructor (Document document, GestureManager gestureManager, String url); // O(1)
attribute String title; // O(1)
readonly attribute GestureManager gestureManager;
class Application extends AbstractModule {
Application({String url, Root elements, this.gestureManager}) :
super(url: url, elements: elements); // O(1)
external String get title; // O(1)
external void set title(String newValue); // O(1)
final GestureManager gestureManager;
}
```
Naming modules
--------------
The ``as`` attribute on the ``import`` element binds a name to the
imported module:
```html
<import src="path/to/chocolate.sky" as="chocolate" />
```
The parser executes the contents of script elements inside a module as
if they were executed as follow:
```javascript
(new Function(name_1, ..., name_n, module, source_code)).call(
value_1, ..., value_n, source_module);
```
Where ``name_1`` through ``name_n`` are the names bound to the
various named imports in the script element's document,
``source_code`` is the text content of the script element,
``source_module`` is the ``Module`` object of the script element's
module, and ``value_1`` through ``value_n`` are the values
exported by the various named imports in the script element's
document.
When an import fails to load, the ``as`` name for the import gets
bound to ``undefined``.
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册