Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5966)

Unified Diff: chrome/browser/resources/md_downloads/crisper.js

Issue 1462153007: MD Downloads: fix up some Polymer 1.2.3 issues and re-vulcanize (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@update-polymer
Patch Set: new patchset Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | chrome/browser/resources/md_downloads/manager.css » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/resources/md_downloads/crisper.js
diff --git a/chrome/browser/resources/md_downloads/crisper.js b/chrome/browser/resources/md_downloads/crisper.js
index 49ea6974f7a2836f59d20dad47cf5299136340f7..da4452387f9851bc529b874c8665cd0736bb3498 100644
--- a/chrome/browser/resources/md_downloads/crisper.js
+++ b/chrome/browser/resources/md_downloads/crisper.js
@@ -1465,12 +1465,15 @@ function elide(original, maxLength) {
* @return {T} A non-null |condition|.
*/
function assert(condition, opt_message) {
- 'use strict';
if (!condition) {
- var msg = 'Assertion failed';
+ var message = 'Assertion failed';
if (opt_message)
- msg = msg + ': ' + opt_message;
- throw new Error(msg);
+ message = message + ': ' + opt_message;
+ var error = new Error(message);
+ var global = function() { return this; }();
+ if (global.traceAssertionsForTesting)
+ console.warn(error.stack);
+ throw error;
}
return condition;
}
@@ -1497,7 +1500,7 @@ function assert(condition, opt_message) {
* @param {string=} opt_message A message to show when this is hit.
*/
function assertNotReached(opt_message) {
- throw new Error(opt_message || 'Unreachable code hit');
+ assert(false, opt_message || 'Unreachable code hit');
}
/**
@@ -1508,10 +1511,8 @@ function assertNotReached(opt_message) {
* @template T
*/
function assertInstanceof(value, type, opt_message) {
- if (!(value instanceof type)) {
- throw new Error(opt_message ||
- value + ' is not a[n] ' + (type.name || typeof type));
- }
+ assert(value instanceof type,
+ opt_message || value + ' is not a[n] ' + (type.name || typeof type));
return value;
};
// Copyright 2015 The Chromium Authors. All rights reserved.
@@ -1804,10 +1805,11 @@ addEventListener('DOMContentLoaded', resolve);
window.Polymer = {
Settings: function () {
var user = window.Polymer || {};
-location.search.slice(1).split('&').forEach(function (o) {
+var parts = location.search.slice(1).split('&');
+for (var i = 0, o; i < parts.length && (o = parts[i]); i++) {
o = o.split('=');
o[0] && (user[o[0]] = o[1] || true);
-});
+}
var wantShadow = user.dom === 'shadow';
var hasShadow = Boolean(Element.prototype.createShadowRoot);
var nativeShadow = hasShadow && !window.ShadowDOMPolyfill;
@@ -1894,15 +1896,53 @@ this._callbacks.push(cb);
},
_makeReady: function () {
this._ready = true;
-this._callbacks.forEach(function (cb) {
-cb();
-});
+for (var i = 0; i < this._callbacks.length; i++) {
+this._callbacks[i]();
+}
this._callbacks = [];
},
_catchFirstRender: function () {
requestAnimationFrame(function () {
Polymer.RenderStatus._makeReady();
});
+},
+_afterNextRenderQueue: [],
+_waitingNextRender: false,
+afterNextRender: function (element, fn, args) {
+this._watchNextRender();
+this._afterNextRenderQueue.push([
+element,
+fn,
+args
+]);
+},
+_watchNextRender: function () {
+if (!this._waitingNextRender) {
+this._waitingNextRender = true;
+var fn = function () {
+Polymer.RenderStatus._flushNextRender();
+};
+if (!this._ready) {
+this.whenReady(fn);
+} else {
+requestAnimationFrame(fn);
+}
+}
+},
+_flushNextRender: function () {
+var self = this;
+setTimeout(function () {
+self._flushRenderCallbacks(self._afterNextRenderQueue);
+self._afterNextRenderQueue = [];
+self._waitingNextRender = false;
+});
+},
+_flushRenderCallbacks: function (callbacks) {
+for (var i = 0, h; i < callbacks.length; i++) {
+h = callbacks[i];
+h[1].apply(h[0], h[2] || Polymer.nar);
+}
+;
}
};
if (window.HTMLImports) {
@@ -1932,27 +1972,33 @@ this._doBehavior('created');
this._initFeatures();
},
attachedCallback: function () {
+var self = this;
Polymer.RenderStatus.whenReady(function () {
-this.isAttached = true;
-this._doBehavior('attached');
-}.bind(this));
+self.isAttached = true;
+self._doBehavior('attached');
+});
},
detachedCallback: function () {
this.isAttached = false;
this._doBehavior('detached');
},
-attributeChangedCallback: function (name) {
+attributeChangedCallback: function (name, oldValue, newValue) {
this._attributeChangedImpl(name);
-this._doBehavior('attributeChanged', arguments);
+this._doBehavior('attributeChanged', [
+name,
+oldValue,
+newValue
+]);
},
_attributeChangedImpl: function (name) {
this._setAttributeToProperty(this, name);
},
extend: function (prototype, api) {
if (prototype && api) {
-Object.getOwnPropertyNames(api).forEach(function (n) {
+var n$ = Object.getOwnPropertyNames(api);
+for (var i = 0, n; i < n$.length && (n = n$[i]); i++) {
this.copyOwnProperty(n, api, prototype);
-}, this);
+}
}
return prototype || api;
},
@@ -2030,7 +2076,7 @@ import: function (id, selector) {
if (id) {
var m = findModule(id);
if (!m) {
-forceDocumentUpgrade();
+forceDomModulesUpgrade();
m = findModule(id);
}
if (m && selector) {
@@ -2042,12 +2088,17 @@ return m;
});
var cePolyfill = window.CustomElements && !CustomElements.useNative;
document.registerElement('dom-module', DomModule);
-function forceDocumentUpgrade() {
+function forceDomModulesUpgrade() {
if (cePolyfill) {
var script = document._currentScript || document.currentScript;
-var doc = script && script.ownerDocument;
-if (doc) {
-CustomElements.upgradeAll(doc);
+var doc = script && script.ownerDocument || document;
+var modules = doc.querySelectorAll('dom-module');
+for (var i = modules.length - 1, m; i >= 0 && (m = modules[i]); i--) {
+if (m.__upgraded__) {
+return;
+} else {
+CustomElements.upgrade(m);
+}
}
}
}
@@ -2082,7 +2133,8 @@ return behaviors;
},
_flattenBehaviorsList: function (behaviors) {
var flat = [];
-behaviors.forEach(function (b) {
+for (var i = 0; i < behaviors.length; i++) {
+var b = behaviors[i];
if (b instanceof Array) {
flat = flat.concat(this._flattenBehaviorsList(b));
} else if (b) {
@@ -2090,31 +2142,16 @@ flat.push(b);
} else {
this._warn(this._logf('_flattenBehaviorsList', 'behavior is null, check for missing or 404 import'));
}
-}, this);
+}
return flat;
},
_mixinBehavior: function (b) {
-Object.getOwnPropertyNames(b).forEach(function (n) {
-switch (n) {
-case 'hostAttributes':
-case 'registered':
-case 'properties':
-case 'observers':
-case 'listeners':
-case 'created':
-case 'attached':
-case 'detached':
-case 'attributeChanged':
-case 'configure':
-case 'ready':
-break;
-default:
-if (!this.hasOwnProperty(n)) {
+var n$ = Object.getOwnPropertyNames(b);
+for (var i = 0, n; i < n$.length && (n = n$[i]); i++) {
+if (!Polymer.Base._behaviorProperties[n] && !this.hasOwnProperty(n)) {
this.copyOwnProperty(n, b, this);
}
-break;
}
-}, this);
},
_prepBehaviors: function () {
this._prepFlattenedBehaviors(this.behaviors);
@@ -2126,9 +2163,9 @@ this._prepBehavior(behaviors[i]);
this._prepBehavior(this);
},
_doBehavior: function (name, args) {
-this.behaviors.forEach(function (b) {
-this._invokeBehavior(b, name, args);
-}, this);
+for (var i = 0; i < this.behaviors.length; i++) {
+this._invokeBehavior(this.behaviors[i], name, args);
+}
this._invokeBehavior(this, name, args);
},
_invokeBehavior: function (b, name, args) {
@@ -2138,12 +2175,24 @@ fn.apply(this, args || Polymer.nar);
}
},
_marshalBehaviors: function () {
-this.behaviors.forEach(function (b) {
-this._marshalBehavior(b);
-}, this);
+for (var i = 0; i < this.behaviors.length; i++) {
+this._marshalBehavior(this.behaviors[i]);
+}
this._marshalBehavior(this);
}
});
+Polymer.Base._behaviorProperties = {
+hostAttributes: true,
+registered: true,
+properties: true,
+observers: true,
+listeners: true,
+created: true,
+attached: true,
+detached: true,
+attributeChanged: true,
+ready: true
+};
Polymer.Base._addFeature({
_getExtendedPrototype: function (tag) {
return this._getExtendedNativePrototype(tag);
@@ -2195,9 +2244,13 @@ properties: {},
getPropertyInfo: function (property) {
var info = this._getPropertyInfo(property, this.properties);
if (!info) {
-this.behaviors.some(function (b) {
-return info = this._getPropertyInfo(property, b.properties);
-}, this);
+for (var i = 0; i < this.behaviors.length; i++) {
+info = this._getPropertyInfo(property, this.behaviors[i].properties);
+if (info) {
+return info;
+}
+}
+;
}
return info || Polymer.nob;
},
@@ -2210,6 +2263,40 @@ if (p) {
p.defined = true;
}
return p;
+},
+_prepPropertyInfo: function () {
+this._propertyInfo = {};
+for (var i = 0, p; i < this.behaviors.length; i++) {
+this._addPropertyInfo(this._propertyInfo, this.behaviors[i].properties);
+}
+this._addPropertyInfo(this._propertyInfo, this.properties);
+this._addPropertyInfo(this._propertyInfo, this._propertyEffects);
+},
+_addPropertyInfo: function (target, source) {
+if (source) {
+var t, s;
+for (var i in source) {
+t = target[i];
+s = source[i];
+if (i[0] === '_' && !s.readOnly) {
+continue;
+}
+if (!target[i]) {
+target[i] = {
+type: typeof s === 'function' ? s : s.type,
+readOnly: s.readOnly,
+attribute: Polymer.CaseMap.camelToDashCase(i)
+};
+} else {
+if (!t.type) {
+t.type = s.type;
+}
+if (!t.readOnly) {
+t.readOnly = s.readOnly;
+}
+}
+}
+}
}
});
Polymer.CaseMap = {
@@ -2237,21 +2324,24 @@ return g[0] + '-' + g[1].toLowerCase();
}
};
Polymer.Base._addFeature({
-_prepAttributes: function () {
-this._aggregatedAttributes = {};
-},
_addHostAttributes: function (attributes) {
+if (!this._aggregatedAttributes) {
+this._aggregatedAttributes = {};
+}
if (attributes) {
this.mixin(this._aggregatedAttributes, attributes);
}
},
_marshalHostAttributes: function () {
+if (this._aggregatedAttributes) {
this._applyAttributes(this, this._aggregatedAttributes);
+}
},
_applyAttributes: function (node, attr$) {
for (var n in attr$) {
if (!this.hasAttribute(n) && n !== 'class') {
-this.serializeValueToAttribute(attr$[n], n, this);
+var v = attr$[n];
+this.serializeValueToAttribute(v, n, this);
}
}
},
@@ -2259,29 +2349,40 @@ _marshalAttributes: function () {
this._takeAttributesToModel(this);
},
_takeAttributesToModel: function (model) {
-for (var i = 0, l = this.attributes.length; i < l; i++) {
-this._setAttributeToProperty(model, this.attributes[i].name);
+if (this.hasAttributes()) {
+for (var i in this._propertyInfo) {
+var info = this._propertyInfo[i];
+if (this.hasAttribute(info.attribute)) {
+this._setAttributeToProperty(model, info.attribute, i, info);
+}
+}
}
},
-_setAttributeToProperty: function (model, attrName) {
+_setAttributeToProperty: function (model, attribute, property, info) {
if (!this._serializing) {
-var propName = Polymer.CaseMap.dashToCamelCase(attrName);
-var info = this.getPropertyInfo(propName);
-if (info.defined || this._propertyEffects && this._propertyEffects[propName]) {
-var val = this.getAttribute(attrName);
-model[propName] = this.deserialize(val, info.type);
+var property = property || Polymer.CaseMap.dashToCamelCase(attribute);
+info = info || this._propertyInfo && this._propertyInfo[property];
+if (info && !info.readOnly) {
+var v = this.getAttribute(attribute);
+model[property] = this.deserialize(v, info.type);
}
}
},
_serializing: false,
-reflectPropertyToAttribute: function (name) {
+reflectPropertyToAttribute: function (property, attribute, value) {
this._serializing = true;
-this.serializeValueToAttribute(this[name], Polymer.CaseMap.camelToDashCase(name));
+value = value === undefined ? this[property] : value;
+this.serializeValueToAttribute(value, attribute || Polymer.CaseMap.camelToDashCase(property));
this._serializing = false;
},
serializeValueToAttribute: function (value, attribute, node) {
var str = this.serialize(value);
-(node || this)[str === undefined ? 'removeAttribute' : 'setAttribute'](attribute, str);
+node = node || this;
+if (str === undefined) {
+node.removeAttribute(attribute);
+} else {
+node.setAttribute(attribute, str);
+}
},
deserialize: function (value, type) {
switch (type) {
@@ -2357,13 +2458,13 @@ debouncer.stop();
}
}
});
-Polymer.version = '1.1.5';
+Polymer.version = '1.2.3';
Polymer.Base._addFeature({
_registerFeatures: function () {
this._prepIs();
-this._prepAttributes();
this._prepBehaviors();
this._prepConstructor();
+this._prepPropertyInfo();
},
_prepBehavior: function (b) {
this._addHostAttributes(b.hostAttributes);
@@ -2378,13 +2479,14 @@ this._marshalBehaviors();
});
Polymer.Base._addFeature({
_prepTemplate: function () {
-this._template = this._template || Polymer.DomModule.import(this.is, 'template');
+if (this._template === undefined) {
+this._template = Polymer.DomModule.import(this.is, 'template');
+}
if (this._template && this._template.hasAttribute('is')) {
this._warn(this._logf('_prepTemplate', 'top-level Polymer template ' + 'must not be a type-extension, found', this._template, 'Move inside simple <template>.'));
}
-if (this._template && !this._template.content && HTMLTemplateElement.bootstrap) {
+if (this._template && !this._template.content && window.HTMLTemplateElement && HTMLTemplateElement.decorate) {
HTMLTemplateElement.decorate(this._template);
-HTMLTemplateElement.bootstrap(this._template.content);
}
},
_stampTemplate: function () {
@@ -2403,20 +2505,19 @@ Polymer.Base._addFeature({
_hostStack: [],
ready: function () {
},
-_pushHost: function (host) {
+_registerHost: function (host) {
this.dataHost = host = host || Polymer.Base._hostStack[Polymer.Base._hostStack.length - 1];
if (host && host._clients) {
host._clients.push(this);
}
-this._beginHost();
},
-_beginHost: function () {
+_beginHosting: function () {
Polymer.Base._hostStack.push(this);
if (!this._clients) {
this._clients = [];
}
},
-_popHost: function () {
+_endHosting: function () {
Polymer.Base._hostStack.pop();
},
_tryReady: function () {
@@ -2429,20 +2530,24 @@ return !this.dataHost || this.dataHost._clientsReadied;
},
_ready: function () {
this._beforeClientsReady();
+if (this._template) {
this._setupRoot();
this._readyClients();
+}
+this._clientsReadied = true;
+this._clients = null;
this._afterClientsReady();
this._readySelf();
},
_readyClients: function () {
this._beginDistribute();
var c$ = this._clients;
+if (c$) {
for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) {
c._ready();
}
+}
this._finishDistribute();
-this._clientsReadied = true;
-this._clients = null;
},
_readySelf: function () {
this._doBehavior('ready');
@@ -2638,61 +2743,6 @@ return currentValue === previousValue;
};
return new ArraySplice();
}();
-Polymer.EventApi = function () {
-var Settings = Polymer.Settings;
-var EventApi = function (event) {
-this.event = event;
-};
-if (Settings.useShadow) {
-EventApi.prototype = {
-get rootTarget() {
-return this.event.path[0];
-},
-get localTarget() {
-return this.event.target;
-},
-get path() {
-return this.event.path;
-}
-};
-} else {
-EventApi.prototype = {
-get rootTarget() {
-return this.event.target;
-},
-get localTarget() {
-var current = this.event.currentTarget;
-var currentRoot = current && Polymer.dom(current).getOwnerRoot();
-var p$ = this.path;
-for (var i = 0; i < p$.length; i++) {
-if (Polymer.dom(p$[i]).getOwnerRoot() === currentRoot) {
-return p$[i];
-}
-}
-},
-get path() {
-if (!this.event._path) {
-var path = [];
-var o = this.rootTarget;
-while (o) {
-path.push(o);
-o = Polymer.dom(o).parentNode || o.host;
-}
-path.push(window);
-this.event._path = path;
-}
-return this.event._path;
-}
-};
-}
-var factory = function (event) {
-if (!event.__eventApi) {
-event.__eventApi = new EventApi(event);
-}
-return event.__eventApi;
-};
-return { factory: factory };
-}();
Polymer.domInnerHTML = function () {
var escapeAttrRegExp = /[&\u00A0"]/g;
var escapeDataRegExp = /[&\u00A0<>]/g;
@@ -2800,24 +2850,31 @@ var nativeRemoveChild = Element.prototype.removeChild;
var nativeAppendChild = Element.prototype.appendChild;
var nativeCloneNode = Element.prototype.cloneNode;
var nativeImportNode = Document.prototype.importNode;
-var DomApi = function (node) {
-this.node = node;
-if (this.patch) {
-this.patch();
-}
+var needsToWrap = Settings.hasShadow && !Settings.nativeShadow;
+var wrap = window.wrap ? window.wrap : function (node) {
+return node;
};
-if (window.wrap && Settings.useShadow && !Settings.useNativeShadow) {
-DomApi = function (node) {
-this.node = wrap(node);
+var DomApi = function (node) {
+this.node = needsToWrap ? wrap(node) : node;
if (this.patch) {
this.patch();
}
};
-}
DomApi.prototype = {
flush: function () {
Polymer.dom.flush();
},
+deepContains: function (node) {
+if (this.node.contains(node)) {
+return true;
+}
+var n = node;
+var wrappedDocument = wrap(document);
+while (n && n !== wrappedDocument && n !== this.node) {
+n = Polymer.dom(n).parentNode || n.host;
+}
+return n === this.node;
+},
_lazyDistribute: function (host) {
if (host.shadyRoot && host.shadyRoot._distributionClean) {
host.shadyRoot._distributionClean = false;
@@ -2831,7 +2888,7 @@ insertBefore: function (node, ref_node) {
return this._addNode(node, ref_node);
},
_addNode: function (node, ref_node) {
-this._removeNodeFromHost(node, true);
+this._removeNodeFromParent(node);
var addedInsertionPoint;
var root = this.getOwnerRoot();
if (root) {
@@ -2863,6 +2920,7 @@ nativeAppendChild.call(container, node);
if (addedInsertionPoint) {
this._updateInsertionPoints(root.host);
}
+this.notifyObserver();
return node;
},
removeChild: function (node) {
@@ -2877,6 +2935,7 @@ removeFromComposedParent(container, node);
nativeRemoveChild.call(container, node);
}
}
+this.notifyObserver();
return node;
},
replaceChild: function (node, ref_node) {
@@ -2969,6 +3028,13 @@ return Boolean(node._lightChildren !== undefined);
_parentNeedsDistribution: function (parent) {
return parent && parent.shadyRoot && hasInsertionPoint(parent.shadyRoot);
},
+_removeNodeFromParent: function (node) {
+var parent = node._lightParent || node.parentNode;
+if (parent && hasDomApi(parent)) {
+factory(parent).notifyObserver();
+}
+this._removeNodeFromHost(node, true);
+},
_removeNodeFromHost: function (node, ensureComposedRemoval) {
var hostNeedsDist;
var root;
@@ -2980,7 +3046,7 @@ if (root) {
root.host._elementRemove(node);
hostNeedsDist = this._removeDistributedChildren(root, node);
}
-this._removeLogicalInfo(node, node._lightParent);
+this._removeLogicalInfo(node, parent);
}
this._removeOwnerShadyRoot(node);
if (root && hostNeedsDist) {
@@ -3028,7 +3094,7 @@ _addLogicalInfo: function (node, container, index) {
var children = factory(container).childNodes;
index = index === undefined ? children.length : index;
if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
-var c$ = Array.prototype.slice.call(node.childNodes);
+var c$ = arrayCopyChildNodes(node);
for (var i = 0, n; i < c$.length && (n = c$[i]); i++) {
children.splice(index++, 0, n);
n._lightParent = container;
@@ -3099,24 +3165,29 @@ getDistributedNodes: function () {
return this.node._distributedNodes || [];
},
queryDistributedElements: function (selector) {
-var c$ = this.childNodes;
+var c$ = this.getEffectiveChildNodes();
var list = [];
-this._distributedFilter(selector, c$, list);
for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) {
-if (c.localName === CONTENT) {
-this._distributedFilter(selector, factory(c).getDistributedNodes(), list);
+if (c.nodeType === Node.ELEMENT_NODE && matchesSelector.call(c, selector)) {
+list.push(c);
}
}
return list;
},
-_distributedFilter: function (selector, list, results) {
-results = results || [];
-for (var i = 0, l = list.length, d; i < l && (d = list[i]); i++) {
-if (d.nodeType === Node.ELEMENT_NODE && d.localName !== CONTENT && matchesSelector.call(d, selector)) {
-results.push(d);
+getEffectiveChildNodes: function () {
+var list = [];
+var c$ = this.childNodes;
+for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) {
+if (c.localName === CONTENT) {
+var d$ = factory(c).getDistributedNodes();
+for (var j = 0; j < d$.length; j++) {
+list.push(d$[j]);
+}
+} else {
+list.push(c);
}
}
-return results;
+return list;
},
_clear: function () {
while (this.childNodes.length) {
@@ -3160,36 +3231,24 @@ d.appendChild(nc);
}
}
return n;
+},
+observeNodes: function (callback) {
+if (callback) {
+if (!this.observer) {
+this.observer = this.node.localName === CONTENT ? new DomApi.DistributedNodesObserver(this) : new DomApi.EffectiveNodesObserver(this);
}
-};
-Object.defineProperty(DomApi.prototype, 'classList', {
-get: function () {
-if (!this._classList) {
-this._classList = new DomApi.ClassList(this);
+return this.observer.addListener(callback);
}
-return this._classList;
},
-configurable: true
-});
-DomApi.ClassList = function (host) {
-this.domApi = host;
-this.node = host.node;
-};
-DomApi.ClassList.prototype = {
-add: function () {
-this.node.classList.add.apply(this.node.classList, arguments);
-this.domApi._distributeParent();
-},
-remove: function () {
-this.node.classList.remove.apply(this.node.classList, arguments);
-this.domApi._distributeParent();
-},
-toggle: function () {
-this.node.classList.toggle.apply(this.node.classList, arguments);
-this.domApi._distributeParent();
+unobserveNodes: function (handle) {
+if (this.observer) {
+this.observer.removeListener(handle);
+}
},
-contains: function () {
-return this.node.classList.contains.apply(this.node.classList, arguments);
+notifyObserver: function () {
+if (this.observer) {
+this.observer.notify();
+}
}
};
if (!Settings.useShadow) {
@@ -3197,7 +3256,7 @@ Object.defineProperties(DomApi.prototype, {
childNodes: {
get: function () {
var c$ = getLightChildren(this.node);
-return Array.isArray(c$) ? c$ : Array.prototype.slice.call(c$);
+return Array.isArray(c$) ? c$ : arrayCopyChildNodes(this.node);
},
configurable: true
},
@@ -3320,7 +3379,7 @@ if (nt !== Node.TEXT_NODE || nt !== Node.COMMENT_NODE) {
this._clear();
var d = document.createElement('div');
d.innerHTML = text;
-var c$ = Array.prototype.slice.call(d.childNodes);
+var c$ = arrayCopyChildNodes(d);
for (var i = 0; i < c$.length; i++) {
this.appendChild(c$[i]);
}
@@ -3333,20 +3392,25 @@ DomApi.prototype._getComposedInnerHTML = function () {
return getInnerHTML(this.node, true);
};
} else {
-var forwardMethods = [
+var forwardMethods = function (m$) {
+for (var i = 0; i < m$.length; i++) {
+forwardMethod(m$[i]);
+}
+};
+var forwardMethod = function (method) {
+DomApi.prototype[method] = function () {
+return this.node[method].apply(this.node, arguments);
+};
+};
+forwardMethods([
'cloneNode',
'appendChild',
'insertBefore',
'removeChild',
'replaceChild'
-];
-forwardMethods.forEach(function (name) {
-DomApi.prototype[name] = function () {
-return this.node[name].apply(this.node, arguments);
-};
-});
+]);
DomApi.prototype.querySelectorAll = function (selector) {
-return Array.prototype.slice.call(this.node.querySelectorAll(selector));
+return arrayCopy(this.node.querySelectorAll(selector));
};
DomApi.prototype.getOwnerRoot = function () {
var n = this.node;
@@ -3363,24 +3427,24 @@ return doc.importNode(externalNode, deep);
};
DomApi.prototype.getDestinationInsertionPoints = function () {
var n$ = this.node.getDestinationInsertionPoints && this.node.getDestinationInsertionPoints();
-return n$ ? Array.prototype.slice.call(n$) : [];
+return n$ ? arrayCopy(n$) : [];
};
DomApi.prototype.getDistributedNodes = function () {
var n$ = this.node.getDistributedNodes && this.node.getDistributedNodes();
-return n$ ? Array.prototype.slice.call(n$) : [];
+return n$ ? arrayCopy(n$) : [];
};
DomApi.prototype._distributeParent = function () {
};
Object.defineProperties(DomApi.prototype, {
childNodes: {
get: function () {
-return Array.prototype.slice.call(this.node.childNodes);
+return arrayCopyChildNodes(this.node);
},
configurable: true
},
children: {
get: function () {
-return Array.prototype.slice.call(this.node.children);
+return arrayCopyChildren(this.node);
},
configurable: true
},
@@ -3403,7 +3467,20 @@ return this.node.innerHTML = value;
configurable: true
}
});
-var forwardProperties = [
+var forwardProperties = function (f$) {
+for (var i = 0; i < f$.length; i++) {
+forwardProperty(f$[i]);
+}
+};
+var forwardProperty = function (name) {
+Object.defineProperty(DomApi.prototype, name, {
+get: function () {
+return this.node[name];
+},
+configurable: true
+});
+};
+forwardProperties([
'parentNode',
'firstChild',
'lastChild',
@@ -3413,24 +3490,21 @@ var forwardProperties = [
'lastElementChild',
'nextElementSibling',
'previousElementSibling'
-];
-forwardProperties.forEach(function (name) {
-Object.defineProperty(DomApi.prototype, name, {
-get: function () {
-return this.node[name];
-},
-configurable: true
-});
-});
+]);
}
var CONTENT = 'content';
-var factory = function (node, patch) {
+function factory(node, patch) {
node = node || document;
if (!node.__domApi) {
node.__domApi = new DomApi(node, patch);
}
return node.__domApi;
-};
+}
+;
+function hasDomApi(node) {
+return Boolean(node.__domApi);
+}
+;
Polymer.dom = function (obj, patch) {
if (obj instanceof Event) {
return Polymer.EventApi.factory(obj);
@@ -3438,50 +3512,13 @@ return Polymer.EventApi.factory(obj);
return factory(obj, patch);
}
};
-Polymer.Base.extend(Polymer.dom, {
-_flushGuard: 0,
-_FLUSH_MAX: 100,
-_needsTakeRecords: !Polymer.Settings.useNativeCustomElements,
-_debouncers: [],
-_finishDebouncer: null,
-flush: function () {
-for (var i = 0; i < this._debouncers.length; i++) {
-this._debouncers[i].complete();
-}
-if (this._finishDebouncer) {
-this._finishDebouncer.complete();
-}
-this._flushPolyfills();
-if (this._debouncers.length && this._flushGuard < this._FLUSH_MAX) {
-this._flushGuard++;
-this.flush();
-} else {
-if (this._flushGuard >= this._FLUSH_MAX) {
-console.warn('Polymer.dom.flush aborted. Flush may not be complete.');
-}
-this._flushGuard = 0;
-}
-},
-_flushPolyfills: function () {
-if (this._needsTakeRecords) {
-CustomElements.takeRecords();
-}
-},
-addDebouncer: function (debouncer) {
-this._debouncers.push(debouncer);
-this._finishDebouncer = Polymer.Debounce(this._finishDebouncer, this._finishFlush);
-},
-_finishFlush: function () {
-Polymer.dom._debouncers = [];
-}
-});
function getLightChildren(node) {
var children = node._lightChildren;
return children ? children : node.childNodes;
}
function getComposedChildren(node) {
if (!node._composedChildren) {
-node._composedChildren = Array.prototype.slice.call(node.childNodes);
+node._composedChildren = arrayCopyChildNodes(node);
}
return node._composedChildren;
}
@@ -3517,13 +3554,35 @@ children.splice(i, 1);
}
function saveLightChildrenIfNeeded(node) {
if (!node._lightChildren) {
-var c$ = Array.prototype.slice.call(node.childNodes);
+var c$ = arrayCopyChildNodes(node);
for (var i = 0, l = c$.length, child; i < l && (child = c$[i]); i++) {
child._lightParent = child._lightParent || node;
}
node._lightChildren = c$;
}
}
+function arrayCopyChildNodes(parent) {
+var copy = [], i = 0;
+for (var n = parent.firstChild; n; n = n.nextSibling) {
+copy[i++] = n;
+}
+return copy;
+}
+function arrayCopyChildren(parent) {
+var copy = [], i = 0;
+for (var n = parent.firstElementChild; n; n = n.nextElementSibling) {
+copy[i++] = n;
+}
+return copy;
+}
+function arrayCopy(a$) {
+var l = a$.length;
+var copy = new Array(l);
+for (var i = 0; i < l; i++) {
+copy[i] = a$[i];
+}
+return copy;
+}
function hasInsertionPoint(root) {
return Boolean(root && root._insertionPoints.length);
}
@@ -3538,15 +3597,416 @@ saveLightChildrenIfNeeded: saveLightChildrenIfNeeded,
matchesSelector: matchesSelector,
hasInsertionPoint: hasInsertionPoint,
ctor: DomApi,
-factory: factory
+factory: factory,
+hasDomApi: hasDomApi,
+arrayCopy: arrayCopy,
+arrayCopyChildNodes: arrayCopyChildNodes,
+arrayCopyChildren: arrayCopyChildren,
+wrap: wrap
};
}();
-(function () {
-Polymer.Base._addFeature({
-_prepShady: function () {
-this._useContent = this._useContent || Boolean(this._template);
-},
-_poolContent: function () {
+Polymer.Base.extend(Polymer.dom, {
+_flushGuard: 0,
+_FLUSH_MAX: 100,
+_needsTakeRecords: !Polymer.Settings.useNativeCustomElements,
+_debouncers: [],
+_staticFlushList: [],
+_finishDebouncer: null,
+flush: function () {
+this._flushGuard = 0;
+this._prepareFlush();
+while (this._debouncers.length && this._flushGuard < this._FLUSH_MAX) {
+for (var i = 0; i < this._debouncers.length; i++) {
+this._debouncers[i].complete();
+}
+if (this._finishDebouncer) {
+this._finishDebouncer.complete();
+}
+this._prepareFlush();
+this._flushGuard++;
+}
+if (this._flushGuard >= this._FLUSH_MAX) {
+console.warn('Polymer.dom.flush aborted. Flush may not be complete.');
+}
+},
+_prepareFlush: function () {
+if (this._needsTakeRecords) {
+CustomElements.takeRecords();
+}
+for (var i = 0; i < this._staticFlushList.length; i++) {
+this._staticFlushList[i]();
+}
+},
+addStaticFlush: function (fn) {
+this._staticFlushList.push(fn);
+},
+removeStaticFlush: function (fn) {
+var i = this._staticFlushList.indexOf(fn);
+if (i >= 0) {
+this._staticFlushList.splice(i, 1);
+}
+},
+addDebouncer: function (debouncer) {
+this._debouncers.push(debouncer);
+this._finishDebouncer = Polymer.Debounce(this._finishDebouncer, this._finishFlush);
+},
+_finishFlush: function () {
+Polymer.dom._debouncers = [];
+}
+});
+Polymer.EventApi = function () {
+'use strict';
+var DomApi = Polymer.DomApi.ctor;
+var Settings = Polymer.Settings;
+DomApi.Event = function (event) {
+this.event = event;
+};
+if (Settings.useShadow) {
+DomApi.Event.prototype = {
+get rootTarget() {
+return this.event.path[0];
+},
+get localTarget() {
+return this.event.target;
+},
+get path() {
+return this.event.path;
+}
+};
+} else {
+DomApi.Event.prototype = {
+get rootTarget() {
+return this.event.target;
+},
+get localTarget() {
+var current = this.event.currentTarget;
+var currentRoot = current && Polymer.dom(current).getOwnerRoot();
+var p$ = this.path;
+for (var i = 0; i < p$.length; i++) {
+if (Polymer.dom(p$[i]).getOwnerRoot() === currentRoot) {
+return p$[i];
+}
+}
+},
+get path() {
+if (!this.event._path) {
+var path = [];
+var o = this.rootTarget;
+while (o) {
+path.push(o);
+o = Polymer.dom(o).parentNode || o.host;
+}
+path.push(window);
+this.event._path = path;
+}
+return this.event._path;
+}
+};
+}
+var factory = function (event) {
+if (!event.__eventApi) {
+event.__eventApi = new DomApi.Event(event);
+}
+return event.__eventApi;
+};
+return { factory: factory };
+}();
+(function () {
+'use strict';
+var DomApi = Polymer.DomApi.ctor;
+Object.defineProperty(DomApi.prototype, 'classList', {
+get: function () {
+if (!this._classList) {
+this._classList = new DomApi.ClassList(this);
+}
+return this._classList;
+},
+configurable: true
+});
+DomApi.ClassList = function (host) {
+this.domApi = host;
+this.node = host.node;
+};
+DomApi.ClassList.prototype = {
+add: function () {
+this.node.classList.add.apply(this.node.classList, arguments);
+this.domApi._distributeParent();
+},
+remove: function () {
+this.node.classList.remove.apply(this.node.classList, arguments);
+this.domApi._distributeParent();
+},
+toggle: function () {
+this.node.classList.toggle.apply(this.node.classList, arguments);
+this.domApi._distributeParent();
+},
+contains: function () {
+return this.node.classList.contains.apply(this.node.classList, arguments);
+}
+};
+}());
+(function () {
+'use strict';
+var DomApi = Polymer.DomApi.ctor;
+var Settings = Polymer.Settings;
+var hasDomApi = Polymer.DomApi.hasDomApi;
+DomApi.EffectiveNodesObserver = function (domApi) {
+this.domApi = domApi;
+this.node = this.domApi.node;
+this._listeners = [];
+};
+DomApi.EffectiveNodesObserver.prototype = {
+addListener: function (callback) {
+if (!this._isSetup) {
+this._setup();
+this._isSetup = true;
+}
+var listener = {
+fn: callback,
+_nodes: []
+};
+this._listeners.push(listener);
+this._scheduleNotify();
+return listener;
+},
+removeListener: function (handle) {
+var i = this._listeners.indexOf(handle);
+if (i >= 0) {
+this._listeners.splice(i, 1);
+handle._nodes = [];
+}
+if (!this._hasListeners()) {
+this._cleanup();
+this._isSetup = false;
+}
+},
+_setup: function () {
+this._observeContentElements(this.domApi.childNodes);
+},
+_cleanup: function () {
+this._unobserveContentElements(this.domApi.childNodes);
+},
+_hasListeners: function () {
+return Boolean(this._listeners.length);
+},
+_scheduleNotify: function () {
+if (this._debouncer) {
+this._debouncer.stop();
+}
+this._debouncer = Polymer.Debounce(this._debouncer, this._notify);
+this._debouncer.context = this;
+Polymer.dom.addDebouncer(this._debouncer);
+},
+notify: function () {
+if (this._hasListeners()) {
+this._scheduleNotify();
+}
+},
+_notify: function (mxns) {
+this._beforeCallListeners();
+this._callListeners();
+},
+_beforeCallListeners: function () {
+this._updateContentElements();
+},
+_updateContentElements: function () {
+this._observeContentElements(this.domApi.childNodes);
+},
+_observeContentElements: function (elements) {
+for (var i = 0, n; i < elements.length && (n = elements[i]); i++) {
+if (this._isContent(n)) {
+n.__observeNodesMap = n.__observeNodesMap || new WeakMap();
+if (!n.__observeNodesMap.has(this)) {
+n.__observeNodesMap.set(this, this._observeContent(n));
+}
+}
+}
+},
+_observeContent: function (content) {
+var self = this;
+var h = Polymer.dom(content).observeNodes(function () {
+self._scheduleNotify();
+});
+h._avoidChangeCalculation = true;
+return h;
+},
+_unobserveContentElements: function (elements) {
+for (var i = 0, n, h; i < elements.length && (n = elements[i]); i++) {
+if (this._isContent(n)) {
+h = n.__observeNodesMap.get(this);
+if (h) {
+Polymer.dom(n).unobserveNodes(h);
+n.__observeNodesMap.delete(this);
+}
+}
+}
+},
+_isContent: function (node) {
+return node.localName === 'content';
+},
+_callListeners: function () {
+var o$ = this._listeners;
+var nodes = this._getEffectiveNodes();
+for (var i = 0, o; i < o$.length && (o = o$[i]); i++) {
+var info = this._generateListenerInfo(o, nodes);
+if (info || o._alwaysNotify) {
+this._callListener(o, info);
+}
+}
+},
+_getEffectiveNodes: function () {
+return this.domApi.getEffectiveChildNodes();
+},
+_generateListenerInfo: function (listener, newNodes) {
+if (listener._avoidChangeCalculation) {
+return true;
+}
+var oldNodes = listener._nodes;
+var info = {
+target: this.node,
+addedNodes: [],
+removedNodes: []
+};
+var splices = Polymer.ArraySplice.calculateSplices(newNodes, oldNodes);
+for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
+for (var j = 0, n; j < s.removed.length && (n = s.removed[j]); j++) {
+info.removedNodes.push(n);
+}
+}
+for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
+for (var j = s.index; j < s.index + s.addedCount; j++) {
+info.addedNodes.push(newNodes[j]);
+}
+}
+listener._nodes = newNodes;
+if (info.addedNodes.length || info.removedNodes.length) {
+return info;
+}
+},
+_callListener: function (listener, info) {
+return listener.fn.call(this.node, info);
+},
+enableShadowAttributeTracking: function () {
+}
+};
+if (Settings.useShadow) {
+var baseSetup = DomApi.EffectiveNodesObserver.prototype._setup;
+var baseCleanup = DomApi.EffectiveNodesObserver.prototype._cleanup;
+var beforeCallListeners = DomApi.EffectiveNodesObserver.prototype._beforeCallListeners;
+Polymer.Base.extend(DomApi.EffectiveNodesObserver.prototype, {
+_setup: function () {
+if (!this._observer) {
+var self = this;
+this._mutationHandler = function (mxns) {
+if (mxns && mxns.length) {
+self._scheduleNotify();
+}
+};
+this._observer = new MutationObserver(this._mutationHandler);
+this._boundFlush = function () {
+self._flush();
+};
+Polymer.dom.addStaticFlush(this._boundFlush);
+this._observer.observe(this.node, { childList: true });
+}
+baseSetup.call(this);
+},
+_cleanup: function () {
+this._observer.disconnect();
+this._observer = null;
+this._mutationHandler = null;
+Polymer.dom.removeStaticFlush(this._boundFlush);
+baseCleanup.call(this);
+},
+_flush: function () {
+if (this._observer) {
+this._mutationHandler(this._observer.takeRecords());
+}
+},
+enableShadowAttributeTracking: function () {
+if (this._observer) {
+this._makeContentListenersAlwaysNotify();
+this._observer.disconnect();
+this._observer.observe(this.node, {
+childList: true,
+attributes: true,
+subtree: true
+});
+var root = this.domApi.getOwnerRoot();
+var host = root && root.host;
+if (host && Polymer.dom(host).observer) {
+Polymer.dom(host).observer.enableShadowAttributeTracking();
+}
+}
+},
+_makeContentListenersAlwaysNotify: function () {
+for (var i = 0, h; i < this._listeners.length; i++) {
+h = this._listeners[i];
+h._alwaysNotify = h._isContentListener;
+}
+}
+});
+}
+}());
+(function () {
+'use strict';
+var DomApi = Polymer.DomApi.ctor;
+var Settings = Polymer.Settings;
+DomApi.DistributedNodesObserver = function (domApi) {
+DomApi.EffectiveNodesObserver.call(this, domApi);
+};
+DomApi.DistributedNodesObserver.prototype = Object.create(DomApi.EffectiveNodesObserver.prototype);
+Polymer.Base.extend(DomApi.DistributedNodesObserver.prototype, {
+_setup: function () {
+},
+_cleanup: function () {
+},
+_beforeCallListeners: function () {
+},
+_getEffectiveNodes: function () {
+return this.domApi.getDistributedNodes();
+}
+});
+if (Settings.useShadow) {
+Polymer.Base.extend(DomApi.DistributedNodesObserver.prototype, {
+_setup: function () {
+if (!this._observer) {
+var root = this.domApi.getOwnerRoot();
+var host = root && root.host;
+if (host) {
+var self = this;
+this._observer = Polymer.dom(host).observeNodes(function () {
+self._scheduleNotify();
+});
+this._observer._isContentListener = true;
+if (this._hasAttrSelect()) {
+Polymer.dom(host).observer.enableShadowAttributeTracking();
+}
+}
+}
+},
+_hasAttrSelect: function () {
+var select = this.node.getAttribute('select');
+return select && select.match(/[[.]+/);
+},
+_cleanup: function () {
+var root = this.domApi.getOwnerRoot();
+var host = root && root.host;
+if (host) {
+Polymer.dom(host).unobserveNodes(this._observer);
+}
+this._observer = null;
+}
+});
+}
+}());
+(function () {
+var hasDomApi = Polymer.DomApi.hasDomApi;
+Polymer.Base._addFeature({
+_prepShady: function () {
+this._useContent = this._useContent || Boolean(this._template);
+},
+_poolContent: function () {
if (this._useContent) {
saveLightChildrenIfNeeded(this);
}
@@ -3562,6 +4022,7 @@ upgradeLightChildren(this._lightChildren);
_createLocalRoot: function () {
this.shadyRoot = this.root;
this.shadyRoot._distributionClean = false;
+this.shadyRoot._hasDistributed = false;
this.shadyRoot._isShadyRoot = true;
this.shadyRoot._dirtyRoots = [];
var i$ = this.shadyRoot._insertionPoints = !this._notes || this._notes._hasContent ? this.shadyRoot.querySelectorAll('content') : [];
@@ -3612,6 +4073,7 @@ if (this._useContent) {
this.shadyRoot._distributionClean = true;
if (hasInsertionPoint(this.shadyRoot)) {
this._composeTree();
+notifyContentObservers(this.shadyRoot);
} else {
if (!this.shadyRoot._hasDistributed) {
this.textContent = '';
@@ -3622,6 +4084,9 @@ var children = this._composeNode(this);
this._updateChildNodes(this, children);
}
}
+if (!this.shadyRoot._hasDistributed) {
+notifyInitialDistribution(this);
+}
this.shadyRoot._hasDistributed = true;
}
},
@@ -3839,6 +4304,19 @@ return host.domHost;
}
}
}
+function notifyContentObservers(root) {
+for (var i = 0, c; i < root._insertionPoints.length; i++) {
+c = root._insertionPoints[i];
+if (hasDomApi(c)) {
+Polymer.dom(c).notifyObserver();
+}
+}
+}
+function notifyInitialDistribution(host) {
+if (hasDomApi(host)) {
+Polymer.dom(host).notifyObserver();
+}
+}
var needsUpgrade = window.CustomElements && !CustomElements.useNative;
function upgradeLightChildren(children) {
if (needsUpgrade && children) {
@@ -3871,20 +4349,23 @@ Polymer.DomModule = document.createElement('dom-module');
Polymer.Base._addFeature({
_registerFeatures: function () {
this._prepIs();
-this._prepAttributes();
this._prepBehaviors();
this._prepConstructor();
this._prepTemplate();
this._prepShady();
+this._prepPropertyInfo();
},
_prepBehavior: function (b) {
this._addHostAttributes(b.hostAttributes);
},
_initFeatures: function () {
+this._registerHost();
+if (this._template) {
this._poolContent();
-this._pushHost();
+this._beginHosting();
this._stampTemplate();
-this._popHost();
+this._endHosting();
+}
this._marshalHostAttributes();
this._setupDebouncers();
this._marshalBehaviors();
@@ -3898,35 +4379,79 @@ Polymer.Annotations = {
parseAnnotations: function (template) {
var list = [];
var content = template._content || template.content;
-this._parseNodeAnnotations(content, list);
+this._parseNodeAnnotations(content, list, template.hasAttribute('strip-whitespace'));
return list;
},
-_parseNodeAnnotations: function (node, list) {
-return node.nodeType === Node.TEXT_NODE ? this._parseTextNodeAnnotation(node, list) : this._parseElementAnnotations(node, list);
+_parseNodeAnnotations: function (node, list, stripWhiteSpace) {
+return node.nodeType === Node.TEXT_NODE ? this._parseTextNodeAnnotation(node, list) : this._parseElementAnnotations(node, list, stripWhiteSpace);
},
-_testEscape: function (value) {
-var escape = value.slice(0, 2);
-if (escape === '{{' || escape === '[[') {
-return escape;
+_bindingRegex: /([^{[]*)(\{\{|\[\[)(?!\}\}|\]\])(.+?)(?:\]\]|\}\})/g,
+_parseBindings: function (text) {
+var re = this._bindingRegex;
+var parts = [];
+var m, lastIndex;
+while ((m = re.exec(text)) !== null) {
+if (m[1]) {
+parts.push({ literal: m[1] });
+}
+var mode = m[2][0];
+var value = m[3].trim();
+var negate = false;
+if (value[0] == '!') {
+negate = true;
+value = value.substring(1).trim();
+}
+var customEvent, notifyEvent, colon;
+if (mode == '{' && (colon = value.indexOf('::')) > 0) {
+notifyEvent = value.substring(colon + 2);
+value = value.substring(0, colon);
+customEvent = true;
+}
+parts.push({
+compoundIndex: parts.length,
+value: value,
+mode: mode,
+negate: negate,
+event: notifyEvent,
+customEvent: customEvent
+});
+lastIndex = re.lastIndex;
+}
+if (lastIndex && lastIndex < text.length) {
+var literal = text.substring(lastIndex);
+if (literal) {
+parts.push({ literal: literal });
+}
+}
+if (parts.length) {
+return parts;
}
},
+_literalFromParts: function (parts) {
+var s = '';
+for (var i = 0; i < parts.length; i++) {
+var literal = parts[i].literal;
+s += literal || '';
+}
+return s;
+},
_parseTextNodeAnnotation: function (node, list) {
-var v = node.textContent;
-var escape = this._testEscape(v);
-if (escape) {
-node.textContent = ' ';
+var parts = this._parseBindings(node.textContent);
+if (parts) {
+node.textContent = this._literalFromParts(parts) || ' ';
var annote = {
bindings: [{
kind: 'text',
-mode: escape[0],
-value: v.slice(2, -2).trim()
+name: 'textContent',
+parts: parts,
+isCompound: parts.length !== 1
}]
};
list.push(annote);
return annote;
}
},
-_parseElementAnnotations: function (element, list) {
+_parseElementAnnotations: function (element, list, stripWhiteSpace) {
var annote = {
bindings: [],
events: []
@@ -3934,7 +4459,7 @@ events: []
if (element.localName === 'content') {
list._hasContent = true;
}
-this._parseChildNodesAnnotations(element, annote, list);
+this._parseChildNodesAnnotations(element, annote, list, stripWhiteSpace);
if (element.attributes) {
this._parseNodeAttributeAnnotations(element, annote, list);
if (this.prepElement) {
@@ -3946,26 +4471,38 @@ list.push(annote);
}
return annote;
},
-_parseChildNodesAnnotations: function (root, annote, list, callback) {
+_parseChildNodesAnnotations: function (root, annote, list, stripWhiteSpace) {
if (root.firstChild) {
-for (var i = 0, node = root.firstChild; node; node = node.nextSibling, i++) {
+var node = root.firstChild;
+var i = 0;
+while (node) {
+var next = node.nextSibling;
if (node.localName === 'template' && !node.hasAttribute('preserve-content')) {
this._parseTemplate(node, i, list, annote);
}
if (node.nodeType === Node.TEXT_NODE) {
-var n = node.nextSibling;
+var n = next;
while (n && n.nodeType === Node.TEXT_NODE) {
node.textContent += n.textContent;
+next = n.nextSibling;
root.removeChild(n);
-n = n.nextSibling;
+n = next;
+}
+if (stripWhiteSpace && !node.textContent.trim()) {
+root.removeChild(node);
+i--;
}
}
-var childAnnotation = this._parseNodeAnnotations(node, list, callback);
+if (node.parentNode) {
+var childAnnotation = this._parseNodeAnnotations(node, list, stripWhiteSpace);
if (childAnnotation) {
childAnnotation.parent = annote;
childAnnotation.index = i;
}
}
+node = next;
+i++;
+}
}
},
_parseTemplate: function (node, index, list, parent) {
@@ -3981,62 +4518,50 @@ index: index
});
},
_parseNodeAttributeAnnotations: function (node, annotation) {
-for (var i = node.attributes.length - 1, a; a = node.attributes[i]; i--) {
-var n = a.name, v = a.value;
-if (n === 'id' && !this._testEscape(v)) {
-annotation.id = v;
-} else if (n.slice(0, 3) === 'on-') {
+var attrs = Array.prototype.slice.call(node.attributes);
+for (var i = attrs.length - 1, a; a = attrs[i]; i--) {
+var n = a.name;
+var v = a.value;
+var b;
+if (n.slice(0, 3) === 'on-') {
node.removeAttribute(n);
annotation.events.push({
name: n.slice(3),
value: v
});
-} else {
-var b = this._parseNodeAttributeAnnotation(node, n, v);
-if (b) {
+} else if (b = this._parseNodeAttributeAnnotation(node, n, v)) {
annotation.bindings.push(b);
-}
+} else if (n === 'id') {
+annotation.id = v;
}
}
},
-_parseNodeAttributeAnnotation: function (node, n, v) {
-var escape = this._testEscape(v);
-if (escape) {
-var customEvent;
-var name = n;
-var mode = escape[0];
-v = v.slice(2, -2).trim();
-var not = false;
-if (v[0] == '!') {
-v = v.substring(1);
-not = true;
-}
+_parseNodeAttributeAnnotation: function (node, name, value) {
+var parts = this._parseBindings(value);
+if (parts) {
+var origName = name;
var kind = 'property';
-if (n[n.length - 1] == '$') {
-name = n.slice(0, -1);
+if (name[name.length - 1] == '$') {
+name = name.slice(0, -1);
kind = 'attribute';
}
-var notifyEvent, colon;
-if (mode == '{' && (colon = v.indexOf('::')) > 0) {
-notifyEvent = v.substring(colon + 2);
-v = v.substring(0, colon);
-customEvent = true;
+var literal = this._literalFromParts(parts);
+if (literal && kind == 'attribute') {
+node.setAttribute(name, literal);
}
-if (node.localName == 'input' && n == 'value') {
-node.setAttribute(n, '');
+if (node.localName == 'input' && name == 'value') {
+node.setAttribute(origName, '');
}
-node.removeAttribute(n);
+node.removeAttribute(origName);
if (kind === 'property') {
name = Polymer.CaseMap.dashToCamelCase(name);
}
return {
kind: kind,
-mode: mode,
name: name,
-value: v,
-negate: not,
-event: notifyEvent,
-customEvent: customEvent
+parts: parts,
+literal: literal,
+isCompound: parts.length !== 1
};
}
},
@@ -4112,7 +4637,10 @@ _prepAnnotations: function () {
if (!this._template) {
this._notes = [];
} else {
-Polymer.Annotations.prepElement = this._prepElement.bind(this);
+var self = this;
+Polymer.Annotations.prepElement = function (element) {
+self._prepElement(element);
+};
if (this._template._content && this._template._content._notes) {
this._notes = this._template._content._notes;
} else {
@@ -4127,9 +4655,14 @@ for (var i = 0; i < notes.length; i++) {
var note = notes[i];
for (var j = 0; j < note.bindings.length; j++) {
var b = note.bindings[j];
-b.signature = this._parseMethod(b.value);
-if (!b.signature) {
-b.model = this._modelForPath(b.value);
+for (var k = 0; k < b.parts.length; k++) {
+var p = b.parts[k];
+if (!p.literal) {
+p.signature = this._parseMethod(p.value);
+if (!p.signature) {
+p.model = this._modelForPath(p.value);
+}
+}
}
}
if (note.templateContent) {
@@ -4140,10 +4673,12 @@ for (var prop in pp) {
bindings.push({
index: note.index,
kind: 'property',
-mode: '{',
name: '_parent_' + prop,
+parts: [{
+mode: '{',
model: prop,
value: prop
+}]
});
}
note.bindings = note.bindings.concat(bindings);
@@ -4152,22 +4687,24 @@ note.bindings = note.bindings.concat(bindings);
},
_discoverTemplateParentProps: function (notes) {
var pp = {};
-notes.forEach(function (n) {
-n.bindings.forEach(function (b) {
-if (b.signature) {
-var args = b.signature.args;
-for (var k = 0; k < args.length; k++) {
-pp[args[k].model] = true;
+for (var i = 0, n; i < notes.length && (n = notes[i]); i++) {
+for (var j = 0, b$ = n.bindings, b; j < b$.length && (b = b$[j]); j++) {
+for (var k = 0, p$ = b.parts, p; k < p$.length && (p = p$[k]); k++) {
+if (p.signature) {
+var args = p.signature.args;
+for (var kk = 0; kk < args.length; kk++) {
+pp[args[kk].model] = true;
}
} else {
-pp[b.model] = true;
+pp[p.model] = true;
+}
+}
}
-});
if (n.templateContent) {
var tpp = n.templateContent._parentProps;
Polymer.Base.mixin(pp, tpp);
}
-});
+}
return pp;
},
_prepElement: function (element) {
@@ -4181,56 +4718,86 @@ this._marshalAnnotatedNodes();
this._marshalAnnotatedListeners();
}
},
-_configureAnnotationReferences: function () {
-this._configureTemplateContent();
+_configureAnnotationReferences: function (config) {
+var notes = this._notes;
+var nodes = this._nodes;
+for (var i = 0; i < notes.length; i++) {
+var note = notes[i];
+var node = nodes[i];
+this._configureTemplateContent(note, node);
+this._configureCompoundBindings(note, node);
+}
},
-_configureTemplateContent: function () {
-this._notes.forEach(function (note, i) {
+_configureTemplateContent: function (note, node) {
if (note.templateContent) {
-this._nodes[i]._content = note.templateContent;
+node._content = note.templateContent;
+}
+},
+_configureCompoundBindings: function (note, node) {
+var bindings = note.bindings;
+for (var i = 0; i < bindings.length; i++) {
+var binding = bindings[i];
+if (binding.isCompound) {
+var storage = node.__compoundStorage__ || (node.__compoundStorage__ = {});
+var parts = binding.parts;
+var literals = new Array(parts.length);
+for (var j = 0; j < parts.length; j++) {
+literals[j] = parts[j].literal;
+}
+var name = binding.name;
+storage[name] = literals;
+if (binding.literal && binding.kind == 'property') {
+if (node._configValue) {
+node._configValue(name, binding.literal);
+} else {
+node[name] = binding.literal;
+}
+}
+}
}
-}, this);
},
_marshalIdNodes: function () {
this.$ = {};
-this._notes.forEach(function (a) {
+for (var i = 0, l = this._notes.length, a; i < l && (a = this._notes[i]); i++) {
if (a.id) {
this.$[a.id] = this._findAnnotatedNode(this.root, a);
}
-}, this);
+}
},
_marshalAnnotatedNodes: function () {
-if (this._nodes) {
-this._nodes = this._nodes.map(function (a) {
-return this._findAnnotatedNode(this.root, a);
-}, this);
+if (this._notes && this._notes.length) {
+var r = new Array(this._notes.length);
+for (var i = 0; i < this._notes.length; i++) {
+r[i] = this._findAnnotatedNode(this.root, this._notes[i]);
+}
+this._nodes = r;
}
},
_marshalAnnotatedListeners: function () {
-this._notes.forEach(function (a) {
+for (var i = 0, l = this._notes.length, a; i < l && (a = this._notes[i]); i++) {
if (a.events && a.events.length) {
var node = this._findAnnotatedNode(this.root, a);
-a.events.forEach(function (e) {
+for (var j = 0, e$ = a.events, e; j < e$.length && (e = e$[j]); j++) {
this.listen(node, e.name, e.value);
-}, this);
}
-}, this);
+}
+}
}
});
Polymer.Base._addFeature({
listeners: {},
_listenListeners: function (listeners) {
-var node, name, key;
-for (key in listeners) {
-if (key.indexOf('.') < 0) {
+var node, name, eventName;
+for (eventName in listeners) {
+if (eventName.indexOf('.') < 0) {
node = this;
-name = key;
+name = eventName;
} else {
-name = key.split('.');
+name = eventName.split('.');
node = this.$[name[0]];
name = name[1];
}
-this.listen(node, name, listeners[key]);
+this.listen(node, name, listeners[eventName]);
}
},
listen: function (node, eventName, methodName) {
@@ -4301,6 +4868,7 @@ node.removeEventListener(eventName, handler);
});
(function () {
'use strict';
+var wrap = Polymer.DomApi.wrap;
var HAS_NATIVE_TA = typeof document.head.style.touchAction === 'string';
var GESTURE_KEY = '__polymerGestures';
var HANDLED_OBJ = '__polymerGesturesHandled';
@@ -4451,8 +5019,11 @@ return ev.target;
handleNative: function (ev) {
var handled;
var type = ev.type;
-var node = ev.currentTarget;
+var node = wrap(ev.currentTarget);
var gobj = node[GESTURE_KEY];
+if (!gobj) {
+return;
+}
var gs = gobj[type];
if (!gs) {
return;
@@ -4535,6 +5106,7 @@ Gestures.prevent('track');
}
},
add: function (node, evType, handler) {
+node = wrap(node);
var recognizer = this.gestures[evType];
var deps = recognizer.deps;
var name = recognizer.name;
@@ -4563,6 +5135,7 @@ this.setTouchAction(node, recognizer.touchAction);
}
},
remove: function (node, evType, handler) {
+node = wrap(node);
var recognizer = this.gestures[evType];
var deps = recognizer.deps;
var name = recognizer.name;
@@ -4689,7 +5262,9 @@ Gestures.fire(target, type, {
x: event.clientX,
y: event.clientY,
sourceEvent: event,
-prevent: Gestures.prevent.bind(Gestures)
+prevent: function (e) {
+return Gestures.prevent(e);
+}
});
}
});
@@ -4981,12 +5556,17 @@ this._callbacks.splice(0, len);
this._lastVal += len;
}
};
-new (window.MutationObserver || JsMutationObserver)(Polymer.Async._atEndOfMicrotask.bind(Polymer.Async)).observe(Polymer.Async._twiddle, { characterData: true });
+new window.MutationObserver(function () {
+Polymer.Async._atEndOfMicrotask();
+}).observe(Polymer.Async._twiddle, { characterData: true });
Polymer.Debounce = function () {
var Async = Polymer.Async;
var Debouncer = function (context) {
this.context = context;
-this.boundComplete = this.complete.bind(this);
+var self = this;
+this.boundComplete = function () {
+self.complete();
+};
};
Debouncer.prototype = {
go: function (callback, wait) {
@@ -5063,6 +5643,32 @@ if (toElement) {
Polymer.dom(toElement).setAttribute(name, '');
}
},
+getEffectiveChildNodes: function () {
+return Polymer.dom(this).getEffectiveChildNodes();
+},
+getEffectiveChildren: function () {
+var list = Polymer.dom(this).getEffectiveChildNodes();
+return list.filter(function (n) {
+return n.nodeType === Node.ELEMENT_NODE;
+});
+},
+getEffectiveTextContent: function () {
+var cn = this.getEffectiveChildNodes();
+var tc = [];
+for (var i = 0, c; c = cn[i]; i++) {
+if (c.nodeType !== Node.COMMENT_NODE) {
+tc.push(Polymer.dom(c).textContent);
+}
+}
+return tc.join('');
+},
+queryEffectiveChildren: function (slctr) {
+var e$ = Polymer.dom(this).queryDistributedElements(slctr);
+return e$ && e$[0];
+},
+queryAllEffectiveChildren: function (slctr) {
+return Polymer.dom(this).queryDistributedElements(slctr);
+},
getContentChildNodes: function (slctr) {
var content = Polymer.dom(this.root).querySelector(slctr || 'content');
return content ? Polymer.dom(content).getDistributedNodes() : [];
@@ -5075,19 +5681,37 @@ return n.nodeType === Node.ELEMENT_NODE;
fire: function (type, detail, options) {
options = options || Polymer.nob;
var node = options.node || this;
-var detail = detail === null || detail === undefined ? Polymer.nob : detail;
+var detail = detail === null || detail === undefined ? {} : detail;
var bubbles = options.bubbles === undefined ? true : options.bubbles;
var cancelable = Boolean(options.cancelable);
-var event = new CustomEvent(type, {
+var useCache = options._useCache;
+var event = this._getEvent(type, bubbles, cancelable, useCache);
+event.detail = detail;
+if (useCache) {
+this.__eventCache[type] = null;
+}
+node.dispatchEvent(event);
+if (useCache) {
+this.__eventCache[type] = event;
+}
+return event;
+},
+__eventCache: {},
+_getEvent: function (type, bubbles, cancelable, useCache) {
+var event = useCache && this.__eventCache[type];
+if (!event || (event.bubbles != bubbles || event.cancelable != cancelable)) {
+event = new Event(type, {
bubbles: Boolean(bubbles),
-cancelable: cancelable,
-detail: detail
+cancelable: cancelable
});
-node.dispatchEvent(event);
+}
return event;
},
async: function (callback, waitTime) {
-return Polymer.Async.run(callback.bind(this), waitTime);
+var self = this;
+return Polymer.Async.run(function () {
+callback.call(self);
+}, waitTime);
},
cancelAsync: function (handle) {
Polymer.Async.cancel(handle);
@@ -5100,7 +5724,7 @@ if (index >= 0) {
return path.splice(index, 1);
}
} else {
-var arr = this.get(path);
+var arr = this._get(path);
index = arr.indexOf(item);
if (index >= 0) {
return this.splice(path, index, 1);
@@ -5120,11 +5744,16 @@ importHref: function (href, onload, onerror) {
var l = document.createElement('link');
l.rel = 'import';
l.href = href;
+var self = this;
if (onload) {
-l.onload = onload.bind(this);
+l.onload = function (e) {
+return onload.call(self, e);
+};
}
if (onerror) {
-l.onerror = onerror.bind(this);
+l.onerror = function (e) {
+return onerror.call(self, e);
+};
}
document.head.appendChild(l);
return l;
@@ -5139,24 +5768,25 @@ elt[n] = props[n];
return elt;
},
isLightDescendant: function (node) {
-return this.contains(node) && Polymer.dom(this).getOwnerRoot() === Polymer.dom(node).getOwnerRoot();
+return this !== node && this.contains(node) && Polymer.dom(this).getOwnerRoot() === Polymer.dom(node).getOwnerRoot();
},
isLocalDescendant: function (node) {
return this.root === Polymer.dom(node).getOwnerRoot();
}
});
Polymer.Bind = {
+_dataEventCache: {},
prepareModel: function (model) {
-model._propertyEffects = {};
-model._bindListeners = [];
Polymer.Base.mixin(model, this._modelApi);
},
_modelApi: {
-_notifyChange: function (property) {
-var eventName = Polymer.CaseMap.camelToDashCase(property) + '-changed';
-Polymer.Base.fire(eventName, { value: this[property] }, {
+_notifyChange: function (source, event, value) {
+value = value === undefined ? this[source] : value;
+event = event || Polymer.CaseMap.camelToDashCase(source) + '-changed';
+this.fire(event, { value: value }, {
bubbles: false,
-node: this
+cancelable: false,
+_useCache: true
});
},
_propertySetter: function (property, value, effects, fromAbove) {
@@ -5185,12 +5815,9 @@ node[property] = value;
}
},
_effectEffects: function (property, value, effects, old, fromAbove) {
-effects.forEach(function (fx) {
-var fn = Polymer.Bind['_' + fx.kind + 'Effect'];
-if (fn) {
-fn.call(this, property, value, fx.effect, old, fromAbove);
+for (var i = 0, l = effects.length, fx; i < l && (fx = effects[i]); i++) {
+fx.fn.call(this, property, value, fx.effect, old, fromAbove);
}
-}, this);
},
_clearPath: function (path) {
for (var prop in this.__data__) {
@@ -5201,6 +5828,9 @@ this.__data__[prop] = undefined;
}
},
ensurePropertyEffects: function (model, property) {
+if (!model._propertyEffects) {
+model._propertyEffects = {};
+}
var fx = model._propertyEffects[property];
if (!fx) {
fx = model._propertyEffects[property] = [];
@@ -5209,10 +5839,13 @@ return fx;
},
addPropertyEffect: function (model, property, kind, effect) {
var fx = this.ensurePropertyEffects(model, property);
-fx.push({
+var propEffect = {
kind: kind,
-effect: effect
-});
+effect: effect,
+fn: Polymer.Bind['_' + kind + 'Effect']
+};
+fx.push(propEffect);
+return propEffect;
},
createBindings: function (model) {
var fx$ = model._propertyEffects;
@@ -5262,7 +5895,10 @@ upper: function (name) {
return name[0].toUpperCase() + name.substring(1);
},
_addAnnotatedListener: function (model, index, property, path, event) {
-var fn = this._notedListenerFactory(property, path, this._isStructured(path), this._isEventBogus);
+if (!model._bindListeners) {
+model._bindListeners = [];
+}
+var fn = this._notedListenerFactory(property, path, this._isStructured(path));
var eventName = event || Polymer.CaseMap.camelToDashCase(property) + '-changed';
model._bindListeners.push({
index: index,
@@ -5278,54 +5914,59 @@ return path.indexOf('.') > 0;
_isEventBogus: function (e, target) {
return e.path && e.path[0] !== target;
},
-_notedListenerFactory: function (property, path, isStructured, bogusTest) {
-return function (e, target) {
-if (!bogusTest(e, target)) {
-if (e.detail && e.detail.path) {
-this.notifyPath(this._fixPath(path, property, e.detail.path), e.detail.value);
+_notedListenerFactory: function (property, path, isStructured) {
+return function (target, value, targetPath) {
+if (targetPath) {
+this._notifyPath(this._fixPath(path, property, targetPath), value);
} else {
-var value = target[property];
+value = target[property];
if (!isStructured) {
-this[path] = target[property];
+this[path] = value;
} else {
if (this.__data__[path] != value) {
this.set(path, value);
}
}
}
-}
};
},
prepareInstance: function (inst) {
inst.__data__ = Object.create(null);
},
setupBindListeners: function (inst) {
-inst._bindListeners.forEach(function (info) {
+var b$ = inst._bindListeners;
+for (var i = 0, l = b$.length, info; i < l && (info = b$[i]); i++) {
var node = inst._nodes[info.index];
-node.addEventListener(info.event, inst._notifyListener.bind(inst, info.changedFn));
+this._addNotifyListener(node, inst, info.event, info.changedFn);
+}
+;
+},
+_addNotifyListener: function (element, context, event, changedFn) {
+element.addEventListener(event, function (e) {
+return context._notifyListener(changedFn, e);
});
}
};
Polymer.Base.extend(Polymer.Bind, {
_shouldAddListener: function (effect) {
-return effect.name && effect.mode === '{' && !effect.negate && effect.kind != 'attribute';
+return effect.name && effect.kind != 'attribute' && effect.kind != 'text' && !effect.isCompound && effect.parts[0].mode === '{' && !effect.parts[0].negate;
},
_annotationEffect: function (source, value, effect) {
if (source != effect.value) {
-value = this.get(effect.value);
+value = this._get(effect.value);
this.__data__[effect.value] = value;
}
var calc = effect.negate ? !value : value;
if (!effect.customEvent || this._nodes[effect.index][effect.name] !== calc) {
-return this._applyEffectValue(calc, effect);
+return this._applyEffectValue(effect, calc);
}
},
-_reflectEffect: function (source) {
-this.reflectPropertyToAttribute(source);
+_reflectEffect: function (source, value, effect) {
+this.reflectPropertyToAttribute(source, effect.attribute, value);
},
_notifyEffect: function (source, value, effect, old, fromAbove) {
if (!fromAbove) {
-this._notifyChange(source);
+this._notifyChange(source, effect.event, value);
}
},
_functionEffect: function (source, value, fn, old, fromAbove) {
@@ -5355,7 +5996,7 @@ var args = Polymer.Bind._marshalArgs(this.__data__, effect, source, value);
if (args) {
var fn = this[effect.method];
if (fn) {
-this.__setProperty(effect.property, fn.apply(this, args));
+this.__setProperty(effect.name, fn.apply(this, args));
} else {
this._warn(this._logf('_computeEffect', 'compute method `' + effect.method + '` not defined'));
}
@@ -5371,7 +6012,7 @@ var computedvalue = fn.apply(computedHost, args);
if (effect.negate) {
computedvalue = !computedvalue;
}
-this._applyEffectValue(computedvalue, effect);
+this._applyEffectValue(effect, computedvalue);
}
} else {
computedHost._warn(computedHost._logf('_annotatedComputationEffect', 'compute method `' + effect.method + '` not defined'));
@@ -5387,7 +6028,7 @@ var v;
if (arg.literal) {
v = arg.value;
} else if (arg.structured) {
-v = Polymer.Base.get(name, model);
+v = Polymer.Base._get(name, model);
} else {
v = model[name];
}
@@ -5411,7 +6052,8 @@ return values;
});
Polymer.Base._addFeature({
_addPropertyEffect: function (property, kind, effect) {
-Polymer.Bind.addPropertyEffect(this, property, kind, effect);
+var prop = Polymer.Bind.addPropertyEffect(this, property, kind, effect);
+prop.pathFn = this['_' + prop.kind + 'PathEffect'];
},
_prepEffects: function () {
Polymer.Bind.prepareModel(this);
@@ -5432,10 +6074,10 @@ prop.readOnly = true;
this._addComputedEffect(p, prop.computed);
}
if (prop.notify) {
-this._addPropertyEffect(p, 'notify');
+this._addPropertyEffect(p, 'notify', { event: Polymer.CaseMap.camelToDashCase(p) + '-changed' });
}
if (prop.reflectToAttribute) {
-this._addPropertyEffect(p, 'reflect');
+this._addPropertyEffect(p, 'reflect', { attribute: Polymer.CaseMap.camelToDashCase(p) });
}
if (prop.readOnly) {
Polymer.Bind.ensurePropertyEffects(this, p);
@@ -5445,14 +6087,14 @@ Polymer.Bind.ensurePropertyEffects(this, p);
},
_addComputedEffect: function (name, expression) {
var sig = this._parseMethod(expression);
-sig.args.forEach(function (arg) {
+for (var i = 0, arg; i < sig.args.length && (arg = sig.args[i]); i++) {
this._addPropertyEffect(arg.model, 'compute', {
method: sig.method,
args: sig.args,
trigger: arg,
-property: name
+name: name
});
-}, this);
+}
},
_addObserverEffect: function (property, observer) {
this._addPropertyEffect(property, 'observer', {
@@ -5462,61 +6104,74 @@ property: property
},
_addComplexObserverEffects: function (observers) {
if (observers) {
-observers.forEach(function (observer) {
-this._addComplexObserverEffect(observer);
-}, this);
+for (var i = 0, o; i < observers.length && (o = observers[i]); i++) {
+this._addComplexObserverEffect(o);
+}
}
},
_addComplexObserverEffect: function (observer) {
var sig = this._parseMethod(observer);
-sig.args.forEach(function (arg) {
+for (var i = 0, arg; i < sig.args.length && (arg = sig.args[i]); i++) {
this._addPropertyEffect(arg.model, 'complexObserver', {
method: sig.method,
args: sig.args,
trigger: arg
});
-}, this);
+}
},
_addAnnotationEffects: function (notes) {
-this._nodes = [];
-notes.forEach(function (note) {
-var index = this._nodes.push(note) - 1;
-note.bindings.forEach(function (binding) {
-this._addAnnotationEffect(binding, index);
-}, this);
-}, this);
+for (var i = 0, note; i < notes.length && (note = notes[i]); i++) {
+var b$ = note.bindings;
+for (var j = 0, binding; j < b$.length && (binding = b$[j]); j++) {
+this._addAnnotationEffect(binding, i);
+}
+}
},
_addAnnotationEffect: function (note, index) {
if (Polymer.Bind._shouldAddListener(note)) {
-Polymer.Bind._addAnnotatedListener(this, index, note.name, note.value, note.event);
+Polymer.Bind._addAnnotatedListener(this, index, note.name, note.parts[0].value, note.parts[0].event);
+}
+for (var i = 0; i < note.parts.length; i++) {
+var part = note.parts[i];
+if (part.signature) {
+this._addAnnotatedComputationEffect(note, part, index);
+} else if (!part.literal) {
+this._addPropertyEffect(part.model, 'annotation', {
+kind: note.kind,
+index: index,
+name: note.name,
+value: part.value,
+isCompound: note.isCompound,
+compoundIndex: part.compoundIndex,
+event: part.event,
+customEvent: part.customEvent,
+negate: part.negate
+});
}
-if (note.signature) {
-this._addAnnotatedComputationEffect(note, index);
-} else {
-note.index = index;
-this._addPropertyEffect(note.model, 'annotation', note);
}
},
-_addAnnotatedComputationEffect: function (note, index) {
-var sig = note.signature;
+_addAnnotatedComputationEffect: function (note, part, index) {
+var sig = part.signature;
if (sig.static) {
-this.__addAnnotatedComputationEffect('__static__', index, note, sig, null);
+this.__addAnnotatedComputationEffect('__static__', index, note, part, null);
} else {
-sig.args.forEach(function (arg) {
+for (var i = 0, arg; i < sig.args.length && (arg = sig.args[i]); i++) {
if (!arg.literal) {
-this.__addAnnotatedComputationEffect(arg.model, index, note, sig, arg);
+this.__addAnnotatedComputationEffect(arg.model, index, note, part, arg);
+}
}
-}, this);
}
},
-__addAnnotatedComputationEffect: function (property, index, note, sig, trigger) {
+__addAnnotatedComputationEffect: function (property, index, note, part, trigger) {
this._addPropertyEffect(property, 'annotatedComputation', {
index: index,
+isCompound: note.isCompound,
+compoundIndex: part.compoundIndex,
kind: note.kind,
-property: note.name,
-negate: note.negate,
-method: sig.method,
-args: sig.args,
+name: note.name,
+negate: part.negate,
+method: part.signature.method,
+args: part.signature.args,
trigger: trigger
});
},
@@ -5583,11 +6238,18 @@ return a;
},
_marshalInstanceEffects: function () {
Polymer.Bind.prepareInstance(this);
+if (this._bindListeners) {
Polymer.Bind.setupBindListeners(this);
+}
},
-_applyEffectValue: function (value, info) {
+_applyEffectValue: function (info, value) {
var node = this._nodes[info.index];
-var property = info.property || info.name || 'textContent';
+var property = info.name;
+if (info.isCompound) {
+var storage = node.__compoundStorage__[property];
+storage[info.compoundIndex] = value;
+value = storage.join('');
+}
if (info.kind == 'attribute') {
this.serializeValueToAttribute(value, property, node);
} else {
@@ -5597,11 +6259,14 @@ value = this._scopeElementClass(node, value);
if (property === 'textContent' || node.localName == 'input' && property == 'value') {
value = value == undefined ? '' : value;
}
-return node[property] = value;
+var pinfo;
+if (!node._propertyInfo || !(pinfo = node._propertyInfo[property]) || !pinfo.readOnly) {
+this.__setProperty(property, value, true, node);
+}
}
},
_executeStaticEffects: function () {
-if (this._propertyEffects.__static__) {
+if (this._propertyEffects && this._propertyEffects.__static__) {
this._effectEffects('__static__', null, this._propertyEffects.__static__);
}
}
@@ -5609,12 +6274,14 @@ this._effectEffects('__static__', null, this._propertyEffects.__static__);
Polymer.Base._addFeature({
_setupConfigure: function (initialConfig) {
this._config = {};
+this._handlers = [];
+if (initialConfig) {
for (var i in initialConfig) {
if (initialConfig[i] !== undefined) {
this._config[i] = initialConfig[i];
}
}
-this._handlers = [];
+}
},
_marshalAttributes: function () {
this._takeAttributesToModel(this._config);
@@ -5624,7 +6291,10 @@ var model = this._clientsReadied ? this : this._config;
this._setAttributeToProperty(model, name);
},
_configValue: function (name, value) {
+var info = this._propertyInfo[name];
+if (!info || !info.readOnly) {
this._config[name] = value;
+}
},
_beforeClientsReady: function () {
this._configure();
@@ -5633,13 +6303,15 @@ _configure: function () {
this._configureAnnotationReferences();
this._aboveConfig = this.mixin({}, this._config);
var config = {};
-this.behaviors.forEach(function (b) {
-this._configureProperties(b.properties, config);
-}, this);
+for (var i = 0; i < this.behaviors.length; i++) {
+this._configureProperties(this.behaviors[i].properties, config);
+}
this._configureProperties(this.properties, config);
-this._mixinConfigure(config, this._aboveConfig);
+this.mixin(config, this._aboveConfig);
this._config = config;
+if (this._clients && this._clients.length) {
this._distributeConfig(this._config);
+}
},
_configureProperties: function (properties, config) {
for (var i in properties) {
@@ -5653,13 +6325,6 @@ config[i] = value;
}
}
},
-_mixinConfigure: function (a, b) {
-for (var prop in b) {
-if (!this.getPropertyInfo(prop).readOnly) {
-a[prop] = b[prop];
-}
-}
-},
_distributeConfig: function (config) {
var fx$ = this._propertyEffects;
if (fx$) {
@@ -5667,10 +6332,10 @@ for (var p in config) {
var fx = fx$[p];
if (fx) {
for (var i = 0, l = fx.length, x; i < l && (x = fx[i]); i++) {
-if (x.kind === 'annotation') {
+if (x.kind === 'annotation' && !x.isCompound) {
var node = this._nodes[x.effect.index];
if (node._configValue) {
-var value = p === x.effect.value ? config[p] : this.get(x.effect.value, config);
+var value = p === x.effect.value ? config[p] : this._get(x.effect.value, config);
node._configValue(x.effect.name, value);
}
}
@@ -5692,14 +6357,22 @@ this.__setProperty(n, config[n], n in aboveConfig);
}
},
_notifyListener: function (fn, e) {
+if (!Polymer.Bind._isEventBogus(e, e.target)) {
+var value, path;
+if (e.detail) {
+value = e.detail.value;
+path = e.detail.path;
+}
if (!this._clientsReadied) {
this._queueHandler([
fn,
-e,
-e.target
+e.target,
+value,
+path
]);
} else {
-return fn.call(this, e, e.target);
+return fn.call(this, e.target, value, path);
+}
}
},
_queueHandler: function (args) {
@@ -5708,7 +6381,7 @@ this._handlers.push(args);
_flushHandlers: function () {
var h$ = this._handlers;
for (var i = 0, l = h$.length, h; i < l && (h = h$[i]); i++) {
-h[0].call(this, h[1], h[2]);
+h[0].call(this, h[1], h[2], h[3]);
}
this._handlers = [];
}
@@ -5717,11 +6390,16 @@ this._handlers = [];
'use strict';
Polymer.Base._addFeature({
notifyPath: function (path, value, fromAbove) {
+var info = {};
+this._get(path, this, info);
+this._notifyPath(info.path, value, fromAbove);
+},
+_notifyPath: function (path, value, fromAbove) {
var old = this._propertySetter(path, value);
if (old !== value && (old === old || value === value)) {
this._pathEffector(path, value);
if (!fromAbove) {
-this._notifyPath(path, value);
+this._notifyPathUp(path, value);
}
return true;
}
@@ -5748,52 +6426,78 @@ var last = parts[parts.length - 1];
if (parts.length > 1) {
for (var i = 0; i < parts.length - 1; i++) {
var part = parts[i];
+if (array && part[0] == '#') {
+prop = Polymer.Collection.get(array).getItem(part);
+} else {
prop = prop[part];
-if (array && parseInt(part) == part) {
+if (array && parseInt(part, 10) == part) {
parts[i] = Polymer.Collection.get(array).getKey(prop);
}
+}
if (!prop) {
return;
}
array = Array.isArray(prop) ? prop : null;
}
-if (array && parseInt(last) == last) {
+if (array) {
var coll = Polymer.Collection.get(array);
+if (last[0] == '#') {
+var key = last;
+var old = coll.getItem(key);
+last = array.indexOf(old);
+coll.setItem(key, value);
+} else if (parseInt(last, 10) == last) {
var old = prop[last];
var key = coll.getKey(old);
parts[i] = key;
coll.setItem(key, value);
}
+}
prop[last] = value;
if (!root) {
-this.notifyPath(parts.join('.'), value);
+this._notifyPath(parts.join('.'), value);
}
} else {
prop[path] = value;
}
},
get: function (path, root) {
+return this._get(path, root);
+},
+_get: function (path, root, info) {
var prop = root || this;
var parts = this._getPathParts(path);
-var last = parts.pop();
-while (parts.length) {
-prop = prop[parts.shift()];
+var array;
+for (var i = 0; i < parts.length; i++) {
if (!prop) {
return;
}
+var part = parts[i];
+if (array && part[0] == '#') {
+prop = Polymer.Collection.get(array).getItem(part);
+} else {
+prop = prop[part];
+if (info && array && parseInt(part, 10) == part) {
+parts[i] = Polymer.Collection.get(array).getKey(prop);
+}
+}
+array = Array.isArray(prop) ? prop : null;
+}
+if (info) {
+info.path = parts.join('.');
}
-return prop[last];
+return prop;
},
_pathEffector: function (path, value) {
var model = this._modelForPath(path);
-var fx$ = this._propertyEffects[model];
+var fx$ = this._propertyEffects && this._propertyEffects[model];
if (fx$) {
-fx$.forEach(function (fx) {
-var fxFn = this['_' + fx.kind + 'PathEffect'];
+for (var i = 0, fx; i < fx$.length && (fx = fx$[i]); i++) {
+var fxFn = fx.pathFn;
if (fxFn) {
fxFn.call(this, path, value, fx.effect);
}
-}, this);
+}
}
if (this._boundPaths) {
this._notifyBoundPaths(path, value);
@@ -5804,9 +6508,9 @@ if (effect.value === path || effect.value.indexOf(path + '.') === 0) {
Polymer.Bind._annotationEffect.call(this, path, value, effect);
} else if (path.indexOf(effect.value + '.') === 0 && !effect.negate) {
var node = this._nodes[effect.index];
-if (node && node.notifyPath) {
+if (node && node._notifyPath) {
var p = this._fixPath(effect.name, effect.value, path);
-node.notifyPath(p, value, true);
+node._notifyPath(p, value, true);
}
}
},
@@ -5846,70 +6550,88 @@ _notifyBoundPaths: function (path, value) {
for (var a in this._boundPaths) {
var b = this._boundPaths[a];
if (path.indexOf(a + '.') == 0) {
-this.notifyPath(this._fixPath(b, a, path), value);
+this._notifyPath(this._fixPath(b, a, path), value);
} else if (path.indexOf(b + '.') == 0) {
-this.notifyPath(this._fixPath(a, b, path), value);
+this._notifyPath(this._fixPath(a, b, path), value);
}
}
},
_fixPath: function (property, root, path) {
return property + path.slice(root.length);
},
-_notifyPath: function (path, value) {
+_notifyPathUp: function (path, value) {
var rootName = this._modelForPath(path);
var dashCaseName = Polymer.CaseMap.camelToDashCase(rootName);
var eventName = dashCaseName + this._EVENT_CHANGED;
this.fire(eventName, {
path: path,
value: value
-}, { bubbles: false });
+}, {
+bubbles: false,
+_useCache: true
+});
},
_modelForPath: function (path) {
var dot = path.indexOf('.');
return dot < 0 ? path : path.slice(0, dot);
},
_EVENT_CHANGED: '-changed',
-_notifySplice: function (array, path, index, added, removed) {
-var splices = [{
-index: index,
-addedCount: added,
-removed: removed,
-object: array,
-type: 'splice'
-}];
+notifySplices: function (path, splices) {
+var info = {};
+var array = this._get(path, this, info);
+this._notifySplices(array, info.path, splices);
+},
+_notifySplices: function (array, path, splices) {
var change = {
keySplices: Polymer.Collection.applySplices(array, splices),
indexSplices: splices
};
-this.set(path + '.splices', change);
-if (added != removed.length) {
-this.notifyPath(path + '.length', array.length);
+if (!array.hasOwnProperty('splices')) {
+Object.defineProperty(array, 'splices', {
+configurable: true,
+writable: true
+});
}
+array.splices = change;
+this._notifyPath(path + '.splices', change);
+this._notifyPath(path + '.length', array.length);
change.keySplices = null;
change.indexSplices = null;
},
+_notifySplice: function (array, path, index, added, removed) {
+this._notifySplices(array, path, [{
+index: index,
+addedCount: added,
+removed: removed,
+object: array,
+type: 'splice'
+}]);
+},
push: function (path) {
-var array = this.get(path);
+var info = {};
+var array = this._get(path, this, info);
var args = Array.prototype.slice.call(arguments, 1);
var len = array.length;
var ret = array.push.apply(array, args);
if (args.length) {
-this._notifySplice(array, path, len, args.length, []);
+this._notifySplice(array, info.path, len, args.length, []);
}
return ret;
},
pop: function (path) {
-var array = this.get(path);
+var info = {};
+var array = this._get(path, this, info);
var hadLength = Boolean(array.length);
var args = Array.prototype.slice.call(arguments, 1);
var ret = array.pop.apply(array, args);
if (hadLength) {
-this._notifySplice(array, path, array.length, 0, [ret]);
+this._notifySplice(array, info.path, array.length, 0, [ret]);
}
return ret;
},
splice: function (path, start, deleteCount) {
-var array = this.get(path);
+var info = {};
+var array = this._get(path, this, info);
if (start < 0) {
start = array.length - Math.floor(-start);
} else {
@@ -5922,35 +6644,41 @@ var args = Array.prototype.slice.call(arguments, 1);
var ret = array.splice.apply(array, args);
var addedCount = Math.max(args.length - 2, 0);
if (addedCount || ret.length) {
-this._notifySplice(array, path, start, addedCount, ret);
+this._notifySplice(array, info.path, start, addedCount, ret);
}
return ret;
},
shift: function (path) {
-var array = this.get(path);
+var info = {};
+var array = this._get(path, this, info);
var hadLength = Boolean(array.length);
var args = Array.prototype.slice.call(arguments, 1);
var ret = array.shift.apply(array, args);
if (hadLength) {
-this._notifySplice(array, path, 0, 0, [ret]);
+this._notifySplice(array, info.path, 0, 0, [ret]);
}
return ret;
},
unshift: function (path) {
-var array = this.get(path);
+var info = {};
+var array = this._get(path, this, info);
var args = Array.prototype.slice.call(arguments, 1);
var ret = array.unshift.apply(array, args);
if (args.length) {
-this._notifySplice(array, path, 0, args.length, []);
+this._notifySplice(array, info.path, 0, args.length, []);
}
return ret;
},
prepareModelNotifyPath: function (model) {
this.mixin(model, {
fire: Polymer.Base.fire,
+_getEvent: Polymer.Base._getEvent,
+__eventCache: Polymer.Base.__eventCache,
notifyPath: Polymer.Base.notifyPath,
+_get: Polymer.Base._get,
_EVENT_CHANGED: Polymer.Base._EVENT_CHANGED,
_notifyPath: Polymer.Base._notifyPath,
+_notifyPathUp: Polymer.Base._notifyPathUp,
_pathEffector: Polymer.Base._pathEffector,
_annotationPathEffect: Polymer.Base._annotationPathEffect,
_complexObserverPathEffect: Polymer.Base._complexObserverPathEffect,
@@ -5958,7 +6686,8 @@ _annotatedComputationPathEffect: Polymer.Base._annotatedComputationPathEffect,
_computePathEffect: Polymer.Base._computePathEffect,
_modelForPath: Polymer.Base._modelForPath,
_pathMatchesEffect: Polymer.Base._pathMatchesEffect,
-_notifyBoundPaths: Polymer.Base._notifyBoundPaths
+_notifyBoundPaths: Polymer.Base._notifyBoundPaths,
+_getPathParts: Polymer.Base._getPathParts
});
}
});
@@ -6018,6 +6747,8 @@ node.parsedCssText = node.cssText = t.trim();
if (node.parent) {
var ss = node.previous ? node.previous.end : node.parent.start;
t = text.substring(ss, node.start - 1);
+t = this._expandUnicodeEscapes(t);
+t = t.replace(this._rx.multipleSpaces, ' ');
t = t.substring(t.lastIndexOf(';') + 1);
var s = node.parsedSelector = node.selector = t.trim();
node.atRule = s.indexOf(this.AT_START) === 0;
@@ -6043,6 +6774,15 @@ this._parseCss(r, text);
}
return node;
},
+_expandUnicodeEscapes: function (s) {
+return s.replace(/\\([0-9a-f]{1,6})\s/gi, function () {
+var code = arguments[1], repeat = 6 - code.length;
+while (repeat--) {
+code = '0' + code;
+}
+return '\\' + code;
+});
+},
stringify: function (node, preserveProperties, text) {
text = text || '';
var cssText = '';
@@ -6072,7 +6812,7 @@ text += this.CLOSE_BRACE + '\n\n';
return text;
},
_hasMixinRules: function (rules) {
-return rules[0].selector.indexOf(this.VAR_START) >= 0;
+return rules[0].selector.indexOf(this.VAR_START) === 0;
},
removeCustomProps: function (cssText) {
return cssText;
@@ -6095,10 +6835,11 @@ _rx: {
comments: /\/\*[^*]*\*+([^\/*][^*]*\*+)*\//gim,
port: /@import[^;]*;/gim,
customProp: /(?:^|[\s;])--[^;{]*?:[^{};]*?(?:[;\n]|$)/gim,
-mixinProp: /(?:^|[\s;])--[^;{]*?:[^{;]*?{[^}]*?}(?:[;\n]|$)?/gim,
+mixinProp: /(?:^|[\s;])?--[^;{]*?:[^{;]*?{[^}]*?}(?:[;\n]|$)?/gim,
mixinApply: /@apply[\s]*\([^)]*?\)[\s]*(?:[;\n]|$)?/gim,
-varApply: /[^;:]*?:[^;]*var[^;]*(?:[;\n]|$)?/gim,
-keyframesRule: /^@[^\s]*keyframes/
+varApply: /[^;:]*?:[^;]*?var\([^;]*\)(?:[;\n]|$)?/gim,
+keyframesRule: /^@[^\s]*keyframes/,
+multipleSpaces: /\s+/g
},
VAR_START: '--',
MEDIA_START: '@media',
@@ -6178,21 +6919,21 @@ return cssText;
cssFromModule: function (moduleId, warnIfNotFound) {
var m = Polymer.DomModule.import(moduleId);
if (m && !m._cssText) {
-m._cssText = this._cssFromElement(m);
+m._cssText = this.cssFromElement(m);
}
if (!m && warnIfNotFound) {
console.warn('Could not find style data in module named', moduleId);
}
return m && m._cssText || '';
},
-_cssFromElement: function (element) {
+cssFromElement: function (element) {
var cssText = '';
var content = element.content || element;
-var e$ = Array.prototype.slice.call(content.querySelectorAll(this.MODULE_STYLES_SELECTOR));
+var e$ = Polymer.DomApi.arrayCopy(content.querySelectorAll(this.MODULE_STYLES_SELECTOR));
for (var i = 0, e; i < e$.length; i++) {
e = e$[i];
if (e.localName === 'template') {
-cssText += this._cssFromElement(e);
+cssText += this.cssFromElement(e);
} else {
if (e.localName === 'style') {
var include = e.getAttribute(this.INCLUDE_ATTR);
@@ -6441,7 +7182,7 @@ _extendRule: function (target, source) {
if (target.parent !== source.parent) {
this._cloneAndAddRuleToParent(source, target.parent);
}
-target.extends = target.extends || (target.extends = []);
+target.extends = target.extends || [];
target.extends.push(source);
source.selector = source.selector.replace(this.rx.STRIP, '');
source.selector = (source.selector && source.selector + ',\n') + target.selector;
@@ -6482,14 +7223,18 @@ _prepStyles: function () {
if (this._encapsulateStyle === undefined) {
this._encapsulateStyle = !nativeShadow && Boolean(this._template);
}
+if (this._template) {
this._styles = this._collectStyles();
var cssText = styleTransformer.elementStyles(this);
-if (cssText && this._template) {
+if (cssText) {
var style = styleUtil.applyCss(cssText, this.is, nativeShadow ? this._template.content : null);
if (!nativeShadow) {
this._scopeStyle = style;
}
}
+} else {
+this._styles = [];
+}
},
_collectStyles: function () {
var styles = [];
@@ -6500,6 +7245,10 @@ cssText += styleUtil.cssFromModule(m);
}
}
cssText += styleUtil.cssFromModule(this.is);
+var p = this._template && this._template.parentNode;
+if (this._template && (!p || p.id.toLowerCase() !== this.is)) {
+cssText += styleUtil.cssFromElement(this._template);
+}
if (cssText) {
var style = document.createElement('style');
style.textContent = cssText;
@@ -6533,21 +7282,21 @@ var scopify = function (node) {
if (node.nodeType === Node.ELEMENT_NODE) {
node.className = self._scopeElementClass(node, node.className);
var n$ = node.querySelectorAll('*');
-Array.prototype.forEach.call(n$, function (n) {
+for (var i = 0, n; i < n$.length && (n = n$[i]); i++) {
n.className = self._scopeElementClass(n, n.className);
-});
+}
}
};
scopify(container);
if (shouldObserve) {
var mo = new MutationObserver(function (mxns) {
-mxns.forEach(function (m) {
+for (var i = 0, m; i < mxns.length && (m = mxns[i]); i++) {
if (m.addedNodes) {
-for (var i = 0; i < m.addedNodes.length; i++) {
-scopify(m.addedNodes[i]);
+for (var j = 0; j < m.addedNodes.length; j++) {
+scopify(m.addedNodes[j]);
+}
}
}
-});
});
mo.observe(container, {
childList: true,
@@ -6672,7 +7421,9 @@ p = pp.join(':');
parts[i] = p && p.lastIndexOf(';') === p.length - 1 ? p.slice(0, -1) : p || '';
}
}
-return parts.join(';');
+return parts.filter(function (v) {
+return v;
+}).join(';');
},
applyProperties: function (rule, props) {
var output = '';
@@ -6798,7 +7549,7 @@ props[i] = v;
}
},
rx: {
-VAR_ASSIGN: /(?:^|[;\n]\s*)(--[\w-]*?):\s*(?:([^;{]*)|{([^}]*)})(?:(?=[;\n])|$)/gi,
+VAR_ASSIGN: /(?:^|[;\s{]\s*)(--[\w-]*?)\s*:\s*(?:([^;{]*)|{([^}]*)})(?:(?=[;\s}])|$)/gi,
MIXIN_MATCH: /(?:^|\W+)@apply[\s]*\(([^)]*)\)/i,
VAR_MATCH: /(^|\W+)var\([\s]*([^,)]*)[\s]*,?[\s]*((?:[^,)]*)|(?:[^;]*\([^;)]*\)))[\s]*?\)/gi,
VAR_CAPTURE: /\([\s]*(--[^,\s)]*)(?:,[\s]*(--[^,\s)]*))?(?:\)|,)/gi,
@@ -6917,9 +7668,12 @@ var styleDefaults = Polymer.StyleDefaults;
var nativeShadow = Polymer.Settings.useNativeShadow;
Polymer.Base._addFeature({
_prepStyleProperties: function () {
-this._ownStylePropertyNames = this._styles ? propertyUtils.decorateStyles(this._styles) : [];
+this._ownStylePropertyNames = this._styles ? propertyUtils.decorateStyles(this._styles) : null;
+},
+customStyle: null,
+getComputedStyleValue: function (property) {
+return this._styleProperties && this._styleProperties[property] || getComputedStyle(this).getPropertyValue(property);
},
-customStyle: {},
_setupStyleProperties: function () {
this.customStyle = {};
},
@@ -7016,7 +7770,7 @@ if (host) {
value = host._scopeElementClass(node, value);
}
}
-node = Polymer.dom(node);
+node = this.shadyRoot && this.shadyRoot._hasDistributed ? Polymer.dom(node) : node;
serializeValueToAttribute.call(this, value, attribute, node);
},
_scopeElementClass: function (element, selector) {
@@ -7065,7 +7819,6 @@ var XSCOPE_NAME = propertyUtils.XSCOPE_NAME;
Polymer.Base._addFeature({
_registerFeatures: function () {
this._prepIs();
-this._prepAttributes();
this._prepConstructor();
this._prepTemplate();
this._prepStyles();
@@ -7073,6 +7826,7 @@ this._prepStyleProperties();
this._prepAnnotations();
this._prepEffects();
this._prepBehaviors();
+this._prepPropertyInfo();
this._prepBindings();
this._prepShady();
},
@@ -7082,23 +7836,28 @@ this._addComplexObserverEffects(b.observers);
this._addHostAttributes(b.hostAttributes);
},
_initFeatures: function () {
-this._poolContent();
this._setupConfigure();
this._setupStyleProperties();
-this._pushHost();
+this._setupDebouncers();
+this._registerHost();
+if (this._template) {
+this._poolContent();
+this._beginHosting();
this._stampTemplate();
-this._popHost();
+this._endHosting();
this._marshalAnnotationReferences();
-this._setupDebouncers();
+}
this._marshalInstanceEffects();
-this._marshalHostAttributes();
this._marshalBehaviors();
+this._marshalHostAttributes();
this._marshalAttributes();
this._tryReady();
},
_marshalBehavior: function (b) {
+if (b.listeners) {
this._listenListeners(b.listeners);
}
+}
});
(function () {
var nativeShadow = Polymer.Settings.useNativeShadow;
@@ -7110,6 +7869,7 @@ var styleTransformer = Polymer.StyleTransformer;
Polymer({
is: 'custom-style',
extends: 'style',
+_template: null,
properties: { include: String },
ready: function () {
this._tryApply();
@@ -7124,18 +7884,19 @@ this._appliesToDocument = true;
var e = this.__appliedElement || this;
styleDefaults.addStyle(e);
if (e.textContent || this.include) {
-this._apply();
+this._apply(true);
} else {
+var self = this;
var observer = new MutationObserver(function () {
observer.disconnect();
-this._apply();
-}.bind(this));
+self._apply(true);
+});
observer.observe(e, { childList: true });
}
}
}
},
-_apply: function () {
+_apply: function (deferProperties) {
var e = this.__appliedElement || this;
if (this.include) {
e.textContent = styleUtil.cssFromModules(this.include, true) + e.textContent;
@@ -7144,7 +7905,19 @@ if (e.textContent) {
styleUtil.forEachStyleRule(styleUtil.rulesForStyle(e), function (rule) {
styleTransformer.documentRule(rule);
});
-this._applyCustomProperties(e);
+var self = this;
+function fn() {
+self._applyCustomProperties(e);
+}
+if (this._pendingApplyProperties) {
+cancelAnimationFrame(this._pendingApplyProperties);
+this._pendingApplyProperties = null;
+}
+if (deferProperties) {
+this._pendingApplyProperties = requestAnimationFrame(fn);
+} else {
+fn();
+}
}
},
_applyCustomProperties: function (element) {
@@ -7181,8 +7954,9 @@ this._prepParentProperties(archetype, template);
archetype._prepEffects();
this._customPrepEffects(archetype);
archetype._prepBehaviors();
+archetype._prepPropertyInfo();
archetype._prepBindings();
-archetype._notifyPath = this._notifyPathImpl;
+archetype._notifyPathUp = this._notifyPathUpImpl;
archetype._scopeElementClass = this._scopeElementClassImpl;
archetype.listen = this._listenImpl;
archetype._showHideChildren = this._showHideChildrenImpl;
@@ -7243,7 +8017,9 @@ var c = template._content;
if (!c._notes) {
var rootDataHost = archetype._rootDataHost;
if (rootDataHost) {
-Polymer.Annotations.prepElement = rootDataHost._prepElement.bind(rootDataHost);
+Polymer.Annotations.prepElement = function () {
+rootDataHost._prepElement();
+};
}
c._notes = Polymer.Annotations.parseAnnotations(template);
Polymer.Annotations.prepElement = null;
@@ -7271,19 +8047,29 @@ var parentProp = this._parentPropPrefix + prop;
var effects = [
{
kind: 'function',
-effect: this._createForwardPropEffector(prop)
+effect: this._createForwardPropEffector(prop),
+fn: Polymer.Bind._functionEffect
},
-{ kind: 'notify' }
+{
+kind: 'notify',
+fn: Polymer.Bind._notifyEffect,
+effect: { event: Polymer.CaseMap.camelToDashCase(parentProp) + '-changed' }
+}
];
Polymer.Bind._createAccessors(proto, parentProp, effects);
}
}
+var self = this;
if (template != this) {
Polymer.Bind.prepareInstance(template);
-template._forwardParentProp = this._forwardParentProp.bind(this);
+template._forwardParentProp = function (source, value) {
+self._forwardParentProp(source, value);
+};
}
this._extendTemplate(template, proto);
-template._pathEffector = this._pathEffectorImpl.bind(this);
+template._pathEffector = function (path, value, fromAbove) {
+return self._pathEffectorImpl(path, value, fromAbove);
+};
}
},
_createForwardPropEffector: function (prop) {
@@ -7305,14 +8091,15 @@ this.dataHost._forwardInstanceProp(this, prop, value);
};
},
_extendTemplate: function (template, proto) {
-Object.getOwnPropertyNames(proto).forEach(function (n) {
+var n$ = Object.getOwnPropertyNames(proto);
+for (var i = 0, n; i < n$.length && (n = n$[i]); i++) {
var val = template[n];
var pd = Object.getOwnPropertyDescriptor(proto, n);
Object.defineProperty(template, n, pd);
if (val !== undefined) {
template._propertySetter(n, val);
}
-});
+}
},
_showHideChildren: function (hidden) {
},
@@ -7320,7 +8107,7 @@ _forwardInstancePath: function (inst, path, value) {
},
_forwardInstanceProp: function (inst, prop, value) {
},
-_notifyPathImpl: function (path, value) {
+_notifyPathUpImpl: function (path, value) {
var dataHost = this.dataHost;
var dot = path.indexOf('.');
var root = dot < 0 ? path : path.slice(0, dot);
@@ -7333,19 +8120,23 @@ _pathEffectorImpl: function (path, value, fromAbove) {
if (this._forwardParentPath) {
if (path.indexOf(this._parentPropPrefix) === 0) {
var subPath = path.substring(this._parentPropPrefix.length);
+var model = this._modelForPath(subPath);
+if (model in this._parentProps) {
this._forwardParentPath(subPath, value);
}
}
+}
Polymer.Base._pathEffector.call(this._templatized, path, value, fromAbove);
},
_constructorImpl: function (model, host) {
this._rootDataHost = host._getRootDataHost();
this._setupConfigure(model);
-this._pushHost(host);
+this._registerHost(host);
+this._beginHosting();
this.root = this.instanceTemplate(this._template);
this.root.__noContent = !this._notes._hasContent;
this.root.__styleScoped = true;
-this._popHost();
+this._endHosting();
this._marshalAnnotatedNodes();
this._marshalInstanceEffects();
this._marshalAnnotatedListeners();
@@ -7404,6 +8195,7 @@ el = el.parentNode;
Polymer({
is: 'dom-template',
extends: 'template',
+_template: null,
behaviors: [Polymer.Templatizer],
ready: function () {
this.templatize(this);
@@ -7438,9 +8230,10 @@ this.omap.set(item, key);
} else {
this.pmap[item] = key;
}
-return key;
+return '#' + key;
},
removeKey: function (key) {
+key = this._parseKey(key);
this._removeFromMap(this.store[key]);
delete this.store[key];
},
@@ -7457,16 +8250,29 @@ this.removeKey(key);
return key;
},
getKey: function (item) {
+var key;
if (item && typeof item == 'object') {
-return this.omap.get(item);
+key = this.omap.get(item);
} else {
-return this.pmap[item];
+key = this.pmap[item];
+}
+if (key != undefined) {
+return '#' + key;
}
},
getKeys: function () {
-return Object.keys(this.store);
+return Object.keys(this.store).map(function (key) {
+return '#' + key;
+});
+},
+_parseKey: function (key) {
+if (key[0] == '#') {
+return key.slice(1);
+}
+throw new Error('unexpected key ' + key);
},
setItem: function (key, item) {
+key = this._parseKey(key);
var old = this.store[key];
if (old) {
this._removeFromMap(old);
@@ -7479,6 +8285,7 @@ this.pmap[item] = key;
this.store[key] = item;
},
getItem: function (key) {
+key = this._parseKey(key);
return this.store[key];
},
getItems: function () {
@@ -7489,21 +8296,21 @@ items.push(store[key]);
return items;
},
_applySplices: function (splices) {
-var keyMap = {}, key, i;
-splices.forEach(function (s) {
+var keyMap = {}, key;
+for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
s.addedKeys = [];
-for (i = 0; i < s.removed.length; i++) {
-key = this.getKey(s.removed[i]);
+for (var j = 0; j < s.removed.length; j++) {
+key = this.getKey(s.removed[j]);
keyMap[key] = keyMap[key] ? null : -1;
}
-for (i = 0; i < s.addedCount; i++) {
-var item = this.userArray[s.index + i];
+for (var j = 0; j < s.addedCount; j++) {
+var item = this.userArray[s.index + j];
key = this.getKey(item);
key = key === undefined ? this.add(item) : key;
keyMap[key] = keyMap[key] ? null : 1;
s.addedKeys.push(key);
}
-}, this);
+}
var removed = [];
var added = [];
for (var key in keyMap) {
@@ -7531,6 +8338,7 @@ return coll ? coll._applySplices(splices) : null;
Polymer({
is: 'dom-repeat',
extends: 'template',
+_template: null,
properties: {
items: { type: Array },
as: {
@@ -7553,22 +8361,37 @@ observe: {
type: String,
observer: '_observeChanged'
},
-delay: Number
+delay: Number,
+initialCount: {
+type: Number,
+observer: '_initializeChunking'
+},
+targetFramerate: {
+type: Number,
+value: 20
+},
+_targetFrameTime: { computed: '_computeFrameTime(targetFramerate)' }
},
behaviors: [Polymer.Templatizer],
observers: ['_itemsChanged(items.*)'],
created: function () {
this._instances = [];
+this._pool = [];
+this._limit = Infinity;
+var self = this;
+this._boundRenderChunk = function () {
+self._renderChunk();
+};
},
detached: function () {
for (var i = 0; i < this._instances.length; i++) {
-this._detachRow(i);
+this._detachInstance(i);
}
},
attached: function () {
-var parentNode = Polymer.dom(this).parentNode;
+var parent = Polymer.dom(Polymer.dom(this).parentNode);
for (var i = 0; i < this._instances.length; i++) {
-Polymer.dom(parentNode).insertBefore(this._instances[i].root, this);
+this._attachInstance(i, parent);
}
},
ready: function () {
@@ -7579,9 +8402,8 @@ if (!this.ctor) {
this.templatize(this);
}
},
-_sortChanged: function () {
+_sortChanged: function (sort) {
var dataHost = this._getRootDataHost();
-var sort = this.sort;
this._sortFn = sort && (typeof sort == 'function' ? sort : function () {
return dataHost[sort].apply(dataHost, arguments);
});
@@ -7590,9 +8412,8 @@ if (this.items) {
this._debounceTemplate(this._render);
}
},
-_filterChanged: function () {
+_filterChanged: function (filter) {
var dataHost = this._getRootDataHost();
-var filter = this.filter;
this._filterFn = filter && (typeof filter == 'function' ? filter : function () {
return dataHost[filter].apply(dataHost, arguments);
});
@@ -7601,6 +8422,32 @@ if (this.items) {
this._debounceTemplate(this._render);
}
},
+_computeFrameTime: function (rate) {
+return Math.ceil(1000 / rate);
+},
+_initializeChunking: function () {
+if (this.initialCount) {
+this._limit = this.initialCount;
+this._chunkCount = this.initialCount;
+this._lastChunkTime = performance.now();
+}
+},
+_tryRenderChunk: function () {
+if (this.items && this._limit < this.items.length) {
+this.debounce('renderChunk', this._requestRenderChunk);
+}
+},
+_requestRenderChunk: function () {
+requestAnimationFrame(this._boundRenderChunk);
+},
+_renderChunk: function () {
+var currChunkTime = performance.now();
+var ratio = this._targetFrameTime / (currChunkTime - this._lastChunkTime);
+this._chunkCount = Math.round(this._chunkCount * ratio) || 1;
+this._limit += this._chunkCount;
+this._lastChunkTime = currChunkTime;
+this._debounceTemplate(this._render);
+},
_observeChanged: function () {
this._observePaths = this.observe && this.observe.replace('.*', '.').split(' ');
},
@@ -7616,6 +8463,7 @@ this._error(this._logf('dom-repeat', 'expected array for `items`,' + ' found', t
this._keySplices = [];
this._indexSplices = [];
this._needFullRefresh = true;
+this._initializeChunking();
this._debounceTemplate(this._render);
} else if (change.path == 'items.splices') {
this._keySplices = this._keySplices.concat(change.value.keySplices);
@@ -7654,7 +8502,7 @@ var c = this.collection;
if (this._needFullRefresh) {
this._applyFullRefresh();
this._needFullRefresh = false;
-} else {
+} else if (this._keySplices.length) {
if (this._sortFn) {
this._applySplicesUserSort(this._keySplices);
} else {
@@ -7664,16 +8512,26 @@ this._applyFullRefresh();
this._applySplicesArrayOrder(this._indexSplices);
}
}
+} else {
}
this._keySplices = [];
this._indexSplices = [];
var keyToIdx = this._keyToInstIdx = {};
-for (var i = 0; i < this._instances.length; i++) {
+for (var i = this._instances.length - 1; i >= 0; i--) {
var inst = this._instances[i];
+if (inst.isPlaceholder && i < this._limit) {
+inst = this._insertInstance(i, inst.__key__);
+} else if (!inst.isPlaceholder && i >= this._limit) {
+inst = this._downgradeInstance(i, inst.__key__);
+}
keyToIdx[inst.__key__] = i;
+if (!inst.isPlaceholder) {
inst.__setProperty(this.indexAs, i, true);
}
+}
+this._pool.length = 0;
this.fire('dom-change');
+this._tryRenderChunk();
},
_applyFullRefresh: function () {
var c = this.collection;
@@ -7689,33 +8547,34 @@ keys.push(c.getKey(items[i]));
}
}
}
+var self = this;
if (this._filterFn) {
keys = keys.filter(function (a) {
-return this._filterFn(c.getItem(a));
-}, this);
+return self._filterFn(c.getItem(a));
+});
}
if (this._sortFn) {
keys.sort(function (a, b) {
-return this._sortFn(c.getItem(a), c.getItem(b));
-}.bind(this));
+return self._sortFn(c.getItem(a), c.getItem(b));
+});
}
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var inst = this._instances[i];
if (inst) {
-inst.__setProperty('__key__', key, true);
+inst.__key__ = key;
+if (!inst.isPlaceholder && i < this._limit) {
inst.__setProperty(this.as, c.getItem(key), true);
+}
+} else if (i < this._limit) {
+this._insertInstance(i, key);
} else {
-this._instances.push(this._insertRow(i, key));
+this._insertPlaceholder(i, key);
}
}
-for (; i < this._instances.length; i++) {
-this._detachRow(i);
+for (var j = this._instances.length - 1; j >= i; j--) {
+this._detachAndRemoveInstance(j);
}
-this._instances.splice(keys.length, this._instances.length - keys.length);
-},
-_keySort: function (a, b) {
-return this.collection.getKey(a) - this.collection.getKey(b);
},
_numericSort: function (a, b) {
return a - b;
@@ -7724,18 +8583,16 @@ _applySplicesUserSort: function (splices) {
var c = this.collection;
var instances = this._instances;
var keyMap = {};
-var pool = [];
-var sortFn = this._sortFn || this._keySort.bind(this);
-splices.forEach(function (s) {
-for (var i = 0; i < s.removed.length; i++) {
-var key = s.removed[i];
+for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
+for (var j = 0; j < s.removed.length; j++) {
+var key = s.removed[j];
keyMap[key] = keyMap[key] ? null : -1;
}
-for (var i = 0; i < s.added.length; i++) {
-var key = s.added[i];
+for (var j = 0; j < s.added.length; j++) {
+var key = s.added[j];
keyMap[key] = keyMap[key] ? null : 1;
}
-}, this);
+}
var removedIdxs = [];
var addedKeys = [];
for (var key in keyMap) {
@@ -7751,36 +8608,35 @@ removedIdxs.sort(this._numericSort);
for (var i = removedIdxs.length - 1; i >= 0; i--) {
var idx = removedIdxs[i];
if (idx !== undefined) {
-pool.push(this._detachRow(idx));
-instances.splice(idx, 1);
+this._detachAndRemoveInstance(idx);
}
}
}
+var self = this;
if (addedKeys.length) {
if (this._filterFn) {
addedKeys = addedKeys.filter(function (a) {
-return this._filterFn(c.getItem(a));
-}, this);
+return self._filterFn(c.getItem(a));
+});
}
addedKeys.sort(function (a, b) {
-return this._sortFn(c.getItem(a), c.getItem(b));
-}.bind(this));
+return self._sortFn(c.getItem(a), c.getItem(b));
+});
var start = 0;
for (var i = 0; i < addedKeys.length; i++) {
-start = this._insertRowUserSort(start, addedKeys[i], pool);
+start = this._insertRowUserSort(start, addedKeys[i]);
}
}
},
-_insertRowUserSort: function (start, key, pool) {
+_insertRowUserSort: function (start, key) {
var c = this.collection;
var item = c.getItem(key);
var end = this._instances.length - 1;
var idx = -1;
-var sortFn = this._sortFn || this._keySort.bind(this);
while (start <= end) {
var mid = start + end >> 1;
var midKey = this._instances[mid].__key__;
-var cmp = sortFn(c.getItem(midKey), item);
+var cmp = this._sortFn(c.getItem(midKey), item);
if (cmp < 0) {
start = mid + 1;
} else if (cmp > 0) {
@@ -7793,65 +8649,80 @@ break;
if (idx < 0) {
idx = end + 1;
}
-this._instances.splice(idx, 0, this._insertRow(idx, key, pool));
+this._insertPlaceholder(idx, key);
return idx;
},
_applySplicesArrayOrder: function (splices) {
-var pool = [];
var c = this.collection;
-splices.forEach(function (s) {
-for (var i = 0; i < s.removed.length; i++) {
-var inst = this._detachRow(s.index + i);
-if (!inst.isPlaceholder) {
-pool.push(inst);
-}
-}
-this._instances.splice(s.index, s.removed.length);
-for (var i = 0; i < s.addedKeys.length; i++) {
-var inst = {
-isPlaceholder: true,
-key: s.addedKeys[i]
-};
-this._instances.splice(s.index + i, 0, inst);
+for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
+for (var j = 0; j < s.removed.length; j++) {
+this._detachAndRemoveInstance(s.index);
}
-}, this);
-for (var i = this._instances.length - 1; i >= 0; i--) {
-var inst = this._instances[i];
-if (inst.isPlaceholder) {
-this._instances[i] = this._insertRow(i, inst.key, pool, true);
+for (var j = 0; j < s.addedKeys.length; j++) {
+this._insertPlaceholder(s.index + j, s.addedKeys[j]);
}
}
},
-_detachRow: function (idx) {
+_detachInstance: function (idx) {
var inst = this._instances[idx];
if (!inst.isPlaceholder) {
-var parentNode = Polymer.dom(this).parentNode;
for (var i = 0; i < inst._children.length; i++) {
var el = inst._children[i];
Polymer.dom(inst.root).appendChild(el);
}
-}
return inst;
+}
+},
+_attachInstance: function (idx, parent) {
+var inst = this._instances[idx];
+if (!inst.isPlaceholder) {
+parent.insertBefore(inst.root, this);
+}
+},
+_detachAndRemoveInstance: function (idx) {
+var inst = this._detachInstance(idx);
+if (inst) {
+this._pool.push(inst);
+}
+this._instances.splice(idx, 1);
+},
+_insertPlaceholder: function (idx, key) {
+this._instances.splice(idx, 0, {
+isPlaceholder: true,
+__key__: key
+});
+},
+_stampInstance: function (idx, key) {
+var model = { __key__: key };
+model[this.as] = this.collection.getItem(key);
+model[this.indexAs] = idx;
+return this.stamp(model);
},
-_insertRow: function (idx, key, pool, replace) {
-var inst;
-if (inst = pool && pool.pop()) {
+_insertInstance: function (idx, key) {
+var inst = this._pool.pop();
+if (inst) {
inst.__setProperty(this.as, this.collection.getItem(key), true);
inst.__setProperty('__key__', key, true);
} else {
-inst = this._generateRow(idx, key);
+inst = this._stampInstance(idx, key);
}
-var beforeRow = this._instances[replace ? idx + 1 : idx];
-var beforeNode = beforeRow ? beforeRow._children[0] : this;
+var beforeRow = this._instances[idx + 1];
+var beforeNode = beforeRow && !beforeRow.isPlaceholder ? beforeRow._children[0] : this;
var parentNode = Polymer.dom(this).parentNode;
Polymer.dom(parentNode).insertBefore(inst.root, beforeNode);
+this._instances[idx] = inst;
return inst;
},
-_generateRow: function (idx, key) {
-var model = { __key__: key };
-model[this.as] = this.collection.getItem(key);
-model[this.indexAs] = idx;
-var inst = this.stamp(model);
+_downgradeInstance: function (idx, key) {
+var inst = this._detachInstance(idx);
+if (inst) {
+this._pool.push(inst);
+}
+inst = {
+isPlaceholder: true,
+__key__: key
+};
+this._instances[idx] = inst;
return inst;
},
_showHideChildren: function (hidden) {
@@ -7872,18 +8743,24 @@ this.set('items.' + idx, value);
},
_forwardInstancePath: function (inst, path, value) {
if (path.indexOf(this.as + '.') === 0) {
-this.notifyPath('items.' + inst.__key__ + '.' + path.slice(this.as.length + 1), value);
+this._notifyPath('items.' + inst.__key__ + '.' + path.slice(this.as.length + 1), value);
}
},
_forwardParentProp: function (prop, value) {
-this._instances.forEach(function (inst) {
+var i$ = this._instances;
+for (var i = 0, inst; i < i$.length && (inst = i$[i]); i++) {
+if (!inst.isPlaceholder) {
inst.__setProperty(prop, value, true);
-}, this);
+}
+}
},
_forwardParentPath: function (path, value) {
-this._instances.forEach(function (inst) {
-inst.notifyPath(path, value, true);
-}, this);
+var i$ = this._instances;
+for (var i = 0, inst; i < i$.length && (inst = i$[i]); i++) {
+if (!inst.isPlaceholder) {
+inst._notifyPath(path, value, true);
+}
+}
},
_forwardItemPath: function (path, value) {
if (this._keyToInstIdx) {
@@ -7891,10 +8768,10 @@ var dot = path.indexOf('.');
var key = path.substring(0, dot < 0 ? path.length : dot);
var idx = this._keyToInstIdx[key];
var inst = this._instances[idx];
-if (inst) {
+if (inst && !inst.isPlaceholder) {
if (dot >= 0) {
path = this.as + '.' + path.substring(dot + 1);
-inst.notifyPath(path, value, true);
+inst._notifyPath(path, value, true);
} else {
inst.__setProperty(this.as, value, true);
}
@@ -7916,6 +8793,7 @@ return instance && instance[this.indexAs];
});
Polymer({
is: 'array-selector',
+_template: null,
properties: {
items: {
type: Array,
@@ -7946,6 +8824,7 @@ this.unlinkPaths('selected.' + i);
}
} else {
this.unlinkPaths('selected');
+this.unlinkPaths('selectedItem');
}
if (this.multi) {
if (!this.selected || this.selected.length) {
@@ -8007,6 +8886,7 @@ this.linkPaths('selectedItem', 'items.' + key);
Polymer({
is: 'dom-if',
extends: 'template',
+_template: null,
properties: {
'if': {
type: Boolean,
@@ -8054,20 +8934,23 @@ this._lastIf = this.if;
},
_ensureInstance: function () {
if (!this._instance) {
+var parentNode = Polymer.dom(this).parentNode;
+if (parentNode) {
+var parent = Polymer.dom(parentNode);
this._instance = this.stamp();
var root = this._instance.root;
-var parent = Polymer.dom(Polymer.dom(this).parentNode);
parent.insertBefore(root, this);
}
+}
},
_teardownInstance: function () {
if (this._instance) {
-var c = this._instance._children;
-if (c) {
-var parent = Polymer.dom(Polymer.dom(c[0]).parentNode);
-c.forEach(function (n) {
+var c$ = this._instance._children;
+if (c$) {
+var parent = Polymer.dom(Polymer.dom(c$[0]).parentNode);
+for (var i = 0, n; i < c$.length && (n = c$[i]); i++) {
parent.removeChild(n);
-});
+}
}
this._instance = null;
}
@@ -8085,15 +8968,19 @@ this._instance[prop] = value;
},
_forwardParentPath: function (path, value) {
if (this._instance) {
-this._instance.notifyPath(path, value, true);
+this._instance._notifyPath(path, value, true);
}
}
});
Polymer({
is: 'dom-bind',
extends: 'template',
+_template: null,
created: function () {
-Polymer.RenderStatus.whenReady(this._markImportsReady.bind(this));
+var self = this;
+Polymer.RenderStatus.whenReady(function () {
+self._markImportsReady();
+});
},
_ensureReady: function () {
if (!this._readied) {
@@ -8132,7 +9019,10 @@ var config = {};
for (var prop in this._propertyEffects) {
config[prop] = this[prop];
}
-this._setupConfigure = this._setupConfigure.bind(this, config);
+var setupConfigure = this._setupConfigure;
+this._setupConfigure = function () {
+setupConfigure.call(this, config);
+};
},
attached: function () {
if (this._importsReady) {
@@ -8151,8 +9041,9 @@ this._prepEffects();
this._prepBehaviors();
this._prepConfigure();
this._prepBindings();
+this._prepPropertyInfo();
Polymer.Base._initFeatures.call(this);
-this._children = Array.prototype.slice.call(this.root.childNodes);
+this._children = Polymer.DomApi.arrayCopyChildNodes(this.root);
}
this._insertChildren();
this.fire('dom-change');
@@ -8340,7 +9231,7 @@ this.fire('dom-change');
var IOS = navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/);
var IOS_TOUCH_SCROLLING = IOS && IOS[1] >= 8;
- var DEFAULT_PHYSICAL_COUNT = 20;
+ var DEFAULT_PHYSICAL_COUNT = 3;
var MAX_PHYSICAL_COUNT = 500;
Polymer({
@@ -8523,7 +9414,7 @@ this.fire('dom-change');
_scrollHeight: 0,
/**
- * The size of the viewport
+ * The height of the list. This is referred as the viewport in the context of list.
*/
_viewportSize: 0,
@@ -8559,6 +9450,16 @@ this.fire('dom-change');
_itemsRendered: false,
/**
+ * The page that is currently rendered.
+ */
+ _lastPage: null,
+
+ /**
+ * The max number of pages to render. One page is equivalent to the height of the list.
+ */
+ _maxPages: 3,
+
+ /**
* The bottom of the physical content.
*/
get _physicalBottom() {
@@ -8566,6 +9467,13 @@ this.fire('dom-change');
},
/**
+ * The bottom of the scroll.
+ */
+ get _scrollBottom() {
+ return this._scrollPosition + this._viewportSize;
+ },
+
+ /**
* The n-th item rendered in the last physical item.
*/
get _virtualEnd() {
@@ -8623,7 +9531,7 @@ this.fire('dom-change');
* to a viewport of physical items above and below the user's viewport.
*/
get _optPhysicalSize() {
- return this._viewportSize * 3;
+ return this._viewportSize * this._maxPages;
},
/**
@@ -8720,19 +9628,13 @@ this.fire('dom-change');
* items in the viewport and recycle tiles as needed.
*/
_refresh: function() {
- var SCROLL_DIRECTION_UP = -1;
- var SCROLL_DIRECTION_DOWN = 1;
- var SCROLL_DIRECTION_NONE = 0;
-
// clamp the `scrollTop` value
// IE 10|11 scrollTop may go above `_maxScrollTop`
// iOS `scrollTop` may go below 0 and above `_maxScrollTop`
var scrollTop = Math.max(0, Math.min(this._maxScrollTop, this._scroller.scrollTop));
-
- var tileHeight, kth, recycledTileSet;
+ var tileHeight, tileTop, kth, recycledTileSet, scrollBottom, physicalBottom;
var ratio = this._ratio;
var delta = scrollTop - this._scrollPosition;
- var direction = SCROLL_DIRECTION_NONE;
var recycledTiles = 0;
var hiddenContentSize = this._hiddenContentSize;
var currentRatio = ratio;
@@ -8744,10 +9646,12 @@ this.fire('dom-change');
// clear cached visible index
this._firstVisibleIndexVal = null;
+ scrollBottom = this._scrollBottom;
+ physicalBottom = this._physicalBottom;
+
// random access
if (Math.abs(delta) > this._physicalSize) {
this._physicalTop += delta;
- direction = SCROLL_DIRECTION_NONE;
recycledTiles = Math.round(delta / this._physicalAverage);
}
// scroll up
@@ -8755,7 +9659,6 @@ this.fire('dom-change');
var topSpace = scrollTop - this._physicalTop;
var virtualStart = this._virtualStart;
- direction = SCROLL_DIRECTION_UP;
recycledTileSet = [];
kth = this._physicalEnd;
@@ -8768,12 +9671,14 @@ this.fire('dom-change');
// recycle less physical items than the total
recycledTiles < this._physicalCount &&
// ensure that these recycled tiles are needed
- virtualStart - recycledTiles > 0
+ virtualStart - recycledTiles > 0 &&
+ // ensure that the tile is not visible
+ physicalBottom - this._physicalSizes[kth] > scrollBottom
) {
- tileHeight = this._physicalSizes[kth] || this._physicalAverage;
+ tileHeight = this._physicalSizes[kth];
currentRatio += tileHeight / hiddenContentSize;
-
+ physicalBottom -= tileHeight;
recycledTileSet.push(kth);
recycledTiles++;
kth = (kth === 0) ? this._physicalCount - 1 : kth - 1;
@@ -8781,15 +9686,13 @@ this.fire('dom-change');
movingUp = recycledTileSet;
recycledTiles = -recycledTiles;
-
}
// scroll down
else if (delta > 0) {
- var bottomSpace = this._physicalBottom - (scrollTop + this._viewportSize);
+ var bottomSpace = physicalBottom - scrollBottom;
var virtualEnd = this._virtualEnd;
var lastVirtualItemIndex = this._virtualCount-1;
- direction = SCROLL_DIRECTION_DOWN;
recycledTileSet = [];
kth = this._physicalStart;
@@ -8802,10 +9705,12 @@ this.fire('dom-change');
// recycle less physical items than the total
recycledTiles < this._physicalCount &&
// ensure that these recycled tiles are needed
- virtualEnd + recycledTiles < lastVirtualItemIndex
+ virtualEnd + recycledTiles < lastVirtualItemIndex &&
+ // ensure that the tile is not visible
+ this._physicalTop + this._physicalSizes[kth] < scrollTop
) {
- tileHeight = this._physicalSizes[kth] || this._physicalAverage;
+ tileHeight = this._physicalSizes[kth];
currentRatio += tileHeight / hiddenContentSize;
this._physicalTop += tileHeight;
@@ -8815,7 +9720,14 @@ this.fire('dom-change');
}
}
- if (recycledTiles !== 0) {
+ if (recycledTiles === 0) {
+ // If the list ever reach this case, the physical average is not significant enough
+ // to create all the items needed to cover the entire viewport.
+ // e.g. A few items have a height that differs from the average by serveral order of magnitude.
+ if (physicalBottom < scrollBottom || this._physicalTop > scrollTop) {
+ this.async(this._increasePool.bind(this, 1));
+ }
+ } else {
this._virtualStart = this._virtualStart + recycledTiles;
this._update(recycledTileSet, movingUp);
}
@@ -8845,11 +9757,8 @@ this.fire('dom-change');
// set the scroller size
this._updateScrollerSize();
- // increase the pool of physical items if needed
- if (this._increasePoolIfNeeded()) {
- // set models to the new items
- this.async(this._update);
- }
+ // increase the pool of physical items
+ this._increasePoolIfNeeded();
},
/**
@@ -8862,7 +9771,6 @@ this.fire('dom-change');
for (var i = 0; i < size; i++) {
var inst = this.stamp(null);
-
// First element child is item; Safari doesn't support children[0]
// on a doc fragment
physicalItems[i] = inst.root.querySelector('*');
@@ -8873,47 +9781,52 @@ this.fire('dom-change');
},
/**
- * Increases the pool size. That is, the physical items in the DOM.
+ * Increases the pool of physical items only if needed.
* This function will allocate additional physical items
- * (limited by `MAX_PHYSICAL_COUNT`) if the content size is shorter than
- * `_optPhysicalSize`
- *
- * @return boolean
+ * if the physical size is shorter than `_optPhysicalSize`
*/
_increasePoolIfNeeded: function() {
- if (this._physicalSize >= this._optPhysicalSize || this._physicalAverage === 0) {
- return false;
+ if (this._viewportSize !== 0 && this._physicalSize < this._optPhysicalSize) {
+ // 0 <= `currentPage` <= `_maxPages`
+ var currentPage = Math.floor(this._physicalSize / this._viewportSize);
+
+ if (currentPage === 0) {
+ // fill the first page
+ this.async(this._increasePool.bind(this, Math.round(this._physicalCount * 0.5)));
+ } else if (this._lastPage !== currentPage) {
+ // once a page is filled up, paint it and defer the next increase
+ requestAnimationFrame(this._increasePool.bind(this, 1));
+ } else {
+ // fill the rest of the pages
+ this.async(this._increasePool.bind(this, 1));
+ }
+ this._lastPage = currentPage;
+ return true;
}
+ return false;
+ },
- // the estimated number of physical items that we will need to reach
- // the cap established by `_optPhysicalSize`.
- var missingItems = Math.round(
- (this._optPhysicalSize - this._physicalSize) * 1.2 / this._physicalAverage
- );
-
+ /**
+ * Increases the pool size.
+ */
+ _increasePool: function(missingItems) {
// limit the size
var nextPhysicalCount = Math.min(
this._physicalCount + missingItems,
this._virtualCount,
MAX_PHYSICAL_COUNT
);
-
var prevPhysicalCount = this._physicalCount;
var delta = nextPhysicalCount - prevPhysicalCount;
- if (delta <= 0) {
- return false;
- }
-
- var newPhysicalItems = this._createPool(delta);
- var emptyArray = new Array(delta);
+ if (delta > 0) {
+ [].push.apply(this._physicalItems, this._createPool(delta));
+ [].push.apply(this._physicalSizes, new Array(delta));
- [].push.apply(this._physicalItems, newPhysicalItems);
- [].push.apply(this._physicalSizes, emptyArray);
-
- this._physicalCount = prevPhysicalCount + delta;
-
- return true;
+ this._physicalCount = prevPhysicalCount + delta;
+ // tail call
+ return this._update();
+ }
},
/**
@@ -8923,7 +9836,8 @@ this.fire('dom-change');
_render: function() {
var requiresUpdate = this._virtualCount > 0 || this._physicalCount > 0;
- if (this.isAttached && !this._itemsRendered && this._isVisible && requiresUpdate) {
+ if (this.isAttached && !this._itemsRendered && this._isVisible && requiresUpdate) {
+ this._lastPage = 0;
this._update();
this._itemsRendered = true;
}
@@ -9287,7 +10201,7 @@ this.fire('dom-change');
var hiddenContentSize = this._hiddenContentSize;
// scroll to the item as much as we can
- while (currentVirtualItem !== idx && targetOffsetTop < hiddenContentSize) {
+ while (currentVirtualItem < idx && targetOffsetTop < hiddenContentSize) {
targetOffsetTop = targetOffsetTop + this._physicalSizes[currentTopItem];
currentTopItem = (currentTopItem + 1) % this._physicalCount;
currentVirtualItem++;
@@ -9303,10 +10217,7 @@ this.fire('dom-change');
this._resetScrollPosition(this._physicalTop + targetOffsetTop + 1);
// increase the pool of physical items if needed
- if (this._increasePoolIfNeeded()) {
- // set models to the new items
- this.async(this._update);
- }
+ this._increasePoolIfNeeded();
// clear cached visible index
this._firstVisibleIndexVal = null;
@@ -9381,363 +10292,117 @@ this.fire('dom-change');
this.$.selector.select(item);
},
- /**
- * Deselects the given item list if it is already selected.
- *
-
- * @method deselect
- * @param {(Object|number)} item The item object or its index
- */
- deselectItem: function(item) {
- item = this._getNormalizedItem(item);
- var model = this._getModelFromItem(item);
-
- if (model) {
- model[this.selectedAs] = false;
- }
- this.$.selector.deselect(item);
- },
-
- /**
- * Select or deselect a given item depending on whether the item
- * has already been selected.
- *
- * @method toggleSelectionForItem
- * @param {(Object|number)} item The item object or its index
- */
- toggleSelectionForItem: function(item) {
- item = this._getNormalizedItem(item);
- if (/** @type {!ArraySelectorElement} */ (this.$.selector).isSelected(item)) {
- this.deselectItem(item);
- } else {
- this.selectItem(item);
- }
- },
-
- /**
- * Clears the current selection state of the list.
- *
- * @method clearSelection
- */
- clearSelection: function() {
- function unselect(item) {
- var model = this._getModelFromItem(item);
- if (model) {
- model[this.selectedAs] = false;
- }
- }
-
- if (Array.isArray(this.selectedItems)) {
- this.selectedItems.forEach(unselect, this);
- } else if (this.selectedItem) {
- unselect.call(this, this.selectedItem);
- }
-
- /** @type {!ArraySelectorElement} */ (this.$.selector).clearSelection();
- },
-
- /**
- * Add an event listener to `tap` if `selectionEnabled` is true,
- * it will remove the listener otherwise.
- */
- _selectionEnabledChanged: function(selectionEnabled) {
- if (selectionEnabled) {
- this.listen(this, 'tap', '_selectionHandler');
- this.listen(this, 'keypress', '_selectionHandler');
- } else {
- this.unlisten(this, 'tap', '_selectionHandler');
- this.unlisten(this, 'keypress', '_selectionHandler');
- }
- },
-
- /**
- * Select an item from an event object.
- */
- _selectionHandler: function(e) {
- if (e.type !== 'keypress' || e.keyCode === 13) {
- var model = this.modelForElement(e.target);
- if (model) {
- this.toggleSelectionForItem(model[this.as]);
- }
- }
- },
-
- _multiSelectionChanged: function(multiSelection) {
- this.clearSelection();
- this.$.selector.multi = multiSelection;
- },
-
- /**
- * Updates the size of an item.
- *
- * @method updateSizeForItem
- * @param {(Object|number)} item The item object or its index
- */
- updateSizeForItem: function(item) {
- item = this._getNormalizedItem(item);
- var key = this._collection.getKey(item);
- var pidx = this._physicalIndexForKey[key];
-
- if (pidx !== undefined) {
- this._updateMetrics([pidx]);
- this._positionItems();
- }
- }
- });
-
-})();
-(function() {
-
- 'use strict';
-
- var SHADOW_WHEN_SCROLLING = 1;
- var SHADOW_ALWAYS = 2;
-
-
- var MODE_CONFIGS = {
-
- outerScroll: {
- 'scroll': true
- },
-
- shadowMode: {
- 'standard': SHADOW_ALWAYS,
- 'waterfall': SHADOW_WHEN_SCROLLING,
- 'waterfall-tall': SHADOW_WHEN_SCROLLING
- },
-
- tallMode: {
- 'waterfall-tall': true
- }
- };
-
- Polymer({
-
- is: 'paper-header-panel',
-
- /**
- * Fired when the content has been scrolled. `event.detail.target` returns
- * the scrollable element which you can use to access scroll info such as
- * `scrollTop`.
- *
- * <paper-header-panel on-content-scroll="scrollHandler">
- * ...
- * </paper-header-panel>
- *
- *
- * scrollHandler: function(event) {
- * var scroller = event.detail.target;
- * console.log(scroller.scrollTop);
- * }
- *
- * @event content-scroll
- */
-
- properties: {
-
- /**
- * Controls header and scrolling behavior. Options are
- * `standard`, `seamed`, `waterfall`, `waterfall-tall`, `scroll` and
- * `cover`. Default is `standard`.
- *
- * `standard`: The header is a step above the panel. The header will consume the
- * panel at the point of entry, preventing it from passing through to the
- * opposite side.
- *
- * `seamed`: The header is presented as seamed with the panel.
- *
- * `waterfall`: Similar to standard mode, but header is initially presented as
- * seamed with panel, but then separates to form the step.
- *
- * `waterfall-tall`: The header is initially taller (`tall` class is added to
- * the header). As the user scrolls, the header separates (forming an edge)
- * while condensing (`tall` class is removed from the header).
- *
- * `scroll`: The header keeps its seam with the panel, and is pushed off screen.
- *
- * `cover`: The panel covers the whole `paper-header-panel` including the
- * header. This allows user to style the panel in such a way that the panel is
- * partially covering the header.
- *
- * <paper-header-panel mode="cover">
- * <paper-toolbar class="tall">
- * <core-icon-button icon="menu"></core-icon-button>
- * </paper-toolbar>
- * <div class="content"></div>
- * </paper-header-panel>
- */
- mode: {
- type: String,
- value: 'standard',
- observer: '_modeChanged',
- reflectToAttribute: true
- },
-
- /**
- * If true, the drop-shadow is always shown no matter what mode is set to.
- */
- shadow: {
- type: Boolean,
- value: false
- },
-
- /**
- * The class used in waterfall-tall mode. Change this if the header
- * accepts a different class for toggling height, e.g. "medium-tall"
- */
- tallClass: {
- type: String,
- value: 'tall'
- },
-
- /**
- * If true, the scroller is at the top
- */
- atTop: {
- type: Boolean,
- value: true,
- readOnly: true
- }
- },
-
- observers: [
- '_computeDropShadowHidden(atTop, mode, shadow)'
- ],
-
- ready: function() {
- this.scrollHandler = this._scroll.bind(this);
- this._addListener();
-
- // Run `scroll` logic once to initialze class names, etc.
- this._keepScrollingState();
- },
-
- detached: function() {
- this._removeListener();
- },
-
- /**
- * Returns the header element
- *
- * @property header
- * @type Object
- */
- get header() {
- return Polymer.dom(this.$.headerContent).getDistributedNodes()[0];
- },
-
- /**
- * Returns the scrollable element.
- *
- * @property scroller
- * @type Object
- */
- get scroller() {
- return this._getScrollerForMode(this.mode);
- },
-
- /**
- * Returns true if the scroller has a visible shadow.
- *
- * @property visibleShadow
- * @type Boolean
- */
- get visibleShadow() {
- return this.$.dropShadow.classList.contains('has-shadow');
- },
-
- _computeDropShadowHidden: function(atTop, mode, shadow) {
-
- var shadowMode = MODE_CONFIGS.shadowMode[mode];
-
- if (this.shadow) {
- this.toggleClass('has-shadow', true, this.$.dropShadow);
-
- } else if (shadowMode === SHADOW_ALWAYS) {
- this.toggleClass('has-shadow', true, this.$.dropShadow);
-
- } else if (shadowMode === SHADOW_WHEN_SCROLLING && !atTop) {
- this.toggleClass('has-shadow', true, this.$.dropShadow);
-
- } else {
- this.toggleClass('has-shadow', false, this.$.dropShadow);
-
- }
- },
-
- _computeMainContainerClass: function(mode) {
- // TODO: It will be useful to have a utility for classes
- // e.g. Polymer.Utils.classes({ foo: true });
-
- var classes = {};
-
- classes['flex'] = mode !== 'cover';
-
- return Object.keys(classes).filter(
- function(className) {
- return classes[className];
- }).join(' ');
- },
+ /**
+ * Deselects the given item list if it is already selected.
+ *
- _addListener: function() {
- this.scroller.addEventListener('scroll', this.scrollHandler, false);
- },
+ * @method deselect
+ * @param {(Object|number)} item The item object or its index
+ */
+ deselectItem: function(item) {
+ item = this._getNormalizedItem(item);
+ var model = this._getModelFromItem(item);
- _removeListener: function() {
- this.scroller.removeEventListener('scroll', this.scrollHandler);
- },
+ if (model) {
+ model[this.selectedAs] = false;
+ }
+ this.$.selector.deselect(item);
+ },
- _modeChanged: function(newMode, oldMode) {
- var configs = MODE_CONFIGS;
- var header = this.header;
- var animateDuration = 200;
+ /**
+ * Select or deselect a given item depending on whether the item
+ * has already been selected.
+ *
+ * @method toggleSelectionForItem
+ * @param {(Object|number)} item The item object or its index
+ */
+ toggleSelectionForItem: function(item) {
+ item = this._getNormalizedItem(item);
+ if (/** @type {!ArraySelectorElement} */ (this.$.selector).isSelected(item)) {
+ this.deselectItem(item);
+ } else {
+ this.selectItem(item);
+ }
+ },
- if (header) {
- // in tallMode it may add tallClass to the header; so do the cleanup
- // when mode is changed from tallMode to not tallMode
- if (configs.tallMode[oldMode] && !configs.tallMode[newMode]) {
- header.classList.remove(this.tallClass);
- this.async(function() {
- header.classList.remove('animate');
- }, animateDuration);
- } else {
- header.classList.toggle('animate', configs.tallMode[newMode]);
- }
+ /**
+ * Clears the current selection state of the list.
+ *
+ * @method clearSelection
+ */
+ clearSelection: function() {
+ function unselect(item) {
+ var model = this._getModelFromItem(item);
+ if (model) {
+ model[this.selectedAs] = false;
}
- this._keepScrollingState();
- },
+ }
+
+ if (Array.isArray(this.selectedItems)) {
+ this.selectedItems.forEach(unselect, this);
+ } else if (this.selectedItem) {
+ unselect.call(this, this.selectedItem);
+ }
- _keepScrollingState: function() {
- var main = this.scroller;
- var header = this.header;
+ /** @type {!ArraySelectorElement} */ (this.$.selector).clearSelection();
+ },
- this._setAtTop(main.scrollTop === 0);
+ /**
+ * Add an event listener to `tap` if `selectionEnabled` is true,
+ * it will remove the listener otherwise.
+ */
+ _selectionEnabledChanged: function(selectionEnabled) {
+ if (selectionEnabled) {
+ this.listen(this, 'tap', '_selectionHandler');
+ this.listen(this, 'keypress', '_selectionHandler');
+ } else {
+ this.unlisten(this, 'tap', '_selectionHandler');
+ this.unlisten(this, 'keypress', '_selectionHandler');
+ }
+ },
- if (header && this.tallClass && MODE_CONFIGS.tallMode[this.mode]) {
- this.toggleClass(this.tallClass, this.atTop ||
- header.classList.contains(this.tallClass) &&
- main.scrollHeight < this.offsetHeight, header);
+ /**
+ * Select an item from an event object.
+ */
+ _selectionHandler: function(e) {
+ if (e.type !== 'keypress' || e.keyCode === 13) {
+ var model = this.modelForElement(e.target);
+ if (model) {
+ this.toggleSelectionForItem(model[this.as]);
}
- },
+ }
+ },
- _scroll: function() {
- this._keepScrollingState();
- this.fire('content-scroll', {target: this.scroller}, {bubbles: false});
- },
+ _multiSelectionChanged: function(multiSelection) {
+ this.clearSelection();
+ this.$.selector.multi = multiSelection;
+ },
- _getScrollerForMode: function(mode) {
- return MODE_CONFIGS.outerScroll[mode] ?
- this : this.$.mainContainer;
- }
+ /**
+ * Updates the size of an item.
+ *
+ * @method updateSizeForItem
+ * @param {(Object|number)} item The item object or its index
+ */
+ updateSizeForItem: function(item) {
+ item = this._getNormalizedItem(item);
+ var key = this._collection.getKey(item);
+ var pidx = this._physicalIndexForKey[key];
- });
+ if (pidx !== undefined) {
+ this._updateMetrics([pidx]);
+ this._positionItems();
+ }
+ }
+ });
- })();
+})();
(function() {
// monostate data
var metaDatas = {};
var metaArrays = {};
+ var singleton = null;
Polymer.IronMeta = Polymer({
@@ -9790,9 +10455,15 @@ this.fire('dom-change');
},
+ hostAttributes: {
+ hidden: true
+ },
+
/**
* Only runs if someone invokes the factory/constructor directly
* e.g. `new Polymer.IronMeta()`
+ *
+ * @param {{type: (string|undefined), key: (string|undefined), value}=} config
*/
factoryImpl: function(config) {
if (config) {
@@ -9884,6 +10555,13 @@ this.fire('dom-change');
});
+ Polymer.IronMeta.getIronMeta = function getIronMeta() {
+ if (singleton === null) {
+ singleton = new Polymer.IronMeta();
+ }
+ return singleton;
+ };
+
/**
`iron-meta-query` can be used to access infomation stored in `iron-meta`.
@@ -9950,6 +10628,8 @@ this.fire('dom-change');
/**
* Actually a factory method, not a true constructor. Only runs if
* someone invokes it directly (via `new Polymer.IronMeta()`);
+ *
+ * @param {{type: (string|undefined), key: (string|undefined)}=} config
*/
factoryImpl: function(config) {
if (config) {
@@ -10086,9 +10766,9 @@ Polymer({
* `iron-iconset-svg` element. Multiple icons should be given distinct id's.
*
* Using svg elements to create icons has a few advantages over traditional
- * bitmap graphics like jpg or png. Icons that use svg are vector based so they
- * are resolution independent and should look good on any device. They are
- * stylable via css. Icons can be themed, colorized, and even animated.
+ * bitmap graphics like jpg or png. Icons that use svg are vector based so
+ * they are resolution independent and should look good on any device. They
+ * are stylable via css. Icons can be themed, colorized, and even animated.
*
* Example:
*
@@ -10096,8 +10776,8 @@ Polymer({
* <svg>
* <defs>
* <g id="shape">
- * <rect x="50" y="50" width="50" height="50" />
- * <circle cx="50" cy="50" r="50" />
+ * <rect x="12" y="0" width="12" height="24" />
+ * <circle cx="12" cy="12" r="12" />
* </g>
* </defs>
* </svg>
@@ -10113,18 +10793,15 @@ Polymer({
*
* @element iron-iconset-svg
* @demo demo/index.html
+ * @implements {Polymer.Iconset}
*/
Polymer({
-
is: 'iron-iconset-svg',
properties: {
/**
* The name of the iconset.
- *
- * @attribute name
- * @type string
*/
name: {
type: String,
@@ -10133,10 +10810,6 @@ Polymer({
/**
* The size of an individual icon. Note that icons must be square.
- *
- * @attribute iconSize
- * @type number
- * @default 24
*/
size: {
type: Number,
@@ -10145,6 +10818,10 @@ Polymer({
},
+ attached: function() {
+ this.style.display = 'none';
+ },
+
/**
* Construct an array of all icon names in this iconset.
*
@@ -10166,7 +10843,7 @@ Polymer({
* @method applyIcon
* @param {Element} element Element to which the icon is applied.
* @param {string} iconName Name of the icon to apply.
- * @return {Element} The svg element which renders the icon.
+ * @return {?Element} The svg element which renders the icon.
*/
applyIcon: function(element, iconName) {
// insert svg element into shadow root, if it exists
@@ -10506,6 +11183,15 @@ Polymer({
}
},
+ /**
+ * If true, this property will cause the implementing element to
+ * automatically stop propagation on any handled KeyboardEvents.
+ */
+ stopKeyboardEventPropagation: {
+ type: Boolean,
+ value: false
+ },
+
_boundKeyHandlers: {
type: Array,
value: function() {
@@ -10649,6 +11335,10 @@ Polymer({
},
_onKeyBindingEvent: function(keyBindings, event) {
+ if (this.stopKeyboardEventPropagation) {
+ event.stopPropagation();
+ }
+
keyBindings.forEach(function(keyBinding) {
var keyCombo = keyBinding[0];
var handlerName = keyBinding[1];
@@ -10662,10 +11352,14 @@ Polymer({
_triggerKeyHandler: function(keyCombo, handlerName, keyboardEvent) {
var detail = Object.create(keyCombo);
detail.keyboardEvent = keyboardEvent;
-
- this[handlerName].call(this, new CustomEvent(keyCombo.event, {
- detail: detail
- }));
+ var event = new CustomEvent(keyCombo.event, {
+ detail: detail,
+ cancelable: true
+ });
+ this[handlerName].call(this, event);
+ if (event.defaultPrevented) {
+ keyboardEvent.preventDefault();
+ }
}
};
})();
@@ -10729,9 +11423,8 @@ Polymer({
// handled). In either case, we can disregard `event.path`.
if (event.target === this) {
- var focused = event.type === 'focus';
- this._setFocused(focused);
- } else if (!this.shadowRoot) {
+ this._setFocused(event.type === 'focus');
+ } else if (!this.shadowRoot && !this.isLightDescendant(event.target)) {
this.fire(event.type, {sourceEvent: event}, {
node: this,
bubbles: event.bubbles,
@@ -10882,14 +11575,35 @@ Polymer({
this._setPressed(false);
},
+ /**
+ * @param {!KeyboardEvent} event .
+ */
_spaceKeyDownHandler: function(event) {
var keyboardEvent = event.detail.keyboardEvent;
+ var target = Polymer.dom(keyboardEvent).localTarget;
+
+ // Ignore the event if this is coming from a focused light child, since that
+ // element will deal with it.
+ if (this.isLightDescendant(target))
+ return;
+
keyboardEvent.preventDefault();
keyboardEvent.stopImmediatePropagation();
this._setPressed(true);
},
- _spaceKeyUpHandler: function() {
+ /**
+ * @param {!KeyboardEvent} event .
+ */
+ _spaceKeyUpHandler: function(event) {
+ var keyboardEvent = event.detail.keyboardEvent;
+ var target = Polymer.dom(keyboardEvent).localTarget;
+
+ // Ignore the event if this is coming from a focused light child, since that
+ // element will deal with it.
+ if (this.isLightDescendant(target))
+ return;
+
if (this.pressed) {
this._asyncClick();
}
@@ -11350,10 +12064,6 @@ Polymer({
}
},
- observers: [
- '_noinkChanged(noink, isAttached)'
- ],
-
get target () {
var ownerRoot = Polymer.dom(this).getOwnerRoot();
var target;
@@ -11374,6 +12084,10 @@ Polymer({
},
attached: function() {
+ // Set up a11yKeysBehavior to listen to key events on the target,
+ // so that space and enter activate the ripple even if the target doesn't
+ // handle key events. The key handlers deal with `noink` themselves.
+ this.keyEventTarget = this.target;
this.listen(this.target, 'up', 'uiUpAction');
this.listen(this.target, 'down', 'uiDownAction');
},
@@ -11543,12 +12257,6 @@ Polymer({
} else {
this.upAction();
}
- },
-
- _noinkChanged: function(noink, attached) {
- if (attached) {
- this.keyEventTarget = noink ? this : this.target;
- }
}
});
})();
@@ -11605,10 +12313,10 @@ Polymer({
/**
* Ensures this element contains a ripple effect. For startup efficiency
* the ripple effect is dynamically on demand when needed.
- * @param {!Event=} opt_triggeringEvent (optional) event that triggered the
+ * @param {!Event=} optTriggeringEvent (optional) event that triggered the
* ripple.
*/
- ensureRipple: function(opt_triggeringEvent) {
+ ensureRipple: function(optTriggeringEvent) {
if (!this.hasRipple()) {
this._ripple = this._createRipple();
this._ripple.noink = this.noink;
@@ -11616,12 +12324,14 @@ Polymer({
if (rippleContainer) {
Polymer.dom(rippleContainer).appendChild(this._ripple);
}
- var domContainer = rippleContainer === this.shadyRoot ? this :
- rippleContainer;
- if (opt_triggeringEvent) {
- var target = opt_triggeringEvent.target;
- if (domContainer.contains(/** @type {Node} */(target))) {
- this._ripple.uiDownAction(opt_triggeringEvent);
+ if (optTriggeringEvent) {
+ // Check if the event happened inside of the ripple container
+ // Fall back to host instead of the root because distributed text
+ // nodes are not valid event targets
+ var domContainer = Polymer.dom(this._rippleContainer || this);
+ var target = Polymer.dom(optTriggeringEvent).rootTarget;
+ if (domContainer.deepContains( /** @type {Node} */(target))) {
+ this._ripple.uiDownAction(optTriggeringEvent);
}
}
}
@@ -11666,7 +12376,7 @@ Polymer({
/**
* `Polymer.PaperInkyFocusBehavior` implements a ripple when the element has keyboard focus.
*
- * @polymerBehavior Polymer.PaperInkyFocusBehaviorImpl
+ * @polymerBehavior Polymer.PaperInkyFocusBehavior
*/
Polymer.PaperInkyFocusBehaviorImpl = {
@@ -11704,7 +12414,6 @@ Polymer({
is: 'paper-material',
properties: {
-
/**
* The z-depth of this element, from 0-5. Setting to 0 will remove the
* shadow, and each increasing number greater than 0 will be "deeper"
@@ -11846,11 +12555,11 @@ Polymer({
}
}
});
-/**
+/**
* `iron-range-behavior` provides the behavior for something with a minimum to maximum range.
*
* @demo demo/index.html
- * @polymerBehavior
+ * @polymerBehavior
*/
Polymer.IronRangeBehavior = {
@@ -11919,7 +12628,7 @@ Polymer({
_calcStep: function(value) {
/**
* if we calculate the step using
- * `Math.round(value / step) * step` we may hit a precision point issue
+ * `Math.round(value / step) * step` we may hit a precision point issue
* eg. 0.1 * 0.2 = 0.020000000000000004
* http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
*
@@ -11927,7 +12636,8 @@ Polymer({
*/
// polymer/issues/2493
value = parseFloat(value);
- return this.step ? (Math.round((value + this.min) / this.step) / (1 / this.step)) - this.min : value;
+ return this.step ? (Math.round((value + this.min) / this.step) -
+ (this.min / this.step)) / (1 / this.step) : value;
},
_validateValue: function() {
@@ -12378,17 +13088,25 @@ cr.define('downloads', function() {
Item: Item,
};
});
+/** @polymerBehavior Polymer.PaperItemBehavior */
+ Polymer.PaperItemBehaviorImpl = {
+ hostAttributes: {
+ role: 'option',
+ tabindex: '0'
+ }
+ };
+
+ /** @polymerBehavior */
+ Polymer.PaperItemBehavior = [
+ Polymer.IronControlState,
+ Polymer.IronButtonState,
+ Polymer.PaperItemBehaviorImpl
+ ];
Polymer({
is: 'paper-item',
- hostAttributes: {
- role: 'listitem',
- tabindex: '0'
- },
-
behaviors: [
- Polymer.IronControlState,
- Polymer.IronButtonState
+ Polymer.PaperItemBehavior
]
});
/**
@@ -12542,6 +13260,8 @@ Polymer({
/**
* Returns the currently selected item.
+ *
+ * @type {?Object}
*/
selectedItem: {
type: Object,
@@ -12583,10 +13303,20 @@ Polymer({
},
/**
+ * The list of items from which a selection can be made.
+ */
+ items: {
+ type: Array,
+ readOnly: true,
+ value: function() {
+ return [];
+ }
+ },
+
+ /**
* The set of excluded elements where the key is the `localName`
* of the element that will be ignored from the item list.
*
- * @type {object}
* @default {template: 1}
*/
_excludedLocalNames: {
@@ -12606,15 +13336,12 @@ Polymer({
created: function() {
this._bindFilterItem = this._filterItem.bind(this);
this._selection = new Polymer.IronSelection(this._applySelection.bind(this));
- // TODO(cdata): When polymer/polymer#2535 lands, we do not need to do this
- // book keeping anymore:
- this.__listeningForActivate = false;
},
attached: function() {
this._observer = this._observeItems(this);
- this._contentObserver = this._observeContent(this);
- if (!this.selectedItem && this.selected) {
+ this._updateItems();
+ if (!this._shouldUpdateSelection) {
this._updateSelected(this.attrForSelected,this.selected)
}
this._addListener(this.activateEvent);
@@ -12622,26 +13349,12 @@ Polymer({
detached: function() {
if (this._observer) {
- this._observer.disconnect();
- }
- if (this._contentObserver) {
- this._contentObserver.disconnect();
+ Polymer.dom(this).unobserveNodes(this._observer);
}
this._removeListener(this.activateEvent);
},
/**
- * Returns an array of selectable items.
- *
- * @property items
- * @type Array
- */
- get items() {
- var nodes = Polymer.dom(this).queryDistributedElements(this.selectable || '*');
- return Array.prototype.filter.call(nodes, this._bindFilterItem);
- },
-
- /**
* Returns the index of the given item.
*
* @method indexOf
@@ -12683,18 +13396,16 @@ Polymer({
this.selected = this._indexToValue(index);
},
- _addListener: function(eventName) {
- if (!this.isAttached || this.__listeningForActivate) {
- return;
- }
+ get _shouldUpdateSelection() {
+ return this.selected != null;
+ },
- this.__listeningForActivate = true;
+ _addListener: function(eventName) {
this.listen(this, eventName, '_activateHandler');
},
_removeListener: function(eventName) {
this.unlisten(this, eventName, '_activateHandler');
- this.__listeningForActivate = false;
},
_activateEventChanged: function(eventName, old) {
@@ -12702,6 +13413,12 @@ Polymer({
this._addListener(eventName);
},
+ _updateItems: function() {
+ var nodes = Polymer.dom(this).queryDistributedElements(this.selectable || '*');
+ nodes = Array.prototype.filter.call(nodes, this._bindFilterItem);
+ this._setItems(nodes);
+ },
+
_updateSelected: function() {
this._selectSelected(this.selected);
},
@@ -12760,18 +13477,9 @@ Polymer({
this._setSelectedItem(this._selection.get());
},
- // observe content changes under the given node.
- _observeContent: function(node) {
- var content = node.querySelector('content');
- if (content && content.parentElement === node) {
- return this._observeItems(node.domHost);
- }
- },
-
// observe items change under the given node.
_observeItems: function(node) {
- // TODO(cdata): Update this when we get distributed children changed.
- var observer = new MutationObserver(function(mutations) {
+ return Polymer.dom(node).observeNodes(function(mutations) {
// Let other interested parties know about the change so that
// we don't have to recreate mutation observers everywher.
this.fire('iron-items-changed', mutations, {
@@ -12779,15 +13487,12 @@ Polymer({
cancelable: false
});
- if (this.selected != null) {
+ this._updateItems();
+
+ if (this._shouldUpdateSelection) {
this._updateSelected();
}
- }.bind(this));
- observer.observe(node, {
- childList: true,
- subtree: true
});
- return observer;
},
_activateHandler: function(e) {
@@ -12872,6 +13577,11 @@ Polymer({
this._selection.multi = multi;
},
+ get _shouldUpdateSelection() {
+ return this.selected != null ||
+ (this.selectedValues != null && this.selectedValues.length);
+ },
+
_updateSelected: function() {
if (this.multi) {
this._selectMulti(this.selectedValues);
@@ -13209,18 +13919,14 @@ Polymer({
Polymer.IronMenuBehaviorImpl
];
(function() {
+ Polymer({
+ is: 'paper-menu',
- Polymer({
-
- is: 'paper-menu',
-
- behaviors: [
- Polymer.IronMenuBehavior
- ]
-
- });
-
-})();
+ behaviors: [
+ Polymer.IronMenuBehavior
+ ]
+ });
+ })();
/**
Polymer.IronFitBehavior fits an element in another element using `max-height` and `max-width`, and
optionally centers it in the window or another element.
@@ -13416,6 +14122,10 @@ CSS properties | Action
if (!this._fitInfo.positionedBy.horizontally) {
this.style.left = '0px';
}
+ if (!this._fitInfo.positionedBy.vertically || !this._fitInfo.positionedBy.horizontally) {
+ // need position:fixed to properly size the element
+ this.style.position = 'fixed';
+ }
// need border-box for margin/padding
this.sizingTarget.style.boxSizing = 'border-box';
// constrain the width and height if not already set
@@ -13461,60 +14171,74 @@ CSS properties | Action
}
};
-Polymer.IronOverlayManager = (function() {
+Polymer.IronOverlayManager = {
+
+ _overlays: [],
+
+ // iframes have a default z-index of 100, so this default should be at least
+ // that.
+ _minimumZ: 101,
+
+ _backdrops: [],
- var overlays = [];
- var DEFAULT_Z = 10;
- var backdrops = [];
+ _applyOverlayZ: function(overlay, aboveZ) {
+ this._setZ(overlay, aboveZ + 2);
+ },
+
+ _setZ: function(element, z) {
+ element.style.zIndex = z;
+ },
// track overlays for z-index and focus managemant
- function addOverlay(overlay) {
- var z0 = currentOverlayZ();
- overlays.push(overlay);
- var z1 = currentOverlayZ();
- if (z1 <= z0) {
- applyOverlayZ(overlay, z0);
+ addOverlay: function(overlay) {
+ var minimumZ = Math.max(this.currentOverlayZ(), this._minimumZ);
+ this._overlays.push(overlay);
+ var newZ = this.currentOverlayZ();
+ if (newZ <= minimumZ) {
+ this._applyOverlayZ(overlay, minimumZ);
}
- }
+ },
- function removeOverlay(overlay) {
- var i = overlays.indexOf(overlay);
+ removeOverlay: function(overlay) {
+ var i = this._overlays.indexOf(overlay);
if (i >= 0) {
- overlays.splice(i, 1);
- setZ(overlay, '');
+ this._overlays.splice(i, 1);
+ this._setZ(overlay, '');
}
- }
-
- function applyOverlayZ(overlay, aboveZ) {
- setZ(overlay, aboveZ + 2);
- }
-
- function setZ(element, z) {
- element.style.zIndex = z;
- }
+ },
- function currentOverlay() {
- var i = overlays.length - 1;
- while (overlays[i] && !overlays[i].opened) {
+ currentOverlay: function() {
+ var i = this._overlays.length - 1;
+ while (this._overlays[i] && !this._overlays[i].opened) {
--i;
}
- return overlays[i];
- }
+ return this._overlays[i];
+ },
- function currentOverlayZ() {
- var z;
- var current = currentOverlay();
+ currentOverlayZ: function() {
+ var z = this._minimumZ;
+ var current = this.currentOverlay();
if (current) {
var z1 = window.getComputedStyle(current).zIndex;
if (!isNaN(z1)) {
z = Number(z1);
}
}
- return z || DEFAULT_Z;
- }
+ return z;
+ },
+
+ /**
+ * Ensures that the minimum z-index of new overlays is at least `minimumZ`.
+ * This does not effect the z-index of any existing overlays.
+ *
+ * @param {number} minimumZ
+ */
+ ensureMinimumZ: function(minimumZ) {
+ this._minimumZ = Math.max(this._minimumZ, minimumZ);
+ },
- function focusOverlay() {
- var current = currentOverlay();
+ focusOverlay: function() {
+ var current = this.currentOverlay();
// We have to be careful to focus the next overlay _after_ any current
// transitions are complete (due to the state being toggled prior to the
// transition). Otherwise, we risk infinite recursion when a transitioning
@@ -13526,36 +14250,26 @@ Polymer.IronOverlayManager = (function() {
if (current && !current.transitioning) {
current._applyFocus();
}
- }
+ },
- function trackBackdrop(element) {
+ trackBackdrop: function(element) {
// backdrops contains the overlays with a backdrop that are currently
// visible
if (element.opened) {
- backdrops.push(element);
+ this._backdrops.push(element);
} else {
- var index = backdrops.indexOf(element);
+ var index = this._backdrops.indexOf(element);
if (index >= 0) {
- backdrops.splice(index, 1);
+ this._backdrops.splice(index, 1);
}
}
- }
+ },
- function getBackdrops() {
- return backdrops;
+ getBackdrops: function() {
+ return this._backdrops;
}
- return {
- addOverlay: addOverlay,
- removeOverlay: removeOverlay,
- currentOverlay: currentOverlay,
- currentOverlayZ: currentOverlayZ,
- focusOverlay: focusOverlay,
- trackBackdrop: trackBackdrop,
- getBackdrops: getBackdrops
- };
-
- })();
+ };
(function() {
Polymer({
@@ -14042,6 +14756,12 @@ context. You should place this element as a child of `<body>` whenever possible.
*/
/**
+ * Fired when the `iron-overlay` is canceled, but before it is closed.
+ * Cancel the event to prevent the `iron-overlay` from closing.
+ * @event iron-overlay-canceled
+ */
+
+/**
* Fired after the `iron-overlay` closes.
* @event iron-overlay-closed
* @param {{canceled: (boolean|undefined)}} set to the `closingReason` attribute
@@ -15407,7 +16127,20 @@ Polymer({
}
});
/**
- * Use `Polymer.IronValidatableBehavior` to implement an element that validates user input.
+ * `Use Polymer.IronValidatableBehavior` to implement an element that validates user input.
+ * Use the related `Polymer.IronValidatorBehavior` to add custom validation logic to an iron-input.
+ *
+ * By default, an `<iron-form>` element validates its fields when the user presses the submit button.
+ * To validate a form imperatively, call the form's `validate()` method, which in turn will
+ * call `validate()` on all its children. By using `Polymer.IronValidatableBehavior`, your
+ * custom element will get a public `validate()`, which
+ * will return the validity of the element, and a corresponding `invalid` attribute,
+ * which can be used for styling.
+ *
+ * To implement the custom validation logic of your element, you must override
+ * the protected `_getValidity()` method of this behaviour, rather than `validate()`.
+ * See [this](https://github.com/PolymerElements/iron-form/blob/master/demo/simple-element.html)
+ * for an example.
*
* ### Accessibility
*
@@ -15577,7 +16310,8 @@ is separate from validation, and `allowed-pattern` does not affect how the input
* Regular expression to match valid input characters.
*/
allowedPattern: {
- type: String
+ type: String,
+ observer: "_allowedPatternChanged"
},
_previousValidInput: {
@@ -15628,6 +16362,11 @@ is separate from validation, and `allowed-pattern` does not affect how the input
this.fire('bind-value-changed', {value: this.bindValue});
},
+ _allowedPatternChanged: function() {
+ // Force to prevent invalid input when an `allowed-pattern` is set
+ this.preventInvalidInput = this.allowedPattern ? true : false;
+ },
+
_onInput: function() {
// Need to validate each of the characters pasted if they haven't
// been validated inside `_onKeypress` already.
@@ -15974,21 +16713,19 @@ Polymer({
if (alwaysFloatLabel || _inputHasContent) {
cls += ' label-is-floating';
+ // If the label is floating, ignore any offsets that may have been
+ // applied from a prefix element.
+ this.$.labelAndInputContainer.style.position = 'static';
+
if (invalid) {
cls += ' is-invalid';
} else if (focused) {
cls += " label-is-highlighted";
}
- // The label might have a horizontal offset if a prefix element exists
- // which needs to be undone when displayed as a floating label.
- if (Polymer.dom(this.$.prefix).getDistributedNodes().length > 0 &&
- label && label.offsetParent) {
- label.style.left = -label.offsetParent.offsetLeft + 'px';
- }
} else {
// When the label is not floating, it should overlap the input element.
if (label) {
- label.style.left = 0;
+ this.$.labelAndInputContainer.style.position = 'relative';
}
}
} else {
@@ -16209,6 +16946,10 @@ cr.define('downloads', function() {
},
},
+ hostAttributes: {
+ loading: true,
+ },
+
/**
* @param {Event} e
* @private
@@ -16291,7 +17032,7 @@ cr.define('downloads', function() {
if (loadTimeData.getBoolean('allowDeletingHistory'))
this.$.toolbar.downloadsShowing = this.hasDownloads_;
- this.$.panel.classList.remove('loading');
+ this.removeAttribute('loading');
},
/**
« no previous file with comments | « no previous file | chrome/browser/resources/md_downloads/manager.css » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698