diff --git a/lib/legacy/class.html b/lib/legacy/class.html
index 135cdd9999..00e6a1bdcc 100644
--- a/lib/legacy/class.html
+++ b/lib/legacy/class.html
@@ -26,6 +26,20 @@
behaviors: true
};
+ function copyProperties(source, target) {
+ for (let p in source) {
+ // NOTE: cannot copy `metaProps` methods onto prototype at least because
+ // `super.ready` must be called and is not included in the user fn.
+ if (!(p in metaProps)) {
+ let pd = Object.getOwnPropertyDescriptor(source, p);
+ if (pd) {
+ Object.defineProperty(target, p, pd);
+ }
+ }
+ }
+ }
+
+ // TODO(sorvell): this breaks `Polymer.mixinBehaviors`; should fix via factoring
/**
* Applies a "legacy" behavior or array of behaviors to the provided class.
*
@@ -42,6 +56,15 @@
* @suppress {invalidCasts, checkTypes}
*/
function mixinBehaviors(behaviors, klass) {
+ if (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;
@@ -49,7 +72,7 @@
// 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 = Polymer.LegacyElementMixin(klass);
+ klass = class extends Polymer.LegacyElementMixin(klass) {};
if (!Array.isArray(behaviors)) {
behaviors = [behaviors];
}
@@ -57,7 +80,7 @@
// get flattened, deduped list of behaviors *not* already on super class
behaviors = flattenBehaviors(behaviors, null, superBehaviors);
// mixin new behaviors
- klass = _mixinBehaviors(behaviors, klass);
+ klass = _applyBehaviors(behaviors, klass);
if (superBehaviors) {
behaviors = superBehaviors.concat(behaviors);
}
@@ -96,12 +119,12 @@
// If lifecycle is called (super then me), order is
// (1) C.created, (2) A.created, (3) B.created, (4) element.created
// (again same as 1.x)
- function _mixinBehaviors(behaviors, klass) {
+ function _applyBehaviors(behaviors, klass) {
for (let i=0; i= 0; i--) {
+ b = this.behaviors[i];
+ if (b.hostAttributes) {
+ for (let a in b.hostAttributes) {
+ this._ensureAttribute(a, b.hostAttributes[a]);
+ }
+ }
+ }
+ }
}
/**
@@ -231,6 +355,14 @@
*/
ready() {
super.ready();
+ if (this.behaviors) {
+ for (let i=0, b; i < this.behaviors.length; i++) {
+ b = this.behaviors[i];
+ if (b.ready) {
+ b.ready.call(this);
+ }
+ }
+ }
if (info.ready) {
info.ready.call(this);
}
@@ -240,7 +372,14 @@
* @return {void}
*/
attached() {
- super.attached();
+ if (this.behaviors) {
+ for (let i=0, b; i < this.behaviors.length; i++) {
+ b = this.behaviors[i];
+ if (b.attached) {
+ b.attached.call(this);
+ }
+ }
+ }
if (info.attached) {
info.attached.call(this);
}
@@ -250,7 +389,14 @@
* @return {void}
*/
detached() {
- super.detached();
+ if (this.behaviors) {
+ for (let i=0, b; i < this.behaviors.length; i++) {
+ b = this.behaviors[i];
+ if (b.detached) {
+ b.detached.call(this);
+ }
+ }
+ }
if (info.detached) {
info.detached.call(this);
}
@@ -266,7 +412,14 @@
* @return {void}
*/
attributeChanged(name, old, value) {
- super.attributeChanged(name, old, value);
+ if (this.behaviors) {
+ for (let i=0, b; i < this.behaviors.length; i++) {
+ b = this.behaviors[i];
+ if (b.attributeChanged) {
+ b.attributeChanged.call(this, name, old, value);
+ }
+ }
+ }
if (info.attributeChanged) {
info.attributeChanged.call(this, name, old, value);
}
@@ -275,16 +428,7 @@
PolymerGenerated.generatedFrom = info;
- for (let p in info) {
- // NOTE: cannot copy `metaProps` methods onto prototype at least because
- // `super.ready` must be called and is not included in the user fn.
- if (!(p in metaProps)) {
- let pd = Object.getOwnPropertyDescriptor(info, p);
- if (pd) {
- Object.defineProperty(PolymerGenerated.prototype, p, pd);
- }
- }
- }
+ copyProperties(info, PolymerGenerated.prototype);
return PolymerGenerated;
}
@@ -357,14 +501,16 @@
* @return {function(new:HTMLElement)} Generated class
* @memberof Polymer
*/
- Polymer.Class = function(info) {
+ Polymer.Class = function(info, mixin) {
if (!info) {
console.warn('Polymer.Class requires `info` argument');
}
- let klass = GenerateClassFromInfo(info, info.behaviors ?
- // note: mixinBehaviors ensures `LegacyElementMixin`.
- mixinBehaviors(info.behaviors, HTMLElement) :
- Polymer.LegacyElementMixin(HTMLElement));
+ let klass = mixin ? mixin(Polymer.LegacyElementMixin(HTMLElement)) :
+ Polymer.LegacyElementMixin(HTMLElement);
+ if (info.behaviors) {
+ klass = applyBehaviors(info.behaviors, klass);
+ }
+ klass = GenerateClassFromInfo(info, klass);
// decorate klass with registration info
klass.is = info.is;
return klass;
diff --git a/lib/mixins/element-mixin.html b/lib/mixins/element-mixin.html
index f14c7ffb95..e913ff7e85 100644
--- a/lib/mixins/element-mixin.html
+++ b/lib/mixins/element-mixin.html
@@ -228,7 +228,14 @@
}
// always add observer
if (info.observer) {
- proto._createPropertyObserver(name, info.observer, allProps[info.observer]);
+ if (Array.isArray(info.observer)) {
+ for (let i=0; i < info.observer.length; i++) {
+ const o = info.observer[i];
+ proto._createPropertyObserver(name, o, allProps[o]);
+ }
+ } else {
+ proto._createPropertyObserver(name, info.observer, allProps[info.observer]);
+ }
}
// always create the mapping from attribute back to property for deserialization.
proto._addPropertyToAttributeMap(name);
@@ -245,31 +252,33 @@
* @private
*/
function processElementStyles(klass, template, is, baseURI) {
- const templateStyles = template.content.querySelectorAll('style');
- const stylesWithImports = Polymer.StyleGather.stylesFromTemplate(template);
- // insert styles from at the top of the template
- const linkedStyles = Polymer.StyleGather.stylesFromModuleImports(is);
- const firstTemplateChild = template.content.firstElementChild;
- for (let idx = 0; idx < linkedStyles.length; idx++) {
- let s = linkedStyles[idx];
- s.textContent = klass._processStyleText(s.textContent, baseURI);
- template.content.insertBefore(s, firstTemplateChild);
- }
- // keep track of the last "concrete" style in the template we have encountered
- let templateStyleIndex = 0;
- // ensure all gathered styles are actually in this template.
- for (let i = 0; i < stylesWithImports.length; i++) {
- let s = stylesWithImports[i];
- let templateStyle = templateStyles[templateStyleIndex];
- // if the style is not in this template, it's been "included" and
- // we put a clone of it in the template before the style that included it
- if (templateStyle !== s) {
- s = s.cloneNode(true);
- templateStyle.parentNode.insertBefore(s, templateStyle);
- } else {
- templateStyleIndex++;
+ if (!window.skipStyleIncludesAndUrls) {
+ const templateStyles = template.content.querySelectorAll('style');
+ const stylesWithImports = Polymer.StyleGather.stylesFromTemplate(template);
+ // insert styles from at the top of the template
+ const linkedStyles = Polymer.StyleGather.stylesFromModuleImports(is);
+ const firstTemplateChild = template.content.firstElementChild;
+ for (let idx = 0; idx < linkedStyles.length; idx++) {
+ let s = linkedStyles[idx];
+ s.textContent = klass._processStyleText(s.textContent, baseURI);
+ template.content.insertBefore(s, firstTemplateChild);
+ }
+ // keep track of the last "concrete" style in the template we have encountered
+ let templateStyleIndex = 0;
+ // ensure all gathered styles are actually in this template.
+ for (let i = 0; i < stylesWithImports.length; i++) {
+ let s = stylesWithImports[i];
+ let templateStyle = templateStyles[templateStyleIndex];
+ // if the style is not in this template, it's been "included" and
+ // we put a clone of it in the template before the style that included it
+ if (templateStyle !== s) {
+ s = s.cloneNode(true);
+ templateStyle.parentNode.insertBefore(s, templateStyle);
+ } else {
+ templateStyleIndex++;
+ }
+ s.textContent = klass._processStyleText(s.textContent, baseURI);
}
- s.textContent = klass._processStyleText(s.textContent, baseURI);
}
if (window.ShadyCSS) {
window.ShadyCSS.prepareTemplate(template, is);