blob: 29a4a0b755980cce078a3af617c8645fb8966746 [file] [log] [blame]
// 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.
// TODO(jmesserly): more commentary here.
/**
* This library provides access to Model-Driven-Views APIs on HTML elements.
* More information can be found at: <https://github.com/toolkitchen/mdv>.
*/
library mdv;
import 'dart:async';
import 'dart:collection';
import 'dart:html';
import 'dart:math' as math;
import 'package:observe/observe.dart';
// TODO(jmesserly): get this from somewhere else. See http://dartbug.com/4161.
import 'package:serialization/src/serialization_helpers.dart' show IdentityMap;
part 'src/bindings.dart';
part 'src/element.dart';
part 'src/input_element.dart';
part 'src/node.dart';
part 'src/template.dart';
part 'src/text.dart';
/** Initialize the Model-Driven Views polyfill. */
void initialize() {
TemplateElement.mdvPackage = _mdv;
}
StreamController<DocumentFragment> _instanceCreated;
/**
* *Warning*: This is an implementation helper for Model-Driven Views and
* should not be used in your code.
*
* This event is fired whenever a template is instantiated via
* [Element.createInstance].
*/
// TODO(rafaelw): This is a hack, and is neccesary for the polyfill
// because custom elements are not upgraded during clone()
Stream<DocumentFragment> get instanceCreated {
if (_instanceCreated == null) {
_instanceCreated =
new StreamController<DocumentFragment>(sync: true);
}
return _instanceCreated.stream;
}
/**
* Binds all mustaches recursively starting from the [root] node.
*
* Note: this is not an official Model-Driven-Views API; it is intended to
* support binding the [ShadowRoot]'s content to a model.
*/
// TODO(jmesserly): this is needed to avoid two <template> nodes when using
// bindings in a custom element's template. See also:
// https://github.com/polymer-project/polymer/blob/master/src/bindMDV.js#L68
// Called from:
// https://github.com/polymer-project/polymer/blob/master/src/register.js#L99
void bindModel(Node root, model, [CustomBindingSyntax syntax]) {
_Bindings._addBindings(root, model, syntax);
}
// TODO(jmesserly): investigate if expandos give us enough performance.
// The expando for storing our MDV wrappers.
//
// In general, we need state associated with the nodes. Rather than having a
// bunch of individual expandos, we keep one per node.
//
// Aside from the potentially helping performance, it also keeps things simpler
// if we decide to integrate MDV into the DOM later, and means less code needs
// to worry about expandos.
final Expando _mdvExpando = new Expando('mdv');
_mdv(node) {
var wrapper = _mdvExpando[node];
if (wrapper != null) return wrapper;
if (node is InputElement) {
wrapper = new _InputElementExtension(node);
} else if (node is Element) {
if (node.isTemplate) {
wrapper = new _TemplateExtension(node);
} else {
wrapper = new _ElementExtension(node);
}
} else if (node is Text) {
wrapper = new _TextExtension(node);
} else if (node is Node) {
wrapper = new _NodeExtension(node);
} else {
// TODO(jmesserly): this happens for things like CompoundBinding.
wrapper = node;
}
_mdvExpando[node] = wrapper;
return wrapper;
}