From 279934127f6777bdfb9f752e98eb0da172fbca1b Mon Sep 17 00:00:00 2001 From: Rafael Weinstein Date: Thu, 6 Feb 2014 15:57:51 -0800 Subject: [PATCH] make ref bindable R=arv BUG= Review URL: https://codereview.appspot.com/59220044 --- src/TemplateBinding.js | 48 +++++++++++++++++++++++++++++++++++++++++- tests/tests.js | 31 +++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/src/TemplateBinding.js b/src/TemplateBinding.js index 5af45a5..ab2fa60 100644 --- a/src/TemplateBinding.js +++ b/src/TemplateBinding.js @@ -326,6 +326,15 @@ } } + var templateObserver; + if (typeof MutationObserver == 'function') { + templateObserver = new MutationObserver(function(records) { + for (var i = 0; i < records.length; i++) { + records[i].target.refChanged_(); + } + }); + } + /** * Ensures proper API and content model for template elements. * @param {HTMLTemplateElement} opt_instanceRef The template element which @@ -429,6 +438,25 @@ } mixin(HTMLTemplateElement.prototype, { + bind: function(name, value, oneTime) { + if (name != 'ref') + return Element.prototype.bind.call(this, name, value, oneTime); + + var self = this; + var ref = oneTime ? value : value.open(function(ref) { + self.setAttribute('ref', ref); + self.refChanged_(); + }); + + this.setAttribute('ref', ref); + this.refChanged_(); + if (oneTime) + return; + + this.unbind('ref'); + return this.bindings.ref = value; + }, + processBindingDirectives_: function(directives) { if (this.iterator_) this.iterator_.closeDeps(); @@ -450,6 +478,12 @@ } this.iterator_.updateDependencies(directives, this.model_); + + if (templateObserver) { + templateObserver.observe(this, { attributes: true, + attributeFilter: ['ref'] }); + } + return this.iterator_; }, @@ -458,7 +492,9 @@ if (bindingDelegate) delegate_ = this.newDelegate_(bindingDelegate); - var content = this.ref_.content; + if (!this.refContent_) + this.refContent_ = this.ref_.content; + var content = this.refContent_; var map = this.bindingMap_; if (!map || map.content !== content) { // TODO(rafaelw): Setup a MutationObserver on content to detect @@ -510,10 +546,20 @@ return this.delegate_ && this.delegate_.raw; }, + refChanged_: function() { + if (!this.iterator_ || this.refContent_ === this.ref_.content) + return; + + this.refContent_ = undefined; + this.iterator_.valueChanged(); + this.iterator_.updateIteratedValue(); + }, + clear: function() { this.model_ = undefined; this.delegate_ = undefined; this.bindings_ = undefined; + this.refContent_ = undefined; if (!this.iterator_) return; this.iterator_.valueChanged(); diff --git a/tests/tests.js b/tests/tests.js index fc4870a..bbc61e0 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -1499,6 +1499,12 @@ suite('Template Instantiation', function() { }); test('Update Ref', function(done) { + // Updating ref by observing the attribute is dependent on MutationObservers + if (typeof MutationObserver != 'function') { + done(); + return; + } + var div = createTestHtml( '' + '' + @@ -1516,7 +1522,32 @@ suite('Template Instantiation', function() { }).then(function() { assert.strictEqual(5, div.childNodes.length); + assert.strictEqual('Hola, Fry', div.childNodes[3].textContent); + assert.strictEqual('Hola, Leela', div.childNodes[4].textContent); + + done(); + }); + }); + + test('Bound Ref', function(done) { + var div = createTestHtml( + '' + + '' + + ''); + var template = div.childNodes[2]; + var model = { ref: 'A', people: ['Fry'] }; + template.model = model; + + then(function() { + assert.strictEqual(4, div.childNodes.length); assert.strictEqual('Hi, Fry', div.childNodes[3].textContent); + + model.ref = 'B'; + model.people.push('Leela'); + + }).then(function() { + assert.strictEqual(5, div.childNodes.length); + assert.strictEqual('Hola, Fry', div.childNodes[3].textContent); assert.strictEqual('Hola, Leela', div.childNodes[4].textContent); done();