/*
* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
* Code distributed by Google as part of the polymer project is also
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/
(function(scope) {
/**
* @class polymer-base
*/
// imports
var log = window.WebComponents ? WebComponents.flags.log : {};
// element api supporting mdv
var mdv = {
/**
* Creates dom cloned from the given template, instantiating bindings
* with this element as the template model and `PolymerExpressions` as the
* binding delegate.
*
* @method instanceTemplate
* @param {Template} template source template from which to create dom.
*/
instanceTemplate: function(template) {
// ensure template is decorated (lets' things like
work)
HTMLTemplateElement.decorate(template);
// ensure a default bindingDelegate
var syntax = this.syntax || (!template.bindingDelegate &&
this.element.syntax);
var dom = template.createInstance(this, syntax);
var observers = dom.bindings_;
for (var i = 0; i < observers.length; i++) {
this.registerObserver(observers[i]);
}
return dom;
},
// Called by TemplateBinding/NodeBind to setup a binding to the given
// property. It's overridden here to support property bindings
// in addition to attribute bindings that are supported by default.
bind: function(name, observable, oneTime) {
var property = this.propertyForAttribute(name);
if (!property) {
// TODO(sjmiles): this mixin method must use the special form
// of `super` installed by `mixinMethod` in declaration/prototype.js
return this.mixinSuper(arguments);
} else {
// use n-way Polymer binding
var observer = this.bindProperty(property, observable, oneTime);
// NOTE: reflecting binding information is typically required only for
// tooling. It has a performance cost so it's opt-in in Node.bind.
if (Platform.enableBindingsReflection && observer) {
observer.path = observable.path_;
this._recordBinding(property, observer);
}
if (this.reflect[property]) {
this.reflectPropertyToAttribute(property);
}
return observer;
}
},
_recordBinding: function(name, observer) {
this.bindings_ = this.bindings_ || {};
this.bindings_[name] = observer;
},
// Called by TemplateBinding when all bindings on an element have been
// executed. This signals that all element inputs have been gathered
// and it's safe to ready the element, create shadow-root and start
// data-observation.
bindFinished: function() {
this.makeElementReady();
},
// called at detached time to signal that an element's bindings should be
// cleaned up. This is done asynchronously so that users have the chance
// to call `cancelUnbindAll` to prevent unbinding.
asyncUnbindAll: function() {
if (!this._unbound) {
log.unbind && console.log('[%s] asyncUnbindAll', this.localName);
this._unbindAllJob = this.job(this._unbindAllJob, this.unbindAll, 0);
}
},
/**
* This method should rarely be used and only if
* `cancelUnbindAll` has been called to
* prevent element unbinding. In this case, the element's bindings will
* not be automatically cleaned up and it cannot be garbage collected
* by the system. If memory pressure is a concern or a
* large amount of elements need to be managed in this way, `unbindAll`
* can be called to deactivate the element's bindings and allow its
* memory to be reclaimed.
*
* @method unbindAll
*/
unbindAll: function() {
if (!this._unbound) {
this.closeObservers();
this.closeNamedObservers();
this._unbound = true;
}
},
/**
* Call in `detached` to prevent the element from unbinding when it is
* detached from the dom. The element is unbound as a cleanup step that
* allows its memory to be reclaimed.
* If `cancelUnbindAll` is used, consider calling
* `unbindAll` when the element is no longer
* needed. This will allow its memory to be reclaimed.
*
* @method cancelUnbindAll
*/
cancelUnbindAll: function() {
if (this._unbound) {
log.unbind && console.warn('[%s] already unbound, cannot cancel unbindAll', this.localName);
return;
}
log.unbind && console.log('[%s] cancelUnbindAll', this.localName);
if (this._unbindAllJob) {
this._unbindAllJob = this._unbindAllJob.stop();
}
}
};
function unbindNodeTree(node) {
forNodeTree(node, _nodeUnbindAll);
}
function _nodeUnbindAll(node) {
node.unbindAll();
}
function forNodeTree(node, callback) {
if (node) {
callback(node);
for (var child = node.firstChild; child; child = child.nextSibling) {
forNodeTree(child, callback);
}
}
}
var mustachePattern = /\{\{([^{}]*)}}/;
// exports
scope.bindPattern = mustachePattern;
scope.api.instance.mdv = mdv;
})(Polymer);