mirror of
https://github.com/Polymer/polymer.git
synced 2025-02-25 18:55:30 -06:00
Merge branch 'legacy-undefined-noBatch' into legacy-undefined-noBatch-fastDomIfFlush
This commit is contained in:
commit
8b699334a4
@ -158,6 +158,29 @@ Polymer.orderedComputed;
|
|||||||
*/
|
*/
|
||||||
var PolymerElement = function() {};
|
var PolymerElement = function() {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The tag name of the cutom element type.
|
||||||
|
* @type {string|undefined}
|
||||||
|
*/
|
||||||
|
PolymerElement.is;
|
||||||
|
/**
|
||||||
|
* The template to stamp when creating this element type.
|
||||||
|
* @type {!HTMLTemplateElement|undefined}
|
||||||
|
*/
|
||||||
|
PolymerElement.template;
|
||||||
|
/**
|
||||||
|
* The properties of the cutom element type.
|
||||||
|
* @type {!PolymerElementProperties|undefined}
|
||||||
|
*/
|
||||||
|
PolymerElement.properties;
|
||||||
|
/**
|
||||||
|
* The observers of this custom element type.
|
||||||
|
* @type {!Array<string>|undefined}
|
||||||
|
*/
|
||||||
|
PolymerElement.observers;
|
||||||
|
/** @type {!PolymerInit|undefined} */
|
||||||
|
PolymerElement.generatedFrom;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On create callback.
|
* On create callback.
|
||||||
* @override
|
* @override
|
||||||
|
@ -134,6 +134,12 @@ export const PropertiesChanged = dedupingMixin(
|
|||||||
if (!this.hasOwnProperty('__dataAttributes')) {
|
if (!this.hasOwnProperty('__dataAttributes')) {
|
||||||
this.__dataAttributes = Object.assign({}, this.__dataAttributes);
|
this.__dataAttributes = Object.assign({}, this.__dataAttributes);
|
||||||
}
|
}
|
||||||
|
// This check is technically not correct; it's an optimization that
|
||||||
|
// assumes that if a _property_ name is already in the map (note this is
|
||||||
|
// an attr->property map), the property mapped directly to the attribute
|
||||||
|
// and it has already been mapped. This would fail if
|
||||||
|
// `attributeNameForProperty` were overridden such that this was not the
|
||||||
|
// case.
|
||||||
let attr = this.__dataAttributes[property];
|
let attr = this.__dataAttributes[property];
|
||||||
if (!attr) {
|
if (!attr) {
|
||||||
attr = this.constructor.attributeNameForProperty(property);
|
attr = this.constructor.attributeNameForProperty(property);
|
||||||
|
@ -22,6 +22,53 @@ const templateExtensions = {
|
|||||||
'dom-if': true,
|
'dom-if': true,
|
||||||
'dom-repeat': true
|
'dom-repeat': true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let placeholderBugDetect = false;
|
||||||
|
let placeholderBug = false;
|
||||||
|
|
||||||
|
function hasPlaceholderBug() {
|
||||||
|
if (!placeholderBugDetect) {
|
||||||
|
placeholderBugDetect = true;
|
||||||
|
const t = document.createElement('textarea');
|
||||||
|
t.placeholder = 'a';
|
||||||
|
placeholderBug = t.placeholder === t.textContent;
|
||||||
|
}
|
||||||
|
return placeholderBug;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some browsers have a bug with textarea, where placeholder text is copied as
|
||||||
|
* a textnode child of the textarea.
|
||||||
|
*
|
||||||
|
* If the placeholder is a binding, this can break template stamping in two
|
||||||
|
* ways.
|
||||||
|
*
|
||||||
|
* One issue is that when the `placeholder` attribute is removed when the
|
||||||
|
* binding is processed, the textnode child of the textarea is deleted, and the
|
||||||
|
* template info tries to bind into that node.
|
||||||
|
*
|
||||||
|
* With `legacyOptimizations` in use, when the template is stamped and the
|
||||||
|
* `textarea.textContent` binding is processed, no corresponding node is found
|
||||||
|
* because it was removed during parsing. An exception is generated when this
|
||||||
|
* binding is updated.
|
||||||
|
*
|
||||||
|
* With `legacyOptimizations` not in use, the template is cloned before
|
||||||
|
* processing and this changes the above behavior. The cloned template also has
|
||||||
|
* a value property set to the placeholder and textContent. This prevents the
|
||||||
|
* removal of the textContent when the placeholder attribute is removed.
|
||||||
|
* Therefore the exception does not occur. However, there is an extra
|
||||||
|
* unnecessary binding.
|
||||||
|
*
|
||||||
|
* @param {!Node} node Check node for placeholder bug
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
function fixPlaceholder(node) {
|
||||||
|
if (hasPlaceholderBug() && node.localName === 'textarea' && node.placeholder
|
||||||
|
&& node.placeholder === node.textContent) {
|
||||||
|
node.textContent = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function wrapTemplateExtension(node) {
|
function wrapTemplateExtension(node) {
|
||||||
let is = node.getAttribute('is');
|
let is = node.getAttribute('is');
|
||||||
if (is && templateExtensions[is]) {
|
if (is && templateExtensions[is]) {
|
||||||
@ -251,6 +298,7 @@ export const TemplateStamp = dedupingMixin(
|
|||||||
// For ShadyDom optimization, indicating there is an insertion point
|
// For ShadyDom optimization, indicating there is an insertion point
|
||||||
templateInfo.hasInsertionPoint = true;
|
templateInfo.hasInsertionPoint = true;
|
||||||
}
|
}
|
||||||
|
fixPlaceholder(element);
|
||||||
if (element.firstChild) {
|
if (element.firstChild) {
|
||||||
this._parseTemplateChildNodes(element, templateInfo, nodeInfo);
|
this._parseTemplateChildNodes(element, templateInfo, nodeInfo);
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<script src="../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js"></script>
|
<script src="../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js"></script>
|
||||||
<script src="wct-browser-config.js"></script>
|
<script src="wct-browser-config.js"></script>
|
||||||
<script src="wct-browser-config.js"></script>
|
|
||||||
<script src="../../node_modules/wct-browser-legacy/browser.js"></script>
|
<script src="../../node_modules/wct-browser-legacy/browser.js"></script>
|
||||||
<script type="module" src="../../polymer-element.js"></script>
|
<script type="module" src="../../polymer-element.js"></script>
|
||||||
<script type="module" src="../../lib/mixins/gesture-event-listeners.js"></script>
|
<script type="module" src="../../lib/mixins/gesture-event-listeners.js"></script>
|
||||||
@ -286,9 +285,10 @@ customElements.define(XBinding.is, XBinding);
|
|||||||
</dom-module>
|
</dom-module>
|
||||||
|
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import '../../polymer-element.js';
|
import {PolymerElement, html} from '../../polymer-element.js';
|
||||||
import '../../lib/mixins/gesture-event-listeners.js';
|
import '../../lib/mixins/gesture-event-listeners.js';
|
||||||
import '../../lib/elements/dom-if.js';
|
import '../../lib/elements/dom-if.js';
|
||||||
|
import {setLegacyOptimizations} from '../../lib/utils/settings.js';
|
||||||
|
|
||||||
suite('runtime template stamping', function() {
|
suite('runtime template stamping', function() {
|
||||||
|
|
||||||
@ -828,6 +828,41 @@ suite('template parsing hooks', () => {
|
|||||||
document.body.removeChild(el);
|
document.body.removeChild(el);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
suite('textarea placeholder bug', function() {
|
||||||
|
class PlaceholderBase extends PolymerElement {
|
||||||
|
static get template() {
|
||||||
|
return html`<textarea id="textarea" placeholder="[[value]]"></textarea>`;
|
||||||
|
}
|
||||||
|
static get properties() {
|
||||||
|
return {value: {type: String}};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test('placeholder binding does not leak to textContent', function() {
|
||||||
|
customElements.define('placeholder-duplicate', class extends PlaceholderBase {});
|
||||||
|
const el = document.createElement('placeholder-duplicate');
|
||||||
|
document.body.appendChild(el);
|
||||||
|
const textarea = el.$.textarea;
|
||||||
|
el.value = 'before';
|
||||||
|
textarea.value = 'Hello!';
|
||||||
|
el.value = 'after';
|
||||||
|
assert.equal(textarea.value, 'Hello!');
|
||||||
|
});
|
||||||
|
suite('legacyOptimizations', function() {
|
||||||
|
suiteSetup(function() {
|
||||||
|
setLegacyOptimizations(true);
|
||||||
|
});
|
||||||
|
suiteTeardown(function() {
|
||||||
|
setLegacyOptimizations(false);
|
||||||
|
});
|
||||||
|
test('textarea placeholder binding works with legacyOptimizations', function() {
|
||||||
|
customElements.define('placeholder-bug', class extends PlaceholderBase {});
|
||||||
|
const el = document.createElement('placeholder-bug');
|
||||||
|
document.body.appendChild(el);
|
||||||
|
assert.doesNotThrow(() => {el.value = 'bar';});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
Loading…
Reference in New Issue
Block a user