Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(374)

Unified Diff: sdk/lib/html/dartium/html_dartium.dart

Issue 12754013: Adding an inheriting data model to Node (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
Download patch
Index: sdk/lib/html/dartium/html_dartium.dart
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 6ce15f69bc9ce6f39d26a39138dcae473bbd4370..28d0991750081df758e2a1ce5f5d450e4dc17475 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -19128,6 +19128,80 @@ class Node extends EventTarget {
}
}
+ // Note that this may either be the locally set model or a cached value
+ // of the inherited model. This is cached to minimize model change
+ // notifications.
+ var _model;
+ bool _hasLocalModel;
+ StreamController _modelChangedStream;
+
+ /**
+ * The data model which is inherited through the tree.
+ *
+ * Setting this will propagate the value to all descendant nodes. If the
+ * model is not set on this node then it will be inherited from ancestor
+ * nodes.
+ *
+ * [clearModel] must be used to remove the model property from this node
+ * and have the model inherit from ancestor nodes.
+ */
+ @Experimental
+ get model {
+ // If we have a change handler then we've cached the model locally.
+ if (_modelChangedStream != null) {
+ return _model;
+ }
+ // Otherwise start looking up the tree.
+ for (var node = this; node != null; node = node.parentNode) {
+ if (node._hasLocalModel == true) {
+ return node._model;
+ }
+ }
+ return null;
+ }
+
+ @Experimental
+ void set model(value) {
+ _model = value;
+ _hasLocalModel = true;
+ _ModelTreeObserver.initialize();
+
+ if (_modelChangedStream != null) {
+ _modelChangedStream.add(value);
+ }
+ // Propagate new model to all descendants.
+ _ModelTreeObserver.propagateModel(this, value, false);
+ }
+
+ /**
+ * Clears the locally set model and makes this model be inherited from parent
+ * nodes.
+ */
+ void clearModel() {
+ if (_hasLocalModel == true) {
+ _hasLocalModel = false;
+
+ // Propagate new model to all descendants.
+ if (parentNode != null) {
+ _ModelTreeObserver.propagateModel(this, parentNode.model, false);
+ } else {
+ _ModelTreeObserver.propagateModel(this, null, false);
+ }
+ }
+ }
+
+ /**
+ * Get a stream of models, whenever the model changes.
+ */
+ Stream get onModelChanged {
+ if (_modelChangedStream == null) {
+ // Ensure the model is cached locally to minimize change notifications.
+ _model = model;
+ _modelChangedStream = new StreamController.broadcast();
+ }
+ return _modelChangedStream.stream;
+ }
+
Node.internal() : super.internal();
@DomName('Node.childNodes')
@@ -34065,6 +34139,91 @@ abstract class KeyName {
// BSD-style license that can be found in the LICENSE file.
+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;
+
+ 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;
+ 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 &&
+ node._modelChangedStream != null) {
+ node._model = model;
+ node._modelChangedStream.add(model);
+ }
+ for (var child = node.$dom_firstChild; child != null;
+ child = child.nextNode) {
+ if (child._hasLocalModel != true) {
+ propagateModel(child, model, fullTree);
+ } else if (fullTree) {
+ propagateModel(child, child._model, true);
+ }
+ }
+ }
+}
+// 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.
+
+
/**
* A utility class for representing two-dimensional positions.
*/

Powered by Google App Engine
This is Rietveld 408576698