| OLD | NEW |
| 1 Sky DOM APIs | 1 Sky DOM APIs |
| 2 ============ | 2 ============ |
| 3 | 3 |
| 4 ```dart | 4 ```dart |
| 5 SKY MODULE | 5 SKY MODULE |
| 6 <!-- part of dart:sky --> | 6 <!-- part of dart:sky --> |
| 7 | 7 |
| 8 <script> | 8 <script> |
| 9 // ELEMENT TREE API | 9 // ELEMENT TREE API |
| 10 | 10 |
| 11 abstract class Node extends EventTarget { | 11 abstract class Node extends EventTarget { |
| 12 @override | 12 @override |
| 13 external List<EventTarget> getEventDispatchChain(); // O(N) in number of ances
tors across shadow trees | 13 external List<EventTarget> getEventDispatchChain(); // O(N) in number of ances
tors across shadow trees |
| 14 // implements EventTarget.getEventDispatchChain() | 14 // implements EventTarget.getEventDispatchChain() |
| 15 // returns the event dispatch chain (including handling shadow trees) | 15 // returns the event dispatch chain (including handling shadow trees) |
| 16 | 16 |
| 17 external Root get owner; // O(1) | 17 external Root get owner; // O(1) |
| 18 | 18 |
| 19 external ParentNode get parentNode; // O(1) | 19 external ParentNode get parentNode; // O(1) |
| 20 Element get parentElement => { | 20 Element get parentElement { |
| 21 if (parentNode is Element) | 21 if (parentNode is Element) |
| 22 return parentNode as Element; | 22 return parentNode as Element; |
| 23 return null; | 23 return null; |
| 24 } | 24 } |
| 25 | 25 |
| 26 external Node get previousSibling; // O(1) | 26 external Node get previousSibling; // O(1) |
| 27 Element get previousElementSibling => { | 27 Element get previousElementSibling { |
| 28 var result = previousSibling; | 28 var result = previousSibling; |
| 29 while (result != null && result is! Element) | 29 while (result != null && result is! Element) |
| 30 result = result.previousSibling; | 30 result = result.previousSibling; |
| 31 return result as Element; | 31 return result as Element; |
| 32 } | 32 } |
| 33 | 33 |
| 34 external Node get nextSibling; // O(1) | 34 external Node get nextSibling; // O(1) |
| 35 Element get nextElementSibling => { | 35 Element get nextElementSibling { |
| 36 var result = nextSibling; | 36 var result = nextSibling; |
| 37 while (result != null && result is! Element) | 37 while (result != null && result is! Element) |
| 38 result = result.nextSibling; | 38 result = result.nextSibling; |
| 39 return result as Element; | 39 return result as Element; |
| 40 } | 40 } |
| 41 | 41 |
| 42 // TODO(ianh): rename insertBefore() and insertAfter() since the Web | 42 // TODO(ianh): rename insertBefore() and insertAfter() since the Web |
| 43 // has an insertBefore() that means something else. What's a good | 43 // has an insertBefore() that means something else. What's a good |
| 44 // name, though? | 44 // name, though? |
| 45 | 45 |
| 46 external void _insertBefore(Node node); // O(N) in number of descendants | 46 external void _insertBefore(Node node); // O(N) in number of descendants |
| 47 // node must be Text or Element, parentNode must be non-null | 47 // node must be Text or Element, parentNode must be non-null |
| 48 void insertBefore(List nodes) { | 48 void insertBefore(List nodes) { |
| 49 List.forEach((node) { | 49 List.forEach((node) { |
| 50 if (node is String) | 50 if (node is String) |
| 51 node = new Text(node); | 51 node = new Text(node); |
| 52 _insertBefore(node); | 52 _insertBefore(node); |
| 53 }); | 53 }); |
| 54 } | 54 } |
| 55 | 55 |
| 56 void _insertAfter(Node node); // O(N) in number of arguments plus all their de
scendants | 56 external void _insertAfter(Node node); // O(N) in number of arguments plus all
their descendants |
| 57 // node must be Text or Element, parentNode must be non-null | 57 // node must be Text or Element, parentNode must be non-null |
| 58 void insertAfter(List nodes) { | 58 void insertAfter(List nodes) { |
| 59 var lastNode = this; | 59 var lastNode = this; |
| 60 List.forEach((node) { | 60 List.forEach((node) { |
| 61 if (node is String) | 61 if (node is String) |
| 62 node = new Text(node); | 62 node = new Text(node); |
| 63 lastNode._insertAfter(node); | 63 lastNode._insertAfter(node); |
| 64 lastNode = node; | 64 lastNode = node; |
| 65 }); | 65 }); |
| 66 } | 66 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 112 void resetLayoutManager() { // O(1) | 112 void resetLayoutManager() { // O(1) |
| 113 if (renderNode != null) { | 113 if (renderNode != null) { |
| 114 renderNode._layoutManager = null; | 114 renderNode._layoutManager = null; |
| 115 renderNode._needsManager = true; | 115 renderNode._needsManager = true; |
| 116 } | 116 } |
| 117 } | 117 } |
| 118 } | 118 } |
| 119 | 119 |
| 120 abstract class ParentNode extends Node { | 120 abstract class ParentNode extends Node { |
| 121 external Node get firstChild; // O(1) | 121 external Node get firstChild; // O(1) |
| 122 Element get firstElementChild => { | 122 Element get firstElementChild { |
| 123 var result = firstChild; | 123 var result = firstChild; |
| 124 while (result != null && result is! Element) | 124 while (result != null && result is! Element) |
| 125 result = result.nextSibling; | 125 result = result.nextSibling; |
| 126 return result as Element; | 126 return result as Element; |
| 127 } | 127 } |
| 128 | 128 |
| 129 external Node get lastChild; // O(1) | 129 external Node get lastChild; // O(1) |
| 130 Element get lastElementChild => { | 130 Element get lastElementChild { |
| 131 var result = lastChild; | 131 var result = lastChild; |
| 132 while (result != null && result is! Element) | 132 while (result != null && result is! Element) |
| 133 result = result.previousSibling; | 133 result = result.previousSibling; |
| 134 return result as Element; | 134 return result as Element; |
| 135 } | 135 } |
| 136 | 136 |
| 137 // Returns a new List every time. | 137 // Returns a new List every time. |
| 138 external List<Node> getChildren(); // O(N) in number of child nodes | 138 external List<Node> getChildren(); // O(N) in number of child nodes |
| 139 List<Element> getChildElements() { | 139 List<Element> getChildElements() { |
| 140 // that the following works without a cast is absurd | 140 // that the following works without a cast is absurd |
| 141 return getChildren().where((node) => node is Element).toList(); | 141 return getChildren().where((node) => node is Element).toList(); |
| 142 } | 142 } |
| 143 | 143 |
| 144 external void _appendChild(Node node); // O(N) in number of descendants | 144 external void _appendChild(Node node); // O(N) in number of descendants |
| 145 // node must be Text or Element | 145 // node must be Text or Element |
| 146 void appendChild(Node node) { | 146 void appendChild(node) { |
| 147 if (node is String) | 147 if (node is String) |
| 148 node = new Text(node); | 148 node = new Text(node); |
| 149 _appendChild(node); | 149 _appendChild(node); |
| 150 } | 150 } |
| 151 void append(List nodes) { | 151 void append(List nodes) { |
| 152 nodes.forEach(appendChild); | 152 nodes.forEach(appendChild); |
| 153 } | 153 } |
| 154 | 154 |
| 155 external void _prependChild(Node node); // O(N) in number of descendants | 155 external void _prependChild(Node node); // O(N) in number of descendants |
| 156 // node must be Text or Element | 156 // node must be Text or Element |
| 157 void prependChild(Node node) { | 157 void prependChild(node) { |
| 158 if (node is String) | 158 if (node is String) |
| 159 node = new Text(node); | 159 node = new Text(node); |
| 160 _prependChild(node); | 160 _prependChild(node); |
| 161 } | 161 } |
| 162 void prepend(List nodes) { | 162 void prepend(List nodes) { |
| 163 // note: not implemented in terms of _prependChild() | 163 // note: not implemented in terms of _prependChild() |
| 164 if (firstChild != null) | 164 if (firstChild != null) |
| 165 firstChild.insertBefore(nodes); | 165 firstChild.insertBefore(nodes); |
| 166 else | 166 else |
| 167 append(nodes); | 167 append(nodes); |
| 168 } | 168 } |
| 169 | 169 |
| 170 external void removeChildren(); // O(N) in number of descendants | 170 external void removeChildren(); // O(N) in number of descendants |
| 171 void setChild(Node node) { | 171 void setChild(node) { |
| 172 removeChildren(); | 172 removeChildren(); |
| 173 appendChild(node); | 173 appendChild(node); |
| 174 } | 174 } |
| 175 void setChildren(List nodes) { | 175 void setChildren(List nodes) { |
| 176 removeChildren(); | 176 removeChildren(); |
| 177 append(nodes); | 177 append(nodes); |
| 178 } | 178 } |
| 179 } | 179 } |
| 180 | 180 |
| 181 class Attr { | 181 class Attr { |
| 182 const Attr (this.name, [this.value = '']); // O(1) | 182 const Attr (this.name, [this.value = '']); // O(1) |
| 183 final String name; // O(1) | 183 final String name; // O(1) |
| 184 final String value; // O(1) | 184 final String value; // O(1) |
| 185 } | 185 } |
| 186 | 186 |
| 187 // @tagname annotation for registering elements | 187 // @tagname annotation for registering elements |
| 188 // only useful when placed on classes that inherit from Element | 188 // only useful when placed on classes that inherit from Element |
| 189 class tagname extends AutomaticMetadata { | 189 class tagname extends AutomaticMetadata { |
| 190 const tagname(this.name); | 190 const tagname(this.name); |
| 191 final String name; | 191 final String name; |
| 192 void init(DeclarationMirror target, Module module) { | 192 void init(DeclarationMirror target, Module module) { |
| 193 assert(target is ClassMirror); | 193 assert(target is ClassMirror); |
| 194 if (!target.isSubclassOf(reflectClass(Element))) | 194 if (!(target as ClassMirror).isSubclassOf(reflectClass(Element))) |
| 195 throw Error('@tagname can only be used on descendants of Element'); | 195 throw new UnsupportedError('@tagname can only be used on descendants of El
ement'); |
| 196 module.registerElement(name, (target as ClassMirror).reflectedType); | 196 module.registerElement(name, (target as ClassMirror).reflectedType); |
| 197 } | 197 } |
| 198 } | 198 } |
| 199 | 199 |
| 200 // @hasShadow annotation for registering elements | 200 // @hasShadow annotation for registering elements |
| 201 class _HasShadow { | 201 class _HasShadow { |
| 202 const HasShadow(); | 202 const _HasShadow(); |
| 203 } | 203 } |
| 204 const hasShadow = const _HasShadow(); | 204 const hasShadow = const _HasShadow(); |
| 205 | 205 |
| 206 abstract class Element extends ParentNode { | 206 abstract class Element extends ParentNode { |
| 207 Element({Map<String, String> attributes: null, | 207 Element({Map<String, String> attributes: null, |
| 208 List children: null, | 208 List children: null, |
| 209 Module hostModule: null}) { // O(M+N), M = number of attributes, N =
number of children nodes plus all their descendants | 209 Module hostModule: null}) { // O(M+N), M = number of attributes, N =
number of children nodes plus all their descendants |
| 210 var shadowClass = reflectClass(hasShadow); | 210 var shadowClass = reflectClass(hasShadow.runtimeType); |
| 211 bool needsShadow = reflect(this).type.metadata.singleWhere((mirror) => mirro
r.type == hasShadowClass); | 211 var shadowAnnotations = reflect(this).type.metadata.where((mirror) => mirror
.type == shadowClass); |
| 212 if (shadowAnnotations.length > 2) |
| 213 throw new StateError('@hasShadow specified multiple times on ' + currentMi
rrorSystem().getName(reflectClass(this.runtimeType).simpleName)); |
| 214 bool needsShadow = shadowAnnotations.length == 1; |
| 212 if (children != null) | 215 if (children != null) |
| 213 children = children.map((node) => node is String ? new Text(node) : node).
toList(); | 216 children = children.map((node) => node is String ? new Text(node) : node).
toList(); |
| 214 this._initElement(attributes, children, hostModule, needsShadow); | 217 this._initElement(attributes, children, hostModule, needsShadow); |
| 215 } | 218 } |
| 216 external void _initElement(Map<String, String> attributes, List children, Modu
le hostModule, bool needsShadow); | 219 external void _initElement(Map<String, String> attributes, List children, Modu
le hostModule, bool needsShadow); |
| 217 // initialises the internal attributes table, which is a ordered list | 220 // initialises the internal attributes table, which is a ordered list |
| 218 // appends the given children nodes | 221 // appends the given children nodes |
| 219 // children must be Text or Element | 222 // children must be Text or Element |
| 220 // if needsShadow is true, creates a shadow tree | 223 // if needsShadow is true, creates a shadow tree |
| 221 | 224 |
| 222 String get tagName { // O(N) in number of annotations on the class | 225 String get tagName { // O(N) in number of annotations on the class |
| 223 // throws a StateError if the class doesn't have an @tagname annotation | 226 // throws a StateError if the class doesn't have an @tagname annotation |
| 224 var tagnameClass = reflectClass(tagname); | 227 var tagnameClass = reflectClass(tagname); |
| 225 return (reflectClass(this.runtimeType).metadata.singleWhere((mirror) => mirr
or.type == tagnameClass).reflectee as tagname).value; | 228 return (reflectClass(this.runtimeType).metadata.singleWhere((mirror) => mirr
or.type == tagnameClass).reflectee as tagname).name; |
| 226 } | 229 } |
| 227 | 230 |
| 228 external bool hasAttribute(String name); // O(N) in number of attributes | 231 external bool hasAttribute(String name); // O(N) in number of attributes |
| 229 external String getAttribute(String name); // O(N) in number of attributes | 232 external String getAttribute(String name); // O(N) in number of attributes |
| 230 external void setAttribute(String name, [String value = '']); // O(N) in numbe
r of attributes | 233 external void setAttribute(String name, [String value = '']); // O(N) in numbe
r of attributes |
| 231 external void removeAttribute(String name); // O(N) in number of attributes | 234 external void removeAttribute(String name); // O(N) in number of attributes |
| 232 // calling setAttribute() with a null value removes the attribute | 235 // calling setAttribute() with a null value removes the attribute |
| 233 // (calling it without a value sets it to the empty string) | 236 // (calling it without a value sets it to the empty string) |
| 234 | 237 |
| 235 // Returns a new Array and new Attr instances every time. | 238 // Returns a new Array and new Attr instances every time. |
| 236 external List<Attr> getAttributes(); // O(N) in number of attributes | 239 external List<Attr> getAttributes(); // O(N) in number of attributes |
| 237 | 240 |
| 238 external final Root shadowRoot; // O(1) | 241 external Root get shadowRoot; // O(1) |
| 239 // returns the shadow root | 242 // returns the shadow root |
| 240 | 243 |
| 241 void endTagParsedCallback() { } | 244 void endTagParsedCallback() { } |
| 242 void attributeChangeCallback(String name, String oldValue, String newValue) {
} | 245 void attributeChangeCallback(String name, String oldValue, String newValue) {
} |
| 243 // name will never be null when this is called by sky | 246 // name will never be null when this is called by sky |
| 244 | 247 |
| 245 // TODO(ianh): does a node ever need to know when it's been redistributed? | 248 // TODO(ianh): does a node ever need to know when it's been redistributed? |
| 246 | 249 |
| 247 @override | 250 @override |
| 248 Type getLayoutManager() { // O(1) | 251 Type getLayoutManager() { // O(1) |
| (...skipping 14 matching lines...) Expand all Loading... |
| 263 @override | 266 @override |
| 264 Type getLayoutManager() => TextLayoutManager; // O(1) | 267 Type getLayoutManager() => TextLayoutManager; // O(1) |
| 265 } | 268 } |
| 266 | 269 |
| 267 class Fragment extends ParentNode { | 270 class Fragment extends ParentNode { |
| 268 Fragment({List children}); // O(N) in number of arguments plus all their desce
ndants | 271 Fragment({List children}); // O(N) in number of arguments plus all their desce
ndants |
| 269 // children must be String, Text, or Element | 272 // children must be String, Text, or Element |
| 270 } | 273 } |
| 271 | 274 |
| 272 class Root extends ParentNode { | 275 class Root extends ParentNode { |
| 273 external Root ({List children, Element host}); // O(N) in number of children n
odes arguments plus all their descendants | 276 Root({List children: null, this.host}) { // O(N) in number of children nodes p
lus all their descendants |
| 274 // children must be String, Text, or Element | 277 if (children != null) |
| 278 children = children.map((node) => node is String ? new Text(node) : node).
toList(); |
| 279 this._initRoot(children); |
| 280 } |
| 281 external void _initRoot(List children); |
| 282 // appends the given children nodes |
| 283 // children must be Text or Element |
| 275 | 284 |
| 276 final Element host; | 285 final Element host; |
| 277 | 286 |
| 278 external Element findId(String id); // O(1) | 287 external Element findId(String id); // O(1) |
| 279 // throws if id is null | 288 // throws if id is null |
| 280 } | 289 } |
| 281 | 290 |
| 282 class ApplicationRoot extends Root { | 291 class ApplicationRoot extends Root { |
| 283 external ApplicationRoot ({List children}) : Root(children: children); // O(N)
in number of children nodes arguments plus all their descendants | 292 ApplicationRoot ({List children}) : super(children: children); // O(N) in numb
er of children nodes arguments plus all their descendants |
| 284 // children must be String, Text, or Element | |
| 285 | 293 |
| 286 @override | 294 @override |
| 287 Type getLayoutManager() => rootLayoutManager; // O(1) | 295 Type getLayoutManager() => rootLayoutManager; // O(1) |
| 288 } | 296 } |
| 289 | 297 |
| 290 Type rootLayoutManager = BlockLayoutManager; // O(1) | 298 Type rootLayoutManager = BlockLayoutManager; // O(1) |
| 291 | 299 |
| 292 | 300 |
| 293 // BUILT-IN ELEMENTS | 301 // BUILT-IN ELEMENTS |
| 294 | 302 |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 397 external bool matches(Element element); // O(F()) | 405 external bool matches(Element element); // O(F()) |
| 398 external Element find(Node root); // O(N*F())+O(M) where N is the number of de
scendants and M the average depth of the tree | 406 external Element find(Node root); // O(N*F())+O(M) where N is the number of de
scendants and M the average depth of the tree |
| 399 external List<Element> findAll(Node root); // O(N*F())+O(N*M) where N is the n
umber of descendants and M the average depth of the tree | 407 external List<Element> findAll(Node root); // O(N*F())+O(N*M) where N is the n
umber of descendants and M the average depth of the tree |
| 400 // find() and findAll() throw if the root is not one of the following: | 408 // find() and findAll() throw if the root is not one of the following: |
| 401 // - Element | 409 // - Element |
| 402 // - Fragment | 410 // - Fragment |
| 403 // - Root | 411 // - Root |
| 404 } | 412 } |
| 405 </script> | 413 </script> |
| 406 ``` | 414 ``` |
| OLD | NEW |