diff --git a/lib/mixins/template-stamp.js b/lib/mixins/template-stamp.js index e7a576ec2a..736091416a 100644 --- a/lib/mixins/template-stamp.js +++ b/lib/mixins/template-stamp.js @@ -22,6 +22,49 @@ const templateExtensions = { 'dom-if': true, 'dom-repeat': true }; + +let placeholderBugDetect = false; +let placeholderBug = false; + +function hasPlaceholderBug() { + if (!placeholderBugDetect) { + 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` binding is removed, the textnode + * child of the textarea is deleted, and the template info tries to bind into + * that node. + * + * When `legacyOptimizations` is enabled, the node is removed from the textarea + * when the `placeholder` binding is processed, leaving an "undefined" cell in + * the binding metadata object. + * + * When `legacyOptimizations` is disabled, the template is cloned before + * processing, and has an extra binding to the textContent of the text node + * child of the textarea. This at best is an extra binding to process that has + * no useful effect, and at worst throws exceptions trying to update the text + * node. + * + * @param {!Node} node Check node for placeholder bug + * @return {boolean} True if placeholder is bugged + */ +function shouldFixPlaceholder(node) { + return hasPlaceholderBug() + && node.localName === 'textarea' && node.placeholder + && node.placeholder === node.textContent; +} + function wrapTemplateExtension(node) { let is = node.getAttribute('is'); if (is && templateExtensions[is]) { @@ -251,6 +294,9 @@ export const TemplateStamp = dedupingMixin( // For ShadyDom optimization, indicating there is an insertion point templateInfo.hasInsertionPoint = true; } + if (shouldFixPlaceholder(node)) { + node.textContent = null; + } if (element.firstChild) { this._parseTemplateChildNodes(element, templateInfo, nodeInfo); } diff --git a/test/unit/property-effects-template.html b/test/unit/property-effects-template.html index 2f761f672a..56327de127 100644 --- a/test/unit/property-effects-template.html +++ b/test/unit/property-effects-template.html @@ -13,7 +13,6 @@ - @@ -282,9 +281,10 @@