From a68e2fc0723b622719212a2c361523c0a1a1c0de Mon Sep 17 00:00:00 2001 From: Steve Orvell Date: Fri, 16 Jan 2015 10:27:57 -0800 Subject: [PATCH] use ShadyDOM whenever localDom is required; update shadow feature to match api changes; add shadow feature tests --- src/features/mini/content.html | 54 +++---- src/features/more/shadow.html | 81 +++++----- test/runner.html | 1 + test/unit/projection-shadow.html | 26 ++++ test/unit/projection.html | 254 +----------------------------- test/unit/projection.js | 260 +++++++++++++++++++++++++++++++ 6 files changed, 354 insertions(+), 322 deletions(-) create mode 100644 test/unit/projection-shadow.html create mode 100644 test/unit/projection.js diff --git a/src/features/mini/content.html b/src/features/mini/content.html index c771d01f66..5e68e3a8f1 100644 --- a/src/features/mini/content.html +++ b/src/features/mini/content.html @@ -21,15 +21,8 @@ Base.addFeature({ _prepContent: function() { - // Use this system iff projection is needed, otherwise localDom - // === composed DOM. - // TODO(sorvell): we should use ShadyDOM whenever there's a template - // not just when there's an a priori content. We need to measure the - // perf impact of this. - // This impacts https://github.com/Polymer/polymer/issues/1078. - this._useContent = this._useContent || - Boolean(this._template && - this._template.content.querySelector('content')); + // Use this system iff localDom is needed. + this._useContent = this._useContent || Boolean(this._template); }, // called as part of content initialization, prior to template stamping @@ -37,26 +30,25 @@ if (this._useContent) { // capture lightChildren to help reify dom scoping saveLightChildrenIfNeeded(this); - this.lightDom = new DomRoot(this, this); } }, // called as part of content initialization, after template stamping _setupRoot: function() { if (this._useContent) { - // ensure shadyRoot exists - this.shadyRoot = this.root; - this.shadyRoot.host = this; - this.localDom = new DomRoot(this.shadyRoot, this); - this.root = this; + this._createLocalRoot(); } else { - var hasLocalDom = (this._template); - var defRoot = new DomRoot(this, this); - var nullRoot = new DomRoot(nullFragment, this); - nullRoot.emptyRoot = true; - this.localDom = hasLocalDom ? defRoot : nullRoot; - this.lightDom = !hasLocalDom ? defRoot : nullRoot; + this.localDom = new Base.DomRoot(nullFragment, this); + this.localDom.emptyRoot = true; } + this.lightDom = new Base.DomRoot(this, this); + }, + + _createLocalRoot: function() { + this.shadyRoot = this.root; + this.shadyRoot.host = this; + this.localDom = new Base.DomRoot(this.shadyRoot, this); + this.root = this; }, distributeContent: function() { @@ -361,17 +353,17 @@ p.oMatchesSelector || p.webkitMatchesSelector; - var DomRoot = function(node, host) { + Base.DomRoot = function(node, host) { //saveLightChildrenIfNeeded(node); this.node = node; - this.host = host; + this.host = host || Base; }; // TODO(sorvell): the api here does not cover the case of inserting an // element into an insertion point parent. We need api of this type to // handle that case appendChildTo(parent, node) // where node goes into parent.lightChildren iff that exists. - DomRoot.prototype = { + Base.DomRoot.prototype = { domRoot: true, @@ -485,20 +477,20 @@ } }, - querySelector: function(selector) { - return this.querySelectorAll(selector)[0]; + querySelector: function(selector, node) { + return this.querySelectorAll(selector, node)[0]; }, - querySelectorAll: function(selector) { + querySelectorAll: function(selector, node) { var self = this; return this._query(function(n) { return self.host.elementMatches(selector, n); - }); + }, node); }, - _query: function(matcher) { + _query: function(matcher, node) { var list = []; - this._queryElements(this.children(), matcher, list); + this._queryElements(this.children(node), matcher, list); return list; }, @@ -521,6 +513,8 @@ var nullFragment = document.createDocumentFragment(); + Polymer.dom = new Base.DomRoot(document.body); + }); diff --git a/src/features/more/shadow.html b/src/features/more/shadow.html index 785d01adee..c23652bb57 100644 --- a/src/features/more/shadow.html +++ b/src/features/more/shadow.html @@ -16,38 +16,22 @@ */ Base.addFeature({ - _prepContent: function() { - this._useContent = this._useContent || Boolean(this._template); - }, - _poolContent: function() { - this.lightDom = new DomRoot(this); - }, + // no-op's when ShadowDOM is in use + _poolContent: function() {}, - // this should happen only 1x. - distributeContent: function() { - if (this.shadowRoot) { - return; - } - // compose "clients" - var c$ = this._getDistributionClients(); - for (var i=0, l= c$.length, c; (i diff --git a/test/runner.html b/test/runner.html index e30b8914b4..0c9e235295 100644 --- a/test/runner.html +++ b/test/runner.html @@ -22,6 +22,7 @@ 'unit/ready.html', 'unit/content.html', 'unit/projection.html', + 'unit/projection-shadow.html', 'unit/bind.html', 'unit/notify-path.html' ]); diff --git a/test/unit/projection-shadow.html b/test/unit/projection-shadow.html new file mode 100644 index 0000000000..7182381f95 --- /dev/null +++ b/test/unit/projection-shadow.html @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + diff --git a/test/unit/projection.html b/test/unit/projection.html index 21aae233ea..db0d907737 100644 --- a/test/unit/projection.html +++ b/test/unit/projection.html @@ -14,265 +14,13 @@ - - - suite('projection', function() { - - function getDestinationInsertionPoints(node) { - return node._destinationInsertionPoints || - Array.prototype.slice.call(node.getDestinationInsertionPoints(), 0); - } - - function getDistributedNodes(node) { - return node._distributedNodes || - Array.prototype.slice.call(node.getDistributedNodes(), 0); - } - - - test('localDom.querySelector', function() { - var test = document.querySelector('x-test'); - var projected = test.localDom.querySelector('#projected'); - assert.equal(projected.textContent, 'projected'); - var p2 = test.lightDom.querySelector('#projected'); - assert.isUndefined(p2); - var rere = test.localDom.querySelector('x-rereproject'); - assert.equal(rere.is, 'x-rereproject'); - var re = rere.localDom.querySelector('x-reproject'); - assert.equal(re.is, 'x-reproject'); - var p = re.localDom.querySelector('x-project'); - assert.equal(p.is, 'x-project'); - }); - - test('localDom.querySelectorAll', function() { - var test = document.querySelector('x-test'); - var rere = test.localDom.querySelector('x-rereproject'); - var re = rere.localDom.querySelector('x-reproject'); - var p = re.localDom.querySelector('x-project'); - var rereList = rere.localDom.querySelectorAll('*'); - assert.include(rereList, re); - assert.equal(rereList.length, 2); - var reList = re.localDom.querySelectorAll('*'); - assert.include(reList, p); - assert.equal(reList.length, 2); - var pList = p.localDom.querySelectorAll('*'); - assert.equal(pList.length, 1); - }); - - test('lightDom.querySelector', function() { - var test = document.querySelector('x-test'); - var projected = test.localDom.querySelector('#projected'); - var rere = test.localDom.querySelector('x-rereproject'); - var re = rere.localDom.querySelector('x-reproject'); - var p = re.localDom.querySelector('x-project'); - assert.equal(rere.lightDom.querySelector('#projected'), projected); - assert(re.lightDom.querySelector('content')); - assert(p.lightDom.querySelector('content')); - }); - - test('lightDom.querySelectorAll', function() { - var test = document.querySelector('x-test'); - var projected = test.localDom.querySelector('#projected'); - var rere = test.localDom.querySelector('x-rereproject'); - var re = rere.localDom.querySelector('x-reproject'); - var p = re.localDom.querySelector('x-project'); - assert.equal(rere.lightDom.querySelectorAll('#projected')[0], projected); - assert(re.lightDom.querySelectorAll('content').length, 1); - assert(p.lightDom.querySelectorAll('content').length, 1); - }); - - test('querySelectorAllComposed', function() { - var test = document.querySelector('x-test'); - var projected = test.localDom.querySelector('#projected'); - var rere = test.localDom.querySelector('x-rereproject'); - var re = rere.localDom.querySelector('x-reproject'); - var p = re.localDom.querySelector('x-project'); - assert.equal(rere.querySelectorAllComposed('#projected')[0], projected); - assert.equal(re.querySelectorAllComposed('#projected')[0], projected); - assert.equal(p.querySelectorAllComposed('#projected')[0], projected); - }); - - - test('projection', function() { - var test = document.querySelector('x-test'); - var projected = test.localDom.querySelector('#projected'); - assert.equal(projected.textContent, 'projected'); - var rere = test.localDom.querySelector('x-rereproject'); - assert.equal(rere.is, 'x-rereproject'); - var re = rere.localDom.querySelector('x-reproject'); - assert.equal(re.is, 'x-reproject'); - var p = re.localDom.querySelector('x-project'); - assert.equal(p.is, 'x-project'); - var c1 = rere.localDom.querySelector('content'); - assert.include(getDistributedNodes(c1), projected); - var c2 = re.localDom.querySelector('content'); - assert.include(getDistributedNodes(c2), projected); - var c3 = p.localDom.querySelector('content'); - assert.include(getDistributedNodes(c3), projected); - var ip$ = [c1, c2, c3]; - assert.deepEqual(getDestinationInsertionPoints(projected), ip$); - }); - - test('distributeContent', function() { - var test = document.querySelector('x-test'); - test.distributeContent(); - var rere = test.localDom.querySelector('x-rereproject'); - assert.equal(rere.is, 'x-rereproject'); - var re = rere.localDom.querySelector('x-reproject'); - assert.equal(re.is, 'x-reproject'); - var p = re.localDom.querySelector('x-project'); - assert.equal(p.is, 'x-project'); - }); - - test('lightDom.appendChild', function() { - var test = document.querySelector('x-test'); - var rere = test.localDom.querySelector('x-rereproject'); - var s = document.createElement('span'); - s.id = 'added'; - s.textContent = 'Added'; - rere.lightDom.appendChild(s); - assert.equal(test.localDom.querySelector('#added'), s); - }); - - test('lightDom.insertBefore', function() { - var test = document.querySelector('x-test'); - var rere = test.localDom.querySelector('x-rereproject'); - var ref = test.localDom.querySelector('#added'); - var s = document.createElement('span'); - s.id = 'added2'; - s.textContent = 'Added2'; - rere.lightDom.insertBefore(s, ref); - assert.equal(test.localDom.querySelector('#added2'), s); - }); - - test('lightDom.removeChild', function() { - var test = document.querySelector('x-test'); - var added = test.localDom.querySelector('#added'); - var added2 = test.localDom.querySelector('#added2'); - var rere = test.localDom.querySelector('x-rereproject'); - rere.lightDom.removeChild(added); - rere.lightDom.removeChild(added2); - assert.equal(test.localDom.querySelectorAll().length, 0); - }); - - test('localDom.appendChild', function() { - var test = document.querySelector('x-test'); - var rere = test.localDom.querySelector('x-rereproject'); - var s = document.createElement('span'); - s.id = 'local'; - s.textContent = 'Local'; - rere.localDom.appendChild(s); - assert.equal(rere.localDom.querySelector('#local'), s); - }); - - test('localDom.insertBefore', function() { - var test = document.querySelector('x-test'); - var rere = test.localDom.querySelector('x-rereproject'); - var ref = test.localDom.querySelector('#local'); - var s = document.createElement('span'); - s.id = 'local2'; - s.textContent = 'Local2'; - rere.localDom.insertBefore(s, ref); - assert.equal(rere.localDom.querySelector('#local2'), s); - }); - - test('localDom.removeChild', function() { - var test = document.querySelector('x-test'); - var rere = test.localDom.querySelector('x-rereproject'); - var local = rere.localDom.querySelector('#local'); - var local2 = rere.localDom.querySelector('#local2'); - rere.localDom.removeChild(local); - rere.localDom.removeChild(local2); - assert.equal(rere.localDom.querySelectorAll('#local').length, 0); - }); - - test('localDom.appendChild (fragment)', function() { - var test = document.querySelector('x-test'); - var rere = test.localDom.querySelector('x-rereproject'); - var fragment = document.createDocumentFragment(); - var childCount = 5; - for (var i=0; i < childCount; i++) { - var s = document.createElement('span'); - s.textContent = i; - fragment.appendChild(s); - } - rere.localDom.appendChild(fragment); - var added = rere.localDom.querySelectorAll('span'); - assert.equal(added.length, childCount); - for (var i=0; i < added.length; i++) { - rere.localDom.removeChild(added[i]); - } - assert.equal(rere.localDom.querySelectorAll('span').length, 0); - }); - - test('localDom.insertBefore (fragment)', function() { - var test = document.querySelector('x-test'); - var rere = test.localDom.querySelector('x-rereproject'); - var fragment = document.createDocumentFragment(); - var childCount = 5; - for (var i=0; i < childCount; i++) { - var s = document.createElement('span'); - s.textContent = i; - fragment.appendChild(s); - } - var l = document.createElement('span'); - l.textContent = 'last'; - rere.localDom.appendChild(l); - rere.localDom.insertBefore(fragment, l); - var added = rere.localDom.querySelectorAll('span'); - assert.equal(added.length, childCount+1); - assert.equal(added[added.length-1], l); - for (var i=0; i < added.length; i++) { - rere.localDom.removeChild(added[i]); - } - assert.equal(rere.localDom.querySelectorAll('span').length, 0); - }); - - test('localDom.batch', function() { - var test = document.querySelector('x-test'); - var rere = test.localDom.querySelector('x-rereproject'); - var s = document.createElement('span'); - s.id = 'local'; - s.textContent = 'Local'; - rere.localDom.batch(); - rere.localDom.appendChild(s); - assert.equal(rere.localDom.querySelector('#local'), s); - assert.notEqual(s.parentNode, rere); - rere.localDom.distribute(); - assert.equal(s.parentNode, rere); - rere.localDom.removeChild(s); - }); - - test('localDom.batch function', function() { - var test = document.querySelector('x-test'); - var rere = test.localDom.querySelector('x-rereproject'); - var s = document.createElement('span'); - s.id = 'local'; - s.textContent = 'Local'; - rere.localDom.batch(function() {; - rere.localDom.appendChild(s); - }); - assert.equal(rere.localDom.querySelector('#local'), s); - assert.equal(s.parentNode, rere); - rere.localDom.removeChild(s); - }); - - test('localDom.elementParent', function() { - var test = document.querySelector('x-test'); - var rere = test.localDom.querySelector('x-rereproject'); - var projected = test.localDom.querySelector('#projected'); - assert.equal(test.localDom.elementParent(), document.body); - assert.equal(test.localDom.elementParent(projected), rere); - }); - - }); - - diff --git a/test/unit/projection.js b/test/unit/projection.js new file mode 100644 index 0000000000..62fd0f3582 --- /dev/null +++ b/test/unit/projection.js @@ -0,0 +1,260 @@ +suite('projection', function() { + + function getDestinationInsertionPoints(node) { + return node._destinationInsertionPoints || + Array.prototype.slice.call(node.getDestinationInsertionPoints(), 0); + } + + function getDistributedNodes(node) { + return node._distributedNodes || + Array.prototype.slice.call(node.getDistributedNodes(), 0); + } + + + test('localDom.querySelector', function() { + var test = document.querySelector('x-test'); + var projected = test.localDom.querySelector('#projected'); + assert.equal(projected.textContent, 'projected'); + var p2 = test.lightDom.querySelector('#projected'); + assert.notOk(p2); + var rere = test.localDom.querySelector('x-rereproject'); + assert.equal(rere.is, 'x-rereproject'); + var re = rere.localDom.querySelector('x-reproject'); + assert.equal(re.is, 'x-reproject'); + var p = re.localDom.querySelector('x-project'); + assert.equal(p.is, 'x-project'); + }); + + test('localDom.querySelectorAll', function() { + var test = document.querySelector('x-test'); + var rere = test.localDom.querySelector('x-rereproject'); + var re = rere.localDom.querySelector('x-reproject'); + var p = re.localDom.querySelector('x-project'); + var rereList = rere.localDom.querySelectorAll('*'); + assert.include(rereList, re); + assert.equal(rereList.length, 2); + var reList = re.localDom.querySelectorAll('*'); + assert.include(reList, p); + assert.equal(reList.length, 2); + var pList = p.localDom.querySelectorAll('*'); + assert.equal(pList.length, 1); + }); + + test('lightDom.querySelector', function() { + var test = document.querySelector('x-test'); + var projected = test.localDom.querySelector('#projected'); + var rere = test.localDom.querySelector('x-rereproject'); + var re = rere.localDom.querySelector('x-reproject'); + var p = re.localDom.querySelector('x-project'); + assert.equal(rere.lightDom.querySelector('#projected'), projected); + assert(re.lightDom.querySelector('content')); + assert(p.lightDom.querySelector('content')); + }); + + test('lightDom.querySelectorAll', function() { + var test = document.querySelector('x-test'); + var projected = test.localDom.querySelector('#projected'); + var rere = test.localDom.querySelector('x-rereproject'); + var re = rere.localDom.querySelector('x-reproject'); + var p = re.localDom.querySelector('x-project'); + assert.equal(rere.lightDom.querySelectorAll('#projected')[0], projected); + assert(re.lightDom.querySelectorAll('content').length, 1); + assert(p.lightDom.querySelectorAll('content').length, 1); + }); + + test('querySelectorAllComposed', function() { + var test = document.querySelector('x-test'); + var projected = test.localDom.querySelector('#projected'); + var rere = test.localDom.querySelector('x-rereproject'); + var re = rere.localDom.querySelector('x-reproject'); + var p = re.localDom.querySelector('x-project'); + assert.equal(rere.querySelectorAllComposed('#projected')[0], projected); + assert.equal(re.querySelectorAllComposed('#projected')[0], projected); + assert.equal(p.querySelectorAllComposed('#projected')[0], projected); + }); + + + test('projection', function() { + var test = document.querySelector('x-test'); + var projected = test.localDom.querySelector('#projected'); + assert.equal(projected.textContent, 'projected'); + var rere = test.localDom.querySelector('x-rereproject'); + assert.equal(rere.is, 'x-rereproject'); + var re = rere.localDom.querySelector('x-reproject'); + assert.equal(re.is, 'x-reproject'); + var p = re.localDom.querySelector('x-project'); + assert.equal(p.is, 'x-project'); + var c1 = rere.localDom.querySelector('content'); + assert.include(getDistributedNodes(c1), projected); + var c2 = re.localDom.querySelector('content'); + assert.include(getDistributedNodes(c2), projected); + var c3 = p.localDom.querySelector('content'); + assert.include(getDistributedNodes(c3), projected); + var ip$ = [c1, c2, c3]; + assert.deepEqual(getDestinationInsertionPoints(projected), ip$); + }); + + test('distributeContent', function() { + var test = document.querySelector('x-test'); + test.distributeContent(); + var rere = test.localDom.querySelector('x-rereproject'); + assert.equal(rere.is, 'x-rereproject'); + var re = rere.localDom.querySelector('x-reproject'); + assert.equal(re.is, 'x-reproject'); + var p = re.localDom.querySelector('x-project'); + assert.equal(p.is, 'x-project'); + }); + + test('lightDom.appendChild', function() { + var test = document.querySelector('x-test'); + var rere = test.localDom.querySelector('x-rereproject'); + var s = document.createElement('span'); + s.id = 'added'; + s.textContent = 'Added'; + rere.lightDom.appendChild(s); + assert.equal(test.localDom.querySelector('#added'), s); + }); + + test('lightDom.insertBefore', function() { + var test = document.querySelector('x-test'); + var rere = test.localDom.querySelector('x-rereproject'); + var ref = test.localDom.querySelector('#added'); + var s = document.createElement('span'); + s.id = 'added2'; + s.textContent = 'Added2'; + rere.lightDom.insertBefore(s, ref); + assert.equal(test.localDom.querySelector('#added2'), s); + }); + + test('lightDom.removeChild', function() { + var test = document.querySelector('x-test'); + var added = test.localDom.querySelector('#added'); + var added2 = test.localDom.querySelector('#added2'); + var rere = test.localDom.querySelector('x-rereproject'); + rere.lightDom.removeChild(added); + rere.lightDom.removeChild(added2); + assert.equal(test.localDom.querySelectorAll().length, 0); + }); + + test('localDom.appendChild', function() { + var test = document.querySelector('x-test'); + var rere = test.localDom.querySelector('x-rereproject'); + var s = document.createElement('span'); + s.id = 'local'; + s.textContent = 'Local'; + rere.localDom.appendChild(s); + assert.equal(rere.localDom.querySelector('#local'), s); + }); + + test('localDom.insertBefore', function() { + var test = document.querySelector('x-test'); + var rere = test.localDom.querySelector('x-rereproject'); + var ref = test.localDom.querySelector('#local'); + var s = document.createElement('span'); + s.id = 'local2'; + s.textContent = 'Local2'; + rere.localDom.insertBefore(s, ref); + assert.equal(rere.localDom.querySelector('#local2'), s); + }); + + test('localDom.removeChild', function() { + var test = document.querySelector('x-test'); + var rere = test.localDom.querySelector('x-rereproject'); + var local = rere.localDom.querySelector('#local'); + var local2 = rere.localDom.querySelector('#local2'); + rere.localDom.removeChild(local); + rere.localDom.removeChild(local2); + assert.equal(rere.localDom.querySelectorAll('#local').length, 0); + }); + + test('localDom.appendChild (fragment)', function() { + var test = document.querySelector('x-test'); + var rere = test.localDom.querySelector('x-rereproject'); + var fragment = document.createDocumentFragment(); + var childCount = 5; + for (var i=0; i < childCount; i++) { + var s = document.createElement('span'); + s.textContent = i; + fragment.appendChild(s); + } + rere.localDom.appendChild(fragment); + var added = rere.localDom.querySelectorAll('span'); + assert.equal(added.length, childCount); + for (var i=0; i < added.length; i++) { + rere.localDom.removeChild(added[i]); + } + assert.equal(rere.localDom.querySelectorAll('span').length, 0); + }); + + test('localDom.insertBefore (fragment)', function() { + var test = document.querySelector('x-test'); + var rere = test.localDom.querySelector('x-rereproject'); + var fragment = document.createDocumentFragment(); + var childCount = 5; + for (var i=0; i < childCount; i++) { + var s = document.createElement('span'); + s.textContent = i; + fragment.appendChild(s); + } + var l = document.createElement('span'); + l.textContent = 'last'; + rere.localDom.appendChild(l); + rere.localDom.insertBefore(fragment, l); + var added = rere.localDom.querySelectorAll('span'); + assert.equal(added.length, childCount+1); + assert.equal(added[added.length-1], l); + for (var i=0; i < added.length; i++) { + rere.localDom.removeChild(added[i]); + } + assert.equal(rere.localDom.querySelectorAll('span').length, 0); + }); + + test('localDom.batch', function() { + var test = document.querySelector('x-test'); + var rere = test.localDom.querySelector('x-rereproject'); + var s = document.createElement('span'); + s.id = 'local'; + s.textContent = 'Local'; + rere.localDom.batch(); + rere.localDom.appendChild(s); + assert.equal(rere.localDom.querySelector('#local'), s); + if (rere.shadyRoot) { + assert.notEqual(s.parentNode, rere.root); + } + rere.localDom.distribute(); + assert.equal(s.parentNode, rere.root); + rere.localDom.removeChild(s); + }); + + test('localDom.batch function', function() { + var test = document.querySelector('x-test'); + var rere = test.localDom.querySelector('x-rereproject'); + var s = document.createElement('span'); + s.id = 'local'; + s.textContent = 'Local'; + rere.localDom.batch(function() {; + rere.localDom.appendChild(s); + }); + assert.equal(rere.localDom.querySelector('#local'), s); + assert.equal(s.parentNode, rere.root); + rere.localDom.removeChild(s); + }); + + test('lightDom/localDom.elementParent', function() { + var test = document.querySelector('x-test'); + var rere = test.localDom.querySelector('x-rereproject'); + var projected = test.localDom.querySelector('#projected'); + assert.equal(test.lightDom.elementParent(), wrap(document.body)); + assert.equal(test.localDom.elementParent(projected), rere); + }); + + test('Polymer.dom.querySelector', function() { + var test = Polymer.dom.querySelector('x-test'); + var rere = Polymer.dom.querySelector('x-rereproject'); + var projected = Polymer.dom.querySelector('#projected'); + assert.ok(test); + assert.notOk(rere); + assert.notOk(projected); + }); + +});