polymer-analyzer
Version:
Static analysis for Web Components
347 lines (314 loc) • 11.3 kB
HTML
<!--
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="settings.html">
-->
<script>
(function() {
'use strict';
var settings = Polymer.Settings;
Polymer.Base = {
// Used for `isInstance` type checking; cannot use `instanceof` because
// there is no common Polymer.Base in the prototype chain between type
// extensions and normal custom elements
__isPolymerInstance__: true,
// pluggable features
// `this` context is a prototype, not an instance
_addFeature: function(feature) {
this.mixin(this, feature);
},
// `this` context is a prototype, not an instance
registerCallback: function() {
/*
When lazyRegister is 'max' defer all behavior work until first element
creation.
When set, a behavior cannot setup an element's `is` or
custom constructor via defining `factoryImpl`.
We do call beforeRegister on the prototype to preserve
the ability to use it in ES6. This orders the element
prototype's `beforeRegister` before behaviors' rather than after
as in the normal case.
*/
if (settings.lazyRegister === 'max') {
if (this.beforeRegister) {
this.beforeRegister();
}
} else {
this._desugarBehaviors(); // abstract
// this code was in a function but is unrolled here for perf
for (var i=0, b; i < this.behaviors.length; i++) {
b = this.behaviors[i];
if (b.beforeRegister) {
b.beforeRegister.call(this);
}
}
if (this.beforeRegister) {
this.beforeRegister();
}
}
this._registerFeatures(); // abstract
if (!settings.lazyRegister) {
this.ensureRegisterFinished();
}
},
createdCallback: function() {
if (settings.disableUpgradeEnabled) {
if (this.hasAttribute('disable-upgrade')) {
this._propertySetter = disableUpgradePropertySetter;
this._configValue = null;
this.__data__ = {};
return;
} else {
this.__hasInitialized = true;
}
}
this.__initialize();
},
__initialize: function() {
if (!this.__hasRegisterFinished) {
this._ensureRegisterFinished(this.__proto__);
}
Polymer.telemetry.instanceCount++;
this.root = this;
// this code was in a function but is unrolled here for perf
for (var i=0, b; i < this.behaviors.length; i++) {
b = this.behaviors[i];
if (b.created) {
b.created.call(this);
}
}
if (this.created) {
this.created();
}
this._initFeatures(); // abstract
},
/**
* As an optimization, when `Polymer.Settings.lazyRegister` is set to true
* registration tasks are deferred until the first instance of the element
* is created. If an element should not defer registration tasks until
* this time, `ensureRegisterFinished` may be called
* on the element's prototype.
*/
ensureRegisterFinished: function() {
this._ensureRegisterFinished(this);
},
_ensureRegisterFinished: function(proto) {
if (proto.__hasRegisterFinished !== proto.is || !proto.is) {
// apply behavior's beforeRegister at first instance time
// IFF `lazyRegister` is 'max'
if (settings.lazyRegister === 'max') {
proto._desugarBehaviors(); // abstract
// this code was in a function but is unrolled here for perf
for (var i=0, b; i < proto.behaviors.length; i++) {
b = proto.behaviors[i];
if (b.beforeRegister) {
b.beforeRegister.call(proto);
}
}
}
proto.__hasRegisterFinished = proto.is;
if (proto._finishRegisterFeatures) {
proto._finishRegisterFeatures();
}
// registration extension point
// this code was in a function but is unrolled here for perf
for (var j=0, pb; j < proto.behaviors.length; j++) {
pb = proto.behaviors[j];
if (pb.registered) {
pb.registered.call(proto);
}
}
if (proto.registered) {
proto.registered();
}
// where prototypes are simulated (IE10), element instance
// must be specfically fixed up.
if (settings.usePolyfillProto && proto !== this) {
proto.extend(this, proto);
}
}
},
// reserved for canonical behavior
attachedCallback: function() {
// NOTE: workaround for:
// https://code.google.com/p/chromium/issues/detail?id=516550
// To allow querying style/layout data in attached, we defer it
// until we are sure rendering is ready.
var self = this;
Polymer.RenderStatus.whenReady(function() {
self.isAttached = true;
// this code was in a function but is unrolled here for perf
for (var i=0, b; i < self.behaviors.length; i++) {
b = self.behaviors[i];
if (b.attached) {
b.attached.call(self);
}
}
if (self.attached) {
self.attached();
}
});
},
// reserved for canonical behavior
detachedCallback: function() {
// NOTE: duplicate attachedCallback behavior
var self = this;
Polymer.RenderStatus.whenReady(function() {
self.isAttached = false;
// this code was in a function but is unrolled here for perf
for (var i=0, b; i < self.behaviors.length; i++) {
b = self.behaviors[i];
if (b.detached) {
b.detached.call(self);
}
}
if (self.detached) {
self.detached();
}
});
},
// reserved for canonical behavior
attributeChangedCallback: function(name, oldValue, newValue) {
// TODO(sorvell): consider filtering out changes to host attributes
// note: this was barely measurable with 3 host attributes.
this._attributeChangedImpl(name); // abstract
// this code was in a function but is unrolled here for perf
for (var i=0, b; i < this.behaviors.length; i++) {
b = this.behaviors[i];
if (b.attributeChanged) {
b.attributeChanged.call(this, name, oldValue, newValue);
}
}
if (this.attributeChanged) {
this.attributeChanged(name, oldValue, newValue);
}
},
_attributeChangedImpl: function(name) {
this._setAttributeToProperty(this, name);
},
/**
* Copies own properties (including accessor descriptors) from a source
* object to a target object.
*
* @method extend
* @param {?Object} target Target object to copy properties to.
* @param {?Object} source Source object to copy properties from.
* @return {?Object} Target object that was passed as first argument or
* source object if the target was null.
*/
extend: function(target, source) {
if (target && source) {
var n$ = Object.getOwnPropertyNames(source);
for (var i=0, n; (i<n$.length) && (n=n$[i]); i++) {
this.copyOwnProperty(n, source, target);
}
}
return target || source;
},
/**
* Copies props from a source object to a target object.
*
* Note, this method uses a simple `for...in` strategy for enumerating
* properties. To ensure only `ownProperties` are copied from source
* to target and that accessor implementations are copied, use `extend`.
*
* @method mixin
* @param {!Object} target Target object to copy properties to.
* @param {?Object} source Source object to copy properties from.
* @return {!Object} Target object that was passed as first argument.
*/
mixin: function(target, source) {
for (var i in source) {
target[i] = source[i];
}
return target;
},
copyOwnProperty: function(name, source, target) {
var pd = Object.getOwnPropertyDescriptor(source, name);
if (pd) {
Object.defineProperty(target, name, pd);
}
},
_logger: function(level, args) {
// accept ['foo', 'bar'] and [['foo', 'bar']]
if (args.length === 1 && Array.isArray(args[0])) {
args = args[0];
}
// only accept logging functions
switch(level) {
case 'log':
case 'warn':
case 'error':
console[level].apply(console, args);
break;
}
},
_log: function() {
var args = Array.prototype.slice.call(arguments, 0);
this._logger('log', args);
},
_warn: function() {
var args = Array.prototype.slice.call(arguments, 0);
this._logger('warn', args);
},
_error: function() {
var args = Array.prototype.slice.call(arguments, 0);
this._logger('error', args);
},
_logf: function(/* args*/) {
return this._logPrefix.concat(this.is).concat(Array.prototype.slice.call(arguments, 0));
}
};
Polymer.Base._logPrefix = (function(){
// only Firefox, Chrome, and Safari support colors in console logging
var color = (window.chrome && !(/edge/i.test(navigator.userAgent))) || (/firefox/i.test(navigator.userAgent));
return color ? ['%c[%s::%s]:', 'font-weight: bold; background-color:#EEEE00;'] : ['[%s::%s]:'];
})();
Polymer.Base.chainObject = function(object, inherited) {
if (object && inherited && object !== inherited) {
if (!Object.__proto__) {
object = Polymer.Base.extend(Object.create(inherited), object);
}
object.__proto__ = inherited;
}
return object;
};
Polymer.Base = Polymer.Base.chainObject(Polymer.Base, HTMLElement.prototype);
Polymer.BaseDescriptors = {};
var disableUpgradePropertySetter;
if (settings.disableUpgradeEnabled) {
disableUpgradePropertySetter = function(property, value) {
this.__data__[property] = value;
}
var origAttributeChangedCallback = Polymer.Base.attributeChangedCallback;
Polymer.Base.attributeChangedCallback = function(name, oldValue, newValue) {
if (!this.__hasInitialized && name === 'disable-upgrade') {
this.__hasInitialized = true;
this._propertySetter = Polymer.Bind._modelApi._propertySetter;
this._configValue = Polymer.Base._configValue;
this.__initialize();
}
origAttributeChangedCallback.call(this, name, oldValue, newValue);
}
}
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__);
};
// TODO(sjmiles): ad hoc telemetry
Polymer.telemetry.instanceCount = 0;
})();
</script>