mirror of
https://github.com/Polymer/polymer.git
synced 2025-02-25 18:55:30 -06:00
Updates ported from perf-opt branch
Merging manually from https://github.com/Polymer/polymer/pull/5418.
This commit is contained in:
@@ -11,7 +11,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||||||
import { LegacyElementMixin } from './legacy-element-mixin.js';
|
import { LegacyElementMixin } from './legacy-element-mixin.js';
|
||||||
import { DomModule } from '../elements/dom-module.js';
|
import { DomModule } from '../elements/dom-module.js';
|
||||||
|
|
||||||
let metaProps = {
|
const metaProps = {
|
||||||
attached: true,
|
attached: true,
|
||||||
detached: true,
|
detached: true,
|
||||||
ready: true,
|
ready: true,
|
||||||
@@ -19,15 +19,22 @@ let metaProps = {
|
|||||||
beforeRegister: true,
|
beforeRegister: true,
|
||||||
registered: true,
|
registered: true,
|
||||||
attributeChanged: true,
|
attributeChanged: true,
|
||||||
// meta objects
|
|
||||||
behaviors: true
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const noBehaviorCopyProps = Object.assign({
|
||||||
|
behaviors: true
|
||||||
|
}, metaProps);
|
||||||
|
|
||||||
|
const memoizedProps = Object.assign({
|
||||||
|
listeners: true,
|
||||||
|
hostAttributes: true
|
||||||
|
}, metaProps);
|
||||||
|
|
||||||
function copyProperties(source, target) {
|
function copyProperties(source, target) {
|
||||||
for (let p in source) {
|
for (let p in source) {
|
||||||
// NOTE: cannot copy `metaProps` methods onto prototype at least because
|
// NOTE: cannot copy `noBehaviorCopyProps` methods onto prototype at least because
|
||||||
// `super.ready` must be called and is not included in the user fn.
|
// `super.ready` must be called and is not included in the user fn.
|
||||||
if (!(p in metaProps)) {
|
if (!(p in noBehaviorCopyProps)) {
|
||||||
let pd = Object.getOwnPropertyDescriptor(source, p);
|
let pd = Object.getOwnPropertyDescriptor(source, p);
|
||||||
if (pd) {
|
if (pd) {
|
||||||
Object.defineProperty(target, p, pd);
|
Object.defineProperty(target, p, pd);
|
||||||
@@ -36,7 +43,6 @@ function copyProperties(source, target) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(sorvell): this breaks `Polymer.mixinBehaviors`; should fix via factoring
|
|
||||||
/**
|
/**
|
||||||
* Applies a "legacy" behavior or array of behaviors to the provided class.
|
* Applies a "legacy" behavior or array of behaviors to the provided class.
|
||||||
*
|
*
|
||||||
@@ -53,37 +59,7 @@ function copyProperties(source, target) {
|
|||||||
* @suppress {invalidCasts, checkTypes}
|
* @suppress {invalidCasts, checkTypes}
|
||||||
*/
|
*/
|
||||||
export function mixinBehaviors(behaviors, klass) {
|
export function mixinBehaviors(behaviors, klass) {
|
||||||
if (behaviors) {
|
return GenerateClassFromInfo({}, LegacyElementMixin(klass), behaviors);
|
||||||
klass = applyBehaviors(behaviors, klass);
|
|
||||||
}
|
|
||||||
// provides behaviors functionality
|
|
||||||
return GenerateClassFromInfo({}, klass);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function applyBehaviors(behaviors, klass) {
|
|
||||||
if (!behaviors) {
|
|
||||||
klass = /** @type {HTMLElement} */(klass); // eslint-disable-line no-self-assign
|
|
||||||
return klass;
|
|
||||||
}
|
|
||||||
// NOTE: ensure the behavior is extending a class with
|
|
||||||
// legacy element api. This is necessary since behaviors expect to be able
|
|
||||||
// to access 1.x legacy api.
|
|
||||||
klass = class extends LegacyElementMixin(klass) {};
|
|
||||||
if (!Array.isArray(behaviors)) {
|
|
||||||
behaviors = [behaviors];
|
|
||||||
}
|
|
||||||
let superBehaviors = klass.prototype.behaviors;
|
|
||||||
// get flattened, deduped list of behaviors *not* already on super class
|
|
||||||
behaviors = flattenBehaviors(behaviors, null, superBehaviors);
|
|
||||||
// mixin new behaviors
|
|
||||||
klass = _applyBehaviors(behaviors, klass);
|
|
||||||
if (superBehaviors) {
|
|
||||||
behaviors = superBehaviors.concat(behaviors);
|
|
||||||
}
|
|
||||||
// Set behaviors on prototype for BC...
|
|
||||||
klass.prototype.behaviors = behaviors;
|
|
||||||
return klass;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE:
|
// NOTE:
|
||||||
@@ -116,15 +92,26 @@ function applyBehaviors(behaviors, klass) {
|
|||||||
// If lifecycle is called (super then me), order is
|
// If lifecycle is called (super then me), order is
|
||||||
// (1) C.created, (2) A.created, (3) B.created, (4) element.created
|
// (1) C.created, (2) A.created, (3) B.created, (4) element.created
|
||||||
// (again same as 1.x)
|
// (again same as 1.x)
|
||||||
function _applyBehaviors(behaviors, klass) {
|
function copyBehaviorProperties(behaviors, klass) {
|
||||||
for (let i=0; i<behaviors.length; i++) {
|
const meta = {};
|
||||||
let b = behaviors[i];
|
const superMeta = klass.prototype.__behaviorMetaProps;
|
||||||
if (b) {
|
if (behaviors) {
|
||||||
Array.isArray(b) ? _applyBehaviors(b, klass) :
|
klass.prototype.__behaviorMetaProps = meta;
|
||||||
copyProperties(b, klass.prototype);
|
for (let i=0; i<behaviors.length; i++) {
|
||||||
|
copyProperties(behaviors[i], klass.prototype);
|
||||||
|
memoizeBehaviorMetaProps(meta, behaviors[i], superMeta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
klass.prototype.__behaviorMetaProps = meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
function memoizeBehaviorMetaProps(meta, behavior, superMeta) {
|
||||||
|
for (let p in memoizedProps) {
|
||||||
|
if (behavior[p]) {
|
||||||
|
meta[p] = meta[p] || (superMeta && superMeta[p] ? superMeta[p].slice() : []);
|
||||||
|
meta[p].push(behavior[p]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return klass;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -202,20 +189,20 @@ function mergeProperties(a, b) {
|
|||||||
/**
|
/**
|
||||||
* @param {!PolymerInit} info Polymer info object
|
* @param {!PolymerInit} info Polymer info object
|
||||||
* @param {function(new:HTMLElement)} Base base class to extend with info object
|
* @param {function(new:HTMLElement)} Base base class to extend with info object
|
||||||
|
* @param {Object} behaviors behaviors to copy into the element
|
||||||
* @return {function(new:HTMLElement)} Generated class
|
* @return {function(new:HTMLElement)} Generated class
|
||||||
* @suppress {checkTypes}
|
* @suppress {checkTypes}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
function GenerateClassFromInfo(info, Base) {
|
function GenerateClassFromInfo(info, Base, behaviors) {
|
||||||
|
|
||||||
/** @private */
|
/** @private */
|
||||||
class PolymerGenerated extends Base {
|
class PolymerGenerated extends Base {
|
||||||
|
|
||||||
static get properties() {
|
static get properties() {
|
||||||
const properties = {};
|
const properties = {};
|
||||||
if (this.prototype.behaviors) {
|
if (this.prototype.__behaviors) {
|
||||||
for (let i=0, b; i < this.prototype.behaviors.length; i++) {
|
for (let i=0, b; i < this.prototype.__behaviors.length; i++) {
|
||||||
b = this.prototype.behaviors[i];
|
b = this.prototype.__behaviors[i];
|
||||||
mergeProperties(properties, b.properties);
|
mergeProperties(properties, b.properties);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -225,9 +212,9 @@ function GenerateClassFromInfo(info, Base) {
|
|||||||
|
|
||||||
static get observers() {
|
static get observers() {
|
||||||
let observers = [];
|
let observers = [];
|
||||||
if (this.prototype.behaviors) {
|
if (this.prototype.__behaviors) {
|
||||||
for (let i=0, b; i < this.prototype.behaviors.length; i++) {
|
for (let i=0, b; i < this.prototype.__behaviors.length; i++) {
|
||||||
b = this.prototype.behaviors[i];
|
b = this.prototype.__behaviors[i];
|
||||||
if (b.observers) {
|
if (b.observers) {
|
||||||
observers = observers.concat(b.observers);
|
observers = observers.concat(b.observers);
|
||||||
}
|
}
|
||||||
@@ -243,12 +230,10 @@ function GenerateClassFromInfo(info, Base) {
|
|||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
created() {
|
created() {
|
||||||
if (this.behaviors) {
|
const list = this.__behaviorMetaProps.created;
|
||||||
for (let i=0, b; i < this.behaviors.length; i++) {
|
if (list) {
|
||||||
b = this.behaviors[i];
|
for (let i=0; i < list.length; i++) {
|
||||||
if (b.created) {
|
list[i].call(this);
|
||||||
b.created.call(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (info.created) {
|
if (info.created) {
|
||||||
@@ -259,30 +244,39 @@ function GenerateClassFromInfo(info, Base) {
|
|||||||
/**
|
/**
|
||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
|
// Called on element prototype
|
||||||
_registered() {
|
_registered() {
|
||||||
/* NOTE: `beforeRegister` is called here for bc, but the behavior
|
/* NOTE: `beforeRegister` is called here for bc, but the behavior
|
||||||
is different than in 1.x. In 1.0, the method was called *after*
|
is different than in 1.x. In 1.0, the method was called *after*
|
||||||
mixing prototypes together but *before* processing of meta-objects.
|
mixing prototypes together but *before* processing of meta-objects.
|
||||||
However, dynamic effects can still be set here and can be done either
|
However, dynamic effects can still be set here and can be done either
|
||||||
in `beforeRegister` or `registered`. It is no longer possible to set
|
in `beforeRegister` or `registered`. It is no longer possible to set
|
||||||
`is` in `beforeRegister` as you could in 1.x.
|
`is` in `beforeRegister` as you could in 1.x.
|
||||||
*/
|
*/
|
||||||
if (this.behaviors) {
|
const proto = this;
|
||||||
for (let i=0, b; i < this.behaviors.length; i++) {
|
if (proto.hasOwnProperty('__behaviors')) {
|
||||||
b = this.behaviors[i];
|
copyBehaviorProperties(proto.__behaviors, proto.constructor);
|
||||||
if (b.beforeRegister) {
|
}
|
||||||
b.beforeRegister.call(Object.getPrototypeOf(this));
|
proto.__behaviorMetaProps = proto.__behaviorMetaProps || {};
|
||||||
}
|
copyProperties(info, proto);
|
||||||
if (b.registered) {
|
// Note, previously these were interleaved.
|
||||||
b.registered.call(Object.getPrototypeOf(this));
|
let list = proto.__behaviorMetaProps.beforeRegister;
|
||||||
}
|
if (list) {
|
||||||
|
for (let i=0; i < list.length; i++) {
|
||||||
|
list[i].call(proto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list = proto.__behaviorMetaProps.registered;
|
||||||
|
if (list) {
|
||||||
|
for (let i=0; i < list.length; i++) {
|
||||||
|
list[i].call(proto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (info.beforeRegister) {
|
if (info.beforeRegister) {
|
||||||
info.beforeRegister.call(Object.getPrototypeOf(this));
|
info.beforeRegister.call(proto);
|
||||||
}
|
}
|
||||||
if (info.registered) {
|
if (info.registered) {
|
||||||
info.registered.call(Object.getPrototypeOf(this));
|
info.registered.call(proto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,12 +284,13 @@ function GenerateClassFromInfo(info, Base) {
|
|||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
_applyListeners() {
|
_applyListeners() {
|
||||||
if (this.behaviors) {
|
const list = this.__behaviorMetaProps.listeners;
|
||||||
for (let i=0, b; i < this.behaviors.length; i++) {
|
if (list) {
|
||||||
b = this.behaviors[i];
|
for (let i=0; i < list.length; i++) {
|
||||||
if (b.listeners) {
|
const listeners = list[i];
|
||||||
for (let l in b.listeners) {
|
if (listeners) {
|
||||||
this._addMethodEventListenerToNode(this, l, b.listeners[l]);
|
for (let l in listeners) {
|
||||||
|
this._addMethodEventListenerToNode(this, l, listeners[l]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -319,14 +314,13 @@ function GenerateClassFromInfo(info, Base) {
|
|||||||
this._ensureAttribute(a, info.hostAttributes[a]);
|
this._ensureAttribute(a, info.hostAttributes[a]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.behaviors) {
|
const list = this.__behaviorMetaProps.hostAttributes;
|
||||||
for (let i=this.behaviors.length-1, b; i >= 0; i--) {
|
if (list) {
|
||||||
b = this.behaviors[i];
|
for (let i=list.length-1; i >= 0; i--) {
|
||||||
if (b.hostAttributes) {
|
const hostAttributes = list[i];
|
||||||
for (let a in b.hostAttributes) {
|
for (let a in hostAttributes) {
|
||||||
this._ensureAttribute(a, b.hostAttributes[a]);
|
this._ensureAttribute(a, hostAttributes[a]);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -336,12 +330,10 @@ function GenerateClassFromInfo(info, Base) {
|
|||||||
*/
|
*/
|
||||||
ready() {
|
ready() {
|
||||||
super.ready();
|
super.ready();
|
||||||
if (this.behaviors) {
|
let list = this.__behaviorMetaProps.ready;
|
||||||
for (let i=0, b; i < this.behaviors.length; i++) {
|
if (list) {
|
||||||
b = this.behaviors[i];
|
for (let i=0; i < list.length; i++) {
|
||||||
if (b.ready) {
|
list[i].call(this);
|
||||||
b.ready.call(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (info.ready) {
|
if (info.ready) {
|
||||||
@@ -353,12 +345,10 @@ function GenerateClassFromInfo(info, Base) {
|
|||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
attached() {
|
attached() {
|
||||||
if (this.behaviors) {
|
let list = this.__behaviorMetaProps.attached;
|
||||||
for (let i=0, b; i < this.behaviors.length; i++) {
|
if (list) {
|
||||||
b = this.behaviors[i];
|
for (let i=0; i < list.length; i++) {
|
||||||
if (b.attached) {
|
list[i].call(this);
|
||||||
b.attached.call(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (info.attached) {
|
if (info.attached) {
|
||||||
@@ -370,12 +360,10 @@ function GenerateClassFromInfo(info, Base) {
|
|||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
detached() {
|
detached() {
|
||||||
if (this.behaviors) {
|
let list = this.__behaviorMetaProps.detached;
|
||||||
for (let i=0, b; i < this.behaviors.length; i++) {
|
if (list) {
|
||||||
b = this.behaviors[i];
|
for (let i=0; i < list.length; i++) {
|
||||||
if (b.detached) {
|
list[i].call(this);
|
||||||
b.detached.call(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (info.detached) {
|
if (info.detached) {
|
||||||
@@ -384,6 +372,7 @@ function GenerateClassFromInfo(info, Base) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
*
|
||||||
* Implements native Custom Elements `attributeChangedCallback` to
|
* Implements native Custom Elements `attributeChangedCallback` to
|
||||||
* set an attribute value to a property via `_attributeToProperty`.
|
* set an attribute value to a property via `_attributeToProperty`.
|
||||||
*
|
*
|
||||||
@@ -393,24 +382,37 @@ function GenerateClassFromInfo(info, Base) {
|
|||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
attributeChanged(name, old, value) {
|
attributeChanged(name, old, value) {
|
||||||
if (this.behaviors) {
|
let list = this.__behaviorMetaProps.attributeChanged;
|
||||||
for (let i=0, b; i < this.behaviors.length; i++) {
|
if (list) {
|
||||||
b = this.behaviors[i];
|
for (let i=0; i < list.length; i++) {
|
||||||
if (b.attributeChanged) {
|
list[i].call(this, name, old, value);
|
||||||
b.attributeChanged.call(this, name, old, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (info.attributeChanged) {
|
if (info.attributeChanged) {
|
||||||
info.attributeChanged.call(this, name, old, value);
|
info.attributeChanged.call(this, name, old, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply behaviors
|
||||||
|
if (behaviors) {
|
||||||
|
// NOTE: ensure the behavior is extending a class with
|
||||||
|
// legacy element api. This is necessary since behaviors expect to be able
|
||||||
|
// to access 1.x legacy api.
|
||||||
|
if (!Array.isArray(behaviors)) {
|
||||||
|
behaviors = [behaviors];
|
||||||
|
}
|
||||||
|
let superBehaviors = PolymerGenerated.prototype.behaviors;
|
||||||
|
// get flattened, deduped list of behaviors *not* already on super class
|
||||||
|
behaviors = flattenBehaviors(behaviors, null, superBehaviors);
|
||||||
|
PolymerGenerated.prototype.behaviors = superBehaviors ?
|
||||||
|
superBehaviors.concat(behaviors) : behaviors;
|
||||||
|
PolymerGenerated.prototype.__behaviors = behaviors;
|
||||||
}
|
}
|
||||||
|
|
||||||
PolymerGenerated.generatedFrom = info;
|
PolymerGenerated.generatedFrom = info;
|
||||||
|
|
||||||
copyProperties(info, PolymerGenerated.prototype);
|
|
||||||
|
|
||||||
return PolymerGenerated;
|
return PolymerGenerated;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -486,14 +488,11 @@ function GenerateClassFromInfo(info, Base) {
|
|||||||
*/
|
*/
|
||||||
export const Class = function(info, mixin) {
|
export const Class = function(info, mixin) {
|
||||||
if (!info) {
|
if (!info) {
|
||||||
console.warn(`Polymer's Class function requires \`info\` argument`);
|
console.warn('Polymer.Class requires `info` argument');
|
||||||
}
|
}
|
||||||
let klass = mixin ? mixin(LegacyElementMixin(HTMLElement)) :
|
let klass = mixin ? mixin(LegacyElementMixin(HTMLElement)) :
|
||||||
LegacyElementMixin(HTMLElement);
|
LegacyElementMixin(HTMLElement);
|
||||||
if (info.behaviors) {
|
klass = GenerateClassFromInfo(info, klass, info.behaviors);
|
||||||
klass = applyBehaviors(info.behaviors, klass);
|
|
||||||
}
|
|
||||||
klass = GenerateClassFromInfo(info, klass);
|
|
||||||
// decorate klass with registration info
|
// decorate klass with registration info
|
||||||
klass.is = info.is;
|
klass.is = info.is;
|
||||||
return klass;
|
return klass;
|
||||||
|
|||||||
@@ -77,11 +77,6 @@ export const LegacyElementMixin = dedupingMixin((base) => {
|
|||||||
this.__boundListeners;
|
this.__boundListeners;
|
||||||
/** @type {Object<string, Function>} */
|
/** @type {Object<string, Function>} */
|
||||||
this._debouncers;
|
this._debouncers;
|
||||||
// Ensure listeners are applied immediately so that they are
|
|
||||||
// added before declarative event listeners. This allows an element to
|
|
||||||
// decorate itself via an event prior to any declarative listeners
|
|
||||||
// seeing the event. Note, this ensures compatibility with 1.x ordering.
|
|
||||||
this._applyListeners();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -96,6 +91,11 @@ export const LegacyElementMixin = dedupingMixin((base) => {
|
|||||||
return this.prototype.importMeta;
|
return this.prototype.importMeta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static _finalizeClass() {
|
||||||
|
this.prototype._registered();
|
||||||
|
super._finalizeClass();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Legacy callback called during the `constructor`, for overriding
|
* Legacy callback called during the `constructor`, for overriding
|
||||||
* by the user.
|
* by the user.
|
||||||
@@ -178,14 +178,14 @@ export const LegacyElementMixin = dedupingMixin((base) => {
|
|||||||
* @suppress {invalidCasts}
|
* @suppress {invalidCasts}
|
||||||
*/
|
*/
|
||||||
_initializeProperties() {
|
_initializeProperties() {
|
||||||
let proto = Object.getPrototypeOf(this);
|
|
||||||
if (!proto.hasOwnProperty('__hasRegisterFinished')) {
|
|
||||||
proto.__hasRegisterFinished = true;
|
|
||||||
this._registered();
|
|
||||||
}
|
|
||||||
super._initializeProperties();
|
super._initializeProperties();
|
||||||
this.root = /** @type {HTMLElement} */(this);
|
this.root = /** @type {HTMLElement} */(this);
|
||||||
this.created();
|
this.created();
|
||||||
|
// Ensure listeners are applied immediately so that they are
|
||||||
|
// added before declarative event listeners. This allows an element to
|
||||||
|
// decorate itself via an event prior to any declarative listeners
|
||||||
|
// seeing the event. Note, this ensures compatibility with 1.x ordering.
|
||||||
|
this._applyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { pathFromUrl, resolveCss, resolveUrl } from '../utils/resolve-url.js';
|
|||||||
import { DomModule } from '../elements/dom-module.js';
|
import { DomModule } from '../elements/dom-module.js';
|
||||||
import { PropertyEffects } from './property-effects.js';
|
import { PropertyEffects } from './property-effects.js';
|
||||||
import { PropertiesMixin } from './properties-mixin.js';
|
import { PropertiesMixin } from './properties-mixin.js';
|
||||||
import { skipStyleIncludesAndUrls } from '../utils/settings.js';
|
import { legacyOptimizations } from '../utils/settings.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Current Polymer version in Semver notation.
|
* Current Polymer version in Semver notation.
|
||||||
@@ -24,6 +24,8 @@ import { skipStyleIncludesAndUrls } from '../utils/settings.js';
|
|||||||
*/
|
*/
|
||||||
export const version = '3.0.5';
|
export const version = '3.0.5';
|
||||||
|
|
||||||
|
const builtCSS = window.ShadyCSS && window.ShadyCSS['cssBuild'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Element class mixin that provides the core API for Polymer's meta-programming
|
* Element class mixin that provides the core API for Polymer's meta-programming
|
||||||
* features including template stamping, data-binding, attribute deserialization,
|
* features including template stamping, data-binding, attribute deserialization,
|
||||||
@@ -253,7 +255,7 @@ export const ElementMixin = dedupingMixin(base => {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
function processElementStyles(klass, template, is, baseURI) {
|
function processElementStyles(klass, template, is, baseURI) {
|
||||||
if (!skipStyleIncludesAndUrls) {
|
if (!builtCSS) {
|
||||||
const templateStyles = template.content.querySelectorAll('style');
|
const templateStyles = template.content.querySelectorAll('style');
|
||||||
const stylesWithImports = stylesFromTemplate(template);
|
const stylesWithImports = stylesFromTemplate(template);
|
||||||
// insert styles from <link rel="import" type="css"> at the top of the template
|
// insert styles from <link rel="import" type="css"> at the top of the template
|
||||||
@@ -335,10 +337,6 @@ export const ElementMixin = dedupingMixin(base => {
|
|||||||
*/
|
*/
|
||||||
static _finalizeClass() {
|
static _finalizeClass() {
|
||||||
super._finalizeClass();
|
super._finalizeClass();
|
||||||
if (this.hasOwnProperty(
|
|
||||||
JSCompiler_renameProperty('is', this)) && this.is) {
|
|
||||||
register(this.prototype);
|
|
||||||
}
|
|
||||||
const observers = ownObservers(this);
|
const observers = ownObservers(this);
|
||||||
if (observers) {
|
if (observers) {
|
||||||
this.createObservers(observers, this._properties);
|
this.createObservers(observers, this._properties);
|
||||||
@@ -349,7 +347,7 @@ export const ElementMixin = dedupingMixin(base => {
|
|||||||
if (typeof template === 'string') {
|
if (typeof template === 'string') {
|
||||||
console.error('template getter must return HTMLTemplateElement');
|
console.error('template getter must return HTMLTemplateElement');
|
||||||
template = null;
|
template = null;
|
||||||
} else {
|
} else if (!legacyOptimizations) {
|
||||||
template = template.cloneNode(true);
|
template = template.cloneNode(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -524,7 +522,6 @@ export const ElementMixin = dedupingMixin(base => {
|
|||||||
* @suppress {invalidCasts}
|
* @suppress {invalidCasts}
|
||||||
*/
|
*/
|
||||||
_initializeProperties() {
|
_initializeProperties() {
|
||||||
instanceCount++;
|
|
||||||
this.constructor.finalize();
|
this.constructor.finalize();
|
||||||
// note: finalize template when we have access to `localName` to
|
// note: finalize template when we have access to `localName` to
|
||||||
// avoid dependence on `is` for polyfilling styling.
|
// avoid dependence on `is` for polyfilling styling.
|
||||||
@@ -743,46 +740,6 @@ export const ElementMixin = dedupingMixin(base => {
|
|||||||
return PolymerElement;
|
return PolymerElement;
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* Total number of Polymer element instances created.
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
export let instanceCount = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Array of Polymer element classes that have been finalized.
|
|
||||||
* @type {Array<PolymerElement>}
|
|
||||||
*/
|
|
||||||
export const registrations = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {!PolymerElementConstructor} prototype Element prototype to log
|
|
||||||
* @this {this}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
function _regLog(prototype) {
|
|
||||||
console.log('[' + prototype.is + ']: registered');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers a class prototype for telemetry purposes.
|
|
||||||
* @param {HTMLElement} prototype Element prototype to register
|
|
||||||
* @this {this}
|
|
||||||
* @protected
|
|
||||||
*/
|
|
||||||
export function register(prototype) {
|
|
||||||
registrations.push(prototype);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs all elements registered with an `is` to the console.
|
|
||||||
* @public
|
|
||||||
* @this {this}
|
|
||||||
*/
|
|
||||||
export function dumpRegistrations() {
|
|
||||||
registrations.forEach(_regLog);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When using the ShadyCSS scoping and custom property shim, causes all
|
* When using the ShadyCSS scoping and custom property shim, causes all
|
||||||
* shimmed `styles` (via `custom-style`) in the document (and its subtree)
|
* shimmed `styles` (via `custom-style`) in the document (and its subtree)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||||||
import '../utils/boot.js';
|
import '../utils/boot.js';
|
||||||
|
|
||||||
import { dedupingMixin } from '../utils/mixin.js';
|
import { dedupingMixin } from '../utils/mixin.js';
|
||||||
|
import { register, incrementInstanceCount } from '../utils/telemetry.js';
|
||||||
import { PropertiesChanged } from './properties-changed.js';
|
import { PropertiesChanged } from './properties-changed.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -114,8 +115,12 @@ export const PropertiesMixin = dedupingMixin(superClass => {
|
|||||||
* @suppress {missingProperties} Interfaces in closure do not inherit statics, but classes do
|
* @suppress {missingProperties} Interfaces in closure do not inherit statics, but classes do
|
||||||
*/
|
*/
|
||||||
static get observedAttributes() {
|
static get observedAttributes() {
|
||||||
const props = this._properties;
|
if (!this.hasOwnProperty('__observedAttributes')) {
|
||||||
return props ? Object.keys(props).map(p => this.attributeNameForProperty(p)) : [];
|
register(this.prototype);
|
||||||
|
const props = this._properties;
|
||||||
|
this.__observedAttributes = props ? Object.keys(props).map(p => this.attributeNameForProperty(p)) : [];
|
||||||
|
}
|
||||||
|
return this.__observedAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -189,6 +194,7 @@ export const PropertiesMixin = dedupingMixin(superClass => {
|
|||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
_initializeProperties() {
|
_initializeProperties() {
|
||||||
|
incrementInstanceCount();
|
||||||
this.constructor.finalize();
|
this.constructor.finalize();
|
||||||
super._initializeProperties();
|
super._initializeProperties();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||||||
import '../utils/boot.js';
|
import '../utils/boot.js';
|
||||||
|
|
||||||
import { dedupingMixin } from '../utils/mixin.js';
|
import { dedupingMixin } from '../utils/mixin.js';
|
||||||
|
import { legacyOptimizations } from '../utils/settings.js';
|
||||||
|
|
||||||
|
const walker = document.createTreeWalker(document);
|
||||||
|
|
||||||
// 1.x backwards-compatible auto-wrapper for template type extensions
|
// 1.x backwards-compatible auto-wrapper for template type extensions
|
||||||
// This is a clear layering violation and gives favored-nation status to
|
// This is a clear layering violation and gives favored-nation status to
|
||||||
@@ -45,7 +48,8 @@ function findTemplateNode(root, nodeInfo) {
|
|||||||
if (parent) {
|
if (parent) {
|
||||||
// note: marginally faster than indexing via childNodes
|
// note: marginally faster than indexing via childNodes
|
||||||
// (http://jsperf.com/childnodes-lookup)
|
// (http://jsperf.com/childnodes-lookup)
|
||||||
for (let n=parent.firstChild, i=0; n; n=n.nextSibling) {
|
walker.currentNode = parent;
|
||||||
|
for (let n=walker.firstChild(), i=0; n; n=walker.nextSibling()) {
|
||||||
if (nodeInfo.parentIndex === i++) {
|
if (nodeInfo.parentIndex === i++) {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
@@ -200,7 +204,7 @@ export const TemplateStamp = dedupingMixin(
|
|||||||
if (!template._templateInfo) {
|
if (!template._templateInfo) {
|
||||||
let templateInfo = template._templateInfo = {};
|
let templateInfo = template._templateInfo = {};
|
||||||
templateInfo.nodeInfoList = [];
|
templateInfo.nodeInfoList = [];
|
||||||
templateInfo.stripWhiteSpace =
|
templateInfo.stripWhiteSpace = legacyOptimizations ||
|
||||||
(outerTemplateInfo && outerTemplateInfo.stripWhiteSpace) ||
|
(outerTemplateInfo && outerTemplateInfo.stripWhiteSpace) ||
|
||||||
template.hasAttribute('strip-whitespace');
|
template.hasAttribute('strip-whitespace');
|
||||||
this._parseTemplateContent(template, templateInfo, {parent: null});
|
this._parseTemplateContent(template, templateInfo, {parent: null});
|
||||||
@@ -234,7 +238,8 @@ 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;
|
||||||
}
|
}
|
||||||
if (element.firstChild) {
|
walker.currentNode = element;
|
||||||
|
if (walker.firstChild()) {
|
||||||
noted = this._parseTemplateChildNodes(element, templateInfo, nodeInfo) || noted;
|
noted = this._parseTemplateChildNodes(element, templateInfo, nodeInfo) || noted;
|
||||||
}
|
}
|
||||||
if (element.hasAttributes && element.hasAttributes()) {
|
if (element.hasAttributes && element.hasAttributes()) {
|
||||||
@@ -260,7 +265,8 @@ export const TemplateStamp = dedupingMixin(
|
|||||||
if (root.localName === 'script' || root.localName === 'style') {
|
if (root.localName === 'script' || root.localName === 'style') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (let node=root.firstChild, parentIndex=0, next; node; node=next) {
|
walker.currentNode = root;
|
||||||
|
for (let node=walker.firstChild(), parentIndex=0, next; node; node=next) {
|
||||||
// Wrap templates
|
// Wrap templates
|
||||||
if (node.localName == 'template') {
|
if (node.localName == 'template') {
|
||||||
node = wrapTemplateExtension(node);
|
node = wrapTemplateExtension(node);
|
||||||
@@ -269,12 +275,13 @@ export const TemplateStamp = dedupingMixin(
|
|||||||
// text nodes to be inexplicably split =(
|
// text nodes to be inexplicably split =(
|
||||||
// note that root.normalize() should work but does not so we do this
|
// note that root.normalize() should work but does not so we do this
|
||||||
// manually.
|
// manually.
|
||||||
next = node.nextSibling;
|
walker.currentNode = node;
|
||||||
|
next = walker.nextSibling();
|
||||||
if (node.nodeType === Node.TEXT_NODE) {
|
if (node.nodeType === Node.TEXT_NODE) {
|
||||||
let /** Node */ n = next;
|
let /** Node */ n = next;
|
||||||
while (n && (n.nodeType === Node.TEXT_NODE)) {
|
while (n && (n.nodeType === Node.TEXT_NODE)) {
|
||||||
node.textContent += n.textContent;
|
node.textContent += n.textContent;
|
||||||
next = n.nextSibling;
|
next = walker.nextSibling();
|
||||||
root.removeChild(n);
|
root.removeChild(n);
|
||||||
n = next;
|
n = next;
|
||||||
}
|
}
|
||||||
@@ -289,7 +296,8 @@ export const TemplateStamp = dedupingMixin(
|
|||||||
childInfo.infoIndex = templateInfo.nodeInfoList.push(/** @type {!NodeInfo} */(childInfo)) - 1;
|
childInfo.infoIndex = templateInfo.nodeInfoList.push(/** @type {!NodeInfo} */(childInfo)) - 1;
|
||||||
}
|
}
|
||||||
// Increment if not removed
|
// Increment if not removed
|
||||||
if (node.parentNode) {
|
walker.currentNode = node;
|
||||||
|
if (walker.parentNode()) {
|
||||||
parentIndex++;
|
parentIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,15 +128,16 @@ export const setAllowTemplateFromDomModule = function(allowDomModule) {
|
|||||||
* If no includes or relative urls are used in styles, these steps can be
|
* If no includes or relative urls are used in styles, these steps can be
|
||||||
* skipped as an optimization.
|
* skipped as an optimization.
|
||||||
*/
|
*/
|
||||||
export let skipStyleIncludesAndUrls = false;
|
export let legacyOptimizations = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets `setSkipRewriteStyleUrls` globally for all elements
|
* Sets `legacyOptimizations` globally for all elements to enable optimizations
|
||||||
|
* when only legacy based elements are used.
|
||||||
*
|
*
|
||||||
* @param {boolean} skipIncludesAndUrls enable or disable skipping style
|
* @param {boolean} useLegacyOptimizations enable or disable legacy optimizations
|
||||||
* includes and url rewriting
|
* includes and url rewriting
|
||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
export const setSkipStyleIncludesAndUrls = function(skipIncludesAndUrls) {
|
export const setLegacyOptimizations = function(useLegacyOptimizations) {
|
||||||
skipStyleIncludesAndUrls = skipIncludesAndUrls;
|
legacyOptimizations = useLegacyOptimizations;
|
||||||
};
|
};
|
||||||
53
lib/utils/telemetry.js
Normal file
53
lib/utils/telemetry.js
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/**
|
||||||
|
@license
|
||||||
|
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
|
||||||
|
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||||||
|
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||||||
|
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||||||
|
Code distributed by Google as part of the polymer project is also
|
||||||
|
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total number of Polymer element instances created.
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
export let instanceCount = 0;
|
||||||
|
|
||||||
|
export function incrementInstanceCount() {
|
||||||
|
instanceCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of Polymer element classes that have been finalized.
|
||||||
|
* @type {Array<PolymerElement>}
|
||||||
|
*/
|
||||||
|
export const registrations = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!PolymerElementConstructor} prototype Element prototype to log
|
||||||
|
* @this {this}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function _regLog(prototype) {
|
||||||
|
console.log('[' + prototype.is + ']: registered');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a class prototype for telemetry purposes.
|
||||||
|
* @param {HTMLElement} prototype Element prototype to register
|
||||||
|
* @this {this}
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
export function register(prototype) {
|
||||||
|
registrations.push(prototype);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs all elements registered with an `is` to the console.
|
||||||
|
* @public
|
||||||
|
* @this {this}
|
||||||
|
*/
|
||||||
|
export function dumpRegistrations() {
|
||||||
|
registrations.forEach(_regLog);
|
||||||
|
}
|
||||||
@@ -93,13 +93,17 @@ Polymer({
|
|||||||
type: String
|
type: String
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
listeners: {
|
||||||
|
foo: 'fooHandler'
|
||||||
|
},
|
||||||
created() {
|
created() {
|
||||||
this.hasCreated = true;
|
this.hasCreated = true;
|
||||||
this.prop = 'enabled!';
|
this.prop = 'enabled!';
|
||||||
},
|
},
|
||||||
ready() {
|
ready() {
|
||||||
this.enabled = true;
|
this.enabled = true;
|
||||||
}
|
},
|
||||||
|
fooHandler() {}
|
||||||
});
|
});
|
||||||
|
|
||||||
Polymer({
|
Polymer({
|
||||||
@@ -241,30 +245,39 @@ suite('disable-upgrade-legacy', function() {
|
|||||||
assert.ok(el.$.enabledEl.enabled);
|
assert.ok(el.$.enabledEl.enabled);
|
||||||
assert.ok(el.$.enabledEl.$.element);
|
assert.ok(el.$.enabledEl.$.element);
|
||||||
assert.equal(el.$.enabledEl.$.element.textContent, 'enabled!');
|
assert.equal(el.$.enabledEl.$.element.textContent, 'enabled!');
|
||||||
|
el.$.enabledEl.fooHandler = sinon.spy();
|
||||||
|
el.$.enabledEl.fire('foo');
|
||||||
|
assert.equal(el.$.enabledEl.fooHandler.callCount, 1);
|
||||||
assert.notOk(el.$.disabledEl.hasCreated);
|
assert.notOk(el.$.disabledEl.hasCreated);
|
||||||
assert.notOk(el.$.disabledEl.enabled);
|
assert.notOk(el.$.disabledEl.enabled);
|
||||||
assert.notOk(el.$.disabledEl.$);
|
assert.notOk(el.$.disabledEl.$);
|
||||||
|
el.$.disabledEl.fooHandler = sinon.spy();
|
||||||
|
el.$.disabledEl.fire('foo');
|
||||||
|
assert.equal(el.$.disabledEl.fooHandler.callCount, 0);
|
||||||
assert.notOk(el.$.disabledBoundEl.hasCreated);
|
assert.notOk(el.$.disabledBoundEl.hasCreated);
|
||||||
assert.notOk(el.$.disabledBoundEl.enabled);
|
assert.notOk(el.$.disabledBoundEl.enabled);
|
||||||
assert.notOk(el.$.disabledBoundEl.$);
|
assert.notOk(el.$.disabledBoundEl.$);
|
||||||
|
el.$.disabledBoundEl.fooHandler = sinon.spy();
|
||||||
|
el.$.disabledBoundEl.fire('foo');
|
||||||
|
assert.equal(el.$.disabledBoundEl.fooHandler.callCount, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('elements upgrade when `disable-upgrade` removed', function() {
|
test('elements upgrade when `disable-upgrade` removed', function() {
|
||||||
assert.notOk(el.$.disabledEl.hasCreated);
|
|
||||||
assert.notOk(el.$.disabledEl.enabled);
|
|
||||||
assert.notOk(el.$.disabledEl.$);
|
|
||||||
assert.notOk(el.$.disabledBoundEl.hasCreated);
|
|
||||||
assert.notOk(el.$.disabledBoundEl.enabled);
|
|
||||||
assert.notOk(el.$.disabledBoundEl.$);
|
|
||||||
el.enable();
|
el.enable();
|
||||||
assert.ok(el.$.disabledEl.hasCreated);
|
assert.ok(el.$.disabledEl.hasCreated);
|
||||||
assert.ok(el.$.disabledEl.enabled);
|
assert.ok(el.$.disabledEl.enabled);
|
||||||
assert.ok(el.$.disabledEl.$.element);
|
assert.ok(el.$.disabledEl.$.element);
|
||||||
assert.equal(el.$.disabledEl.$.element.textContent, 'enabled!');
|
assert.equal(el.$.disabledEl.$.element.textContent, 'enabled!');
|
||||||
|
el.$.disabledEl.fooHandler = sinon.spy();
|
||||||
|
el.$.disabledEl.fire('foo');
|
||||||
|
assert.equal(el.$.disabledEl.fooHandler.callCount, 1);
|
||||||
assert.ok(el.$.disabledBoundEl.hasCreated);
|
assert.ok(el.$.disabledBoundEl.hasCreated);
|
||||||
assert.ok(el.$.disabledBoundEl.enabled);
|
assert.ok(el.$.disabledBoundEl.enabled);
|
||||||
assert.ok(el.$.disabledBoundEl.$.element);
|
assert.ok(el.$.disabledBoundEl.$.element);
|
||||||
assert.equal(el.$.disabledBoundEl.$.element.textContent, 'enabled!');
|
assert.equal(el.$.disabledBoundEl.$.element.textContent, 'enabled!');
|
||||||
|
el.$.disabledBoundEl.fooHandler = sinon.spy();
|
||||||
|
el.$.disabledBoundEl.fire('foo');
|
||||||
|
assert.equal(el.$.disabledBoundEl.fooHandler.callCount, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -256,12 +256,12 @@ customElements.define('multi-behaviors',
|
|||||||
import { mixinBehaviors } from '../../lib/legacy/class.js';
|
import { mixinBehaviors } from '../../lib/legacy/class.js';
|
||||||
import { PolymerElement } from '../../polymer-element.js';
|
import { PolymerElement } from '../../polymer-element.js';
|
||||||
customElements.define('nested-behaviors',
|
customElements.define('nested-behaviors',
|
||||||
class extends mixinBehaviors(
|
class extends mixinBehaviors([window.BehaviorD, window.LifeCycleBehavior1], mixinBehaviors(
|
||||||
[
|
[
|
||||||
[window.BehaviorB, [window.BehaviorC, window.BehaviorB], window.BehaviorA],
|
[window.BehaviorB, [window.BehaviorC, window.BehaviorB], window.BehaviorA, window.LifeCycleBehavior2],
|
||||||
[window.BehaviorD]
|
], PolymerElement)) {
|
||||||
], PolymerElement) {
|
}
|
||||||
});
|
);
|
||||||
</script>
|
</script>
|
||||||
</dom-module>
|
</dom-module>
|
||||||
|
|
||||||
@@ -355,7 +355,7 @@ customElements.define(BehaviorRegisteredExt.is, BehaviorRegisteredExt);
|
|||||||
|
|
||||||
<test-fixture id="nested">
|
<test-fixture id="nested">
|
||||||
<template>
|
<template>
|
||||||
<nested-behaviors></nested-behaviors>
|
<nested-behaviors foo="foo"></nested-behaviors>
|
||||||
</template>
|
</template>
|
||||||
</test-fixture>
|
</test-fixture>
|
||||||
|
|
||||||
@@ -554,7 +554,13 @@ suite('nested-behaviors element', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('nested-behavior dedups', function() {
|
test('nested-behavior dedups', function() {
|
||||||
assert.equal(el.behaviors.length, 4);
|
assert.equal(el.behaviors.length, 6);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('nested-behavior lifecycle', function() {
|
||||||
|
assert.equal(el._calledCreated, 2, 'created call count wrong');
|
||||||
|
assert.equal(el._calledAttached, 2, 'attached call count wrong');
|
||||||
|
assert.equal(el._calledAttributeChanged, 1, 'attributeChanged call count wrong');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('nested-behavior overrides ordering', function() {
|
test('nested-behavior overrides ordering', function() {
|
||||||
|
|||||||
Reference in New Issue
Block a user