2016-08-11 18:07:41 -07:00
|
|
|
<!--
|
|
|
|
|
@license
|
|
|
|
|
Copyright (c) 2014 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
|
|
|
|
|
-->
|
|
|
|
|
|
|
|
|
|
<link rel="import" href="../utils/boot.html">
|
|
|
|
|
<link rel="import" href="../utils/utils.html">
|
|
|
|
|
<link rel="import" href="../utils/compat-dom-utils.html">
|
|
|
|
|
<link rel="import" href="../utils/case-map.html">
|
|
|
|
|
<link rel="import" href="../utils/async-render.html">
|
|
|
|
|
<link rel="import" href="../events/gesture-event-listeners.html">
|
|
|
|
|
<link rel="import" href="../template/template-stamp.html">
|
|
|
|
|
<link rel="import" href="../attributes/attribute-to-from-property.html">
|
|
|
|
|
<link rel="import" href="../properties/meta-effects.html">
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
(function() {
|
|
|
|
|
|
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
|
|
var utils = Polymer.Utils;
|
|
|
|
|
var caseMap = Polymer.CaseMap;
|
|
|
|
|
|
|
|
|
|
var events = new Polymer.GestureEventListeners();
|
|
|
|
|
var templateStamp = new Polymer.TemplateStamp(events);
|
|
|
|
|
var attributes = new Polymer.AttributeToFromProperty();
|
|
|
|
|
var data = new Polymer.MetaEffects(templateStamp, attributes);
|
|
|
|
|
|
|
|
|
|
Polymer.ElementMixin = function(Base) {
|
|
|
|
|
|
|
|
|
|
class Element extends Base {
|
|
|
|
|
|
|
|
|
|
static get ownConfig() {
|
|
|
|
|
if (!this.hasOwnProperty('_ownConfig')) {
|
|
|
|
|
this._ownConfig = this.hasOwnProperty('config') ? this.config : {};
|
|
|
|
|
}
|
|
|
|
|
return this._ownConfig;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static get flattenedProperties() {
|
|
|
|
|
if (!this.hasOwnProperty('_flattenedProperties')) {
|
|
|
|
|
this._flattenedProperties = this.ownConfig.properties || {};
|
|
|
|
|
var superCtor = Object.getPrototypeOf(this.prototype).constructor;
|
|
|
|
|
if (superCtor.prototype instanceof Element) {
|
|
|
|
|
this._flattenedProperties = utils.mixin(
|
|
|
|
|
Object.create(superCtor.flattenedProperties),
|
|
|
|
|
this._flattenedProperties);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return this._flattenedProperties;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static get observedAttributes() {
|
|
|
|
|
// TODO(kschaaf): revisit: capture import document, to aid finding dom-module
|
|
|
|
|
var currentScript = document._currentScript || document.currentScript;
|
2016-08-12 11:05:51 -07:00
|
|
|
this.__importDoc = currentScript && currentScript.ownerDocument;
|
2016-08-11 18:07:41 -07:00
|
|
|
// observedAttributes must be finalized at registration time
|
|
|
|
|
var attrs = [];
|
|
|
|
|
return this.addPropertiesToAttributes(this.flattenedProperties, attrs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static addPropertiesToAttributes(properties, attrs) {
|
|
|
|
|
for (var prop in properties) {
|
|
|
|
|
var attr = Polymer.CaseMap.camelToDashCase(prop);
|
|
|
|
|
if (attrs.indexOf(attr) < 0) {
|
|
|
|
|
attrs.push(attr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return attrs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static createProperties(properties) {
|
|
|
|
|
if (properties) {
|
|
|
|
|
this.data.createProperties(this.prototype, properties);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static createExpressionObservers(observers) {
|
|
|
|
|
if (observers) {
|
|
|
|
|
this.data.createExpressionObservers(this.prototype, observers);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static get decorated() {
|
|
|
|
|
return this.prototype.hasOwnProperty('__isDecorated');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static set decorated(value) {
|
|
|
|
|
this.prototype.__isDecorated = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// bikeshed this name... we have `prepare` below which is not good.
|
|
|
|
|
static decorate() {
|
|
|
|
|
var proto = this.prototype;
|
|
|
|
|
if (!this.decorated) {
|
|
|
|
|
if (this.hasOwnProperty('is') && this.is) {
|
|
|
|
|
Polymer.telemetry.register(proto);
|
|
|
|
|
}
|
|
|
|
|
this.decorated = true;
|
|
|
|
|
var superProto = Object.getPrototypeOf(proto);
|
|
|
|
|
var superCtor = superProto && superProto.constructor;
|
|
|
|
|
if (superCtor.prototype instanceof Element) {
|
|
|
|
|
superCtor.decorate();
|
|
|
|
|
}
|
|
|
|
|
var config = this.ownConfig;
|
|
|
|
|
this.createProperties(config.properties);
|
|
|
|
|
this.createExpressionObservers(config.observers);
|
2016-08-12 11:05:51 -07:00
|
|
|
var template = this.prepareTemplate();
|
|
|
|
|
if (template) {
|
|
|
|
|
proto.__notStyleScopeCacheable = template.__notStyleScopeCacheable;
|
|
|
|
|
proto._template = template;
|
|
|
|
|
this.data.bindTemplate(proto, proto._template);
|
|
|
|
|
}
|
2016-08-11 18:07:41 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static prepareTemplate() {
|
|
|
|
|
// TODO(sorvell): support more ways to acquire template.
|
|
|
|
|
// this requires `is` on constructor...
|
2016-08-12 11:05:51 -07:00
|
|
|
// TODO(sorvell): `__importDoc` may not be set if super class
|
|
|
|
|
// has not run defined... falling back to document here is
|
|
|
|
|
// incorrect. This gambit cannot work as is since if the superclass
|
|
|
|
|
// document cannot be discovered via the subclass.
|
|
|
|
|
var template = Polymer.DomModule.import(this.is,
|
|
|
|
|
'template', this.__importDoc || document);
|
|
|
|
|
if (template) {
|
|
|
|
|
Polymer.CompatStyleUtil.normalizeForBC(template.content);
|
2016-08-11 18:07:41 -07:00
|
|
|
// TODO(sorvell): cannot use `this` here, refactor this to only do
|
|
|
|
|
// template preparation and take a name.
|
2016-08-12 11:05:51 -07:00
|
|
|
// TODO(dfreedm): factor so that we do not need an object/element
|
|
|
|
|
// argument
|
|
|
|
|
var info = {
|
|
|
|
|
localName: this.is,
|
|
|
|
|
is: this.is,
|
|
|
|
|
extends: this.extends,
|
|
|
|
|
__cssBuild: this.__cssBuild
|
|
|
|
|
}
|
|
|
|
|
Polymer.StyleLib.prepareTemplate(info, template);
|
|
|
|
|
template.__notStyleScopeCacheable = info.__notStyleScopeCacheable;
|
2016-08-11 18:07:41 -07:00
|
|
|
}
|
2016-08-12 11:05:51 -07:00
|
|
|
return template;
|
2016-08-11 18:07:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
|
super();
|
|
|
|
|
// note: `this.constructor.prototype` is wrong in Safari so make sure to
|
|
|
|
|
// use `__proto__`
|
|
|
|
|
if (!this.constructor.decorated) {
|
|
|
|
|
this.constructor.decorate();
|
|
|
|
|
}
|
2016-08-12 11:05:51 -07:00
|
|
|
Polymer.StyleLib.prepareHost(this, this._template);
|
2016-08-11 18:07:41 -07:00
|
|
|
Polymer.telemetry.instanceCount++;
|
|
|
|
|
// setup batched effects library; will call initialize when flushing
|
|
|
|
|
this.constructor.data.prepare(this, this.ready);
|
|
|
|
|
// add self to host's pending client list
|
|
|
|
|
hostStack.registerHost(this);
|
|
|
|
|
// apply defaults first.
|
|
|
|
|
this.constructor.data.setPropertyDefaults(this,
|
|
|
|
|
this.constructor.flattenedProperties);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// reserved for canonical behavior
|
|
|
|
|
connectedCallback() {
|
|
|
|
|
if (hostStack.isEmpty()) {
|
|
|
|
|
this.constructor.data.flush(this);
|
|
|
|
|
this.updateStyles();
|
|
|
|
|
}
|
|
|
|
|
this.isAttached = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ready() {
|
|
|
|
|
if (!this.root) {
|
|
|
|
|
if (this._template) {
|
|
|
|
|
// BREAKME(sorvell): remove v0 support when we can...
|
|
|
|
|
this.root = Polymer.shadowDomV0 ? this.createShadowRoot() :
|
|
|
|
|
this.attachShadow({mode: 'open'});
|
|
|
|
|
} else {
|
|
|
|
|
this.root = this;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (this._template) {
|
|
|
|
|
hostStack.beginHosting(this);
|
|
|
|
|
var dom = this.constructor.data.stamp(this, this._template);
|
|
|
|
|
this.root.appendChild(dom);
|
|
|
|
|
hostStack.endHosting(this);
|
|
|
|
|
}
|
|
|
|
|
this.constructor.data.flush(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addListeners(listeners) {
|
|
|
|
|
this.constructor.events.addMethodListeners(this, listeners);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ensureAttributes(attrs) {
|
|
|
|
|
this.constructor.attributes.ensureAttributes(this, attrs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
disconnectedCallback() {
|
|
|
|
|
this.isAttached = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
attributeChangedCallback(name, old, value) {
|
|
|
|
|
var property = caseMap.dashToCamelCase(name);
|
|
|
|
|
var type = this.constructor.flattenedProperties[property].type;
|
|
|
|
|
if (!this.constructor.data.hasReadOnlyEffect(
|
|
|
|
|
this.__proto__, name)) {
|
|
|
|
|
this.constructor.attributes.attributeToProperty(this,
|
|
|
|
|
name, value, type);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateStyles(properties) {
|
|
|
|
|
Polymer.StyleLib.applyStyle(this, properties);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Element.events = events;
|
|
|
|
|
Element.templateStamp = templateStamp;
|
|
|
|
|
Element.attributes = attributes;
|
|
|
|
|
Element.data = data;
|
|
|
|
|
|
|
|
|
|
return Element;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var hostStack = {
|
|
|
|
|
|
|
|
|
|
stack: [],
|
|
|
|
|
|
|
|
|
|
isEmpty() {
|
|
|
|
|
return !this.stack.length;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
registerHost(inst) {
|
|
|
|
|
if (this.stack.length) {
|
|
|
|
|
var host = this.stack[this.stack.length-1];
|
|
|
|
|
data.enqueueClient(host, inst);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
beginHosting(inst) {
|
|
|
|
|
this.stack.push(inst);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
endHosting(inst) {
|
|
|
|
|
var stackLen = this.stack.length;
|
|
|
|
|
if (stackLen && this.stack[stackLen-1] == inst) {
|
|
|
|
|
this.stack.pop();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (window.CustomElements) {
|
|
|
|
|
Polymer.instanceof = CustomElements.instanceof;
|
|
|
|
|
} else {
|
|
|
|
|
Polymer.instanceof = function(obj, ctor) {
|
|
|
|
|
return obj instanceof ctor;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Polymer.isInstance = function(obj) {
|
|
|
|
|
return Boolean(obj && obj.__isPolymerInstance);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// telemetry
|
|
|
|
|
Polymer.telemetry = {
|
|
|
|
|
instanceCount: 0,
|
|
|
|
|
registrations: [],
|
|
|
|
|
_regLog: function(prototype) {
|
|
|
|
|
console.log('[' + prototype.is + ']: registered')
|
|
|
|
|
},
|
|
|
|
|
register: function(prototype) {
|
|
|
|
|
this.registrations.push(prototype);
|
|
|
|
|
Polymer.log && this._regLog(prototype);
|
|
|
|
|
},
|
|
|
|
|
dumpRegistrations: function() {
|
|
|
|
|
this.registrations.forEach(this._regLog);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Polymer.Element = Polymer.ElementMixin(HTMLElement);
|
|
|
|
|
|
|
|
|
|
})();
|
|
|
|
|
</script>
|