From 18ba9ae0d904ac5dc8c8c2e1b747a9f72d896655 Mon Sep 17 00:00:00 2001 From: Steven Orvell Date: Thu, 14 Feb 2019 16:38:56 -0800 Subject: [PATCH 01/29] Add `classList` to `Polymer.dom` when `ShadyDOM.noPatch` is used Fixes #5488 --- lib/legacy/polymer.dom.js | 4 + test/unit/polymer-dom-nopatch.html | 138 +++++++++++++++++++++++++++++ test/unit/polymer-dom.html | 138 +++++++++++++++++++++++++++++ 3 files changed, 280 insertions(+) diff --git a/lib/legacy/polymer.dom.js b/lib/legacy/polymer.dom.js index 442d428147..cf5c1ddc66 100644 --- a/lib/legacy/polymer.dom.js +++ b/lib/legacy/polymer.dom.js @@ -395,6 +395,10 @@ if (window['ShadyDOM'] && window['ShadyDOM']['inUse'] && window['ShadyDOM']['noP } }); + forwardReadOnlyProperties(Wrapper.prototype, [ + 'classList' + ]); + DomApiImpl = Wrapper; Object.defineProperties(EventApi.prototype, { diff --git a/test/unit/polymer-dom-nopatch.html b/test/unit/polymer-dom-nopatch.html index 54017de804..6a7e697110 100644 --- a/test/unit/polymer-dom-nopatch.html +++ b/test/unit/polymer-dom-nopatch.html @@ -355,6 +355,144 @@ assert.equal(useNativeCSSProperties, Boolean(!window.ShadyCSS || window.ShadyCSS.nativeCss)); }); +}); + +suite('forwarded native api', function() { + + let el; + + setup(function() { + el = document.createElement('x-container-slot'); + document.body.appendChild(el); + }); + + teardown(function() { + document.body.removeChild(el); + }); + + test('accessors are available', function() { + const d = dom(el); + assert.isDefined(d.parentNode); + assert.isDefined(d.firstChild); + assert.isDefined(d.lastChild); + assert.isDefined(d.nextSibling); + assert.isDefined(d.previousSibling); + assert.isDefined(d.firstElementChild); + assert.isDefined(d.lastElementChild); + assert.isDefined(d.nextElementSibling); + assert.isDefined(d.previousElementSibling); + assert.isDefined(d.childNodes); + assert.isDefined(d.children); + assert.isDefined(d.classList); + assert.isDefined(d.textContent); + assert.isDefined(d.innerHTML); + }); + + test('cloneNode', function() { + const clone = dom(el).cloneNode(el); + assert.ok(clone); + assert.equal(clone.localName, 'x-container-slot'); + }); + + test('appendChild', function() { + const d1 = document.createElement('div'); + dom(el).appendChild(d1); + assert.equal(dom(el).firstChild, d1); + assert.equal(dom(d1).parentNode, el); + }); + + test('insertBefore', function() { + const d1 = document.createElement('div'); + const d2 = document.createElement('div'); + dom(el).appendChild(d1); + dom(el).insertBefore(d2, d1); + assert.equal(dom(d2).nextSibling, d1); + }); + + test('removeChild', function() { + const d1 = document.createElement('div'); + dom(el).appendChild(d1); + dom(el).removeChild(d1); + assert.equal(dom(d1).parentNode, null); + }); + + test('replaceChild', function() { + const d1 = document.createElement('div'); + const d2 = document.createElement('div'); + dom(el).appendChild(d1); + dom(el).replaceChild(d2, d1); + assert.equal(dom(d1).parentNode, null); + assert.equal(dom(el).firstChild, d2); + assert.equal(dom(d2).parentNode, el); + }); + + test('replaceChild', function() { + dom(el).setAttribute('foo', 'foo'); + assert.equal(el.getAttribute('foo'), 'foo'); + }); + + test('replaceChild', function() { + dom(el).setAttribute('foo', 'foo'); + dom(el).removeAttribute('foo'); + assert.isFalse(el.hasAttribute('foo')); + }); + + test('querySelector', function() { + const d1 = document.createElement('div'); + dom(el).appendChild(d1); + const query = dom(el).querySelector('div'); + assert.equal(query, d1); + }); + + test('querySelectorAll', function() { + const d1 = document.createElement('div'); + const d2 = document.createElement('div'); + dom(el).appendChild(d1); + dom(el).appendChild(d2); + const query = dom(el).querySelectorAll('div'); + assert.equal(query[0], d1); + assert.equal(query[1], d2); + assert.equal(query.length, 2); + }); + + test('tree accessors', function() { + const d1 = document.createElement('div'); + const d2 = document.createElement('div'); + dom(el).appendChild(d1); + dom(el).appendChild(d2); + const pel = dom(el); + const pd1 = dom(d1); + const pd2 = dom(d2); + assert.equal(pd1.parentNode, el); + assert.equal(pel.firstChild, d1); + assert.equal(pel.lastChild, d2); + assert.equal(pel.firstElementChild, d1); + assert.equal(pel.lastElementChild, d2); + assert.equal(pd1.nextSibling, d2); + assert.equal(pd2.previousSibling, d1); + assert.equal(pd1.nextElementSibling, d2); + assert.equal(pd2.previousElementSibling, d1); + assert.equal(pel.childNodes[0], d1); + assert.equal(pel.childNodes[1], d2); + assert.equal(pel.children[0], d1); + assert.equal(pel.children[1], d2); + }); + + test('innerHTML', function() { + dom(el).innerHTML = '
'; + assert.equal(dom(el).firstChild.localName, 'div'); + }); + + test('textContent', function() { + dom(el).innerHTML = 'hi'; + assert.equal(dom(dom(el).firstChild).textContent, 'hi'); + }); + + test('classList', function() { + dom(el).classList.add('foo'); + assert.equal(el.className, 'foo'); + }); + }); diff --git a/test/unit/polymer-dom.html b/test/unit/polymer-dom.html index 8bea7e1c1f..30cc025654 100644 --- a/test/unit/polymer-dom.html +++ b/test/unit/polymer-dom.html @@ -342,6 +342,144 @@ assert.equal(useNativeCSSProperties, Boolean(!window.ShadyCSS || window.ShadyCSS.nativeCss)); }); +}); + +suite('forwarded native api', function() { + + let el; + + setup(function() { + el = document.createElement('x-container-slot'); + document.body.appendChild(el); + }); + + teardown(function() { + document.body.removeChild(el); + }); + + test('accessors are available', function() { + const d = dom(el); + assert.isDefined(d.parentNode); + assert.isDefined(d.firstChild); + assert.isDefined(d.lastChild); + assert.isDefined(d.nextSibling); + assert.isDefined(d.previousSibling); + assert.isDefined(d.firstElementChild); + assert.isDefined(d.lastElementChild); + assert.isDefined(d.nextElementSibling); + assert.isDefined(d.previousElementSibling); + assert.isDefined(d.childNodes); + assert.isDefined(d.children); + assert.isDefined(d.classList); + assert.isDefined(d.textContent); + assert.isDefined(d.innerHTML); + }); + + test('cloneNode', function() { + const clone = dom(el).cloneNode(el); + assert.ok(clone); + assert.equal(clone.localName, 'x-container-slot'); + }); + + test('appendChild', function() { + const d1 = document.createElement('div'); + dom(el).appendChild(d1); + assert.equal(dom(el).firstChild, d1); + assert.equal(dom(d1).parentNode, el); + }); + + test('insertBefore', function() { + const d1 = document.createElement('div'); + const d2 = document.createElement('div'); + dom(el).appendChild(d1); + dom(el).insertBefore(d2, d1); + assert.equal(dom(d2).nextSibling, d1); + }); + + test('removeChild', function() { + const d1 = document.createElement('div'); + dom(el).appendChild(d1); + dom(el).removeChild(d1); + assert.equal(dom(d1).parentNode, null); + }); + + test('replaceChild', function() { + const d1 = document.createElement('div'); + const d2 = document.createElement('div'); + dom(el).appendChild(d1); + dom(el).replaceChild(d2, d1); + assert.equal(dom(d1).parentNode, null); + assert.equal(dom(el).firstChild, d2); + assert.equal(dom(d2).parentNode, el); + }); + + test('replaceChild', function() { + dom(el).setAttribute('foo', 'foo'); + assert.equal(el.getAttribute('foo'), 'foo'); + }); + + test('replaceChild', function() { + dom(el).setAttribute('foo', 'foo'); + dom(el).removeAttribute('foo'); + assert.isFalse(el.hasAttribute('foo')); + }); + + test('querySelector', function() { + const d1 = document.createElement('div'); + dom(el).appendChild(d1); + const query = dom(el).querySelector('div'); + assert.equal(query, d1); + }); + + test('querySelectorAll', function() { + const d1 = document.createElement('div'); + const d2 = document.createElement('div'); + dom(el).appendChild(d1); + dom(el).appendChild(d2); + const query = dom(el).querySelectorAll('div'); + assert.equal(query[0], d1); + assert.equal(query[1], d2); + assert.equal(query.length, 2); + }); + + test('tree accessors', function() { + const d1 = document.createElement('div'); + const d2 = document.createElement('div'); + dom(el).appendChild(d1); + dom(el).appendChild(d2); + const pel = dom(el); + const pd1 = dom(d1); + const pd2 = dom(d2); + assert.equal(pd1.parentNode, el); + assert.equal(pel.firstChild, d1); + assert.equal(pel.lastChild, d2); + assert.equal(pel.firstElementChild, d1); + assert.equal(pel.lastElementChild, d2); + assert.equal(pd1.nextSibling, d2); + assert.equal(pd2.previousSibling, d1); + assert.equal(pd1.nextElementSibling, d2); + assert.equal(pd2.previousElementSibling, d1); + assert.equal(pel.childNodes[0], d1); + assert.equal(pel.childNodes[1], d2); + assert.equal(pel.children[0], d1); + assert.equal(pel.children[1], d2); + }); + + test('innerHTML', function() { + dom(el).innerHTML = '
'; + assert.equal(dom(el).firstChild.localName, 'div'); + }); + + test('textContent', function() { + dom(el).innerHTML = 'hi'; + assert.equal(dom(dom(el).firstChild).textContent, 'hi'); + }); + + test('classList', function() { + dom(el).classList.add('foo'); + assert.equal(el.className, 'foo'); + }); + }); From ad05f567fb392bad1e6b3e3ea1d8b328a26192b7 Mon Sep 17 00:00:00 2001 From: Chad Killingsworth Date: Wed, 20 Feb 2019 06:14:45 -0600 Subject: [PATCH 02/29] Add property reflection to notify path and friends calls to support closure-compiler renaming. Also quotes the getStyle method of the custom style method since ShadyCSS references the method quoted. --- lib/elements/array-selector.js | 28 +++++++++++++++++----------- lib/elements/custom-style.js | 2 +- lib/elements/dom-repeat.js | 2 +- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/lib/elements/array-selector.js b/lib/elements/array-selector.js index c4a9816749..158d242cea 100644 --- a/lib/elements/array-selector.js +++ b/lib/elements/array-selector.js @@ -107,7 +107,7 @@ let ArraySelectorMixin = dedupingMixin(superClass => { __updateSelection(multi, itemsInfo) { let path = itemsInfo.path; - if (path == 'items') { + if (path == JSCompiler_renameProperty('items', this)) { // Case 1 - items array changed, so diff against previous array and // deselect any removed items and adjust selected indices let newItems = itemsInfo.base || []; @@ -122,14 +122,14 @@ let ArraySelectorMixin = dedupingMixin(superClass => { } this.__lastItems = newItems; this.__lastMulti = multi; - } else if (itemsInfo.path == 'items.splices') { + } else if (itemsInfo.path == `${JSCompiler_renameProperty('items', this)}.splices`) { // Case 2 - got specific splice information describing the array mutation: // deselect any removed items and adjust selected indices this.__applySplices(itemsInfo.value.indexSplices); } else { // Case 3 - an array element was changed, so deselect the previous // item for that index if it was previously selected - let part = path.slice('items.'.length); + let part = path.slice(`${JSCompiler_renameProperty('items', this)}.`.length); let idx = parseInt(part, 10); if ((part.indexOf('.') < 0) && part == idx) { this.__deselectChangedIdx(idx); @@ -167,7 +167,7 @@ let ArraySelectorMixin = dedupingMixin(superClass => { selected.forEach((idx, item) => { if (idx < 0) { if (this.multi) { - this.splice('selected', sidx, 1); + this.splice(JSCompiler_renameProperty('selected', this), sidx, 1); } else { this.selected = this.selectedItem = null; } @@ -184,13 +184,19 @@ let ArraySelectorMixin = dedupingMixin(superClass => { let sidx = 0; this.__selectedMap.forEach(idx => { if (idx >= 0) { - this.linkPaths('items.' + idx, 'selected.' + sidx++); + this.linkPaths( + `${JSCompiler_renameProperty('items', this)}.${idx}`, + `${JSCompiler_renameProperty('selected', this)}.${sidx++}`); } }); } else { this.__selectedMap.forEach(idx => { - this.linkPaths('selected', 'items.' + idx); - this.linkPaths('selectedItem', 'items.' + idx); + this.linkPaths( + JSCompiler_renameProperty('selected', this), + `${JSCompiler_renameProperty('items', this)}.${idx}`); + this.linkPaths( + JSCompiler_renameProperty('selectedItem', this), + `${JSCompiler_renameProperty('items', this)}.${idx}`); }); } } @@ -248,9 +254,9 @@ let ArraySelectorMixin = dedupingMixin(superClass => { } __selectedIndexForItemIndex(idx) { - let selected = this.__dataLinkedPaths['items.' + idx]; + let selected = this.__dataLinkedPaths[`${JSCompiler_renameProperty('items', this)}.${idx}`]; if (selected) { - return parseInt(selected.slice('selected.'.length), 10); + return parseInt(selected.slice(`${JSCompiler_renameProperty('selected', this)}.`.length), 10); } } @@ -271,7 +277,7 @@ let ArraySelectorMixin = dedupingMixin(superClass => { } this.__updateLinks(); if (this.multi) { - this.splice('selected', sidx, 1); + this.splice(JSCompiler_renameProperty('selected', this), sidx, 1); } else { this.selected = this.selectedItem = null; } @@ -318,7 +324,7 @@ let ArraySelectorMixin = dedupingMixin(superClass => { this.__selectedMap.set(item, idx); this.__updateLinks(); if (this.multi) { - this.push('selected', item); + this.push(JSCompiler_renameProperty('selected', this), item); } else { this.selected = this.selectedItem = item; } diff --git a/lib/elements/custom-style.js b/lib/elements/custom-style.js index f675393118..2bba4de8ab 100644 --- a/lib/elements/custom-style.js +++ b/lib/elements/custom-style.js @@ -75,7 +75,7 @@ export class CustomStyle extends HTMLElement { * @export * @return {HTMLStyleElement} This element's light-DOM `