Chromium Code Reviews| Index: tools/dom/src/ModelTreeObserver.dart |
| diff --git a/tools/dom/src/ModelTreeObserver.dart b/tools/dom/src/ModelTreeObserver.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..7565b942809d5a93fc6d24112919dbf11be4f0cc |
| --- /dev/null |
| +++ b/tools/dom/src/ModelTreeObserver.dart |
| @@ -0,0 +1,86 @@ |
| +// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
| + |
| +part of html; |
| + |
| +class _ModelTreeObserver { |
| + static bool _initialized = false; |
| + |
| + /** |
| + * Start an observer watching the document for tree changes to automatically |
| + * propagate model changes. |
| + */ |
| + static void initialize() { |
| + if (!_initialized) { |
| + _initialized = true; |
| + |
|
Jacob
2013/03/15 18:50:19
What about when there are true shadow DOMs on the
blois
2013/03/15 20:14:10
Done.
|
| + if (MutationObserver.supported) { |
| + var observer = new MutationObserver(_processTreeChange); |
| + observer.observe(document, childList: true, subtree: true); |
| + } else { |
| + document.on['DOMNodeInserted'].listen(_handleNodeInserted); |
| + document.on['DOMNodeRemoved'].listen(_handleNodeRemoved); |
| + } |
| + } |
| + } |
| + |
| + static void _processTreeChange(List<MutationRecord> mutations, |
| + MutationObserver observer) { |
| + for (var record in mutations) { |
| + for (var node in record.addedNodes) { |
| + // When nodes enter the document we need to make sure that all of the |
| + // models are properly propagated through the entire sub-tree. |
| + propagateModel(node, _calculatedModel(node), true); |
| + } |
| + for (var node in record.removedNodes) { |
| + propagateModel(node, _calculatedModel(node), false); |
| + } |
| + } |
| + } |
| + |
| + static void _handleNodeInserted(MutationEvent e) { |
| + var node = e.target; |
|
Jacob
2013/03/15 18:50:19
mutation observers are async while DOMNodeInserted
blois
2013/03/15 20:14:10
Done.
|
| + propagateModel(node, _calculatedModel(node), true); |
| + } |
| + |
| + static void _handleNodeRemoved(MutationEvent e) { |
| + var node = e.target; |
| + propagateModel(node, _calculatedModel(node), false); |
| + } |
| + |
| + /** |
| + * Figures out what the model should be for a node, avoiding any cached |
| + * model values. |
| + */ |
| + static _calculatedModel(node) { |
| + if (node._hasLocalModel == true) { |
| + return node._model; |
| + } else if (node.parentNode != null) { |
| + return node.parentNode._model; |
| + } |
| + return null; |
| + } |
| + |
| + /** |
| + * Pushes model changes down through the tree. |
| + * |
| + * Set fullTree to true if the state of the tree is unknown and model changes |
| + * should be propagated through the entire tree. |
| + */ |
| + static void propagateModel(Node node, model, bool fullTree) { |
| + if (node._hasLocalModel != true && node._model != model && |
|
Jennifer Messerly
2013/03/15 03:20:46
I wonder if it's worth noting that we're potential
blois
2013/03/15 18:26:05
The error handling here is the question- I believ
|
| + node._modelChangedStream != null) { |
| + node._model = model; |
| + node._modelChangedStream.add(model); |
| + } |
| + for (var child = node.$dom_firstChild; child != null; |
|
Jacob
2013/03/15 18:50:19
high level: I think it would be a lot more efficie
blois
2013/03/15 20:14:10
Models are only cached locally when a change liste
|
| + child = child.nextNode) { |
| + if (child._hasLocalModel != true) { |
| + propagateModel(child, model, fullTree); |
| + } else if (fullTree) { |
| + propagateModel(child, child._model, true); |
| + } |
| + } |
| + } |
| +} |