| 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 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 78 void _parentInsertBefore(sky.ParentNode parent, | 78 void _parentInsertBefore(sky.ParentNode parent, |
| 79 sky.Node node, | 79 sky.Node node, |
| 80 sky.Node ref) { | 80 sky.Node ref) { |
| 81 if (ref != null) { | 81 if (ref != null) { |
| 82 ref.insertBefore([node]); | 82 ref.insertBefore([node]); |
| 83 } else { | 83 } else { |
| 84 parent.appendChild(node); | 84 parent.appendChild(node); |
| 85 } | 85 } |
| 86 } | 86 } |
| 87 | 87 |
| 88 enum _SyncOperation { IDENTICAL, INSERTION, STATEFUL, STATELESS, REMOVAL } |
| 89 |
| 88 /* | 90 /* |
| 89 * All Effen nodes derive from Node. All nodes have a _parent, a _key and | 91 * All Effen nodes derive from Node. All nodes have a _parent, a _key and |
| 90 * can be sync'd. | 92 * can be sync'd. |
| 91 */ | 93 */ |
| 92 abstract class Node { | 94 abstract class Node { |
| 93 String _key; | 95 String _key; |
| 94 Node _parent; | 96 Node _parent; |
| 95 sky.Node _root; | 97 sky.Node _root; |
| 96 bool _defunct = false; | 98 bool _defunct = false; |
| 97 int _nodeDepth; | 99 int _nodeDepth; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 129 _ensureDepth(); | 131 _ensureDepth(); |
| 130 StringBuffer buffer = new StringBuffer(); | 132 StringBuffer buffer = new StringBuffer(); |
| 131 int depth = _nodeDepth; | 133 int depth = _nodeDepth; |
| 132 while (depth-- > 0) { | 134 while (depth-- > 0) { |
| 133 buffer.write(' '); | 135 buffer.write(' '); |
| 134 } | 136 } |
| 135 buffer.write(message); | 137 buffer.write(message); |
| 136 print(buffer); | 138 print(buffer); |
| 137 } | 139 } |
| 138 | 140 |
| 141 void _traceSync(_SyncOperation op, String key) { |
| 142 if (!_shouldTrace) |
| 143 return; |
| 144 |
| 145 String opString = op.toString().toLowerCase(); |
| 146 String outString = opString.substring(opString.indexOf('.') + 1); |
| 147 _trace('_sync($outString) $key'); |
| 148 } |
| 149 |
| 139 void _removeChild(Node node) { | 150 void _removeChild(Node node) { |
| 140 _trace('_sync(remove) ${node._key}'); | 151 _traceSync(_SyncOperation.REMOVAL, node._key); |
| 141 node._remove(); | 152 node._remove(); |
| 142 } | 153 } |
| 143 | 154 |
| 144 // Returns the child which should be retained as the child of this node. | 155 // Returns the child which should be retained as the child of this node. |
| 145 Node _syncChild(Node node, Node oldNode, sky.ParentNode host, | 156 Node _syncChild(Node node, Node oldNode, sky.ParentNode host, |
| 146 sky.Node insertBefore) { | 157 sky.Node insertBefore) { |
| 147 | 158 |
| 148 assert(oldNode == null || node._key == oldNode._key); | 159 assert(oldNode == null || node._key == oldNode._key); |
| 149 | 160 |
| 150 if (node == oldNode) { | 161 if (node == oldNode) { |
| 151 _trace('_sync(identical) ${node._key}'); | 162 _traceSync(_SyncOperation.IDENTICAL, node._key); |
| 152 return node; // Nothing to do. Subtrees must be identical. | 163 return node; // Nothing to do. Subtrees must be identical. |
| 153 } | 164 } |
| 154 | 165 |
| 155 // TODO(rafaelw): This eagerly removes the old DOM. It may be that a | 166 // TODO(rafaelw): This eagerly removes the old DOM. It may be that a |
| 156 // new component was built that could re-use some of it. Consider | 167 // new component was built that could re-use some of it. Consider |
| 157 // syncing the new VDOM against the old one. | 168 // syncing the new VDOM against the old one. |
| 158 if (oldNode != null && node._key != oldNode._key) { | 169 if (oldNode != null && node._key != oldNode._key) { |
| 159 _removeChild(oldNode); | 170 _removeChild(oldNode); |
| 160 } | 171 } |
| 161 | 172 |
| 162 if (node._willSync(oldNode)) { | 173 if (node._willSync(oldNode)) { |
| 163 _trace('_sync(statefull) ${node._key}'); | 174 _traceSync(_SyncOperation.STATEFUL, node._key); |
| 164 oldNode._sync(node, host, insertBefore); | 175 oldNode._sync(node, host, insertBefore); |
| 165 node._defunct = true; | 176 node._defunct = true; |
| 166 assert(oldNode._root is sky.Node); | 177 assert(oldNode._root is sky.Node); |
| 167 return oldNode; | 178 return oldNode; |
| 168 } | 179 } |
| 169 | 180 |
| 170 node._parent = this; | 181 node._parent = this; |
| 171 | 182 |
| 172 if (oldNode == null) { | 183 if (oldNode == null) { |
| 173 _trace('_sync(insert) ${node._key}'); | 184 _traceSync(_SyncOperation.INSERTION, node._key); |
| 174 } else { | 185 } else { |
| 175 _trace('_sync(stateless) ${node._key}'); | 186 _traceSync(_SyncOperation.STATELESS, node._key); |
| 176 } | 187 } |
| 177 node._sync(oldNode, host, insertBefore); | 188 node._sync(oldNode, host, insertBefore); |
| 178 if (oldNode != null) | 189 if (oldNode != null) |
| 179 oldNode._defunct = true; | 190 oldNode._defunct = true; |
| 180 | 191 |
| 181 assert(node._root is sky.Node); | 192 assert(node._root is sky.Node); |
| 182 return node; | 193 return node; |
| 183 } | 194 } |
| 184 } | 195 } |
| 185 | 196 |
| (...skipping 477 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 663 super._syncNode(old); | 674 super._syncNode(old); |
| 664 | 675 |
| 665 Anchor oldAnchor = old as Anchor; | 676 Anchor oldAnchor = old as Anchor; |
| 666 sky.HTMLAnchorElement skyAnchor = _root as sky.HTMLAnchorElement; | 677 sky.HTMLAnchorElement skyAnchor = _root as sky.HTMLAnchorElement; |
| 667 | 678 |
| 668 if (href != oldAnchor.href) | 679 if (href != oldAnchor.href) |
| 669 skyAnchor.href = href; | 680 skyAnchor.href = href; |
| 670 } | 681 } |
| 671 } | 682 } |
| 672 | 683 |
| 684 |
| 685 Set<Component> _mountedComponents = new HashSet<Component>(); |
| 686 Set<Component> _unmountedComponents = new HashSet<Component>(); |
| 687 |
| 688 void _enqueueDidMount(Component c) { |
| 689 assert(!_notifingMountStatus); |
| 690 _mountedComponents.add(c); |
| 691 } |
| 692 |
| 693 void _enqueueDidUnmount(Component c) { |
| 694 assert(!_notifingMountStatus); |
| 695 _unmountedComponents.add(c); |
| 696 } |
| 697 |
| 698 bool _notifingMountStatus = false; |
| 699 |
| 700 void _notifyMountStatusChanged() { |
| 701 try { |
| 702 _notifingMountStatus = true; |
| 703 _unmountedComponents.forEach((c) => c._didUnmount()); |
| 704 _mountedComponents.forEach((c) => c._didMount()); |
| 705 _mountedComponents.clear(); |
| 706 _unmountedComponents.clear(); |
| 707 } finally { |
| 708 _notifingMountStatus = false; |
| 709 } |
| 710 } |
| 711 |
| 673 List<Component> _dirtyComponents = new List<Component>(); | 712 List<Component> _dirtyComponents = new List<Component>(); |
| 674 Set<Component> _mountedComponents = new HashSet<Component>(); | |
| 675 Set<Component> _unmountedComponents = new HashSet<Component>(); | |
| 676 | |
| 677 bool _buildScheduled = false; | 713 bool _buildScheduled = false; |
| 678 bool _inRenderDirtyComponents = false; | 714 bool _inRenderDirtyComponents = false; |
| 679 | 715 |
| 680 void _notifyMountStatusChanged() { | |
| 681 _unmountedComponents.forEach((c) => c._didUnmount()); | |
| 682 _mountedComponents.forEach((c) => c._didMount()); | |
| 683 _mountedComponents.clear(); | |
| 684 _unmountedComponents.clear(); | |
| 685 } | |
| 686 | 716 |
| 687 void _buildDirtyComponents() { | 717 void _buildDirtyComponents() { |
| 688 Stopwatch sw; | 718 Stopwatch sw; |
| 689 if (_shouldLogRenderDuration) | 719 if (_shouldLogRenderDuration) |
| 690 sw = new Stopwatch()..start(); | 720 sw = new Stopwatch()..start(); |
| 691 | 721 |
| 692 try { | 722 try { |
| 693 _inRenderDirtyComponents = true; | 723 _inRenderDirtyComponents = true; |
| 694 | 724 |
| 695 _dirtyComponents.sort((a, b) => a._order - b._order); | 725 _dirtyComponents.sort((a, b) => a._order - b._order); |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 771 | 801 |
| 772 // TODO(rafaelw): It seems wrong to expose DOM at all. This is presently | 802 // TODO(rafaelw): It seems wrong to expose DOM at all. This is presently |
| 773 // needed to get sizing info. | 803 // needed to get sizing info. |
| 774 sky.Node getRoot() => _root; | 804 sky.Node getRoot() => _root; |
| 775 | 805 |
| 776 void _remove() { | 806 void _remove() { |
| 777 assert(_built != null); | 807 assert(_built != null); |
| 778 assert(_root != null); | 808 assert(_root != null); |
| 779 _removeChild(_built); | 809 _removeChild(_built); |
| 780 _built = null; | 810 _built = null; |
| 781 _unmountedComponents.add(this); | 811 _enqueueDidUnmount(this); |
| 782 super._remove(); | 812 super._remove(); |
| 783 } | 813 } |
| 784 | 814 |
| 785 bool _willSync(Node old) { | 815 bool _willSync(Node old) { |
| 786 Component oldComponent = old as Component; | 816 Component oldComponent = old as Component; |
| 787 if (oldComponent == null || !oldComponent._stateful) | 817 if (oldComponent == null || !oldComponent._stateful) |
| 788 return false; | 818 return false; |
| 789 | 819 |
| 790 // Make |this| the "old" Component | 820 // Make |this| the "old" Component |
| 791 _stateful = false; | 821 _stateful = false; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 815 | 845 |
| 816 var oldBuilt; | 846 var oldBuilt; |
| 817 if (oldComponent == null) { | 847 if (oldComponent == null) { |
| 818 oldBuilt = _built; | 848 oldBuilt = _built; |
| 819 } else { | 849 } else { |
| 820 assert(_built == null); | 850 assert(_built == null); |
| 821 oldBuilt = oldComponent._built; | 851 oldBuilt = oldComponent._built; |
| 822 } | 852 } |
| 823 | 853 |
| 824 if (oldBuilt == null) | 854 if (oldBuilt == null) |
| 825 _mountedComponents.add(this); | 855 _enqueueDidMount(this); |
| 826 | 856 |
| 827 int lastOrder = _currentOrder; | 857 int lastOrder = _currentOrder; |
| 828 _currentOrder = _order; | 858 _currentOrder = _order; |
| 829 _currentlyBuilding = this; | 859 _currentlyBuilding = this; |
| 830 _built = build(); | 860 _built = build(); |
| 831 _currentlyBuilding = null; | 861 _currentlyBuilding = null; |
| 832 _currentOrder = lastOrder; | 862 _currentOrder = lastOrder; |
| 833 | 863 |
| 834 _built = _syncChild(_built, oldBuilt, host, insertBefore); | 864 _built = _syncChild(_built, oldBuilt, host, insertBefore); |
| 835 _dirty = false; | 865 _dirty = false; |
| (...skipping 28 matching lines...) Expand all Loading... |
| 864 | 894 |
| 865 abstract class App extends Component { | 895 abstract class App extends Component { |
| 866 sky.Node _host; | 896 sky.Node _host; |
| 867 | 897 |
| 868 App() : super(stateful: true) { | 898 App() : super(stateful: true) { |
| 869 _host = sky.document.createElement('div'); | 899 _host = sky.document.createElement('div'); |
| 870 sky.document.appendChild(_host); | 900 sky.document.appendChild(_host); |
| 871 _scheduleComponentForRender(this); | 901 _scheduleComponentForRender(this); |
| 872 } | 902 } |
| 873 } | 903 } |
| OLD | NEW |