Merge pull request #5518 from Polymer/fix-className-bindings-master

Ensure `className` bindings work correctly when `ShadyDOM.noPatch` is…
This commit is contained in:
Daniel Freedman
2019-04-19 17:18:55 -07:00
committed by GitHub
7 changed files with 1550 additions and 1420 deletions

View File

@@ -48,6 +48,9 @@ class DomApiNative {
* @param {Node} node Node for which to create a Polymer.dom helper object.
*/
constructor(node) {
if (window['ShadyDOM'] && window['ShadyDOM']['inUse']) {
window['ShadyDOM']['patch'](node);
}
this.node = node;
}
@@ -441,7 +444,7 @@ if (window['ShadyDOM'] && window['ShadyDOM']['inUse'] && window['ShadyDOM']['noP
]);
forwardProperties(DomApiNative.prototype, [
'textContent', 'innerHTML'
'textContent', 'innerHTML', 'className'
]);
}

View File

@@ -727,6 +727,12 @@ function setupCompoundStorage(node, binding) {
storage[target] = literals;
// Configure properties with their literal parts
if (binding.literal && binding.kind == 'property') {
// Note, className needs style scoping so this needs wrapping.
// We may also want to consider doing this for `textContent` and
// `innerHTML`.
if (target === 'className') {
node = wrap(node);
}
node[target] = binding.literal;
}
}
@@ -1407,6 +1413,10 @@ export const PropertyEffects = dedupingMixin(superClass => {
// implement a whitelist of tag & property values that should never
// be reset (e.g. <input>.value && <select>.value)
if (value !== node[prop] || typeof value == 'object') {
// Note, className needs style scoping so this needs wrapping.
if (prop === 'className') {
node = /** @type {!Node} */(wrap(node));
}
node[prop] = value;
}
}

View File

@@ -19,5 +19,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
* @type {function(Node):Node}
*/
export const wrap = (window['ShadyDOM'] && window['ShadyDOM']['noPatch'] && window['ShadyDOM']['wrap']) ?
window['ShadyDOM']['wrap'] : (n) => n;
window['ShadyDOM']['wrap'] :
(window['ShadyDOM'] ? (n) => ShadyDOM['patch'](n) : (n) => n);

2807
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -30,8 +30,8 @@
"lazypipe": "^1.0.2",
"merge-stream": "^1.0.1",
"parse5": "^4.0.0",
"polymer-build": "^3.1.0",
"polymer-cli": "^1.9.4",
"polymer-build": "^3.1.3",
"polymer-cli": "^1.9.8",
"through2": "^2.0.0",
"typescript": "^2.9.2",
"wct-browser-legacy": "^1.0.2"
@@ -65,7 +65,7 @@
"type-detect": "1.0.0"
},
"dependencies": {
"@webcomponents/shadycss": "^1.8.0"
"@webcomponents/shadycss": "^1.9.1"
},
"files": [
"externs",

View File

@@ -72,6 +72,37 @@ Polymer({
</script>
</dom-module>
<dom-module id="x-class-bindings">
<template>
<style>
.a {
border: 2px solid orange;
}
.aa {
border: 12px solid red;
}
.b {
padding: 4px;
}
</style>
<div>
<div id="class" class$="[[clazz]] b">class</div>
<div id="className" class-name="[[clazz]] b">class</div>
</div>
</template>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
properties: {
clazz: {type: String}
},
is: 'x-class-bindings'
});
</script>
</dom-module>
<test-fixture id="scoped">
<template>
<x-event-scoped></x-event-scoped>
@@ -493,6 +524,37 @@ suite('forwarded native api', function() {
assert.equal(el.className, 'foo');
});
test('className', function() {
dom(el).className = 'foo';
assert.isTrue(el.classList.contains('foo'));
});
test('class bindings work and remained scoped', function() {
const el = document.createElement('x-class-bindings');
document.body.appendChild(el);
assert.equal(getComputedStyle(el.$.class)['border-top-width'], '0px');
assert.equal(getComputedStyle(el.$.class)['padding-top'], '4px');
assert.isTrue(el.$.class.classList.contains('style-scope'));
assert.equal(getComputedStyle(el.$.className)['border-top-width'], '0px');
assert.equal(getComputedStyle(el.$.className)['padding-top'], '4px');
assert.isTrue(el.$.className.classList.contains('style-scope'));
el.clazz = 'a';
assert.equal(getComputedStyle(el.$.class)['border-top-width'], '2px');
assert.equal(getComputedStyle(el.$.class)['padding-top'], '4px');
assert.isTrue(el.$.class.classList.contains('style-scope'));
assert.equal(getComputedStyle(el.$.className)['border-top-width'], '2px');
assert.equal(getComputedStyle(el.$.className)['padding-top'], '4px');
assert.isTrue(el.$.className.classList.contains('style-scope'));
el.clazz = 'aa';
assert.equal(getComputedStyle(el.$.class)['border-top-width'], '12px');
assert.equal(getComputedStyle(el.$.class)['padding-top'], '4px');
assert.isTrue(el.$.class.classList.contains('style-scope'));
assert.equal(getComputedStyle(el.$.className)['border-top-width'], '12px');
assert.equal(getComputedStyle(el.$.className)['padding-top'], '4px');
assert.isTrue(el.$.className.classList.contains('style-scope'));
document.body.removeChild(el);
});
});
</script>

View File

@@ -30,6 +30,17 @@ Polymer({
</script>
</dom-module>
<dom-module id="x-scoped-node">
<template>
<div><div id="first">first</div></div>
</template>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
is: 'x-scoped-node'
});
</script>
<dom-module id="x-container-slot">
<template>
<x-slot id="container"><div id="first">first</div><slot id="slot"></slot><div id="last">last</div></x-slot>
@@ -67,7 +78,38 @@ Polymer({
is: 'x-focusable-in-shadow'
});
</script>
</dom-module>
</dom-module>
<dom-module id="x-class-bindings">
<template>
<style>
.a {
border: 2px solid orange;
}
.aa {
border: 12px solid red;
}
.b {
padding: 4px;
}
</style>
<div>
<div id="class" class$="[[clazz]] b">class</div>
<div id="className" class-name="[[clazz]] b">class</div>
</div>
</template>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
properties: {
clazz: {type: String}
},
is: 'x-class-bindings'
});
</script>
</dom-module>
<test-fixture id="scoped">
<template>
@@ -480,6 +522,39 @@ suite('forwarded native api', function() {
assert.equal(el.className, 'foo');
});
test('className', function() {
const el = document.createElement('x-scoped-node');
document.body.appendChild(el);
const testEl = el.$.first;
const testElDom = dom(testEl);
testElDom.className = 'foo';
assert.isTrue(testEl.classList.contains('foo'));
if (window['ShadyDOM']) {
assert.isTrue(testEl.classList.contains('style-scope'));
}
document.body.removeChild(el);
});
test('class bindings', function() {
const el = document.createElement('x-class-bindings');
document.body.appendChild(el);
assert.equal(getComputedStyle(el.$.class)['border-top-width'], '0px');
assert.equal(getComputedStyle(el.$.class)['padding-top'], '4px');
assert.equal(getComputedStyle(el.$.className)['border-top-width'], '0px');
assert.equal(getComputedStyle(el.$.className)['padding-top'], '4px');
el.clazz = 'a';
assert.equal(getComputedStyle(el.$.class)['border-top-width'], '2px');
assert.equal(getComputedStyle(el.$.class)['padding-top'], '4px');
assert.equal(getComputedStyle(el.$.className)['border-top-width'], '2px');
assert.equal(getComputedStyle(el.$.className)['padding-top'], '4px');
el.clazz = 'aa';
assert.equal(getComputedStyle(el.$.class)['border-top-width'], '12px');
assert.equal(getComputedStyle(el.$.class)['padding-top'], '4px');
assert.equal(getComputedStyle(el.$.className)['border-top-width'], '12px');
assert.equal(getComputedStyle(el.$.className)['padding-top'], '4px');
document.body.removeChild(el);
});
});
</script>