| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 library fn; | 5 library fn; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:collection'; | 8 import 'dart:collection'; |
| 9 import 'dart:sky' as sky; | 9 import 'dart:sky' as sky; |
| 10 import 'reflect.dart' as reflect; | 10 import 'reflect.dart' as reflect; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 60 if (ref != null) { | 60 if (ref != null) { |
| 61 ref.insertBefore([node]); | 61 ref.insertBefore([node]); |
| 62 } else { | 62 } else { |
| 63 parent.appendChild(node); | 63 parent.appendChild(node); |
| 64 } | 64 } |
| 65 } | 65 } |
| 66 | 66 |
| 67 enum _SyncOperation { IDENTICAL, INSERTION, STATEFUL, STATELESS, REMOVAL } | 67 enum _SyncOperation { IDENTICAL, INSERTION, STATEFUL, STATELESS, REMOVAL } |
| 68 | 68 |
| 69 /* | 69 /* |
| 70 * All Effen nodes derive from Node. All nodes have a _parent, a _key and | 70 * All Effen nodes derive from UINode. All nodes have a _parent, a _key and |
| 71 * can be sync'd. | 71 * can be sync'd. |
| 72 */ | 72 */ |
| 73 abstract class Node { | 73 abstract class UINode { |
| 74 String _key; | 74 String _key; |
| 75 Node _parent; | 75 UINode _parent; |
| 76 sky.Node _root; | 76 sky.Node _root; |
| 77 bool _defunct = false; | 77 bool _defunct = false; |
| 78 int _nodeDepth; | 78 int _nodeDepth; |
| 79 | 79 |
| 80 Node({ Object key }) { | 80 UINode({ Object key }) { |
| 81 _key = key == null ? "$runtimeType" : "$runtimeType-$key"; | 81 _key = key == null ? "$runtimeType" : "$runtimeType-$key"; |
| 82 } | 82 } |
| 83 | 83 |
| 84 // Subclasses which implements Nodes that become stateful may return true | 84 // Subclasses which implements Nodes that become stateful may return true |
| 85 // if the |old| node has become stateful and should be retained. | 85 // if the |old| node has become stateful and should be retained. |
| 86 bool _willSync(Node old) => false; | 86 bool _willSync(UINode old) => false; |
| 87 | 87 |
| 88 void _sync(Node old, sky.ParentNode host, sky.Node insertBefore); | 88 void _sync(UINode old, sky.ParentNode host, sky.Node insertBefore); |
| 89 | 89 |
| 90 void _remove() { | 90 void _remove() { |
| 91 _defunct = true; | 91 _defunct = true; |
| 92 _root = null; | 92 _root = null; |
| 93 } | 93 } |
| 94 | 94 |
| 95 void _ensureDepth() { | 95 void _ensureDepth() { |
| 96 if (_nodeDepth == null) { | 96 if (_nodeDepth == null) { |
| 97 _nodeDepth = 0; | 97 _nodeDepth = 0; |
| 98 Node parent = _parent; | 98 UINode parent = _parent; |
| 99 while (parent != null) { | 99 while (parent != null) { |
| 100 _nodeDepth++; | 100 _nodeDepth++; |
| 101 parent = parent._parent; | 101 parent = parent._parent; |
| 102 } | 102 } |
| 103 } | 103 } |
| 104 } | 104 } |
| 105 | 105 |
| 106 void _trace(String message) { | 106 void _trace(String message) { |
| 107 if (!_shouldTrace) | 107 if (!_shouldTrace) |
| 108 return; | 108 return; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 119 | 119 |
| 120 void _traceSync(_SyncOperation op, String key) { | 120 void _traceSync(_SyncOperation op, String key) { |
| 121 if (!_shouldTrace) | 121 if (!_shouldTrace) |
| 122 return; | 122 return; |
| 123 | 123 |
| 124 String opString = op.toString().toLowerCase(); | 124 String opString = op.toString().toLowerCase(); |
| 125 String outString = opString.substring(opString.indexOf('.') + 1); | 125 String outString = opString.substring(opString.indexOf('.') + 1); |
| 126 _trace('_sync($outString) $key'); | 126 _trace('_sync($outString) $key'); |
| 127 } | 127 } |
| 128 | 128 |
| 129 void _removeChild(Node node) { | 129 void _removeChild(UINode node) { |
| 130 _traceSync(_SyncOperation.REMOVAL, node._key); | 130 _traceSync(_SyncOperation.REMOVAL, node._key); |
| 131 node._remove(); | 131 node._remove(); |
| 132 } | 132 } |
| 133 | 133 |
| 134 // Returns the child which should be retained as the child of this node. | 134 // Returns the child which should be retained as the child of this node. |
| 135 Node _syncChild(Node node, Node oldNode, sky.ParentNode host, | 135 UINode _syncChild(UINode node, UINode oldNode, sky.ParentNode host, |
| 136 sky.Node insertBefore) { | 136 sky.Node insertBefore) { |
| 137 | 137 |
| 138 assert(oldNode == null || node._key == oldNode._key); | 138 assert(oldNode == null || node._key == oldNode._key); |
| 139 | 139 |
| 140 if (node == oldNode) { | 140 if (node == oldNode) { |
| 141 _traceSync(_SyncOperation.IDENTICAL, node._key); | 141 _traceSync(_SyncOperation.IDENTICAL, node._key); |
| 142 return node; // Nothing to do. Subtrees must be identical. | 142 return node; // Nothing to do. Subtrees must be identical. |
| 143 } | 143 } |
| 144 | 144 |
| 145 // TODO(rafaelw): This eagerly removes the old DOM. It may be that a | 145 // TODO(rafaelw): This eagerly removes the old DOM. It may be that a |
| (...skipping 20 matching lines...) Expand all Loading... |
| 166 } | 166 } |
| 167 node._sync(oldNode, host, insertBefore); | 167 node._sync(oldNode, host, insertBefore); |
| 168 if (oldNode != null) | 168 if (oldNode != null) |
| 169 oldNode._defunct = true; | 169 oldNode._defunct = true; |
| 170 | 170 |
| 171 assert(node._root is sky.Node); | 171 assert(node._root is sky.Node); |
| 172 return node; | 172 return node; |
| 173 } | 173 } |
| 174 } | 174 } |
| 175 | 175 |
| 176 abstract class ContentNode extends Node { | 176 abstract class ContentNode extends UINode { |
| 177 Node content; | 177 UINode content; |
| 178 | 178 |
| 179 ContentNode(Node content) : this.content = content, super(key: content._key); | 179 ContentNode(UINode content) : this.content = content, super(key: content._key)
; |
| 180 | 180 |
| 181 void _sync(Node old, sky.ParentNode host, sky.Node insertBefore) { | 181 void _sync(UINode old, sky.ParentNode host, sky.Node insertBefore) { |
| 182 Node oldContent = old == null ? null : (old as ContentNode).content; | 182 UINode oldContent = old == null ? null : (old as ContentNode).content; |
| 183 content = _syncChild(content, oldContent, host, insertBefore); | 183 content = _syncChild(content, oldContent, host, insertBefore); |
| 184 _root = content._root; | 184 _root = content._root; |
| 185 } | 185 } |
| 186 | 186 |
| 187 void _remove() { | 187 void _remove() { |
| 188 _removeChild(content); | 188 _removeChild(content); |
| 189 super._remove(); | 189 super._remove(); |
| 190 } | 190 } |
| 191 } | 191 } |
| 192 | 192 |
| 193 class StyleNode extends ContentNode { | 193 class StyleNode extends ContentNode { |
| 194 final Style style; | 194 final Style style; |
| 195 | 195 |
| 196 StyleNode(Node content, this.style): super(content); | 196 StyleNode(UINode content, this.style): super(content); |
| 197 } | 197 } |
| 198 | 198 |
| 199 /* | 199 /* |
| 200 * RenderNodes correspond to a desired state of a sky.Node. They are fully | 200 * RenderNodes correspond to a desired state of a sky.Node. They are fully |
| 201 * immutable, with one exception: A Node which is a Component which lives within | 201 * immutable, with one exception: A UINode which is a Component which lives with
in |
| 202 * an Element's children list, may be replaced with the "old" instance if it | 202 * an WrapperNode's children list, may be replaced with the "old" instance if it |
| 203 * has become stateful. | 203 * has become stateful. |
| 204 */ | 204 */ |
| 205 abstract class RenderNode extends Node { | 205 abstract class RenderNode extends UINode { |
| 206 | 206 |
| 207 static final Map<sky.Node, RenderNode> _nodeMap = | 207 static final Map<sky.Node, RenderNode> _nodeMap = |
| 208 new HashMap<sky.Node, RenderNode>(); | 208 new HashMap<sky.Node, RenderNode>(); |
| 209 | 209 |
| 210 static RenderNode _getMounted(sky.Node node) => _nodeMap[node]; | 210 static RenderNode _getMounted(sky.Node node) => _nodeMap[node]; |
| 211 | 211 |
| 212 RenderNode({ Object key }) : super(key: key); | 212 RenderNode({ Object key }) : super(key: key); |
| 213 | 213 |
| 214 RenderNode get _emptyNode; | 214 RenderNode get _emptyNode; |
| 215 | 215 |
| 216 sky.Node _createNode(); | 216 sky.Node _createNode(); |
| 217 | 217 |
| 218 void _sync(Node old, sky.ParentNode host, sky.Node insertBefore) { | 218 void _sync(UINode old, sky.ParentNode host, sky.Node insertBefore) { |
| 219 if (old == null) { | 219 if (old == null) { |
| 220 _root = _createNode(); | 220 _root = _createNode(); |
| 221 _parentInsertBefore(host, _root, insertBefore); | 221 _parentInsertBefore(host, _root, insertBefore); |
| 222 old = _emptyNode; | 222 old = _emptyNode; |
| 223 } else { | 223 } else { |
| 224 _root = old._root; | 224 _root = old._root; |
| 225 } | 225 } |
| 226 | 226 |
| 227 _nodeMap[_root] = this; | 227 _nodeMap[_root] = this; |
| 228 _syncNode(old); | 228 _syncNode(old); |
| 229 } | 229 } |
| 230 | 230 |
| 231 void _syncNode(RenderNode old); | 231 void _syncNode(RenderNode old); |
| 232 | 232 |
| 233 void _remove() { | 233 void _remove() { |
| 234 assert(_root != null); | 234 assert(_root != null); |
| 235 _root.remove(); | 235 _root.remove(); |
| 236 _nodeMap.remove(_root); | 236 _nodeMap.remove(_root); |
| 237 super._remove(); | 237 super._remove(); |
| 238 } | 238 } |
| 239 } | 239 } |
| 240 | 240 |
| 241 typedef GestureEventListener(sky.GestureEvent e); | 241 typedef GestureEventListener(sky.GestureEvent e); |
| 242 typedef PointerEventListener(sky.PointerEvent e); | 242 typedef PointerEventListener(sky.PointerEvent e); |
| 243 typedef EventListener(sky.Event e); | 243 typedef EventListener(sky.Event e); |
| 244 | 244 |
| 245 class EventTarget extends ContentNode { | 245 class EventListenerNode extends ContentNode { |
| 246 final Map<String, sky.EventListener> listeners; | 246 final Map<String, sky.EventListener> listeners; |
| 247 | 247 |
| 248 static final Set<String> _registeredEvents = new HashSet<String>(); | 248 static final Set<String> _registeredEvents = new HashSet<String>(); |
| 249 | 249 |
| 250 static Map<String, sky.EventListener> _createListeners({ | 250 static Map<String, sky.EventListener> _createListeners({ |
| 251 EventListener onWheel, | 251 EventListener onWheel, |
| 252 GestureEventListener onGestureFlingCancel, | 252 GestureEventListener onGestureFlingCancel, |
| 253 GestureEventListener onGestureFlingStart, | 253 GestureEventListener onGestureFlingStart, |
| 254 GestureEventListener onGestureScrollStart, | 254 GestureEventListener onGestureScrollStart, |
| 255 GestureEventListener onGestureScrollUpdate, | 255 GestureEventListener onGestureScrollUpdate, |
| (...skipping 28 matching lines...) Expand all Loading... |
| 284 if (onPointerDown != null) | 284 if (onPointerDown != null) |
| 285 listeners['pointerdown'] = onPointerDown; | 285 listeners['pointerdown'] = onPointerDown; |
| 286 if (onPointerMove != null) | 286 if (onPointerMove != null) |
| 287 listeners['pointermove'] = onPointerMove; | 287 listeners['pointermove'] = onPointerMove; |
| 288 if (onPointerUp != null) | 288 if (onPointerUp != null) |
| 289 listeners['pointerup'] = onPointerUp; | 289 listeners['pointerup'] = onPointerUp; |
| 290 | 290 |
| 291 return listeners; | 291 return listeners; |
| 292 } | 292 } |
| 293 | 293 |
| 294 EventTarget(Node content, { | 294 EventListenerNode(UINode content, { |
| 295 EventListener onWheel, | 295 EventListener onWheel, |
| 296 GestureEventListener onGestureFlingCancel, | 296 GestureEventListener onGestureFlingCancel, |
| 297 GestureEventListener onGestureFlingStart, | 297 GestureEventListener onGestureFlingStart, |
| 298 GestureEventListener onGestureScrollStart, | 298 GestureEventListener onGestureScrollStart, |
| 299 GestureEventListener onGestureScrollUpdate, | 299 GestureEventListener onGestureScrollUpdate, |
| 300 GestureEventListener onGestureTap, | 300 GestureEventListener onGestureTap, |
| 301 GestureEventListener onGestureTapDown, | 301 GestureEventListener onGestureTapDown, |
| 302 PointerEventListener onPointerCancel, | 302 PointerEventListener onPointerCancel, |
| 303 PointerEventListener onPointerDown, | 303 PointerEventListener onPointerDown, |
| 304 PointerEventListener onPointerMove, | 304 PointerEventListener onPointerMove, |
| (...skipping 16 matching lines...) Expand all Loading... |
| 321 super(content); | 321 super(content); |
| 322 | 322 |
| 323 void _handleEvent(sky.Event e) { | 323 void _handleEvent(sky.Event e) { |
| 324 sky.EventListener listener = listeners[e.type]; | 324 sky.EventListener listener = listeners[e.type]; |
| 325 if (listener != null) { | 325 if (listener != null) { |
| 326 listener(e); | 326 listener(e); |
| 327 } | 327 } |
| 328 } | 328 } |
| 329 | 329 |
| 330 static void _dispatchEvent(sky.Event e) { | 330 static void _dispatchEvent(sky.Event e) { |
| 331 Node target = RenderNode._getMounted(e.target); | 331 UINode target = RenderNode._getMounted(e.target); |
| 332 | 332 |
| 333 // TODO(rafaelw): StopPropagation? | 333 // TODO(rafaelw): StopPropagation? |
| 334 while (target != null) { | 334 while (target != null) { |
| 335 if (target is EventTarget) { | 335 if (target is EventListenerNode) { |
| 336 (target as EventTarget)._handleEvent(e); | 336 (target as EventListenerNode)._handleEvent(e); |
| 337 } | 337 } |
| 338 | 338 |
| 339 target = target._parent; | 339 target = target._parent; |
| 340 } | 340 } |
| 341 } | 341 } |
| 342 | 342 |
| 343 static void _ensureDocumentListener(String eventType) { | 343 static void _ensureDocumentListener(String eventType) { |
| 344 if (_registeredEvents.add(eventType)) { | 344 if (_registeredEvents.add(eventType)) { |
| 345 sky.document.addEventListener(eventType, _dispatchEvent); | 345 sky.document.addEventListener(eventType, _dispatchEvent); |
| 346 } | 346 } |
| 347 } | 347 } |
| 348 | 348 |
| 349 void _sync(Node old, sky.ParentNode host, sky.Node insertBefore) { | 349 void _sync(UINode old, sky.ParentNode host, sky.Node insertBefore) { |
| 350 for (var type in listeners.keys) { | 350 for (var type in listeners.keys) { |
| 351 _ensureDocumentListener(type); | 351 _ensureDocumentListener(type); |
| 352 } | 352 } |
| 353 | 353 |
| 354 super._sync(old, host, insertBefore); | 354 super._sync(old, host, insertBefore); |
| 355 } | 355 } |
| 356 } | 356 } |
| 357 | 357 |
| 358 class Text extends RenderNode { | 358 class Text extends RenderNode { |
| 359 final String data; | 359 final String data; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 373 } | 373 } |
| 374 | 374 |
| 375 void _syncNode(RenderNode old) { | 375 void _syncNode(RenderNode old) { |
| 376 if (old == _emptyText) | 376 if (old == _emptyText) |
| 377 return; // we set inside _createNode(); | 377 return; // we set inside _createNode(); |
| 378 | 378 |
| 379 (_root as sky.Text).data = data; | 379 (_root as sky.Text).data = data; |
| 380 } | 380 } |
| 381 } | 381 } |
| 382 | 382 |
| 383 final List<Node> _emptyList = new List<Node>(); | 383 final List<UINode> _emptyList = new List<UINode>(); |
| 384 | 384 |
| 385 abstract class Element extends RenderNode { | 385 abstract class WrapperNode extends RenderNode { |
| 386 | 386 |
| 387 String get _tagName; | 387 String get _tagName; |
| 388 | 388 |
| 389 sky.Node _createNode() => sky.document.createElement(_tagName); | 389 sky.Node _createNode() => sky.document.createElement(_tagName); |
| 390 | 390 |
| 391 final List<Node> children; | 391 final List<UINode> children; |
| 392 final Style style; | 392 final Style style; |
| 393 final String inlineStyle; | 393 final String inlineStyle; |
| 394 | 394 |
| 395 String _class; | 395 String _class; |
| 396 | 396 |
| 397 Element({ | 397 WrapperNode({ |
| 398 Object key, | 398 Object key, |
| 399 List<Node> children, | 399 List<UINode> children, |
| 400 this.style, | 400 this.style, |
| 401 this.inlineStyle | 401 this.inlineStyle |
| 402 }) : this.children = children == null ? _emptyList : children, | 402 }) : this.children = children == null ? _emptyList : children, |
| 403 super(key:key) { | 403 super(key:key) { |
| 404 | 404 |
| 405 if (_isInCheckedMode) { | 405 if (_isInCheckedMode) { |
| 406 _debugReportDuplicateIds(); | 406 _debugReportDuplicateIds(); |
| 407 } | 407 } |
| 408 } | 408 } |
| 409 | 409 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 430 } | 430 } |
| 431 } | 431 } |
| 432 | 432 |
| 433 void _ensureClass() { | 433 void _ensureClass() { |
| 434 if (_class == null) { | 434 if (_class == null) { |
| 435 List<Style> styles = new List<Style>(); | 435 List<Style> styles = new List<Style>(); |
| 436 if (style != null) { | 436 if (style != null) { |
| 437 styles.add(style); | 437 styles.add(style); |
| 438 } | 438 } |
| 439 | 439 |
| 440 Node parent = _parent; | 440 UINode parent = _parent; |
| 441 while (parent != null && parent is! RenderNode) { | 441 while (parent != null && parent is! RenderNode) { |
| 442 if (parent is StyleNode && (parent as StyleNode).style != null) | 442 if (parent is StyleNode && (parent as StyleNode).style != null) |
| 443 styles.add((parent as StyleNode).style); | 443 styles.add((parent as StyleNode).style); |
| 444 | 444 |
| 445 parent = parent._parent; | 445 parent = parent._parent; |
| 446 } | 446 } |
| 447 | 447 |
| 448 _class = styles.map((s) => s._className).join(' '); | 448 _class = styles.map((s) => s._className).join(' '); |
| 449 } | 449 } |
| 450 } | 450 } |
| 451 | 451 |
| 452 void _syncNode(RenderNode old) { | 452 void _syncNode(RenderNode old) { |
| 453 Element oldElement = old as Element; | 453 WrapperNode oldWrapperNode = old as WrapperNode; |
| 454 sky.Element root = _root as sky.Element; | 454 sky.Element root = _root as sky.Element; |
| 455 | 455 |
| 456 _ensureClass(); | 456 _ensureClass(); |
| 457 if (_class != oldElement._class && _class != '') | 457 if (_class != oldWrapperNode._class && _class != '') |
| 458 root.setAttribute('class', _class); | 458 root.setAttribute('class', _class); |
| 459 | 459 |
| 460 if (inlineStyle != oldElement.inlineStyle) | 460 if (inlineStyle != oldWrapperNode.inlineStyle) |
| 461 root.setAttribute('style', inlineStyle); | 461 root.setAttribute('style', inlineStyle); |
| 462 | 462 |
| 463 _syncChildren(oldElement); | 463 _syncChildren(oldWrapperNode); |
| 464 } | 464 } |
| 465 | 465 |
| 466 void _syncChildren(Element oldElement) { | 466 void _syncChildren(WrapperNode oldWrapperNode) { |
| 467 sky.Element root = _root as sky.Element; | 467 sky.Element root = _root as sky.Element; |
| 468 assert(root != null); | 468 assert(root != null); |
| 469 | 469 |
| 470 var startIndex = 0; | 470 var startIndex = 0; |
| 471 var endIndex = children.length; | 471 var endIndex = children.length; |
| 472 | 472 |
| 473 var oldChildren = oldElement.children; | 473 var oldChildren = oldWrapperNode.children; |
| 474 var oldStartIndex = 0; | 474 var oldStartIndex = 0; |
| 475 var oldEndIndex = oldChildren.length; | 475 var oldEndIndex = oldChildren.length; |
| 476 | 476 |
| 477 sky.Node nextSibling = null; | 477 sky.Node nextSibling = null; |
| 478 Node currentNode = null; | 478 UINode currentNode = null; |
| 479 Node oldNode = null; | 479 UINode oldNode = null; |
| 480 | 480 |
| 481 void sync(int atIndex) { | 481 void sync(int atIndex) { |
| 482 children[atIndex] = _syncChild(currentNode, oldNode, _root, nextSibling); | 482 children[atIndex] = _syncChild(currentNode, oldNode, _root, nextSibling); |
| 483 } | 483 } |
| 484 | 484 |
| 485 // Scan backwards from end of list while nodes can be directly synced | 485 // Scan backwards from end of list while nodes can be directly synced |
| 486 // without reordering. | 486 // without reordering. |
| 487 while (endIndex > startIndex && oldEndIndex > oldStartIndex) { | 487 while (endIndex > startIndex && oldEndIndex > oldStartIndex) { |
| 488 currentNode = children[endIndex - 1]; | 488 currentNode = children[endIndex - 1]; |
| 489 oldNode = oldChildren[oldEndIndex - 1]; | 489 oldNode = oldChildren[oldEndIndex - 1]; |
| 490 | 490 |
| 491 if (currentNode._key != oldNode._key) { | 491 if (currentNode._key != oldNode._key) { |
| 492 break; | 492 break; |
| 493 } | 493 } |
| 494 | 494 |
| 495 endIndex--; | 495 endIndex--; |
| 496 oldEndIndex--; | 496 oldEndIndex--; |
| 497 sync(endIndex); | 497 sync(endIndex); |
| 498 nextSibling = currentNode._root; | 498 nextSibling = currentNode._root; |
| 499 } | 499 } |
| 500 | 500 |
| 501 HashMap<String, Node> oldNodeIdMap = null; | 501 HashMap<String, UINode> oldNodeIdMap = null; |
| 502 | 502 |
| 503 bool oldNodeReordered(String key) { | 503 bool oldNodeReordered(String key) { |
| 504 return oldNodeIdMap != null && | 504 return oldNodeIdMap != null && |
| 505 oldNodeIdMap.containsKey(key) && | 505 oldNodeIdMap.containsKey(key) && |
| 506 oldNodeIdMap[key] == null; | 506 oldNodeIdMap[key] == null; |
| 507 } | 507 } |
| 508 | 508 |
| 509 void advanceOldStartIndex() { | 509 void advanceOldStartIndex() { |
| 510 oldStartIndex++; | 510 oldStartIndex++; |
| 511 while (oldStartIndex < oldEndIndex && | 511 while (oldStartIndex < oldEndIndex && |
| 512 oldNodeReordered(oldChildren[oldStartIndex]._key)) { | 512 oldNodeReordered(oldChildren[oldStartIndex]._key)) { |
| 513 oldStartIndex++; | 513 oldStartIndex++; |
| 514 } | 514 } |
| 515 } | 515 } |
| 516 | 516 |
| 517 void ensureOldIdMap() { | 517 void ensureOldIdMap() { |
| 518 if (oldNodeIdMap != null) | 518 if (oldNodeIdMap != null) |
| 519 return; | 519 return; |
| 520 | 520 |
| 521 oldNodeIdMap = new HashMap<String, Node>(); | 521 oldNodeIdMap = new HashMap<String, UINode>(); |
| 522 for (int i = oldStartIndex; i < oldEndIndex; i++) { | 522 for (int i = oldStartIndex; i < oldEndIndex; i++) { |
| 523 var node = oldChildren[i]; | 523 var node = oldChildren[i]; |
| 524 if (node is! Text) { | 524 if (node is! Text) { |
| 525 oldNodeIdMap.putIfAbsent(node._key, () => node); | 525 oldNodeIdMap.putIfAbsent(node._key, () => node); |
| 526 } | 526 } |
| 527 } | 527 } |
| 528 } | 528 } |
| 529 | 529 |
| 530 bool searchForOldNode() { | 530 bool searchForOldNode() { |
| 531 if (currentNode is Text) | 531 if (currentNode is Text) |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 573 // Removals | 573 // Removals |
| 574 currentNode = null; | 574 currentNode = null; |
| 575 while (oldStartIndex < oldEndIndex) { | 575 while (oldStartIndex < oldEndIndex) { |
| 576 oldNode = oldChildren[oldStartIndex]; | 576 oldNode = oldChildren[oldStartIndex]; |
| 577 _removeChild(oldNode); | 577 _removeChild(oldNode); |
| 578 advanceOldStartIndex(); | 578 advanceOldStartIndex(); |
| 579 } | 579 } |
| 580 } | 580 } |
| 581 } | 581 } |
| 582 | 582 |
| 583 class Container extends Element { | 583 class Container extends WrapperNode { |
| 584 | 584 |
| 585 String get _tagName => 'div'; | 585 String get _tagName => 'div'; |
| 586 | 586 |
| 587 static final Container _emptyContainer = new Container(); | 587 static final Container _emptyContainer = new Container(); |
| 588 | 588 |
| 589 RenderNode get _emptyNode => _emptyContainer; | 589 RenderNode get _emptyNode => _emptyContainer; |
| 590 | 590 |
| 591 Container({ | 591 Container({ |
| 592 Object key, | 592 Object key, |
| 593 List<Node> children, | 593 List<UINode> children, |
| 594 Style style, | 594 Style style, |
| 595 String inlineStyle | 595 String inlineStyle |
| 596 }) : super( | 596 }) : super( |
| 597 key: key, | 597 key: key, |
| 598 children: children, | 598 children: children, |
| 599 style: style, | 599 style: style, |
| 600 inlineStyle: inlineStyle | 600 inlineStyle: inlineStyle |
| 601 ); | 601 ); |
| 602 } | 602 } |
| 603 | 603 |
| 604 class Image extends Element { | 604 class Image extends WrapperNode { |
| 605 | 605 |
| 606 String get _tagName => 'img'; | 606 String get _tagName => 'img'; |
| 607 | 607 |
| 608 static final Image _emptyImage = new Image(); | 608 static final Image _emptyImage = new Image(); |
| 609 | 609 |
| 610 RenderNode get _emptyNode => _emptyImage; | 610 RenderNode get _emptyNode => _emptyImage; |
| 611 | 611 |
| 612 final String src; | 612 final String src; |
| 613 final int width; | 613 final int width; |
| 614 final int height; | 614 final int height; |
| 615 | 615 |
| 616 Image({ | 616 Image({ |
| 617 Object key, | 617 Object key, |
| 618 List<Node> children, | 618 List<UINode> children, |
| 619 Style style, | 619 Style style, |
| 620 String inlineStyle, | 620 String inlineStyle, |
| 621 this.width, | 621 this.width, |
| 622 this.height, | 622 this.height, |
| 623 this.src | 623 this.src |
| 624 }) : super( | 624 }) : super( |
| 625 key: key, | 625 key: key, |
| 626 children: children, | 626 children: children, |
| 627 style: style, | 627 style: style, |
| 628 inlineStyle: inlineStyle | 628 inlineStyle: inlineStyle |
| 629 ); | 629 ); |
| 630 | 630 |
| 631 void _syncNode(Node old) { | 631 void _syncNode(UINode old) { |
| 632 super._syncNode(old); | 632 super._syncNode(old); |
| 633 | 633 |
| 634 Image oldImage = old as Image; | 634 Image oldImage = old as Image; |
| 635 sky.HTMLImageElement skyImage = _root as sky.HTMLImageElement; | 635 sky.HTMLImageElement skyImage = _root as sky.HTMLImageElement; |
| 636 | 636 |
| 637 if (src != oldImage.src) | 637 if (src != oldImage.src) |
| 638 skyImage.src = src; | 638 skyImage.src = src; |
| 639 | 639 |
| 640 if (width != oldImage.width) | 640 if (width != oldImage.width) |
| 641 skyImage.style['width'] = '${width}px'; | 641 skyImage.style['width'] = '${width}px'; |
| 642 | 642 |
| 643 if (height != oldImage.height) | 643 if (height != oldImage.height) |
| 644 skyImage.style['height'] = '${height}px'; | 644 skyImage.style['height'] = '${height}px'; |
| 645 } | 645 } |
| 646 } | 646 } |
| 647 | 647 |
| 648 class Anchor extends Element { | 648 class Anchor extends WrapperNode { |
| 649 | 649 |
| 650 String get _tagName => 'a'; | 650 String get _tagName => 'a'; |
| 651 | 651 |
| 652 static final Anchor _emptyAnchor = new Anchor(); | 652 static final Anchor _emptyAnchor = new Anchor(); |
| 653 | 653 |
| 654 Node get _emptyNode => _emptyAnchor; | 654 UINode get _emptyNode => _emptyAnchor; |
| 655 | 655 |
| 656 final String href; | 656 final String href; |
| 657 final int width; | 657 final int width; |
| 658 final int height; | 658 final int height; |
| 659 | 659 |
| 660 Anchor({ | 660 Anchor({ |
| 661 Object key, | 661 Object key, |
| 662 List<Node> children, | 662 List<UINode> children, |
| 663 Style style, | 663 Style style, |
| 664 String inlineStyle, | 664 String inlineStyle, |
| 665 this.width, | 665 this.width, |
| 666 this.height, | 666 this.height, |
| 667 this.href | 667 this.href |
| 668 }) : super( | 668 }) : super( |
| 669 key: key, | 669 key: key, |
| 670 children: children, | 670 children: children, |
| 671 style: style, | 671 style: style, |
| 672 inlineStyle: inlineStyle | 672 inlineStyle: inlineStyle |
| 673 ); | 673 ); |
| 674 | 674 |
| 675 void _syncNode(Node old) { | 675 void _syncNode(UINode old) { |
| 676 super._syncNode(old); | 676 super._syncNode(old); |
| 677 | 677 |
| 678 Anchor oldAnchor = old as Anchor; | 678 Anchor oldAnchor = old as Anchor; |
| 679 sky.HTMLAnchorElement skyAnchor = _root as sky.HTMLAnchorElement; | 679 sky.HTMLAnchorElement skyAnchor = _root as sky.HTMLAnchorElement; |
| 680 | 680 |
| 681 if (href != oldAnchor.href) | 681 if (href != oldAnchor.href) |
| 682 skyAnchor.href = href; | 682 skyAnchor.href = href; |
| 683 } | 683 } |
| 684 } | 684 } |
| 685 | 685 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 749 void _scheduleComponentForRender(Component c) { | 749 void _scheduleComponentForRender(Component c) { |
| 750 assert(!_inRenderDirtyComponents); | 750 assert(!_inRenderDirtyComponents); |
| 751 _dirtyComponents.add(c); | 751 _dirtyComponents.add(c); |
| 752 | 752 |
| 753 if (!_buildScheduled) { | 753 if (!_buildScheduled) { |
| 754 _buildScheduled = true; | 754 _buildScheduled = true; |
| 755 new Future.microtask(_buildDirtyComponents); | 755 new Future.microtask(_buildDirtyComponents); |
| 756 } | 756 } |
| 757 } | 757 } |
| 758 | 758 |
| 759 abstract class Component extends Node { | 759 abstract class Component extends UINode { |
| 760 bool get _isBuilding => _currentlyBuilding == this; | 760 bool get _isBuilding => _currentlyBuilding == this; |
| 761 bool _dirty = true; | 761 bool _dirty = true; |
| 762 | 762 |
| 763 sky.Node get _host => _root.parentNode; | 763 sky.Node get _host => _root.parentNode; |
| 764 sky.Node get _insertionPoint => _root == null ? _root : _root.nextSibling; | 764 sky.Node get _insertionPoint => _root == null ? _root : _root.nextSibling; |
| 765 | 765 |
| 766 Node _built; | 766 UINode _built; |
| 767 final int _order; | 767 final int _order; |
| 768 static int _currentOrder = 0; | 768 static int _currentOrder = 0; |
| 769 bool _stateful; | 769 bool _stateful; |
| 770 static Component _currentlyBuilding; | 770 static Component _currentlyBuilding; |
| 771 List<Function> _mountCallbacks; | 771 List<Function> _mountCallbacks; |
| 772 List<Function> _unmountCallbacks; | 772 List<Function> _unmountCallbacks; |
| 773 | 773 |
| 774 void onDidMount(Function fn) { | 774 void onDidMount(Function fn) { |
| 775 if (_mountCallbacks == null) | 775 if (_mountCallbacks == null) |
| 776 _mountCallbacks = new List<Function>(); | 776 _mountCallbacks = new List<Function>(); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 810 | 810 |
| 811 void _remove() { | 811 void _remove() { |
| 812 assert(_built != null); | 812 assert(_built != null); |
| 813 assert(_root != null); | 813 assert(_root != null); |
| 814 _removeChild(_built); | 814 _removeChild(_built); |
| 815 _built = null; | 815 _built = null; |
| 816 _enqueueDidUnmount(this); | 816 _enqueueDidUnmount(this); |
| 817 super._remove(); | 817 super._remove(); |
| 818 } | 818 } |
| 819 | 819 |
| 820 bool _willSync(Node old) { | 820 bool _willSync(UINode old) { |
| 821 Component oldComponent = old as Component; | 821 Component oldComponent = old as Component; |
| 822 if (oldComponent == null || !oldComponent._stateful) | 822 if (oldComponent == null || !oldComponent._stateful) |
| 823 return false; | 823 return false; |
| 824 | 824 |
| 825 // Make |this| the "old" Component | 825 // Make |this| the "old" Component |
| 826 _stateful = false; | 826 _stateful = false; |
| 827 _built = oldComponent._built; | 827 _built = oldComponent._built; |
| 828 assert(_built != null); | 828 assert(_built != null); |
| 829 | 829 |
| 830 // Make |oldComponent| the "new" component | 830 // Make |oldComponent| the "new" component |
| 831 reflect.copyPublicFields(this, oldComponent); | 831 reflect.copyPublicFields(this, oldComponent); |
| 832 oldComponent._built = null; | 832 oldComponent._built = null; |
| 833 oldComponent._dirty = true; | 833 oldComponent._dirty = true; |
| 834 return true; | 834 return true; |
| 835 } | 835 } |
| 836 | 836 |
| 837 /* There are three cases here: | 837 /* There are three cases here: |
| 838 * 1) Building for the first time: | 838 * 1) Building for the first time: |
| 839 * assert(_built == null && old == null) | 839 * assert(_built == null && old == null) |
| 840 * 2) Re-building (because a dirty flag got set): | 840 * 2) Re-building (because a dirty flag got set): |
| 841 * assert(_built != null && old == null) | 841 * assert(_built != null && old == null) |
| 842 * 3) Syncing against an old version | 842 * 3) Syncing against an old version |
| 843 * assert(_built == null && old != null) | 843 * assert(_built == null && old != null) |
| 844 */ | 844 */ |
| 845 void _sync(Node old, sky.ParentNode host, sky.Node insertBefore) { | 845 void _sync(UINode old, sky.ParentNode host, sky.Node insertBefore) { |
| 846 assert(!_defunct); | 846 assert(!_defunct); |
| 847 assert(_built == null || old == null); | 847 assert(_built == null || old == null); |
| 848 | 848 |
| 849 Component oldComponent = old as Component; | 849 Component oldComponent = old as Component; |
| 850 | 850 |
| 851 var oldBuilt; | 851 var oldBuilt; |
| 852 if (oldComponent == null) { | 852 if (oldComponent == null) { |
| 853 oldBuilt = _built; | 853 oldBuilt = _built; |
| 854 } else { | 854 } else { |
| 855 assert(_built == null); | 855 assert(_built == null); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 887 void setState(Function fn()) { | 887 void setState(Function fn()) { |
| 888 _stateful = true; | 888 _stateful = true; |
| 889 fn(); | 889 fn(); |
| 890 if (_isBuilding || _dirty || _defunct) | 890 if (_isBuilding || _dirty || _defunct) |
| 891 return; | 891 return; |
| 892 | 892 |
| 893 _dirty = true; | 893 _dirty = true; |
| 894 _scheduleComponentForRender(this); | 894 _scheduleComponentForRender(this); |
| 895 } | 895 } |
| 896 | 896 |
| 897 Node build(); | 897 UINode build(); |
| 898 } | 898 } |
| 899 | 899 |
| 900 abstract class App extends Component { | 900 abstract class App extends Component { |
| 901 sky.Node _host; | 901 sky.Node _host; |
| 902 | 902 |
| 903 App() : super(stateful: true) { | 903 App() : super(stateful: true) { |
| 904 _host = sky.document.createElement('div'); | 904 _host = sky.document.createElement('div'); |
| 905 sky.document.appendChild(_host); | 905 sky.document.appendChild(_host); |
| 906 _scheduleComponentForRender(this); | 906 _scheduleComponentForRender(this); |
| 907 } | 907 } |
| 908 } | 908 } |
| OLD | NEW |