Skip to content

Commit c23ff5e

Browse files
committed
Merge branch 'master' into 5422-ldm-templatizer-fix
2 parents 2c560bc + a7c861b commit c23ff5e

16 files changed

+2605
-973
lines changed

lib/legacy/class.js

Lines changed: 236 additions & 80 deletions
Large diffs are not rendered by default.

lib/legacy/legacy-element-mixin.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,6 @@ export const LegacyElementMixin = dedupingMixin((base) => {
7777
this.__boundListeners;
7878
/** @type {Object<string, Function>} */
7979
this._debouncers;
80-
// Ensure listeners are applied immediately so that they are
81-
// added before declarative event listeners. This allows an element to
82-
// decorate itself via an event prior to any declarative listeners
83-
// seeing the event. Note, this ensures compatibility with 1.x ordering.
84-
this._applyListeners();
8580
}
8681

8782
/**
@@ -180,12 +175,18 @@ export const LegacyElementMixin = dedupingMixin((base) => {
180175
_initializeProperties() {
181176
let proto = Object.getPrototypeOf(this);
182177
if (!proto.hasOwnProperty('__hasRegisterFinished')) {
183-
proto.__hasRegisterFinished = true;
184178
this._registered();
179+
// backstop in case the `_registered` implementation does not set this
180+
proto.__hasRegisterFinished = true;
185181
}
186182
super._initializeProperties();
187183
this.root = /** @type {HTMLElement} */(this);
188184
this.created();
185+
// Ensure listeners are applied immediately so that they are
186+
// added before declarative event listeners. This allows an element to
187+
// decorate itself via an event prior to any declarative listeners
188+
// seeing the event. Note, this ensures compatibility with 1.x ordering.
189+
this._applyListeners();
189190
}
190191

191192
/**

lib/mixins/dir-mixin.js

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ const HOST_DIR_REPLACMENT = ':host([dir="$1"])';
1717
const EL_DIR = /([\s\w-#\.\[\]\*]*):dir\((ltr|rtl)\)/g;
1818
const EL_DIR_REPLACMENT = ':host([dir="$2"]) $1';
1919

20+
const DIR_CHECK = /:dir\((?:ltr|rtl)\)/;
21+
22+
const SHIM_SHADOW = Boolean(window['ShadyDOM'] && window['ShadyDOM']['inUse']);
23+
2024
/**
2125
* @type {!Array<!Polymer_DirMixin>}
2226
*/
@@ -80,10 +84,12 @@ function takeRecords() {
8084
*/
8185
export const DirMixin = dedupingMixin((base) => {
8286

83-
if (!observer) {
84-
getRTL();
85-
observer = new MutationObserver(updateDirection);
86-
observer.observe(document.documentElement, {attributes: true, attributeFilter: ['dir']});
87+
if (!SHIM_SHADOW) {
88+
if (!observer) {
89+
getRTL();
90+
observer = new MutationObserver(updateDirection);
91+
observer.observe(document.documentElement, {attributes: true, attributeFilter: ['dir']});
92+
}
8793
}
8894

8995
/**
@@ -107,7 +113,10 @@ export const DirMixin = dedupingMixin((base) => {
107113
*/
108114
static _processStyleText(cssText, baseURI) {
109115
cssText = super._processStyleText(cssText, baseURI);
110-
cssText = this._replaceDirInCssText(cssText);
116+
if (!SHIM_SHADOW && DIR_CHECK.test(cssText)) {
117+
cssText = this._replaceDirInCssText(cssText);
118+
this.__activateDir = true;
119+
}
111120
return cssText;
112121
}
113122

@@ -121,9 +130,6 @@ export const DirMixin = dedupingMixin((base) => {
121130
let replacedText = text;
122131
replacedText = replacedText.replace(HOST_DIR, HOST_DIR_REPLACMENT);
123132
replacedText = replacedText.replace(EL_DIR, EL_DIR_REPLACMENT);
124-
if (text !== replacedText) {
125-
this.__activateDir = true;
126-
}
127133
return replacedText;
128134
}
129135

lib/mixins/element-mixin.js

Lines changed: 34 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
99
*/
1010
import '../utils/boot.js';
1111

12-
import { rootPath, strictTemplatePolicy, allowTemplateFromDomModule } from '../utils/settings.js';
12+
import { rootPath, strictTemplatePolicy, allowTemplateFromDomModule, legacyOptimizations } from '../utils/settings.js';
1313
import { dedupingMixin } from '../utils/mixin.js';
1414
import { stylesFromTemplate, stylesFromModuleImports } from '../utils/style-gather.js';
1515
import { pathFromUrl, resolveCss, resolveUrl } from '../utils/resolve-url.js';
@@ -23,6 +23,8 @@ import { PropertiesMixin } from './properties-mixin.js';
2323
*/
2424
export const version = '3.0.5';
2525

26+
const builtCSS = window.ShadyCSS && window.ShadyCSS['cssBuild'];
27+
2628
/**
2729
* Element class mixin that provides the core API for Polymer's meta-programming
2830
* features including template stamping, data-binding, attribute deserialization,
@@ -245,31 +247,33 @@ export const ElementMixin = dedupingMixin(base => {
245247
* @private
246248
*/
247249
function processElementStyles(klass, template, is, baseURI) {
248-
const templateStyles = template.content.querySelectorAll('style');
249-
const stylesWithImports = stylesFromTemplate(template);
250-
// insert styles from <link rel="import" type="css"> at the top of the template
251-
const linkedStyles = stylesFromModuleImports(is);
252-
const firstTemplateChild = template.content.firstElementChild;
253-
for (let idx = 0; idx < linkedStyles.length; idx++) {
254-
let s = linkedStyles[idx];
255-
s.textContent = klass._processStyleText(s.textContent, baseURI);
256-
template.content.insertBefore(s, firstTemplateChild);
257-
}
258-
// keep track of the last "concrete" style in the template we have encountered
259-
let templateStyleIndex = 0;
260-
// ensure all gathered styles are actually in this template.
261-
for (let i = 0; i < stylesWithImports.length; i++) {
262-
let s = stylesWithImports[i];
263-
let templateStyle = templateStyles[templateStyleIndex];
264-
// if the style is not in this template, it's been "included" and
265-
// we put a clone of it in the template before the style that included it
266-
if (templateStyle !== s) {
267-
s = s.cloneNode(true);
268-
templateStyle.parentNode.insertBefore(s, templateStyle);
269-
} else {
270-
templateStyleIndex++;
250+
if (!builtCSS) {
251+
const templateStyles = template.content.querySelectorAll('style');
252+
const stylesWithImports = stylesFromTemplate(template);
253+
// insert styles from <link rel="import" type="css"> at the top of the template
254+
const linkedStyles = stylesFromModuleImports(is);
255+
const firstTemplateChild = template.content.firstElementChild;
256+
for (let idx = 0; idx < linkedStyles.length; idx++) {
257+
let s = linkedStyles[idx];
258+
s.textContent = klass._processStyleText(s.textContent, baseURI);
259+
template.content.insertBefore(s, firstTemplateChild);
260+
}
261+
// keep track of the last "concrete" style in the template we have encountered
262+
let templateStyleIndex = 0;
263+
// ensure all gathered styles are actually in this template.
264+
for (let i = 0; i < stylesWithImports.length; i++) {
265+
let s = stylesWithImports[i];
266+
let templateStyle = templateStyles[templateStyleIndex];
267+
// if the style is not in this template, it's been "included" and
268+
// we put a clone of it in the template before the style that included it
269+
if (templateStyle !== s) {
270+
s = s.cloneNode(true);
271+
templateStyle.parentNode.insertBefore(s, templateStyle);
272+
} else {
273+
templateStyleIndex++;
274+
}
275+
s.textContent = klass._processStyleText(s.textContent, baseURI);
271276
}
272-
s.textContent = klass._processStyleText(s.textContent, baseURI);
273277
}
274278
if (window.ShadyCSS) {
275279
window.ShadyCSS.prepareTemplate(template, is);
@@ -325,21 +329,21 @@ export const ElementMixin = dedupingMixin(base => {
325329
*/
326330
static _finalizeClass() {
327331
super._finalizeClass();
328-
if (this.hasOwnProperty(
329-
JSCompiler_renameProperty('is', this)) && this.is) {
330-
register(this.prototype);
331-
}
332332
const observers = ownObservers(this);
333333
if (observers) {
334334
this.createObservers(observers, this._properties);
335335
}
336+
this._prepareTemplate();
337+
}
338+
339+
static _prepareTemplate() {
336340
// note: create "working" template that is finalized at instance time
337341
let template = /** @type {PolymerElementConstructor} */ (this).template;
338342
if (template) {
339343
if (typeof template === 'string') {
340344
console.error('template getter must return HTMLTemplateElement');
341345
template = null;
342-
} else {
346+
} else if (!legacyOptimizations) {
343347
template = template.cloneNode(true);
344348
}
345349
}
@@ -514,7 +518,6 @@ export const ElementMixin = dedupingMixin(base => {
514518
* @suppress {invalidCasts}
515519
*/
516520
_initializeProperties() {
517-
instanceCount++;
518521
this.constructor.finalize();
519522
// note: finalize template when we have access to `localName` to
520523
// avoid dependence on `is` for polyfilling styling.
@@ -733,46 +736,6 @@ export const ElementMixin = dedupingMixin(base => {
733736
return PolymerElement;
734737
});
735738

736-
/**
737-
* Total number of Polymer element instances created.
738-
* @type {number}
739-
*/
740-
export let instanceCount = 0;
741-
742-
/**
743-
* Array of Polymer element classes that have been finalized.
744-
* @type {Array<PolymerElement>}
745-
*/
746-
export const registrations = [];
747-
748-
/**
749-
* @param {!PolymerElementConstructor} prototype Element prototype to log
750-
* @this {this}
751-
* @private
752-
*/
753-
function _regLog(prototype) {
754-
console.log('[' + prototype.is + ']: registered');
755-
}
756-
757-
/**
758-
* Registers a class prototype for telemetry purposes.
759-
* @param {HTMLElement} prototype Element prototype to register
760-
* @this {this}
761-
* @protected
762-
*/
763-
export function register(prototype) {
764-
registrations.push(prototype);
765-
}
766-
767-
/**
768-
* Logs all elements registered with an `is` to the console.
769-
* @public
770-
* @this {this}
771-
*/
772-
export function dumpRegistrations() {
773-
registrations.forEach(_regLog);
774-
}
775-
776739
/**
777740
* When using the ShadyCSS scoping and custom property shim, causes all
778741
* shimmed `styles` (via `custom-style`) in the document (and its subtree)

lib/mixins/properties-mixin.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
1010
import '../utils/boot.js';
1111

1212
import { dedupingMixin } from '../utils/mixin.js';
13+
import { register, incrementInstanceCount } from '../utils/telemetry.js';
1314
import { PropertiesChanged } from './properties-changed.js';
1415

1516
/**
@@ -114,8 +115,12 @@ export const PropertiesMixin = dedupingMixin(superClass => {
114115
* @suppress {missingProperties} Interfaces in closure do not inherit statics, but classes do
115116
*/
116117
static get observedAttributes() {
117-
const props = this._properties;
118-
return props ? Object.keys(props).map(p => this.attributeNameForProperty(p)) : [];
118+
if (!this.hasOwnProperty('__observedAttributes')) {
119+
register(this.prototype);
120+
const props = this._properties;
121+
this.__observedAttributes = props ? Object.keys(props).map(p => this.attributeNameForProperty(p)) : [];
122+
}
123+
return this.__observedAttributes;
119124
}
120125

121126
/**
@@ -189,6 +194,7 @@ export const PropertiesMixin = dedupingMixin(superClass => {
189194
* @return {void}
190195
*/
191196
_initializeProperties() {
197+
incrementInstanceCount();
192198
this.constructor.finalize();
193199
super._initializeProperties();
194200
}

lib/mixins/property-effects.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2543,6 +2543,11 @@ export const PropertyEffects = dedupingMixin(superClass => {
25432543
// Initialize attribute bindings with any literal parts
25442544
let literal = literalFromParts(parts);
25452545
if (literal && kind == 'attribute') {
2546+
// Ensure a ShadyCSS template scoped style is not removed
2547+
// when a class$ binding's initial literal value is set.
2548+
if (name == 'class' && node.hasAttribute('class')) {
2549+
literal += ' ' + node.getAttribute(name);
2550+
}
25462551
node.setAttribute(name, literal);
25472552
}
25482553
// Clear attribute before removing, since IE won't allow removing

lib/mixins/template-stamp.js

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
1010
import '../utils/boot.js';
1111

1212
import { dedupingMixin } from '../utils/mixin.js';
13+
import { legacyOptimizations } from '../utils/settings.js';
14+
15+
const walker = document.createTreeWalker(document, NodeFilter.SHOW_ALL,
16+
null, false);
1317

1418
// 1.x backwards-compatible auto-wrapper for template type extensions
1519
// This is a clear layering violation and gives favored-nation status to
@@ -45,7 +49,8 @@ function findTemplateNode(root, nodeInfo) {
4549
if (parent) {
4650
// note: marginally faster than indexing via childNodes
4751
// (http://jsperf.com/childnodes-lookup)
48-
for (let n=parent.firstChild, i=0; n; n=n.nextSibling) {
52+
walker.currentNode = parent;
53+
for (let n=walker.firstChild(), i=0; n; n=walker.nextSibling()) {
4954
if (nodeInfo.parentIndex === i++) {
5055
return n;
5156
}
@@ -200,7 +205,7 @@ export const TemplateStamp = dedupingMixin(
200205
if (!template._templateInfo) {
201206
let templateInfo = template._templateInfo = {};
202207
templateInfo.nodeInfoList = [];
203-
templateInfo.stripWhiteSpace =
208+
templateInfo.stripWhiteSpace = legacyOptimizations ||
204209
(outerTemplateInfo && outerTemplateInfo.stripWhiteSpace) ||
205210
template.hasAttribute('strip-whitespace');
206211
this._parseTemplateContent(template, templateInfo, {parent: null});
@@ -234,7 +239,8 @@ export const TemplateStamp = dedupingMixin(
234239
// For ShadyDom optimization, indicating there is an insertion point
235240
templateInfo.hasInsertionPoint = true;
236241
}
237-
if (element.firstChild) {
242+
walker.currentNode = element;
243+
if (walker.firstChild()) {
238244
noted = this._parseTemplateChildNodes(element, templateInfo, nodeInfo) || noted;
239245
}
240246
if (element.hasAttributes && element.hasAttributes()) {
@@ -260,7 +266,8 @@ export const TemplateStamp = dedupingMixin(
260266
if (root.localName === 'script' || root.localName === 'style') {
261267
return;
262268
}
263-
for (let node=root.firstChild, parentIndex=0, next; node; node=next) {
269+
walker.currentNode = root;
270+
for (let node=walker.firstChild(), parentIndex=0, next; node; node=next) {
264271
// Wrap templates
265272
if (node.localName == 'template') {
266273
node = wrapTemplateExtension(node);
@@ -269,12 +276,13 @@ export const TemplateStamp = dedupingMixin(
269276
// text nodes to be inexplicably split =(
270277
// note that root.normalize() should work but does not so we do this
271278
// manually.
272-
next = node.nextSibling;
279+
walker.currentNode = node;
280+
next = walker.nextSibling();
273281
if (node.nodeType === Node.TEXT_NODE) {
274282
let /** Node */ n = next;
275283
while (n && (n.nodeType === Node.TEXT_NODE)) {
276284
node.textContent += n.textContent;
277-
next = n.nextSibling;
285+
next = walker.nextSibling();
278286
root.removeChild(n);
279287
n = next;
280288
}
@@ -289,7 +297,8 @@ export const TemplateStamp = dedupingMixin(
289297
childInfo.infoIndex = templateInfo.nodeInfoList.push(/** @type {!NodeInfo} */(childInfo)) - 1;
290298
}
291299
// Increment if not removed
292-
if (node.parentNode) {
300+
walker.currentNode = node;
301+
if (walker.parentNode()) {
293302
parentIndex++;
294303
}
295304
}

lib/utils/settings.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,31 @@ export let allowTemplateFromDomModule = false;
113113
/**
114114
* Sets `lookupTemplateFromDomModule` globally for all elements
115115
*
116-
* @param {boolean} allowDomModule enable or disable template lookup
116+
* @param {boolean} allowDomModule enable or disable template lookup
117117
* globally
118118
* @return {void}
119119
*/
120120
export const setAllowTemplateFromDomModule = function(allowDomModule) {
121121
allowTemplateFromDomModule = allowDomModule;
122122
};
123+
124+
/**
125+
* Setting to skip processing style includes and re-writing urls in css styles.
126+
* Normally "included" styles are pulled into the element and all urls in styles
127+
* are re-written to be relative to the containing script url.
128+
* If no includes or relative urls are used in styles, these steps can be
129+
* skipped as an optimization.
130+
*/
131+
export let legacyOptimizations = false;
132+
133+
/**
134+
* Sets `legacyOptimizations` globally for all elements to enable optimizations
135+
* when only legacy based elements are used.
136+
*
137+
* @param {boolean} useLegacyOptimizations enable or disable legacy optimizations
138+
* includes and url rewriting
139+
* @return {void}
140+
*/
141+
export const setLegacyOptimizations = function(useLegacyOptimizations) {
142+
legacyOptimizations = useLegacyOptimizations;
143+
};

0 commit comments

Comments
 (0)