mirror of
https://github.com/jellyfin/jellyfin-web.git
synced 2024-11-18 11:28:23 -07:00
4817 lines
121 KiB
HTML
4817 lines
121 KiB
HTML
<!--
|
|
@license
|
|
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
|
|
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
|
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
|
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
|
Code distributed by Google as part of the polymer project is also
|
|
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
|
--><!--
|
|
@license
|
|
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
|
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
|
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
|
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
|
Code distributed by Google as part of the polymer project is also
|
|
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
|
--><link rel="import" href="polymer-mini.html">
|
|
|
|
|
|
|
|
<script>Polymer.nar = [];
|
|
Polymer.Annotations = {
|
|
parseAnnotations: function (template) {
|
|
var list = [];
|
|
var content = template._content || template.content;
|
|
this._parseNodeAnnotations(content, list, template.hasAttribute('strip-whitespace'));
|
|
return list;
|
|
},
|
|
_parseNodeAnnotations: function (node, list, stripWhiteSpace) {
|
|
return node.nodeType === Node.TEXT_NODE ? this._parseTextNodeAnnotation(node, list) : this._parseElementAnnotations(node, list, stripWhiteSpace);
|
|
},
|
|
_bindingRegex: function () {
|
|
var IDENT = '(?:' + '[a-zA-Z_$][\\w.:$\\-*]*' + ')';
|
|
var NUMBER = '(?:' + '[-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?' + ')';
|
|
var SQUOTE_STRING = '(?:' + '\'(?:[^\'\\\\]|\\\\.)*\'' + ')';
|
|
var DQUOTE_STRING = '(?:' + '"(?:[^"\\\\]|\\\\.)*"' + ')';
|
|
var STRING = '(?:' + SQUOTE_STRING + '|' + DQUOTE_STRING + ')';
|
|
var ARGUMENT = '(?:' + IDENT + '|' + NUMBER + '|' + STRING + '\\s*' + ')';
|
|
var ARGUMENTS = '(?:' + ARGUMENT + '(?:,\\s*' + ARGUMENT + ')*' + ')';
|
|
var ARGUMENT_LIST = '(?:' + '\\(\\s*' + '(?:' + ARGUMENTS + '?' + ')' + '\\)\\s*' + ')';
|
|
var BINDING = '(' + IDENT + '\\s*' + ARGUMENT_LIST + '?' + ')';
|
|
var OPEN_BRACKET = '(\\[\\[|{{)' + '\\s*';
|
|
var CLOSE_BRACKET = '(?:]]|}})';
|
|
var NEGATE = '(?:(!)\\s*)?';
|
|
var EXPRESSION = OPEN_BRACKET + NEGATE + BINDING + CLOSE_BRACKET;
|
|
return new RegExp(EXPRESSION, 'g');
|
|
}(),
|
|
_parseBindings: function (text) {
|
|
var re = this._bindingRegex;
|
|
var parts = [];
|
|
var lastIndex = 0;
|
|
var m;
|
|
while ((m = re.exec(text)) !== null) {
|
|
if (m.index > lastIndex) {
|
|
parts.push({ literal: text.slice(lastIndex, m.index) });
|
|
}
|
|
var mode = m[1][0];
|
|
var negate = Boolean(m[2]);
|
|
var value = m[3].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 parts = this._parseBindings(node.textContent);
|
|
if (parts) {
|
|
node.textContent = this._literalFromParts(parts) || ' ';
|
|
var annote = {
|
|
bindings: [{
|
|
kind: 'text',
|
|
name: 'textContent',
|
|
parts: parts,
|
|
isCompound: parts.length !== 1
|
|
}]
|
|
};
|
|
list.push(annote);
|
|
return annote;
|
|
}
|
|
},
|
|
_parseElementAnnotations: function (element, list, stripWhiteSpace) {
|
|
var annote = {
|
|
bindings: [],
|
|
events: []
|
|
};
|
|
if (element.localName === 'content') {
|
|
list._hasContent = true;
|
|
}
|
|
this._parseChildNodesAnnotations(element, annote, list, stripWhiteSpace);
|
|
if (element.attributes) {
|
|
this._parseNodeAttributeAnnotations(element, annote, list);
|
|
if (this.prepElement) {
|
|
this.prepElement(element);
|
|
}
|
|
}
|
|
if (annote.bindings.length || annote.events.length || annote.id) {
|
|
list.push(annote);
|
|
}
|
|
return annote;
|
|
},
|
|
_parseChildNodesAnnotations: function (root, annote, list, stripWhiteSpace) {
|
|
if (root.firstChild) {
|
|
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 = next;
|
|
while (n && n.nodeType === Node.TEXT_NODE) {
|
|
node.textContent += n.textContent;
|
|
next = n.nextSibling;
|
|
root.removeChild(n);
|
|
n = next;
|
|
}
|
|
if (stripWhiteSpace && !node.textContent.trim()) {
|
|
root.removeChild(node);
|
|
i--;
|
|
}
|
|
}
|
|
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) {
|
|
var content = document.createDocumentFragment();
|
|
content._notes = this.parseAnnotations(node);
|
|
content.appendChild(node.content);
|
|
list.push({
|
|
bindings: Polymer.nar,
|
|
events: Polymer.nar,
|
|
templateContent: content,
|
|
parent: parent,
|
|
index: index
|
|
});
|
|
},
|
|
_parseNodeAttributeAnnotations: function (node, annotation) {
|
|
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 if (b = this._parseNodeAttributeAnnotation(node, n, v)) {
|
|
annotation.bindings.push(b);
|
|
} else if (n === 'id') {
|
|
annotation.id = v;
|
|
}
|
|
}
|
|
},
|
|
_parseNodeAttributeAnnotation: function (node, name, value) {
|
|
var parts = this._parseBindings(value);
|
|
if (parts) {
|
|
var origName = name;
|
|
var kind = 'property';
|
|
if (name[name.length - 1] == '$') {
|
|
name = name.slice(0, -1);
|
|
kind = 'attribute';
|
|
}
|
|
var literal = this._literalFromParts(parts);
|
|
if (literal && kind == 'attribute') {
|
|
node.setAttribute(name, literal);
|
|
}
|
|
if (node.localName === 'input' && origName === 'value') {
|
|
node.setAttribute(origName, '');
|
|
}
|
|
node.removeAttribute(origName);
|
|
var propertyName = Polymer.CaseMap.dashToCamelCase(name);
|
|
if (kind === 'property') {
|
|
name = propertyName;
|
|
}
|
|
return {
|
|
kind: kind,
|
|
name: name,
|
|
propertyName: propertyName,
|
|
parts: parts,
|
|
literal: literal,
|
|
isCompound: parts.length !== 1
|
|
};
|
|
}
|
|
},
|
|
findAnnotatedNode: function (root, annote) {
|
|
var parent = annote.parent && Polymer.Annotations.findAnnotatedNode(root, annote.parent);
|
|
if (parent) {
|
|
for (var n = parent.firstChild, i = 0; n; n = n.nextSibling) {
|
|
if (annote.index === i++) {
|
|
return n;
|
|
}
|
|
}
|
|
} else {
|
|
return root;
|
|
}
|
|
}
|
|
};
|
|
(function () {
|
|
function resolveCss(cssText, ownerDocument) {
|
|
return cssText.replace(CSS_URL_RX, function (m, pre, url, post) {
|
|
return pre + '\'' + resolve(url.replace(/["']/g, ''), ownerDocument) + '\'' + post;
|
|
});
|
|
}
|
|
function resolveAttrs(element, ownerDocument) {
|
|
for (var name in URL_ATTRS) {
|
|
var a$ = URL_ATTRS[name];
|
|
for (var i = 0, l = a$.length, a, at, v; i < l && (a = a$[i]); i++) {
|
|
if (name === '*' || element.localName === name) {
|
|
at = element.attributes[a];
|
|
v = at && at.value;
|
|
if (v && v.search(BINDING_RX) < 0) {
|
|
at.value = a === 'style' ? resolveCss(v, ownerDocument) : resolve(v, ownerDocument);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function resolve(url, ownerDocument) {
|
|
if (url && url[0] === '#') {
|
|
return url;
|
|
}
|
|
var resolver = getUrlResolver(ownerDocument);
|
|
resolver.href = url;
|
|
return resolver.href || url;
|
|
}
|
|
var tempDoc;
|
|
var tempDocBase;
|
|
function resolveUrl(url, baseUri) {
|
|
if (!tempDoc) {
|
|
tempDoc = document.implementation.createHTMLDocument('temp');
|
|
tempDocBase = tempDoc.createElement('base');
|
|
tempDoc.head.appendChild(tempDocBase);
|
|
}
|
|
tempDocBase.href = baseUri;
|
|
return resolve(url, tempDoc);
|
|
}
|
|
function getUrlResolver(ownerDocument) {
|
|
return ownerDocument.__urlResolver || (ownerDocument.__urlResolver = ownerDocument.createElement('a'));
|
|
}
|
|
var CSS_URL_RX = /(url\()([^)]*)(\))/g;
|
|
var URL_ATTRS = {
|
|
'*': [
|
|
'href',
|
|
'src',
|
|
'style',
|
|
'url'
|
|
],
|
|
form: ['action']
|
|
};
|
|
var BINDING_RX = /\{\{|\[\[/;
|
|
Polymer.ResolveUrl = {
|
|
resolveCss: resolveCss,
|
|
resolveAttrs: resolveAttrs,
|
|
resolveUrl: resolveUrl
|
|
};
|
|
}());
|
|
Polymer.Base._addFeature({
|
|
_prepAnnotations: function () {
|
|
if (!this._template) {
|
|
this._notes = [];
|
|
} else {
|
|
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 {
|
|
this._notes = Polymer.Annotations.parseAnnotations(this._template);
|
|
this._processAnnotations(this._notes);
|
|
}
|
|
Polymer.Annotations.prepElement = null;
|
|
}
|
|
},
|
|
_processAnnotations: function (notes) {
|
|
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];
|
|
for (var k = 0; k < b.parts.length; k++) {
|
|
var p = b.parts[k];
|
|
if (!p.literal) {
|
|
var signature = this._parseMethod(p.value);
|
|
if (signature) {
|
|
p.signature = signature;
|
|
} else {
|
|
p.model = this._modelForPath(p.value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (note.templateContent) {
|
|
this._processAnnotations(note.templateContent._notes);
|
|
var pp = note.templateContent._parentProps = this._discoverTemplateParentProps(note.templateContent._notes);
|
|
var bindings = [];
|
|
for (var prop in pp) {
|
|
bindings.push({
|
|
index: note.index,
|
|
kind: 'property',
|
|
name: '_parent_' + prop,
|
|
parts: [{
|
|
mode: '{',
|
|
model: prop,
|
|
value: prop
|
|
}]
|
|
});
|
|
}
|
|
note.bindings = note.bindings.concat(bindings);
|
|
}
|
|
}
|
|
},
|
|
_discoverTemplateParentProps: function (notes) {
|
|
var pp = {};
|
|
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++) {
|
|
var model = args[kk].model;
|
|
if (model) {
|
|
pp[model] = true;
|
|
}
|
|
}
|
|
} else {
|
|
if (p.model) {
|
|
pp[p.model] = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (n.templateContent) {
|
|
var tpp = n.templateContent._parentProps;
|
|
Polymer.Base.mixin(pp, tpp);
|
|
}
|
|
}
|
|
return pp;
|
|
},
|
|
_prepElement: function (element) {
|
|
Polymer.ResolveUrl.resolveAttrs(element, this._template.ownerDocument);
|
|
},
|
|
_findAnnotatedNode: Polymer.Annotations.findAnnotatedNode,
|
|
_marshalAnnotationReferences: function () {
|
|
if (this._template) {
|
|
this._marshalIdNodes();
|
|
this._marshalAnnotatedNodes();
|
|
this._marshalAnnotatedListeners();
|
|
}
|
|
},
|
|
_configureAnnotationReferences: function () {
|
|
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 (note, node) {
|
|
if (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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
_marshalIdNodes: function () {
|
|
this.$ = {};
|
|
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);
|
|
}
|
|
}
|
|
},
|
|
_marshalAnnotatedNodes: function () {
|
|
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 () {
|
|
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);
|
|
for (var j = 0, e$ = a.events, e; j < e$.length && (e = e$[j]); j++) {
|
|
this.listen(node, e.name, e.value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
Polymer.Base._addFeature({
|
|
listeners: {},
|
|
_listenListeners: function (listeners) {
|
|
var node, name, eventName;
|
|
for (eventName in listeners) {
|
|
if (eventName.indexOf('.') < 0) {
|
|
node = this;
|
|
name = eventName;
|
|
} else {
|
|
name = eventName.split('.');
|
|
node = this.$[name[0]];
|
|
name = name[1];
|
|
}
|
|
this.listen(node, name, listeners[eventName]);
|
|
}
|
|
},
|
|
listen: function (node, eventName, methodName) {
|
|
var handler = this._recallEventHandler(this, eventName, node, methodName);
|
|
if (!handler) {
|
|
handler = this._createEventHandler(node, eventName, methodName);
|
|
}
|
|
if (handler._listening) {
|
|
return;
|
|
}
|
|
this._listen(node, eventName, handler);
|
|
handler._listening = true;
|
|
},
|
|
_boundListenerKey: function (eventName, methodName) {
|
|
return eventName + ':' + methodName;
|
|
},
|
|
_recordEventHandler: function (host, eventName, target, methodName, handler) {
|
|
var hbl = host.__boundListeners;
|
|
if (!hbl) {
|
|
hbl = host.__boundListeners = new WeakMap();
|
|
}
|
|
var bl = hbl.get(target);
|
|
if (!bl) {
|
|
bl = {};
|
|
hbl.set(target, bl);
|
|
}
|
|
var key = this._boundListenerKey(eventName, methodName);
|
|
bl[key] = handler;
|
|
},
|
|
_recallEventHandler: function (host, eventName, target, methodName) {
|
|
var hbl = host.__boundListeners;
|
|
if (!hbl) {
|
|
return;
|
|
}
|
|
var bl = hbl.get(target);
|
|
if (!bl) {
|
|
return;
|
|
}
|
|
var key = this._boundListenerKey(eventName, methodName);
|
|
return bl[key];
|
|
},
|
|
_createEventHandler: function (node, eventName, methodName) {
|
|
var host = this;
|
|
var handler = function (e) {
|
|
if (host[methodName]) {
|
|
host[methodName](e, e.detail);
|
|
} else {
|
|
host._warn(host._logf('_createEventHandler', 'listener method `' + methodName + '` not defined'));
|
|
}
|
|
};
|
|
handler._listening = false;
|
|
this._recordEventHandler(host, eventName, node, methodName, handler);
|
|
return handler;
|
|
},
|
|
unlisten: function (node, eventName, methodName) {
|
|
var handler = this._recallEventHandler(this, eventName, node, methodName);
|
|
if (handler) {
|
|
this._unlisten(node, eventName, handler);
|
|
handler._listening = false;
|
|
}
|
|
},
|
|
_listen: function (node, eventName, handler) {
|
|
node.addEventListener(eventName, handler);
|
|
},
|
|
_unlisten: function (node, eventName, handler) {
|
|
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';
|
|
var TOUCH_ACTION = '__polymerGesturesTouchAction';
|
|
var TAP_DISTANCE = 25;
|
|
var TRACK_DISTANCE = 5;
|
|
var TRACK_LENGTH = 2;
|
|
var MOUSE_TIMEOUT = 2500;
|
|
var MOUSE_EVENTS = [
|
|
'mousedown',
|
|
'mousemove',
|
|
'mouseup',
|
|
'click'
|
|
];
|
|
var MOUSE_WHICH_TO_BUTTONS = [
|
|
0,
|
|
1,
|
|
4,
|
|
2
|
|
];
|
|
var MOUSE_HAS_BUTTONS = function () {
|
|
try {
|
|
return new MouseEvent('test', { buttons: 1 }).buttons === 1;
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}();
|
|
var IS_TOUCH_ONLY = navigator.userAgent.match(/iP(?:[oa]d|hone)|Android/);
|
|
var mouseCanceller = function (mouseEvent) {
|
|
mouseEvent[HANDLED_OBJ] = { skip: true };
|
|
if (mouseEvent.type === 'click') {
|
|
var path = Polymer.dom(mouseEvent).path;
|
|
for (var i = 0; i < path.length; i++) {
|
|
if (path[i] === POINTERSTATE.mouse.target) {
|
|
return;
|
|
}
|
|
}
|
|
mouseEvent.preventDefault();
|
|
mouseEvent.stopPropagation();
|
|
}
|
|
};
|
|
function setupTeardownMouseCanceller(setup) {
|
|
for (var i = 0, en; i < MOUSE_EVENTS.length; i++) {
|
|
en = MOUSE_EVENTS[i];
|
|
if (setup) {
|
|
document.addEventListener(en, mouseCanceller, true);
|
|
} else {
|
|
document.removeEventListener(en, mouseCanceller, true);
|
|
}
|
|
}
|
|
}
|
|
function ignoreMouse() {
|
|
if (IS_TOUCH_ONLY) {
|
|
return;
|
|
}
|
|
if (!POINTERSTATE.mouse.mouseIgnoreJob) {
|
|
setupTeardownMouseCanceller(true);
|
|
}
|
|
var unset = function () {
|
|
setupTeardownMouseCanceller();
|
|
POINTERSTATE.mouse.target = null;
|
|
POINTERSTATE.mouse.mouseIgnoreJob = null;
|
|
};
|
|
POINTERSTATE.mouse.mouseIgnoreJob = Polymer.Debounce(POINTERSTATE.mouse.mouseIgnoreJob, unset, MOUSE_TIMEOUT);
|
|
}
|
|
function hasLeftMouseButton(ev) {
|
|
var type = ev.type;
|
|
if (MOUSE_EVENTS.indexOf(type) === -1) {
|
|
return false;
|
|
}
|
|
if (type === 'mousemove') {
|
|
var buttons = ev.buttons === undefined ? 1 : ev.buttons;
|
|
if (ev instanceof window.MouseEvent && !MOUSE_HAS_BUTTONS) {
|
|
buttons = MOUSE_WHICH_TO_BUTTONS[ev.which] || 0;
|
|
}
|
|
return Boolean(buttons & 1);
|
|
} else {
|
|
var button = ev.button === undefined ? 0 : ev.button;
|
|
return button === 0;
|
|
}
|
|
}
|
|
function isSyntheticClick(ev) {
|
|
if (ev.type === 'click') {
|
|
if (ev.detail === 0) {
|
|
return true;
|
|
}
|
|
var t = Gestures.findOriginalTarget(ev);
|
|
var bcr = t.getBoundingClientRect();
|
|
var x = ev.pageX, y = ev.pageY;
|
|
return !(x >= bcr.left && x <= bcr.right && (y >= bcr.top && y <= bcr.bottom));
|
|
}
|
|
return false;
|
|
}
|
|
var POINTERSTATE = {
|
|
mouse: {
|
|
target: null,
|
|
mouseIgnoreJob: null
|
|
},
|
|
touch: {
|
|
x: 0,
|
|
y: 0,
|
|
id: -1,
|
|
scrollDecided: false
|
|
}
|
|
};
|
|
function firstTouchAction(ev) {
|
|
var path = Polymer.dom(ev).path;
|
|
var ta = 'auto';
|
|
for (var i = 0, n; i < path.length; i++) {
|
|
n = path[i];
|
|
if (n[TOUCH_ACTION]) {
|
|
ta = n[TOUCH_ACTION];
|
|
break;
|
|
}
|
|
}
|
|
return ta;
|
|
}
|
|
function trackDocument(stateObj, movefn, upfn) {
|
|
stateObj.movefn = movefn;
|
|
stateObj.upfn = upfn;
|
|
document.addEventListener('mousemove', movefn);
|
|
document.addEventListener('mouseup', upfn);
|
|
}
|
|
function untrackDocument(stateObj) {
|
|
document.removeEventListener('mousemove', stateObj.movefn);
|
|
document.removeEventListener('mouseup', stateObj.upfn);
|
|
stateObj.movefn = null;
|
|
stateObj.upfn = null;
|
|
}
|
|
var Gestures = {
|
|
gestures: {},
|
|
recognizers: [],
|
|
deepTargetFind: function (x, y) {
|
|
var node = document.elementFromPoint(x, y);
|
|
var next = node;
|
|
while (next && next.shadowRoot) {
|
|
next = next.shadowRoot.elementFromPoint(x, y);
|
|
if (next) {
|
|
node = next;
|
|
}
|
|
}
|
|
return node;
|
|
},
|
|
findOriginalTarget: function (ev) {
|
|
if (ev.path) {
|
|
return ev.path[0];
|
|
}
|
|
return ev.target;
|
|
},
|
|
handleNative: function (ev) {
|
|
var handled;
|
|
var type = ev.type;
|
|
var node = wrap(ev.currentTarget);
|
|
var gobj = node[GESTURE_KEY];
|
|
if (!gobj) {
|
|
return;
|
|
}
|
|
var gs = gobj[type];
|
|
if (!gs) {
|
|
return;
|
|
}
|
|
if (!ev[HANDLED_OBJ]) {
|
|
ev[HANDLED_OBJ] = {};
|
|
if (type.slice(0, 5) === 'touch') {
|
|
var t = ev.changedTouches[0];
|
|
if (type === 'touchstart') {
|
|
if (ev.touches.length === 1) {
|
|
POINTERSTATE.touch.id = t.identifier;
|
|
}
|
|
}
|
|
if (POINTERSTATE.touch.id !== t.identifier) {
|
|
return;
|
|
}
|
|
if (!HAS_NATIVE_TA) {
|
|
if (type === 'touchstart' || type === 'touchmove') {
|
|
Gestures.handleTouchAction(ev);
|
|
}
|
|
}
|
|
if (type === 'touchend' && !ev.__polymerSimulatedTouch) {
|
|
POINTERSTATE.mouse.target = Polymer.dom(ev).rootTarget;
|
|
ignoreMouse(true);
|
|
}
|
|
}
|
|
}
|
|
handled = ev[HANDLED_OBJ];
|
|
if (handled.skip) {
|
|
return;
|
|
}
|
|
var recognizers = Gestures.recognizers;
|
|
for (var i = 0, r; i < recognizers.length; i++) {
|
|
r = recognizers[i];
|
|
if (gs[r.name] && !handled[r.name]) {
|
|
if (r.flow && r.flow.start.indexOf(ev.type) > -1 && r.reset) {
|
|
r.reset();
|
|
}
|
|
}
|
|
}
|
|
for (i = 0, r; i < recognizers.length; i++) {
|
|
r = recognizers[i];
|
|
if (gs[r.name] && !handled[r.name]) {
|
|
handled[r.name] = true;
|
|
r[type](ev);
|
|
}
|
|
}
|
|
},
|
|
handleTouchAction: function (ev) {
|
|
var t = ev.changedTouches[0];
|
|
var type = ev.type;
|
|
if (type === 'touchstart') {
|
|
POINTERSTATE.touch.x = t.clientX;
|
|
POINTERSTATE.touch.y = t.clientY;
|
|
POINTERSTATE.touch.scrollDecided = false;
|
|
} else if (type === 'touchmove') {
|
|
if (POINTERSTATE.touch.scrollDecided) {
|
|
return;
|
|
}
|
|
POINTERSTATE.touch.scrollDecided = true;
|
|
var ta = firstTouchAction(ev);
|
|
var prevent = false;
|
|
var dx = Math.abs(POINTERSTATE.touch.x - t.clientX);
|
|
var dy = Math.abs(POINTERSTATE.touch.y - t.clientY);
|
|
if (!ev.cancelable) {
|
|
} else if (ta === 'none') {
|
|
prevent = true;
|
|
} else if (ta === 'pan-x') {
|
|
prevent = dy > dx;
|
|
} else if (ta === 'pan-y') {
|
|
prevent = dx > dy;
|
|
}
|
|
if (prevent) {
|
|
//ev.preventDefault();
|
|
} else {
|
|
Gestures.prevent('track');
|
|
}
|
|
}
|
|
},
|
|
add: function (node, evType, handler) {
|
|
node = wrap(node);
|
|
var recognizer = this.gestures[evType];
|
|
var deps = recognizer.deps;
|
|
var name = recognizer.name;
|
|
var gobj = node[GESTURE_KEY];
|
|
if (!gobj) {
|
|
node[GESTURE_KEY] = gobj = {};
|
|
}
|
|
for (var i = 0, dep, gd; i < deps.length; i++) {
|
|
dep = deps[i];
|
|
if (IS_TOUCH_ONLY && MOUSE_EVENTS.indexOf(dep) > -1) {
|
|
continue;
|
|
}
|
|
gd = gobj[dep];
|
|
if (!gd) {
|
|
gobj[dep] = gd = { _count: 0 };
|
|
}
|
|
if (gd._count === 0) {
|
|
node.addEventListener(dep, this.handleNative);
|
|
}
|
|
gd[name] = (gd[name] || 0) + 1;
|
|
gd._count = (gd._count || 0) + 1;
|
|
}
|
|
node.addEventListener(evType, handler);
|
|
if (recognizer.touchAction) {
|
|
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;
|
|
var gobj = node[GESTURE_KEY];
|
|
if (gobj) {
|
|
for (var i = 0, dep, gd; i < deps.length; i++) {
|
|
dep = deps[i];
|
|
gd = gobj[dep];
|
|
if (gd && gd[name]) {
|
|
gd[name] = (gd[name] || 1) - 1;
|
|
gd._count = (gd._count || 1) - 1;
|
|
if (gd._count === 0) {
|
|
node.removeEventListener(dep, this.handleNative);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
node.removeEventListener(evType, handler);
|
|
},
|
|
register: function (recog) {
|
|
this.recognizers.push(recog);
|
|
for (var i = 0; i < recog.emits.length; i++) {
|
|
this.gestures[recog.emits[i]] = recog;
|
|
}
|
|
},
|
|
findRecognizerByEvent: function (evName) {
|
|
for (var i = 0, r; i < this.recognizers.length; i++) {
|
|
r = this.recognizers[i];
|
|
for (var j = 0, n; j < r.emits.length; j++) {
|
|
n = r.emits[j];
|
|
if (n === evName) {
|
|
return r;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
},
|
|
setTouchAction: function (node, value) {
|
|
if (HAS_NATIVE_TA) {
|
|
node.style.touchAction = value;
|
|
}
|
|
node[TOUCH_ACTION] = value;
|
|
},
|
|
fire: function (target, type, detail) {
|
|
var ev = Polymer.Base.fire(type, detail, {
|
|
node: target,
|
|
bubbles: true,
|
|
cancelable: true
|
|
});
|
|
if (ev.defaultPrevented) {
|
|
var se = detail.sourceEvent;
|
|
if (se && se.preventDefault) {
|
|
se.preventDefault();
|
|
}
|
|
}
|
|
},
|
|
prevent: function (evName) {
|
|
var recognizer = this.findRecognizerByEvent(evName);
|
|
if (recognizer.info) {
|
|
recognizer.info.prevent = true;
|
|
}
|
|
}
|
|
};
|
|
Gestures.register({
|
|
name: 'downup',
|
|
deps: [
|
|
'mousedown',
|
|
'touchstart',
|
|
'touchend'
|
|
],
|
|
flow: {
|
|
start: [
|
|
'mousedown',
|
|
'touchstart'
|
|
],
|
|
end: [
|
|
'mouseup',
|
|
'touchend'
|
|
]
|
|
},
|
|
emits: [
|
|
'down',
|
|
'up'
|
|
],
|
|
info: {
|
|
movefn: null,
|
|
upfn: null
|
|
},
|
|
reset: function () {
|
|
untrackDocument(this.info);
|
|
},
|
|
mousedown: function (e) {
|
|
if (!hasLeftMouseButton(e)) {
|
|
return;
|
|
}
|
|
var t = Gestures.findOriginalTarget(e);
|
|
var self = this;
|
|
var movefn = function movefn(e) {
|
|
if (!hasLeftMouseButton(e)) {
|
|
self.fire('up', t, e);
|
|
untrackDocument(self.info);
|
|
}
|
|
};
|
|
var upfn = function upfn(e) {
|
|
if (hasLeftMouseButton(e)) {
|
|
self.fire('up', t, e);
|
|
}
|
|
untrackDocument(self.info);
|
|
};
|
|
trackDocument(this.info, movefn, upfn);
|
|
this.fire('down', t, e);
|
|
},
|
|
touchstart: function (e) {
|
|
this.fire('down', Gestures.findOriginalTarget(e), e.changedTouches[0]);
|
|
},
|
|
touchend: function (e) {
|
|
this.fire('up', Gestures.findOriginalTarget(e), e.changedTouches[0]);
|
|
},
|
|
fire: function (type, target, event) {
|
|
Gestures.fire(target, type, {
|
|
x: event.clientX,
|
|
y: event.clientY,
|
|
sourceEvent: event,
|
|
prevent: function (e) {
|
|
return Gestures.prevent(e);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
Gestures.register({
|
|
name: 'track',
|
|
touchAction: 'none',
|
|
deps: [
|
|
'mousedown',
|
|
'touchstart',
|
|
'touchmove',
|
|
'touchend'
|
|
],
|
|
flow: {
|
|
start: [
|
|
'mousedown',
|
|
'touchstart'
|
|
],
|
|
end: [
|
|
'mouseup',
|
|
'touchend'
|
|
]
|
|
},
|
|
emits: ['track'],
|
|
info: {
|
|
x: 0,
|
|
y: 0,
|
|
state: 'start',
|
|
started: false,
|
|
moves: [],
|
|
addMove: function (move) {
|
|
if (this.moves.length > TRACK_LENGTH) {
|
|
this.moves.shift();
|
|
}
|
|
this.moves.push(move);
|
|
},
|
|
movefn: null,
|
|
upfn: null,
|
|
prevent: false
|
|
},
|
|
reset: function () {
|
|
this.info.state = 'start';
|
|
this.info.started = false;
|
|
this.info.moves = [];
|
|
this.info.x = 0;
|
|
this.info.y = 0;
|
|
this.info.prevent = false;
|
|
untrackDocument(this.info);
|
|
},
|
|
hasMovedEnough: function (x, y) {
|
|
if (this.info.prevent) {
|
|
return false;
|
|
}
|
|
if (this.info.started) {
|
|
return true;
|
|
}
|
|
var dx = Math.abs(this.info.x - x);
|
|
var dy = Math.abs(this.info.y - y);
|
|
return dx >= TRACK_DISTANCE || dy >= TRACK_DISTANCE;
|
|
},
|
|
mousedown: function (e) {
|
|
if (!hasLeftMouseButton(e)) {
|
|
return;
|
|
}
|
|
var t = Gestures.findOriginalTarget(e);
|
|
var self = this;
|
|
var movefn = function movefn(e) {
|
|
var x = e.clientX, y = e.clientY;
|
|
if (self.hasMovedEnough(x, y)) {
|
|
self.info.state = self.info.started ? e.type === 'mouseup' ? 'end' : 'track' : 'start';
|
|
if (self.info.state === 'start') {
|
|
Gestures.prevent('tap');
|
|
}
|
|
self.info.addMove({
|
|
x: x,
|
|
y: y
|
|
});
|
|
if (!hasLeftMouseButton(e)) {
|
|
self.info.state = 'end';
|
|
untrackDocument(self.info);
|
|
}
|
|
self.fire(t, e);
|
|
self.info.started = true;
|
|
}
|
|
};
|
|
var upfn = function upfn(e) {
|
|
if (self.info.started) {
|
|
movefn(e);
|
|
}
|
|
untrackDocument(self.info);
|
|
};
|
|
trackDocument(this.info, movefn, upfn);
|
|
this.info.x = e.clientX;
|
|
this.info.y = e.clientY;
|
|
},
|
|
touchstart: function (e) {
|
|
var ct = e.changedTouches[0];
|
|
this.info.x = ct.clientX;
|
|
this.info.y = ct.clientY;
|
|
},
|
|
touchmove: function (e) {
|
|
var t = Gestures.findOriginalTarget(e);
|
|
var ct = e.changedTouches[0];
|
|
var x = ct.clientX, y = ct.clientY;
|
|
if (this.hasMovedEnough(x, y)) {
|
|
if (this.info.state === 'start') {
|
|
Gestures.prevent('tap');
|
|
}
|
|
this.info.addMove({
|
|
x: x,
|
|
y: y
|
|
});
|
|
this.fire(t, ct);
|
|
this.info.state = 'track';
|
|
this.info.started = true;
|
|
}
|
|
},
|
|
touchend: function (e) {
|
|
var t = Gestures.findOriginalTarget(e);
|
|
var ct = e.changedTouches[0];
|
|
if (this.info.started) {
|
|
this.info.state = 'end';
|
|
this.info.addMove({
|
|
x: ct.clientX,
|
|
y: ct.clientY
|
|
});
|
|
this.fire(t, ct);
|
|
}
|
|
},
|
|
fire: function (target, touch) {
|
|
var secondlast = this.info.moves[this.info.moves.length - 2];
|
|
var lastmove = this.info.moves[this.info.moves.length - 1];
|
|
var dx = lastmove.x - this.info.x;
|
|
var dy = lastmove.y - this.info.y;
|
|
var ddx, ddy = 0;
|
|
if (secondlast) {
|
|
ddx = lastmove.x - secondlast.x;
|
|
ddy = lastmove.y - secondlast.y;
|
|
}
|
|
return Gestures.fire(target, 'track', {
|
|
state: this.info.state,
|
|
x: touch.clientX,
|
|
y: touch.clientY,
|
|
dx: dx,
|
|
dy: dy,
|
|
ddx: ddx,
|
|
ddy: ddy,
|
|
sourceEvent: touch,
|
|
hover: function () {
|
|
return Gestures.deepTargetFind(touch.clientX, touch.clientY);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
Gestures.register({
|
|
name: 'tap',
|
|
deps: [
|
|
'mousedown',
|
|
'click',
|
|
'touchstart',
|
|
'touchend'
|
|
],
|
|
flow: {
|
|
start: [
|
|
'mousedown',
|
|
'touchstart'
|
|
],
|
|
end: [
|
|
'click',
|
|
'touchend'
|
|
]
|
|
},
|
|
emits: ['tap'],
|
|
info: {
|
|
x: NaN,
|
|
y: NaN,
|
|
prevent: false
|
|
},
|
|
reset: function () {
|
|
this.info.x = NaN;
|
|
this.info.y = NaN;
|
|
this.info.prevent = false;
|
|
},
|
|
save: function (e) {
|
|
this.info.x = e.clientX;
|
|
this.info.y = e.clientY;
|
|
},
|
|
mousedown: function (e) {
|
|
if (hasLeftMouseButton(e)) {
|
|
this.save(e);
|
|
}
|
|
},
|
|
click: function (e) {
|
|
if (hasLeftMouseButton(e)) {
|
|
this.forward(e);
|
|
}
|
|
},
|
|
touchstart: function (e) {
|
|
this.save(e.changedTouches[0]);
|
|
},
|
|
touchend: function (e) {
|
|
this.forward(e.changedTouches[0]);
|
|
},
|
|
forward: function (e) {
|
|
var dx = Math.abs(e.clientX - this.info.x);
|
|
var dy = Math.abs(e.clientY - this.info.y);
|
|
var t = Gestures.findOriginalTarget(e);
|
|
if (isNaN(dx) || isNaN(dy) || dx <= TAP_DISTANCE && dy <= TAP_DISTANCE || isSyntheticClick(e)) {
|
|
if (!this.info.prevent) {
|
|
Gestures.fire(t, 'tap', {
|
|
x: e.clientX,
|
|
y: e.clientY,
|
|
sourceEvent: e
|
|
});
|
|
}
|
|
}
|
|
}
|
|
});
|
|
var DIRECTION_MAP = {
|
|
x: 'pan-x',
|
|
y: 'pan-y',
|
|
none: 'none',
|
|
all: 'auto'
|
|
};
|
|
Polymer.Base._addFeature({
|
|
_setupGestures: function () {
|
|
this.__polymerGestures = null;
|
|
},
|
|
_listen: function (node, eventName, handler) {
|
|
if (Gestures.gestures[eventName]) {
|
|
Gestures.add(node, eventName, handler);
|
|
} else {
|
|
node.addEventListener(eventName, handler);
|
|
}
|
|
},
|
|
_unlisten: function (node, eventName, handler) {
|
|
if (Gestures.gestures[eventName]) {
|
|
Gestures.remove(node, eventName, handler);
|
|
} else {
|
|
node.removeEventListener(eventName, handler);
|
|
}
|
|
},
|
|
setScrollDirection: function (direction, node) {
|
|
node = node || this;
|
|
Gestures.setTouchAction(node, DIRECTION_MAP[direction] || 'auto');
|
|
}
|
|
});
|
|
Polymer.Gestures = Gestures;
|
|
}());
|
|
Polymer.Base._addFeature({
|
|
$$: function (slctr) {
|
|
return Polymer.dom(this.root).querySelector(slctr);
|
|
},
|
|
toggleClass: function (name, bool, node) {
|
|
node = node || this;
|
|
if (arguments.length == 1) {
|
|
bool = !node.classList.contains(name);
|
|
}
|
|
if (bool) {
|
|
Polymer.dom(node).classList.add(name);
|
|
} else {
|
|
Polymer.dom(node).classList.remove(name);
|
|
}
|
|
},
|
|
toggleAttribute: function (name, bool, node) {
|
|
node = node || this;
|
|
if (arguments.length == 1) {
|
|
bool = !node.hasAttribute(name);
|
|
}
|
|
if (bool) {
|
|
Polymer.dom(node).setAttribute(name, '');
|
|
} else {
|
|
Polymer.dom(node).removeAttribute(name);
|
|
}
|
|
},
|
|
classFollows: function (name, toElement, fromElement) {
|
|
if (fromElement) {
|
|
Polymer.dom(fromElement).classList.remove(name);
|
|
}
|
|
if (toElement) {
|
|
Polymer.dom(toElement).classList.add(name);
|
|
}
|
|
},
|
|
attributeFollows: function (name, toElement, fromElement) {
|
|
if (fromElement) {
|
|
Polymer.dom(fromElement).removeAttribute(name);
|
|
}
|
|
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() : [];
|
|
},
|
|
getContentChildren: function (slctr) {
|
|
return this.getContentChildNodes(slctr).filter(function (n) {
|
|
return n.nodeType === Node.ELEMENT_NODE;
|
|
});
|
|
},
|
|
fire: function (type, detail, options) {
|
|
options = options || Polymer.nob;
|
|
var node = options.node || this;
|
|
detail = detail === null || detail === undefined ? {} : detail;
|
|
var bubbles = options.bubbles === undefined ? true : options.bubbles;
|
|
var cancelable = Boolean(options.cancelable);
|
|
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
|
|
});
|
|
}
|
|
return event;
|
|
},
|
|
async: function (callback, waitTime) {
|
|
var self = this;
|
|
return Polymer.Async.run(function () {
|
|
callback.call(self);
|
|
}, waitTime);
|
|
},
|
|
cancelAsync: function (handle) {
|
|
Polymer.Async.cancel(handle);
|
|
},
|
|
arrayDelete: function (path, item) {
|
|
var index;
|
|
if (Array.isArray(path)) {
|
|
index = path.indexOf(item);
|
|
if (index >= 0) {
|
|
return path.splice(index, 1);
|
|
}
|
|
} else {
|
|
var arr = this._get(path);
|
|
index = arr.indexOf(item);
|
|
if (index >= 0) {
|
|
return this.splice(path, index, 1);
|
|
}
|
|
}
|
|
},
|
|
transform: function (transform, node) {
|
|
node = node || this;
|
|
node.style.webkitTransform = transform;
|
|
node.style.transform = transform;
|
|
},
|
|
translate3d: function (x, y, z, node) {
|
|
node = node || this;
|
|
this.transform('translate3d(' + x + ',' + y + ',' + z + ')', node);
|
|
},
|
|
importHref: function (href, onload, onerror, optAsync) {
|
|
var l = document.createElement('link');
|
|
l.rel = 'import';
|
|
l.href = href;
|
|
optAsync = Boolean(optAsync);
|
|
if (optAsync) {
|
|
l.setAttribute('async', '');
|
|
}
|
|
var self = this;
|
|
if (onload) {
|
|
l.onload = function (e) {
|
|
return onload.call(self, e);
|
|
};
|
|
}
|
|
if (onerror) {
|
|
l.onerror = function (e) {
|
|
return onerror.call(self, e);
|
|
};
|
|
}
|
|
document.head.appendChild(l);
|
|
return l;
|
|
},
|
|
create: function (tag, props) {
|
|
var elt = document.createElement(tag);
|
|
if (props) {
|
|
for (var n in props) {
|
|
elt[n] = props[n];
|
|
}
|
|
}
|
|
return elt;
|
|
},
|
|
isLightDescendant: function (node) {
|
|
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) {
|
|
Polymer.Base.mixin(model, this._modelApi);
|
|
},
|
|
_modelApi: {
|
|
_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,
|
|
cancelable: false,
|
|
_useCache: true
|
|
});
|
|
},
|
|
_propertySetter: function (property, value, effects, fromAbove) {
|
|
var old = this.__data__[property];
|
|
if (old !== value && (old === old || value === value)) {
|
|
this.__data__[property] = value;
|
|
if (typeof value == 'object') {
|
|
this._clearPath(property);
|
|
}
|
|
if (this._propertyChanged) {
|
|
this._propertyChanged(property, value, old);
|
|
}
|
|
if (effects) {
|
|
this._effectEffects(property, value, effects, old, fromAbove);
|
|
}
|
|
}
|
|
return old;
|
|
},
|
|
__setProperty: function (property, value, quiet, node) {
|
|
node = node || this;
|
|
var effects = node._propertyEffects && node._propertyEffects[property];
|
|
if (effects) {
|
|
node._propertySetter(property, value, effects, quiet);
|
|
} else {
|
|
node[property] = value;
|
|
}
|
|
},
|
|
_effectEffects: function (property, value, effects, 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);
|
|
}
|
|
},
|
|
_clearPath: function (path) {
|
|
for (var prop in this.__data__) {
|
|
if (prop.indexOf(path + '.') === 0) {
|
|
this.__data__[prop] = undefined;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
ensurePropertyEffects: function (model, property) {
|
|
if (!model._propertyEffects) {
|
|
model._propertyEffects = {};
|
|
}
|
|
var fx = model._propertyEffects[property];
|
|
if (!fx) {
|
|
fx = model._propertyEffects[property] = [];
|
|
}
|
|
return fx;
|
|
},
|
|
addPropertyEffect: function (model, property, kind, effect) {
|
|
var fx = this.ensurePropertyEffects(model, property);
|
|
var propEffect = {
|
|
kind: kind,
|
|
effect: effect,
|
|
fn: Polymer.Bind['_' + kind + 'Effect']
|
|
};
|
|
fx.push(propEffect);
|
|
return propEffect;
|
|
},
|
|
createBindings: function (model) {
|
|
var fx$ = model._propertyEffects;
|
|
if (fx$) {
|
|
for (var n in fx$) {
|
|
var fx = fx$[n];
|
|
fx.sort(this._sortPropertyEffects);
|
|
this._createAccessors(model, n, fx);
|
|
}
|
|
}
|
|
},
|
|
_sortPropertyEffects: function () {
|
|
var EFFECT_ORDER = {
|
|
'compute': 0,
|
|
'annotation': 1,
|
|
'annotatedComputation': 2,
|
|
'reflect': 3,
|
|
'notify': 4,
|
|
'observer': 5,
|
|
'complexObserver': 6,
|
|
'function': 7
|
|
};
|
|
return function (a, b) {
|
|
return EFFECT_ORDER[a.kind] - EFFECT_ORDER[b.kind];
|
|
};
|
|
}(),
|
|
_createAccessors: function (model, property, effects) {
|
|
var defun = {
|
|
get: function () {
|
|
return this.__data__[property];
|
|
}
|
|
};
|
|
var setter = function (value) {
|
|
this._propertySetter(property, value, effects);
|
|
};
|
|
var info = model.getPropertyInfo && model.getPropertyInfo(property);
|
|
if (info && info.readOnly) {
|
|
if (!info.computed) {
|
|
model['_set' + this.upper(property)] = setter;
|
|
}
|
|
} else {
|
|
defun.set = setter;
|
|
}
|
|
Object.defineProperty(model, property, defun);
|
|
},
|
|
upper: function (name) {
|
|
return name[0].toUpperCase() + name.substring(1);
|
|
},
|
|
_addAnnotatedListener: function (model, index, property, path, event, negated) {
|
|
if (!model._bindListeners) {
|
|
model._bindListeners = [];
|
|
}
|
|
var fn = this._notedListenerFactory(property, path, this._isStructured(path), negated);
|
|
var eventName = event || Polymer.CaseMap.camelToDashCase(property) + '-changed';
|
|
model._bindListeners.push({
|
|
index: index,
|
|
property: property,
|
|
path: path,
|
|
changedFn: fn,
|
|
event: eventName
|
|
});
|
|
},
|
|
_isStructured: function (path) {
|
|
return path.indexOf('.') > 0;
|
|
},
|
|
_isEventBogus: function (e, target) {
|
|
return e.path && e.path[0] !== target;
|
|
},
|
|
_notedListenerFactory: function (property, path, isStructured, negated) {
|
|
return function (target, value, targetPath) {
|
|
if (targetPath) {
|
|
this._notifyPath(this._fixPath(path, property, targetPath), value);
|
|
} else {
|
|
value = target[property];
|
|
if (negated) {
|
|
value = !value;
|
|
}
|
|
if (!isStructured) {
|
|
this[path] = value;
|
|
} else {
|
|
if (this.__data__[path] != value) {
|
|
this.set(path, value);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
},
|
|
prepareInstance: function (inst) {
|
|
inst.__data__ = Object.create(null);
|
|
},
|
|
setupBindListeners: function (inst) {
|
|
var b$ = inst._bindListeners;
|
|
for (var i = 0, l = b$.length, info; i < l && (info = b$[i]); i++) {
|
|
var node = inst._nodes[info.index];
|
|
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.kind != 'attribute' && effect.kind != 'text' && !effect.isCompound && effect.parts[0].mode === '{';
|
|
},
|
|
_annotationEffect: function (source, value, effect) {
|
|
if (source != 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(effect, calc);
|
|
}
|
|
},
|
|
_reflectEffect: function (source, value, effect) {
|
|
this.reflectPropertyToAttribute(source, effect.attribute, value);
|
|
},
|
|
_notifyEffect: function (source, value, effect, old, fromAbove) {
|
|
if (!fromAbove) {
|
|
this._notifyChange(source, effect.event, value);
|
|
}
|
|
},
|
|
_functionEffect: function (source, value, fn, old, fromAbove) {
|
|
fn.call(this, source, value, old, fromAbove);
|
|
},
|
|
_observerEffect: function (source, value, effect, old) {
|
|
var fn = this[effect.method];
|
|
if (fn) {
|
|
fn.call(this, value, old);
|
|
} else {
|
|
this._warn(this._logf('_observerEffect', 'observer method `' + effect.method + '` not defined'));
|
|
}
|
|
},
|
|
_complexObserverEffect: function (source, value, effect) {
|
|
var fn = this[effect.method];
|
|
if (fn) {
|
|
var args = Polymer.Bind._marshalArgs(this.__data__, effect, source, value);
|
|
if (args) {
|
|
fn.apply(this, args);
|
|
}
|
|
} else if (effect.dynamicFn) {
|
|
} else {
|
|
this._warn(this._logf('_complexObserverEffect', 'observer method `' + effect.method + '` not defined'));
|
|
}
|
|
},
|
|
_computeEffect: function (source, value, effect) {
|
|
var fn = this[effect.method];
|
|
if (fn) {
|
|
var args = Polymer.Bind._marshalArgs(this.__data__, effect, source, value);
|
|
if (args) {
|
|
var computedvalue = fn.apply(this, args);
|
|
this.__setProperty(effect.name, computedvalue);
|
|
}
|
|
} else if (effect.dynamicFn) {
|
|
} else {
|
|
this._warn(this._logf('_computeEffect', 'compute method `' + effect.method + '` not defined'));
|
|
}
|
|
},
|
|
_annotatedComputationEffect: function (source, value, effect) {
|
|
var computedHost = this._rootDataHost || this;
|
|
var fn = computedHost[effect.method];
|
|
if (fn) {
|
|
var args = Polymer.Bind._marshalArgs(this.__data__, effect, source, value);
|
|
if (args) {
|
|
var computedvalue = fn.apply(computedHost, args);
|
|
if (effect.negate) {
|
|
computedvalue = !computedvalue;
|
|
}
|
|
this._applyEffectValue(effect, computedvalue);
|
|
}
|
|
} else if (effect.dynamicFn) {
|
|
} else {
|
|
computedHost._warn(computedHost._logf('_annotatedComputationEffect', 'compute method `' + effect.method + '` not defined'));
|
|
}
|
|
},
|
|
_marshalArgs: function (model, effect, path, value) {
|
|
var values = [];
|
|
var args = effect.args;
|
|
var bailoutEarly = args.length > 1 || effect.dynamicFn;
|
|
for (var i = 0, l = args.length; i < l; i++) {
|
|
var arg = args[i];
|
|
var name = arg.name;
|
|
var v;
|
|
if (arg.literal) {
|
|
v = arg.value;
|
|
} else if (arg.structured) {
|
|
v = Polymer.Base._get(name, model);
|
|
} else {
|
|
v = model[name];
|
|
}
|
|
if (bailoutEarly && v === undefined) {
|
|
return;
|
|
}
|
|
if (arg.wildcard) {
|
|
var baseChanged = name.indexOf(path + '.') === 0;
|
|
var matches = effect.trigger.name.indexOf(name) === 0 && !baseChanged;
|
|
values[i] = {
|
|
path: matches ? path : name,
|
|
value: matches ? value : v,
|
|
base: v
|
|
};
|
|
} else {
|
|
values[i] = v;
|
|
}
|
|
}
|
|
return values;
|
|
}
|
|
});
|
|
Polymer.Base._addFeature({
|
|
_addPropertyEffect: function (property, kind, effect) {
|
|
var prop = Polymer.Bind.addPropertyEffect(this, property, kind, effect);
|
|
prop.pathFn = this['_' + prop.kind + 'PathEffect'];
|
|
},
|
|
_prepEffects: function () {
|
|
Polymer.Bind.prepareModel(this);
|
|
this._addAnnotationEffects(this._notes);
|
|
},
|
|
_prepBindings: function () {
|
|
Polymer.Bind.createBindings(this);
|
|
},
|
|
_addPropertyEffects: function (properties) {
|
|
if (properties) {
|
|
for (var p in properties) {
|
|
var prop = properties[p];
|
|
if (prop.observer) {
|
|
this._addObserverEffect(p, prop.observer);
|
|
}
|
|
if (prop.computed) {
|
|
prop.readOnly = true;
|
|
this._addComputedEffect(p, prop.computed);
|
|
}
|
|
if (prop.notify) {
|
|
this._addPropertyEffect(p, 'notify', { event: Polymer.CaseMap.camelToDashCase(p) + '-changed' });
|
|
}
|
|
if (prop.reflectToAttribute) {
|
|
var attr = Polymer.CaseMap.camelToDashCase(p);
|
|
if (attr[0] === '-') {
|
|
this._warn(this._logf('_addPropertyEffects', 'Property ' + p + ' cannot be reflected to attribute ' + attr + ' because "-" is not a valid starting attribute name. Use a lowercase first letter for the property instead.'));
|
|
} else {
|
|
this._addPropertyEffect(p, 'reflect', { attribute: attr });
|
|
}
|
|
}
|
|
if (prop.readOnly) {
|
|
Polymer.Bind.ensurePropertyEffects(this, p);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
_addComputedEffect: function (name, expression) {
|
|
var sig = this._parseMethod(expression);
|
|
var dynamicFn = sig.dynamicFn;
|
|
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,
|
|
name: name,
|
|
dynamicFn: dynamicFn
|
|
});
|
|
}
|
|
if (dynamicFn) {
|
|
this._addPropertyEffect(sig.method, 'compute', {
|
|
method: sig.method,
|
|
args: sig.args,
|
|
trigger: null,
|
|
name: name,
|
|
dynamicFn: dynamicFn
|
|
});
|
|
}
|
|
},
|
|
_addObserverEffect: function (property, observer) {
|
|
this._addPropertyEffect(property, 'observer', {
|
|
method: observer,
|
|
property: property
|
|
});
|
|
},
|
|
_addComplexObserverEffects: function (observers) {
|
|
if (observers) {
|
|
for (var i = 0, o; i < observers.length && (o = observers[i]); i++) {
|
|
this._addComplexObserverEffect(o);
|
|
}
|
|
}
|
|
},
|
|
_addComplexObserverEffect: function (observer) {
|
|
var sig = this._parseMethod(observer);
|
|
if (!sig) {
|
|
throw new Error('Malformed observer expression \'' + observer + '\'');
|
|
}
|
|
var dynamicFn = sig.dynamicFn;
|
|
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,
|
|
dynamicFn: dynamicFn
|
|
});
|
|
}
|
|
if (dynamicFn) {
|
|
this._addPropertyEffect(sig.method, 'complexObserver', {
|
|
method: sig.method,
|
|
args: sig.args,
|
|
trigger: null,
|
|
dynamicFn: dynamicFn
|
|
});
|
|
}
|
|
},
|
|
_addAnnotationEffects: function (notes) {
|
|
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.parts[0].value, note.parts[0].event, note.parts[0].negate);
|
|
}
|
|
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) {
|
|
if (note.kind === 'attribute' && note.name[0] === '-') {
|
|
this._warn(this._logf('_addAnnotationEffect', 'Cannot set attribute ' + note.name + ' because "-" is not a valid attribute starting character'));
|
|
} else {
|
|
this._addPropertyEffect(part.model, 'annotation', {
|
|
kind: note.kind,
|
|
index: index,
|
|
name: note.name,
|
|
propertyName: note.propertyName,
|
|
value: part.value,
|
|
isCompound: note.isCompound,
|
|
compoundIndex: part.compoundIndex,
|
|
event: part.event,
|
|
customEvent: part.customEvent,
|
|
negate: part.negate
|
|
});
|
|
}
|
|
}
|
|
}
|
|
},
|
|
_addAnnotatedComputationEffect: function (note, part, index) {
|
|
var sig = part.signature;
|
|
if (sig.static) {
|
|
this.__addAnnotatedComputationEffect('__static__', index, note, part, null);
|
|
} else {
|
|
for (var i = 0, arg; i < sig.args.length && (arg = sig.args[i]); i++) {
|
|
if (!arg.literal) {
|
|
this.__addAnnotatedComputationEffect(arg.model, index, note, part, arg);
|
|
}
|
|
}
|
|
if (sig.dynamicFn) {
|
|
this.__addAnnotatedComputationEffect(sig.method, index, note, part, null);
|
|
}
|
|
}
|
|
},
|
|
__addAnnotatedComputationEffect: function (property, index, note, part, trigger) {
|
|
this._addPropertyEffect(property, 'annotatedComputation', {
|
|
index: index,
|
|
isCompound: note.isCompound,
|
|
compoundIndex: part.compoundIndex,
|
|
kind: note.kind,
|
|
name: note.name,
|
|
negate: part.negate,
|
|
method: part.signature.method,
|
|
args: part.signature.args,
|
|
trigger: trigger,
|
|
dynamicFn: part.signature.dynamicFn
|
|
});
|
|
},
|
|
_parseMethod: function (expression) {
|
|
var m = expression.match(/([^\s]+?)\(([\s\S]*)\)/);
|
|
if (m) {
|
|
var sig = {
|
|
method: m[1],
|
|
static: true
|
|
};
|
|
if (this.getPropertyInfo(sig.method) !== Polymer.nob) {
|
|
sig.static = false;
|
|
sig.dynamicFn = true;
|
|
}
|
|
if (m[2].trim()) {
|
|
var args = m[2].replace(/\\,/g, ',').split(',');
|
|
return this._parseArgs(args, sig);
|
|
} else {
|
|
sig.args = Polymer.nar;
|
|
return sig;
|
|
}
|
|
}
|
|
},
|
|
_parseArgs: function (argList, sig) {
|
|
sig.args = argList.map(function (rawArg) {
|
|
var arg = this._parseArg(rawArg);
|
|
if (!arg.literal) {
|
|
sig.static = false;
|
|
}
|
|
return arg;
|
|
}, this);
|
|
return sig;
|
|
},
|
|
_parseArg: function (rawArg) {
|
|
var arg = rawArg.trim().replace(/,/g, ',').replace(/\\(.)/g, '$1');
|
|
var a = { name: arg };
|
|
var fc = arg[0];
|
|
if (fc === '-') {
|
|
fc = arg[1];
|
|
}
|
|
if (fc >= '0' && fc <= '9') {
|
|
fc = '#';
|
|
}
|
|
switch (fc) {
|
|
case '\'':
|
|
case '"':
|
|
a.value = arg.slice(1, -1);
|
|
a.literal = true;
|
|
break;
|
|
case '#':
|
|
a.value = Number(arg);
|
|
a.literal = true;
|
|
break;
|
|
}
|
|
if (!a.literal) {
|
|
a.model = this._modelForPath(arg);
|
|
a.structured = arg.indexOf('.') > 0;
|
|
if (a.structured) {
|
|
a.wildcard = arg.slice(-2) == '.*';
|
|
if (a.wildcard) {
|
|
a.name = arg.slice(0, -2);
|
|
}
|
|
}
|
|
}
|
|
return a;
|
|
},
|
|
_marshalInstanceEffects: function () {
|
|
Polymer.Bind.prepareInstance(this);
|
|
if (this._bindListeners) {
|
|
Polymer.Bind.setupBindListeners(this);
|
|
}
|
|
},
|
|
_applyEffectValue: function (info, value) {
|
|
var node = this._nodes[info.index];
|
|
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 {
|
|
if (property === 'className') {
|
|
value = this._scopeElementClass(node, value);
|
|
}
|
|
if (property === 'textContent' || node.localName == 'input' && property == 'value') {
|
|
value = value == undefined ? '' : value;
|
|
}
|
|
var pinfo;
|
|
if (!node._propertyInfo || !(pinfo = node._propertyInfo[property]) || !pinfo.readOnly) {
|
|
this.__setProperty(property, value, false, node);
|
|
}
|
|
}
|
|
},
|
|
_executeStaticEffects: function () {
|
|
if (this._propertyEffects && this._propertyEffects.__static__) {
|
|
this._effectEffects('__static__', null, this._propertyEffects.__static__);
|
|
}
|
|
}
|
|
});
|
|
(function () {
|
|
var usePolyfillProto = Polymer.Settings.usePolyfillProto;
|
|
Polymer.Base._addFeature({
|
|
_setupConfigure: function (initialConfig) {
|
|
this._config = {};
|
|
this._handlers = [];
|
|
this._aboveConfig = null;
|
|
if (initialConfig) {
|
|
for (var i in initialConfig) {
|
|
if (initialConfig[i] !== undefined) {
|
|
this._config[i] = initialConfig[i];
|
|
}
|
|
}
|
|
}
|
|
},
|
|
_marshalAttributes: function () {
|
|
this._takeAttributesToModel(this._config);
|
|
},
|
|
_attributeChangedImpl: function (name) {
|
|
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();
|
|
},
|
|
_configure: function () {
|
|
this._configureAnnotationReferences();
|
|
this._aboveConfig = this.mixin({}, this._config);
|
|
var config = {};
|
|
for (var i = 0; i < this.behaviors.length; i++) {
|
|
this._configureProperties(this.behaviors[i].properties, config);
|
|
}
|
|
this._configureProperties(this.properties, config);
|
|
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) {
|
|
var c = properties[i];
|
|
if (!usePolyfillProto && this.hasOwnProperty(i) && this._propertyEffects && this._propertyEffects[i]) {
|
|
config[i] = this[i];
|
|
delete this[i];
|
|
} else if (c.value !== undefined) {
|
|
var value = c.value;
|
|
if (typeof value == 'function') {
|
|
value = value.call(this, this._config);
|
|
}
|
|
config[i] = value;
|
|
}
|
|
}
|
|
},
|
|
_distributeConfig: function (config) {
|
|
var fx$ = this._propertyEffects;
|
|
if (fx$) {
|
|
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' && !x.isCompound) {
|
|
var node = this._nodes[x.effect.index];
|
|
var name = x.effect.propertyName;
|
|
var isAttr = x.effect.kind == 'attribute';
|
|
var hasEffect = node._propertyEffects && node._propertyEffects[name];
|
|
if (node._configValue && (hasEffect || !isAttr)) {
|
|
var value = p === x.effect.value ? config[p] : this._get(x.effect.value, config);
|
|
if (isAttr) {
|
|
value = node.deserialize(this.serialize(value), node._propertyInfo[name].type);
|
|
}
|
|
node._configValue(name, value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
_afterClientsReady: function () {
|
|
this._executeStaticEffects();
|
|
this._applyConfig(this._config, this._aboveConfig);
|
|
this._flushHandlers();
|
|
},
|
|
_applyConfig: function (config, aboveConfig) {
|
|
for (var n in config) {
|
|
if (this[n] === undefined) {
|
|
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.target,
|
|
value,
|
|
path
|
|
]);
|
|
} else {
|
|
return fn.call(this, e.target, value, path);
|
|
}
|
|
}
|
|
},
|
|
_queueHandler: function (args) {
|
|
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[3]);
|
|
}
|
|
this._handlers = [];
|
|
}
|
|
});
|
|
}());
|
|
(function () {
|
|
'use strict';
|
|
Polymer.Base._addFeature({
|
|
notifyPath: function (path, value, fromAbove) {
|
|
var info = {};
|
|
this._get(path, this, info);
|
|
if (info.path) {
|
|
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._notifyPathUp(path, value);
|
|
}
|
|
return true;
|
|
}
|
|
},
|
|
_getPathParts: function (path) {
|
|
if (Array.isArray(path)) {
|
|
var parts = [];
|
|
for (var i = 0; i < path.length; i++) {
|
|
var args = path[i].toString().split('.');
|
|
for (var j = 0; j < args.length; j++) {
|
|
parts.push(args[j]);
|
|
}
|
|
}
|
|
return parts;
|
|
} else {
|
|
return path.toString().split('.');
|
|
}
|
|
},
|
|
set: function (path, value, root) {
|
|
var prop = root || this;
|
|
var parts = this._getPathParts(path);
|
|
var array;
|
|
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, 10) == part) {
|
|
parts[i] = Polymer.Collection.get(array).getKey(prop);
|
|
}
|
|
}
|
|
if (!prop) {
|
|
return;
|
|
}
|
|
array = Array.isArray(prop) ? prop : null;
|
|
}
|
|
if (array) {
|
|
var coll = Polymer.Collection.get(array);
|
|
var old, key;
|
|
if (last[0] == '#') {
|
|
key = last;
|
|
old = coll.getItem(key);
|
|
last = array.indexOf(old);
|
|
coll.setItem(key, value);
|
|
} else if (parseInt(last, 10) == last) {
|
|
old = prop[last];
|
|
key = coll.getKey(old);
|
|
parts[i] = key;
|
|
coll.setItem(key, value);
|
|
}
|
|
}
|
|
prop[last] = value;
|
|
if (!root) {
|
|
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 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;
|
|
},
|
|
_pathEffector: function (path, value) {
|
|
var model = this._modelForPath(path);
|
|
var fx$ = this._propertyEffects && this._propertyEffects[model];
|
|
if (fx$) {
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
if (this._boundPaths) {
|
|
this._notifyBoundPaths(path, value);
|
|
}
|
|
},
|
|
_annotationPathEffect: function (path, value, effect) {
|
|
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) {
|
|
var p = this._fixPath(effect.name, effect.value, path);
|
|
node._notifyPath(p, value, true);
|
|
}
|
|
}
|
|
},
|
|
_complexObserverPathEffect: function (path, value, effect) {
|
|
if (this._pathMatchesEffect(path, effect)) {
|
|
Polymer.Bind._complexObserverEffect.call(this, path, value, effect);
|
|
}
|
|
},
|
|
_computePathEffect: function (path, value, effect) {
|
|
if (this._pathMatchesEffect(path, effect)) {
|
|
Polymer.Bind._computeEffect.call(this, path, value, effect);
|
|
}
|
|
},
|
|
_annotatedComputationPathEffect: function (path, value, effect) {
|
|
if (this._pathMatchesEffect(path, effect)) {
|
|
Polymer.Bind._annotatedComputationEffect.call(this, path, value, effect);
|
|
}
|
|
},
|
|
_pathMatchesEffect: function (path, effect) {
|
|
var effectArg = effect.trigger.name;
|
|
return effectArg == path || effectArg.indexOf(path + '.') === 0 || effect.trigger.wildcard && path.indexOf(effectArg) === 0;
|
|
},
|
|
linkPaths: function (to, from) {
|
|
this._boundPaths = this._boundPaths || {};
|
|
if (from) {
|
|
this._boundPaths[to] = from;
|
|
} else {
|
|
this.unlinkPaths(to);
|
|
}
|
|
},
|
|
unlinkPaths: function (path) {
|
|
if (this._boundPaths) {
|
|
delete this._boundPaths[path];
|
|
}
|
|
},
|
|
_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);
|
|
} else if (path.indexOf(b + '.') == 0) {
|
|
this._notifyPath(this._fixPath(a, b, path), value);
|
|
}
|
|
}
|
|
},
|
|
_fixPath: function (property, root, path) {
|
|
return property + path.slice(root.length);
|
|
},
|
|
_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,
|
|
_useCache: true
|
|
});
|
|
},
|
|
_modelForPath: function (path) {
|
|
var dot = path.indexOf('.');
|
|
return dot < 0 ? path : path.slice(0, dot);
|
|
},
|
|
_EVENT_CHANGED: '-changed',
|
|
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
|
|
};
|
|
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 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, info.path, len, args.length, []);
|
|
}
|
|
return ret;
|
|
},
|
|
pop: function (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, info.path, array.length, 0, [ret]);
|
|
}
|
|
return ret;
|
|
},
|
|
splice: function (path, start) {
|
|
var info = {};
|
|
var array = this._get(path, this, info);
|
|
if (start < 0) {
|
|
start = array.length - Math.floor(-start);
|
|
} else {
|
|
start = Math.floor(start);
|
|
}
|
|
if (!start) {
|
|
start = 0;
|
|
}
|
|
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, info.path, start, addedCount, ret);
|
|
}
|
|
return ret;
|
|
},
|
|
shift: function (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, info.path, 0, 0, [ret]);
|
|
}
|
|
return ret;
|
|
},
|
|
unshift: function (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, 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,
|
|
_annotatedComputationPathEffect: Polymer.Base._annotatedComputationPathEffect,
|
|
_computePathEffect: Polymer.Base._computePathEffect,
|
|
_modelForPath: Polymer.Base._modelForPath,
|
|
_pathMatchesEffect: Polymer.Base._pathMatchesEffect,
|
|
_notifyBoundPaths: Polymer.Base._notifyBoundPaths,
|
|
_getPathParts: Polymer.Base._getPathParts
|
|
});
|
|
}
|
|
});
|
|
}());
|
|
Polymer.Base._addFeature({
|
|
resolveUrl: function (url) {
|
|
var module = Polymer.DomModule.import(this.is);
|
|
var root = '';
|
|
if (module) {
|
|
var assetPath = module.getAttribute('assetpath') || '';
|
|
root = Polymer.ResolveUrl.resolveUrl(assetPath, module.ownerDocument.baseURI);
|
|
}
|
|
return Polymer.ResolveUrl.resolveUrl(url, root);
|
|
}
|
|
});
|
|
Polymer.CssParse = function () {
|
|
return {
|
|
parse: function (text) {
|
|
text = this._clean(text);
|
|
return this._parseCss(this._lex(text), text);
|
|
},
|
|
_clean: function (cssText) {
|
|
return cssText.replace(this._rx.comments, '').replace(this._rx.port, '');
|
|
},
|
|
_lex: function (text) {
|
|
var root = {
|
|
start: 0,
|
|
end: text.length
|
|
};
|
|
var n = root;
|
|
for (var i = 0, l = text.length; i < l; i++) {
|
|
switch (text[i]) {
|
|
case this.OPEN_BRACE:
|
|
if (!n.rules) {
|
|
n.rules = [];
|
|
}
|
|
var p = n;
|
|
var previous = p.rules[p.rules.length - 1];
|
|
n = {
|
|
start: i + 1,
|
|
parent: p,
|
|
previous: previous
|
|
};
|
|
p.rules.push(n);
|
|
break;
|
|
case this.CLOSE_BRACE:
|
|
n.end = i + 1;
|
|
n = n.parent || root;
|
|
break;
|
|
}
|
|
}
|
|
return root;
|
|
},
|
|
_parseCss: function (node, text) {
|
|
var t = text.substring(node.start, node.end - 1);
|
|
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;
|
|
if (node.atRule) {
|
|
if (s.indexOf(this.MEDIA_START) === 0) {
|
|
node.type = this.types.MEDIA_RULE;
|
|
} else if (s.match(this._rx.keyframesRule)) {
|
|
node.type = this.types.KEYFRAMES_RULE;
|
|
node.keyframesName = node.selector.split(this._rx.multipleSpaces).pop();
|
|
}
|
|
} else {
|
|
if (s.indexOf(this.VAR_START) === 0) {
|
|
node.type = this.types.MIXIN_RULE;
|
|
} else {
|
|
node.type = this.types.STYLE_RULE;
|
|
}
|
|
}
|
|
}
|
|
var r$ = node.rules;
|
|
if (r$) {
|
|
for (var i = 0, l = r$.length, r; i < l && (r = r$[i]); i++) {
|
|
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 = '';
|
|
if (node.cssText || node.rules) {
|
|
var r$ = node.rules;
|
|
if (r$ && (preserveProperties || !this._hasMixinRules(r$))) {
|
|
for (var i = 0, l = r$.length, r; i < l && (r = r$[i]); i++) {
|
|
cssText = this.stringify(r, preserveProperties, cssText);
|
|
}
|
|
} else {
|
|
cssText = preserveProperties ? node.cssText : this.removeCustomProps(node.cssText);
|
|
cssText = cssText.trim();
|
|
if (cssText) {
|
|
cssText = ' ' + cssText + '\n';
|
|
}
|
|
}
|
|
}
|
|
if (cssText) {
|
|
if (node.selector) {
|
|
text += node.selector + ' ' + this.OPEN_BRACE + '\n';
|
|
}
|
|
text += cssText;
|
|
if (node.selector) {
|
|
text += this.CLOSE_BRACE + '\n\n';
|
|
}
|
|
}
|
|
return text;
|
|
},
|
|
_hasMixinRules: function (rules) {
|
|
return rules[0].selector.indexOf(this.VAR_START) === 0;
|
|
},
|
|
removeCustomProps: function (cssText) {
|
|
cssText = this.removeCustomPropAssignment(cssText);
|
|
return this.removeCustomPropApply(cssText);
|
|
},
|
|
removeCustomPropAssignment: function (cssText) {
|
|
return cssText.replace(this._rx.customProp, '').replace(this._rx.mixinProp, '');
|
|
},
|
|
removeCustomPropApply: function (cssText) {
|
|
return cssText.replace(this._rx.mixinApply, '').replace(this._rx.varApply, '');
|
|
},
|
|
types: {
|
|
STYLE_RULE: 1,
|
|
KEYFRAMES_RULE: 7,
|
|
MEDIA_RULE: 4,
|
|
MIXIN_RULE: 1000
|
|
},
|
|
OPEN_BRACE: '{',
|
|
CLOSE_BRACE: '}',
|
|
_rx: {
|
|
comments: /\/\*[^*]*\*+([^\/*][^*]*\*+)*\//gim,
|
|
port: /@import[^;]*;/gim,
|
|
customProp: /(?:^[^;\-\s}]+)?--[^;{}]*?:[^{};]*?(?:[;\n]|$)/gim,
|
|
mixinProp: /(?:^[^;\-\s}]+)?--[^;{}]*?:[^{};]*?{[^}]*?}(?:[;\n]|$)?/gim,
|
|
mixinApply: /@apply[\s]*\([^)]*?\)[\s]*(?:[;\n]|$)?/gim,
|
|
varApply: /[^;:]*?:[^;]*?var\([^;]*\)(?:[;\n]|$)?/gim,
|
|
keyframesRule: /^@[^\s]*keyframes/,
|
|
multipleSpaces: /\s+/g
|
|
},
|
|
VAR_START: '--',
|
|
MEDIA_START: '@media',
|
|
AT_START: '@'
|
|
};
|
|
}();
|
|
Polymer.StyleUtil = function () {
|
|
return {
|
|
MODULE_STYLES_SELECTOR: 'style, link[rel=import][type~=css], template',
|
|
INCLUDE_ATTR: 'include',
|
|
toCssText: function (rules, callback, preserveProperties) {
|
|
if (typeof rules === 'string') {
|
|
rules = this.parser.parse(rules);
|
|
}
|
|
if (callback) {
|
|
this.forEachRule(rules, callback);
|
|
}
|
|
return this.parser.stringify(rules, preserveProperties);
|
|
},
|
|
forRulesInStyles: function (styles, styleRuleCallback, keyframesRuleCallback) {
|
|
if (styles) {
|
|
for (var i = 0, l = styles.length, s; i < l && (s = styles[i]); i++) {
|
|
this.forEachRule(this.rulesForStyle(s), styleRuleCallback, keyframesRuleCallback);
|
|
}
|
|
}
|
|
},
|
|
rulesForStyle: function (style) {
|
|
if (!style.__cssRules && style.textContent) {
|
|
style.__cssRules = this.parser.parse(style.textContent);
|
|
}
|
|
return style.__cssRules;
|
|
},
|
|
isKeyframesSelector: function (rule) {
|
|
return rule.parent && rule.parent.type === this.ruleTypes.KEYFRAMES_RULE;
|
|
},
|
|
forEachRule: function (node, styleRuleCallback, keyframesRuleCallback) {
|
|
if (!node) {
|
|
return;
|
|
}
|
|
var skipRules = false;
|
|
if (node.type === this.ruleTypes.STYLE_RULE) {
|
|
styleRuleCallback(node);
|
|
} else if (keyframesRuleCallback && node.type === this.ruleTypes.KEYFRAMES_RULE) {
|
|
keyframesRuleCallback(node);
|
|
} else if (node.type === this.ruleTypes.MIXIN_RULE) {
|
|
skipRules = true;
|
|
}
|
|
var r$ = node.rules;
|
|
if (r$ && !skipRules) {
|
|
for (var i = 0, l = r$.length, r; i < l && (r = r$[i]); i++) {
|
|
this.forEachRule(r, styleRuleCallback, keyframesRuleCallback);
|
|
}
|
|
}
|
|
},
|
|
applyCss: function (cssText, moniker, target, contextNode) {
|
|
var style = this.createScopeStyle(cssText, moniker);
|
|
target = target || document.head;
|
|
var after = contextNode && contextNode.nextSibling || target.firstChild;
|
|
this.__lastHeadApplyNode = style;
|
|
return target.insertBefore(style, after);
|
|
},
|
|
createScopeStyle: function (cssText, moniker) {
|
|
var style = document.createElement('style');
|
|
if (moniker) {
|
|
style.setAttribute('scope', moniker);
|
|
}
|
|
style.textContent = cssText;
|
|
return style;
|
|
},
|
|
__lastHeadApplyNode: null,
|
|
applyStylePlaceHolder: function (moniker) {
|
|
var placeHolder = document.createComment(' Shady DOM styles for ' + moniker + ' ');
|
|
var after = this.__lastHeadApplyNode ? this.__lastHeadApplyNode.nextSibling : null;
|
|
var scope = document.head;
|
|
scope.insertBefore(placeHolder, after || scope.firstChild);
|
|
this.__lastHeadApplyNode = placeHolder;
|
|
return placeHolder;
|
|
},
|
|
cssFromModules: function (moduleIds, warnIfNotFound) {
|
|
var modules = moduleIds.trim().split(' ');
|
|
var cssText = '';
|
|
for (var i = 0; i < modules.length; i++) {
|
|
cssText += this.cssFromModule(modules[i], warnIfNotFound);
|
|
}
|
|
return cssText;
|
|
},
|
|
cssFromModule: function (moduleId, warnIfNotFound) {
|
|
var m = Polymer.DomModule.import(moduleId);
|
|
if (m && !m._cssText) {
|
|
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) {
|
|
var cssText = '';
|
|
var content = element.content || element;
|
|
var e$ = Polymer.TreeApi.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);
|
|
} else {
|
|
if (e.localName === 'style') {
|
|
var include = e.getAttribute(this.INCLUDE_ATTR);
|
|
if (include) {
|
|
cssText += this.cssFromModules(include, true);
|
|
}
|
|
e = e.__appliedElement || e;
|
|
e.parentNode.removeChild(e);
|
|
cssText += this.resolveCss(e.textContent, element.ownerDocument);
|
|
} else if (e.import && e.import.body) {
|
|
cssText += this.resolveCss(e.import.body.textContent, e.import);
|
|
}
|
|
}
|
|
}
|
|
return cssText;
|
|
},
|
|
resolveCss: Polymer.ResolveUrl.resolveCss,
|
|
parser: Polymer.CssParse,
|
|
ruleTypes: Polymer.CssParse.types
|
|
};
|
|
}();
|
|
Polymer.StyleTransformer = function () {
|
|
var nativeShadow = Polymer.Settings.useNativeShadow;
|
|
var styleUtil = Polymer.StyleUtil;
|
|
var api = {
|
|
dom: function (node, scope, useAttr, shouldRemoveScope) {
|
|
this._transformDom(node, scope || '', useAttr, shouldRemoveScope);
|
|
},
|
|
_transformDom: function (node, selector, useAttr, shouldRemoveScope) {
|
|
if (node.setAttribute) {
|
|
this.element(node, selector, useAttr, shouldRemoveScope);
|
|
}
|
|
var c$ = Polymer.dom(node).childNodes;
|
|
for (var i = 0; i < c$.length; i++) {
|
|
this._transformDom(c$[i], selector, useAttr, shouldRemoveScope);
|
|
}
|
|
},
|
|
element: function (element, scope, useAttr, shouldRemoveScope) {
|
|
if (useAttr) {
|
|
if (shouldRemoveScope) {
|
|
element.removeAttribute(SCOPE_NAME);
|
|
} else {
|
|
element.setAttribute(SCOPE_NAME, scope);
|
|
}
|
|
} else {
|
|
if (scope) {
|
|
if (element.classList) {
|
|
if (shouldRemoveScope) {
|
|
element.classList.remove(SCOPE_NAME);
|
|
element.classList.remove(scope);
|
|
} else {
|
|
element.classList.add(SCOPE_NAME);
|
|
element.classList.add(scope);
|
|
}
|
|
} else if (element.getAttribute) {
|
|
var c = element.getAttribute(CLASS);
|
|
if (shouldRemoveScope) {
|
|
if (c) {
|
|
element.setAttribute(CLASS, c.replace(SCOPE_NAME, '').replace(scope, ''));
|
|
}
|
|
} else {
|
|
element.setAttribute(CLASS, (c ? c + ' ' : '') + SCOPE_NAME + ' ' + scope);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
elementStyles: function (element, callback) {
|
|
var styles = element._styles;
|
|
var cssText = '';
|
|
for (var i = 0, l = styles.length, s; i < l && (s = styles[i]); i++) {
|
|
var rules = styleUtil.rulesForStyle(s);
|
|
cssText += nativeShadow ? styleUtil.toCssText(rules, callback) : this.css(rules, element.is, element.extends, callback, element._scopeCssViaAttr) + '\n\n';
|
|
}
|
|
return cssText.trim();
|
|
},
|
|
css: function (rules, scope, ext, callback, useAttr) {
|
|
var hostScope = this._calcHostScope(scope, ext);
|
|
scope = this._calcElementScope(scope, useAttr);
|
|
var self = this;
|
|
return styleUtil.toCssText(rules, function (rule) {
|
|
if (!rule.isScoped) {
|
|
self.rule(rule, scope, hostScope);
|
|
rule.isScoped = true;
|
|
}
|
|
if (callback) {
|
|
callback(rule, scope, hostScope);
|
|
}
|
|
});
|
|
},
|
|
_calcElementScope: function (scope, useAttr) {
|
|
if (scope) {
|
|
return useAttr ? CSS_ATTR_PREFIX + scope + CSS_ATTR_SUFFIX : CSS_CLASS_PREFIX + scope;
|
|
} else {
|
|
return '';
|
|
}
|
|
},
|
|
_calcHostScope: function (scope, ext) {
|
|
return ext ? '[is=' + scope + ']' : scope;
|
|
},
|
|
rule: function (rule, scope, hostScope) {
|
|
this._transformRule(rule, this._transformComplexSelector, scope, hostScope);
|
|
},
|
|
_transformRule: function (rule, transformer, scope, hostScope) {
|
|
var p$ = rule.selector.split(COMPLEX_SELECTOR_SEP);
|
|
if (!styleUtil.isKeyframesSelector(rule)) {
|
|
for (var i = 0, l = p$.length, p; i < l && (p = p$[i]); i++) {
|
|
p$[i] = transformer.call(this, p, scope, hostScope);
|
|
}
|
|
}
|
|
rule.selector = rule.transformedSelector = p$.join(COMPLEX_SELECTOR_SEP);
|
|
},
|
|
_transformComplexSelector: function (selector, scope, hostScope) {
|
|
var stop = false;
|
|
var hostContext = false;
|
|
var self = this;
|
|
selector = selector.replace(CONTENT_START, HOST + ' $1');
|
|
selector = selector.replace(SIMPLE_SELECTOR_SEP, function (m, c, s) {
|
|
if (!stop) {
|
|
var info = self._transformCompoundSelector(s, c, scope, hostScope);
|
|
stop = stop || info.stop;
|
|
hostContext = hostContext || info.hostContext;
|
|
c = info.combinator;
|
|
s = info.value;
|
|
} else {
|
|
s = s.replace(SCOPE_JUMP, ' ');
|
|
}
|
|
return c + s;
|
|
});
|
|
if (hostContext) {
|
|
selector = selector.replace(HOST_CONTEXT_PAREN, function (m, pre, paren, post) {
|
|
return pre + paren + ' ' + hostScope + post + COMPLEX_SELECTOR_SEP + ' ' + pre + hostScope + paren + post;
|
|
});
|
|
}
|
|
return selector;
|
|
},
|
|
_transformCompoundSelector: function (selector, combinator, scope, hostScope) {
|
|
var jumpIndex = selector.search(SCOPE_JUMP);
|
|
var hostContext = false;
|
|
if (selector.indexOf(HOST_CONTEXT) >= 0) {
|
|
hostContext = true;
|
|
} else if (selector.indexOf(HOST) >= 0) {
|
|
selector = selector.replace(HOST_PAREN, function (m, host, paren) {
|
|
return hostScope + paren;
|
|
});
|
|
selector = selector.replace(HOST, hostScope);
|
|
} else if (jumpIndex !== 0) {
|
|
selector = scope ? this._transformSimpleSelector(selector, scope) : selector;
|
|
}
|
|
if (selector.indexOf(CONTENT) >= 0) {
|
|
combinator = '';
|
|
}
|
|
var stop;
|
|
if (jumpIndex >= 0) {
|
|
selector = selector.replace(SCOPE_JUMP, ' ');
|
|
stop = true;
|
|
}
|
|
return {
|
|
value: selector,
|
|
combinator: combinator,
|
|
stop: stop,
|
|
hostContext: hostContext
|
|
};
|
|
},
|
|
_transformSimpleSelector: function (selector, scope) {
|
|
var p$ = selector.split(PSEUDO_PREFIX);
|
|
p$[0] += scope;
|
|
return p$.join(PSEUDO_PREFIX);
|
|
},
|
|
documentRule: function (rule) {
|
|
rule.selector = rule.parsedSelector;
|
|
this.normalizeRootSelector(rule);
|
|
if (!nativeShadow) {
|
|
this._transformRule(rule, this._transformDocumentSelector);
|
|
}
|
|
},
|
|
normalizeRootSelector: function (rule) {
|
|
if (rule.selector === ROOT) {
|
|
rule.selector = 'body';
|
|
}
|
|
},
|
|
_transformDocumentSelector: function (selector) {
|
|
return selector.match(SCOPE_JUMP) ? this._transformComplexSelector(selector, SCOPE_DOC_SELECTOR) : this._transformSimpleSelector(selector.trim(), SCOPE_DOC_SELECTOR);
|
|
},
|
|
SCOPE_NAME: 'style-scope'
|
|
};
|
|
var SCOPE_NAME = api.SCOPE_NAME;
|
|
var SCOPE_DOC_SELECTOR = ':not([' + SCOPE_NAME + '])' + ':not(.' + SCOPE_NAME + ')';
|
|
var COMPLEX_SELECTOR_SEP = ',';
|
|
var SIMPLE_SELECTOR_SEP = /(^|[\s>+~]+)((?:\[.+?\]|[^\s>+~=\[])+)/g;
|
|
var HOST = ':host';
|
|
var ROOT = ':root';
|
|
var HOST_PAREN = /(:host)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/g;
|
|
var HOST_CONTEXT = ':host-context';
|
|
var HOST_CONTEXT_PAREN = /(.*)(?::host-context)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))(.*)/;
|
|
var CONTENT = '::content';
|
|
var SCOPE_JUMP = /::content|::shadow|\/deep\//;
|
|
var CSS_CLASS_PREFIX = '.';
|
|
var CSS_ATTR_PREFIX = '[' + SCOPE_NAME + '~=';
|
|
var CSS_ATTR_SUFFIX = ']';
|
|
var PSEUDO_PREFIX = ':';
|
|
var CLASS = 'class';
|
|
var CONTENT_START = new RegExp('^(' + CONTENT + ')');
|
|
return api;
|
|
}();
|
|
Polymer.StyleExtends = function () {
|
|
var styleUtil = Polymer.StyleUtil;
|
|
return {
|
|
hasExtends: function (cssText) {
|
|
return Boolean(cssText.match(this.rx.EXTEND));
|
|
},
|
|
transform: function (style) {
|
|
var rules = styleUtil.rulesForStyle(style);
|
|
var self = this;
|
|
styleUtil.forEachRule(rules, function (rule) {
|
|
self._mapRuleOntoParent(rule);
|
|
if (rule.parent) {
|
|
var m;
|
|
while (m = self.rx.EXTEND.exec(rule.cssText)) {
|
|
var extend = m[1];
|
|
var extendor = self._findExtendor(extend, rule);
|
|
if (extendor) {
|
|
self._extendRule(rule, extendor);
|
|
}
|
|
}
|
|
}
|
|
rule.cssText = rule.cssText.replace(self.rx.EXTEND, '');
|
|
});
|
|
return styleUtil.toCssText(rules, function (rule) {
|
|
if (rule.selector.match(self.rx.STRIP)) {
|
|
rule.cssText = '';
|
|
}
|
|
}, true);
|
|
},
|
|
_mapRuleOntoParent: function (rule) {
|
|
if (rule.parent) {
|
|
var map = rule.parent.map || (rule.parent.map = {});
|
|
var parts = rule.selector.split(',');
|
|
for (var i = 0, p; i < parts.length; i++) {
|
|
p = parts[i];
|
|
map[p.trim()] = rule;
|
|
}
|
|
return map;
|
|
}
|
|
},
|
|
_findExtendor: function (extend, rule) {
|
|
return rule.parent && rule.parent.map && rule.parent.map[extend] || this._findExtendor(extend, rule.parent);
|
|
},
|
|
_extendRule: function (target, source) {
|
|
if (target.parent !== source.parent) {
|
|
this._cloneAndAddRuleToParent(source, target.parent);
|
|
}
|
|
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;
|
|
if (source.extends) {
|
|
source.extends.forEach(function (e) {
|
|
this._extendRule(target, e);
|
|
}, this);
|
|
}
|
|
},
|
|
_cloneAndAddRuleToParent: function (rule, parent) {
|
|
rule = Object.create(rule);
|
|
rule.parent = parent;
|
|
if (rule.extends) {
|
|
rule.extends = rule.extends.slice();
|
|
}
|
|
parent.rules.push(rule);
|
|
},
|
|
rx: {
|
|
EXTEND: /@extends\(([^)]*)\)\s*?;/gim,
|
|
STRIP: /%[^,]*$/
|
|
}
|
|
};
|
|
}();
|
|
(function () {
|
|
var prepElement = Polymer.Base._prepElement;
|
|
var nativeShadow = Polymer.Settings.useNativeShadow;
|
|
var styleUtil = Polymer.StyleUtil;
|
|
var styleTransformer = Polymer.StyleTransformer;
|
|
var styleExtends = Polymer.StyleExtends;
|
|
Polymer.Base._addFeature({
|
|
_prepElement: function (element) {
|
|
if (this._encapsulateStyle) {
|
|
styleTransformer.element(element, this.is, this._scopeCssViaAttr);
|
|
}
|
|
prepElement.call(this, element);
|
|
},
|
|
_prepStyles: function () {
|
|
if (!nativeShadow) {
|
|
this._scopeStyle = styleUtil.applyStylePlaceHolder(this.is);
|
|
}
|
|
},
|
|
_prepShimStyles: function () {
|
|
if (this._template) {
|
|
if (this._encapsulateStyle === undefined) {
|
|
this._encapsulateStyle = !nativeShadow;
|
|
}
|
|
this._styles = this._collectStyles();
|
|
var cssText = styleTransformer.elementStyles(this);
|
|
this._prepStyleProperties();
|
|
if (!this._needsStyleProperties() && this._styles.length) {
|
|
styleUtil.applyCss(cssText, this.is, nativeShadow ? this._template.content : null, this._scopeStyle);
|
|
}
|
|
} else {
|
|
this._styles = [];
|
|
}
|
|
},
|
|
_collectStyles: function () {
|
|
var styles = [];
|
|
var cssText = '', m$ = this.styleModules;
|
|
if (m$) {
|
|
for (var i = 0, l = m$.length, m; i < l && (m = m$[i]); i++) {
|
|
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;
|
|
if (styleExtends.hasExtends(style.textContent)) {
|
|
cssText = styleExtends.transform(style);
|
|
}
|
|
styles.push(style);
|
|
}
|
|
return styles;
|
|
},
|
|
_elementAdd: function (node) {
|
|
if (this._encapsulateStyle) {
|
|
if (node.__styleScoped) {
|
|
node.__styleScoped = false;
|
|
} else {
|
|
styleTransformer.dom(node, this.is, this._scopeCssViaAttr);
|
|
}
|
|
}
|
|
},
|
|
_elementRemove: function (node) {
|
|
if (this._encapsulateStyle) {
|
|
styleTransformer.dom(node, this.is, this._scopeCssViaAttr, true);
|
|
}
|
|
},
|
|
scopeSubtree: function (container, shouldObserve) {
|
|
if (nativeShadow) {
|
|
return;
|
|
}
|
|
var self = this;
|
|
var scopify = function (node) {
|
|
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
var className = node.getAttribute('class');
|
|
node.setAttribute('class', self._scopeElementClass(node, className));
|
|
var n$ = node.querySelectorAll('*');
|
|
for (var i = 0, n; i < n$.length && (n = n$[i]); i++) {
|
|
className = n.getAttribute('class');
|
|
n.setAttribute('class', self._scopeElementClass(n, className));
|
|
}
|
|
}
|
|
};
|
|
scopify(container);
|
|
if (shouldObserve) {
|
|
var mo = new MutationObserver(function (mxns) {
|
|
for (var i = 0, m; i < mxns.length && (m = mxns[i]); i++) {
|
|
if (m.addedNodes) {
|
|
for (var j = 0; j < m.addedNodes.length; j++) {
|
|
scopify(m.addedNodes[j]);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
mo.observe(container, {
|
|
childList: true,
|
|
subtree: true
|
|
});
|
|
return mo;
|
|
}
|
|
}
|
|
});
|
|
}());
|
|
Polymer.StyleProperties = function () {
|
|
'use strict';
|
|
var nativeShadow = Polymer.Settings.useNativeShadow;
|
|
var matchesSelector = Polymer.DomApi.matchesSelector;
|
|
var styleUtil = Polymer.StyleUtil;
|
|
var styleTransformer = Polymer.StyleTransformer;
|
|
return {
|
|
decorateStyles: function (styles) {
|
|
var self = this, props = {}, keyframes = [];
|
|
styleUtil.forRulesInStyles(styles, function (rule) {
|
|
self.decorateRule(rule);
|
|
self.collectPropertiesInCssText(rule.propertyInfo.cssText, props);
|
|
}, function onKeyframesRule(rule) {
|
|
keyframes.push(rule);
|
|
});
|
|
styles._keyframes = keyframes;
|
|
var names = [];
|
|
for (var i in props) {
|
|
names.push(i);
|
|
}
|
|
return names;
|
|
},
|
|
decorateRule: function (rule) {
|
|
if (rule.propertyInfo) {
|
|
return rule.propertyInfo;
|
|
}
|
|
var info = {}, properties = {};
|
|
var hasProperties = this.collectProperties(rule, properties);
|
|
if (hasProperties) {
|
|
info.properties = properties;
|
|
rule.rules = null;
|
|
}
|
|
info.cssText = this.collectCssText(rule);
|
|
rule.propertyInfo = info;
|
|
return info;
|
|
},
|
|
collectProperties: function (rule, properties) {
|
|
var info = rule.propertyInfo;
|
|
if (info) {
|
|
if (info.properties) {
|
|
Polymer.Base.mixin(properties, info.properties);
|
|
return true;
|
|
}
|
|
} else {
|
|
var m, rx = this.rx.VAR_ASSIGN;
|
|
var cssText = rule.parsedCssText;
|
|
var any;
|
|
while (m = rx.exec(cssText)) {
|
|
properties[m[1]] = (m[2] || m[3]).trim();
|
|
any = true;
|
|
}
|
|
return any;
|
|
}
|
|
},
|
|
collectCssText: function (rule) {
|
|
return this.collectConsumingCssText(rule.parsedCssText);
|
|
},
|
|
collectConsumingCssText: function (cssText) {
|
|
return cssText.replace(this.rx.BRACKETED, '').replace(this.rx.VAR_ASSIGN, '');
|
|
},
|
|
collectPropertiesInCssText: function (cssText, props) {
|
|
var m;
|
|
while (m = this.rx.VAR_CAPTURE.exec(cssText)) {
|
|
props[m[1]] = true;
|
|
var def = m[2];
|
|
if (def && def.match(this.rx.IS_VAR)) {
|
|
props[def] = true;
|
|
}
|
|
}
|
|
},
|
|
reify: function (props) {
|
|
var names = Object.getOwnPropertyNames(props);
|
|
for (var i = 0, n; i < names.length; i++) {
|
|
n = names[i];
|
|
props[n] = this.valueForProperty(props[n], props);
|
|
}
|
|
},
|
|
valueForProperty: function (property, props) {
|
|
if (property) {
|
|
if (property.indexOf(';') >= 0) {
|
|
property = this.valueForProperties(property, props);
|
|
} else {
|
|
var self = this;
|
|
var fn = function (all, prefix, value, fallback) {
|
|
var propertyValue = self.valueForProperty(props[value], props) || (props[fallback] ? self.valueForProperty(props[fallback], props) : fallback);
|
|
return prefix + (propertyValue || '');
|
|
};
|
|
property = property.replace(this.rx.VAR_MATCH, fn);
|
|
}
|
|
}
|
|
return property && property.trim() || '';
|
|
},
|
|
valueForProperties: function (property, props) {
|
|
var parts = property.split(';');
|
|
for (var i = 0, p, m; i < parts.length; i++) {
|
|
if (p = parts[i]) {
|
|
m = p.match(this.rx.MIXIN_MATCH);
|
|
if (m) {
|
|
p = this.valueForProperty(props[m[1]], props);
|
|
} else {
|
|
var colon = p.indexOf(':');
|
|
if (colon !== -1) {
|
|
var pp = p.substring(colon);
|
|
pp = pp.trim();
|
|
pp = this.valueForProperty(pp, props) || pp;
|
|
p = p.substring(0, colon) + pp;
|
|
}
|
|
}
|
|
parts[i] = p && p.lastIndexOf(';') === p.length - 1 ? p.slice(0, -1) : p || '';
|
|
}
|
|
}
|
|
return parts.join(';');
|
|
},
|
|
applyProperties: function (rule, props) {
|
|
var output = '';
|
|
if (!rule.propertyInfo) {
|
|
this.decorateRule(rule);
|
|
}
|
|
if (rule.propertyInfo.cssText) {
|
|
output = this.valueForProperties(rule.propertyInfo.cssText, props);
|
|
}
|
|
rule.cssText = output;
|
|
},
|
|
applyKeyframeTransforms: function (rule, keyframeTransforms) {
|
|
var input = rule.cssText;
|
|
var output = rule.cssText;
|
|
if (rule.hasAnimations == null) {
|
|
rule.hasAnimations = this.rx.ANIMATION_MATCH.test(input);
|
|
}
|
|
if (rule.hasAnimations) {
|
|
var transform;
|
|
if (rule.keyframeNamesToTransform == null) {
|
|
rule.keyframeNamesToTransform = [];
|
|
for (var keyframe in keyframeTransforms) {
|
|
transform = keyframeTransforms[keyframe];
|
|
output = transform(input);
|
|
if (input !== output) {
|
|
input = output;
|
|
rule.keyframeNamesToTransform.push(keyframe);
|
|
}
|
|
}
|
|
} else {
|
|
for (var i = 0; i < rule.keyframeNamesToTransform.length; ++i) {
|
|
transform = keyframeTransforms[rule.keyframeNamesToTransform[i]];
|
|
input = transform(input);
|
|
}
|
|
output = input;
|
|
}
|
|
}
|
|
rule.cssText = output;
|
|
},
|
|
propertyDataFromStyles: function (styles, element) {
|
|
var props = {}, self = this;
|
|
var o = [], i = 0;
|
|
styleUtil.forRulesInStyles(styles, function (rule) {
|
|
if (!rule.propertyInfo) {
|
|
self.decorateRule(rule);
|
|
}
|
|
if (element && rule.propertyInfo.properties && matchesSelector.call(element, rule.transformedSelector || rule.parsedSelector)) {
|
|
self.collectProperties(rule, props);
|
|
addToBitMask(i, o);
|
|
}
|
|
i++;
|
|
});
|
|
return {
|
|
properties: props,
|
|
key: o
|
|
};
|
|
},
|
|
scopePropertiesFromStyles: function (styles) {
|
|
if (!styles._scopeStyleProperties) {
|
|
styles._scopeStyleProperties = this.selectedPropertiesFromStyles(styles, this.SCOPE_SELECTORS);
|
|
}
|
|
return styles._scopeStyleProperties;
|
|
},
|
|
hostPropertiesFromStyles: function (styles) {
|
|
if (!styles._hostStyleProperties) {
|
|
styles._hostStyleProperties = this.selectedPropertiesFromStyles(styles, this.HOST_SELECTORS);
|
|
}
|
|
return styles._hostStyleProperties;
|
|
},
|
|
selectedPropertiesFromStyles: function (styles, selectors) {
|
|
var props = {}, self = this;
|
|
styleUtil.forRulesInStyles(styles, function (rule) {
|
|
if (!rule.propertyInfo) {
|
|
self.decorateRule(rule);
|
|
}
|
|
for (var i = 0; i < selectors.length; i++) {
|
|
if (rule.parsedSelector === selectors[i]) {
|
|
self.collectProperties(rule, props);
|
|
return;
|
|
}
|
|
}
|
|
});
|
|
return props;
|
|
},
|
|
transformStyles: function (element, properties, scopeSelector) {
|
|
var self = this;
|
|
var hostSelector = styleTransformer._calcHostScope(element.is, element.extends);
|
|
var rxHostSelector = element.extends ? '\\' + hostSelector.slice(0, -1) + '\\]' : hostSelector;
|
|
var hostRx = new RegExp(this.rx.HOST_PREFIX + rxHostSelector + this.rx.HOST_SUFFIX);
|
|
var keyframeTransforms = this._elementKeyframeTransforms(element, scopeSelector);
|
|
return styleTransformer.elementStyles(element, function (rule) {
|
|
self.applyProperties(rule, properties);
|
|
if (!nativeShadow && !Polymer.StyleUtil.isKeyframesSelector(rule) && rule.cssText) {
|
|
self.applyKeyframeTransforms(rule, keyframeTransforms);
|
|
self._scopeSelector(rule, hostRx, hostSelector, element._scopeCssViaAttr, scopeSelector);
|
|
}
|
|
});
|
|
},
|
|
_elementKeyframeTransforms: function (element, scopeSelector) {
|
|
var keyframesRules = element._styles._keyframes;
|
|
var keyframeTransforms = {};
|
|
if (!nativeShadow && keyframesRules) {
|
|
for (var i = 0, keyframesRule = keyframesRules[i]; i < keyframesRules.length; keyframesRule = keyframesRules[++i]) {
|
|
this._scopeKeyframes(keyframesRule, scopeSelector);
|
|
keyframeTransforms[keyframesRule.keyframesName] = this._keyframesRuleTransformer(keyframesRule);
|
|
}
|
|
}
|
|
return keyframeTransforms;
|
|
},
|
|
_keyframesRuleTransformer: function (keyframesRule) {
|
|
return function (cssText) {
|
|
return cssText.replace(keyframesRule.keyframesNameRx, keyframesRule.transformedKeyframesName);
|
|
};
|
|
},
|
|
_scopeKeyframes: function (rule, scopeId) {
|
|
rule.keyframesNameRx = new RegExp(rule.keyframesName, 'g');
|
|
rule.transformedKeyframesName = rule.keyframesName + '-' + scopeId;
|
|
rule.transformedSelector = rule.transformedSelector || rule.selector;
|
|
rule.selector = rule.transformedSelector.replace(rule.keyframesName, rule.transformedKeyframesName);
|
|
},
|
|
_scopeSelector: function (rule, hostRx, hostSelector, viaAttr, scopeId) {
|
|
rule.transformedSelector = rule.transformedSelector || rule.selector;
|
|
var selector = rule.transformedSelector;
|
|
var scope = viaAttr ? '[' + styleTransformer.SCOPE_NAME + '~=' + scopeId + ']' : '.' + scopeId;
|
|
var parts = selector.split(',');
|
|
for (var i = 0, l = parts.length, p; i < l && (p = parts[i]); i++) {
|
|
parts[i] = p.match(hostRx) ? p.replace(hostSelector, scope) : scope + ' ' + p;
|
|
}
|
|
rule.selector = parts.join(',');
|
|
},
|
|
applyElementScopeSelector: function (element, selector, old, viaAttr) {
|
|
var c = viaAttr ? element.getAttribute(styleTransformer.SCOPE_NAME) : element.getAttribute('class') || '';
|
|
var v = old ? c.replace(old, selector) : (c ? c + ' ' : '') + this.XSCOPE_NAME + ' ' + selector;
|
|
if (c !== v) {
|
|
if (viaAttr) {
|
|
element.setAttribute(styleTransformer.SCOPE_NAME, v);
|
|
} else {
|
|
element.setAttribute('class', v);
|
|
}
|
|
}
|
|
},
|
|
applyElementStyle: function (element, properties, selector, style) {
|
|
var cssText = style ? style.textContent || '' : this.transformStyles(element, properties, selector);
|
|
var s = element._customStyle;
|
|
if (s && !nativeShadow && s !== style) {
|
|
s._useCount--;
|
|
if (s._useCount <= 0 && s.parentNode) {
|
|
s.parentNode.removeChild(s);
|
|
}
|
|
}
|
|
if (nativeShadow || (!style || !style.parentNode)) {
|
|
if (nativeShadow && element._customStyle) {
|
|
element._customStyle.textContent = cssText;
|
|
style = element._customStyle;
|
|
} else if (cssText) {
|
|
style = styleUtil.applyCss(cssText, selector, nativeShadow ? element.root : null, element._scopeStyle);
|
|
}
|
|
}
|
|
if (style) {
|
|
style._useCount = style._useCount || 0;
|
|
if (element._customStyle != style) {
|
|
style._useCount++;
|
|
}
|
|
element._customStyle = style;
|
|
}
|
|
return style;
|
|
},
|
|
mixinCustomStyle: function (props, customStyle) {
|
|
var v;
|
|
for (var i in customStyle) {
|
|
v = customStyle[i];
|
|
if (v || v === 0) {
|
|
props[i] = v;
|
|
}
|
|
}
|
|
},
|
|
rx: {
|
|
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,
|
|
ANIMATION_MATCH: /(animation\s*:)|(animation-name\s*:)/,
|
|
IS_VAR: /^--/,
|
|
BRACKETED: /\{[^}]*\}/g,
|
|
HOST_PREFIX: '(?:^|[^.#[:])',
|
|
HOST_SUFFIX: '($|[.:[\\s>+~])'
|
|
},
|
|
HOST_SELECTORS: [':host'],
|
|
SCOPE_SELECTORS: [':root'],
|
|
XSCOPE_NAME: 'x-scope'
|
|
};
|
|
function addToBitMask(n, bits) {
|
|
var o = parseInt(n / 32);
|
|
var v = 1 << n % 32;
|
|
bits[o] = (bits[o] || 0) | v;
|
|
}
|
|
}();
|
|
(function () {
|
|
Polymer.StyleCache = function () {
|
|
this.cache = {};
|
|
};
|
|
Polymer.StyleCache.prototype = {
|
|
MAX: 100,
|
|
store: function (is, data, keyValues, keyStyles) {
|
|
data.keyValues = keyValues;
|
|
data.styles = keyStyles;
|
|
var s$ = this.cache[is] = this.cache[is] || [];
|
|
s$.push(data);
|
|
if (s$.length > this.MAX) {
|
|
s$.shift();
|
|
}
|
|
},
|
|
retrieve: function (is, keyValues, keyStyles) {
|
|
var cache = this.cache[is];
|
|
if (cache) {
|
|
for (var i = cache.length - 1, data; i >= 0; i--) {
|
|
data = cache[i];
|
|
if (keyStyles === data.styles && this._objectsEqual(keyValues, data.keyValues)) {
|
|
return data;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
clear: function () {
|
|
this.cache = {};
|
|
},
|
|
_objectsEqual: function (target, source) {
|
|
var t, s;
|
|
for (var i in target) {
|
|
t = target[i], s = source[i];
|
|
if (!(typeof t === 'object' && t ? this._objectsStrictlyEqual(t, s) : t === s)) {
|
|
return false;
|
|
}
|
|
}
|
|
if (Array.isArray(target)) {
|
|
return target.length === source.length;
|
|
}
|
|
return true;
|
|
},
|
|
_objectsStrictlyEqual: function (target, source) {
|
|
return this._objectsEqual(target, source) && this._objectsEqual(source, target);
|
|
}
|
|
};
|
|
}());
|
|
Polymer.StyleDefaults = function () {
|
|
var styleProperties = Polymer.StyleProperties;
|
|
var StyleCache = Polymer.StyleCache;
|
|
var api = {
|
|
_styles: [],
|
|
_properties: null,
|
|
customStyle: {},
|
|
_styleCache: new StyleCache(),
|
|
addStyle: function (style) {
|
|
this._styles.push(style);
|
|
this._properties = null;
|
|
},
|
|
get _styleProperties() {
|
|
if (!this._properties) {
|
|
styleProperties.decorateStyles(this._styles);
|
|
this._styles._scopeStyleProperties = null;
|
|
this._properties = styleProperties.scopePropertiesFromStyles(this._styles);
|
|
styleProperties.mixinCustomStyle(this._properties, this.customStyle);
|
|
styleProperties.reify(this._properties);
|
|
}
|
|
return this._properties;
|
|
},
|
|
_needsStyleProperties: function () {
|
|
},
|
|
_computeStyleProperties: function () {
|
|
return this._styleProperties;
|
|
},
|
|
updateStyles: function (properties) {
|
|
this._properties = null;
|
|
if (properties) {
|
|
Polymer.Base.mixin(this.customStyle, properties);
|
|
}
|
|
this._styleCache.clear();
|
|
for (var i = 0, s; i < this._styles.length; i++) {
|
|
s = this._styles[i];
|
|
s = s.__importElement || s;
|
|
s._apply();
|
|
}
|
|
}
|
|
};
|
|
return api;
|
|
}();
|
|
(function () {
|
|
'use strict';
|
|
var serializeValueToAttribute = Polymer.Base.serializeValueToAttribute;
|
|
var propertyUtils = Polymer.StyleProperties;
|
|
var styleTransformer = Polymer.StyleTransformer;
|
|
var styleDefaults = Polymer.StyleDefaults;
|
|
var nativeShadow = Polymer.Settings.useNativeShadow;
|
|
Polymer.Base._addFeature({
|
|
_prepStyleProperties: function () {
|
|
this._ownStylePropertyNames = this._styles && this._styles.length ? propertyUtils.decorateStyles(this._styles) : null;
|
|
},
|
|
customStyle: null,
|
|
getComputedStyleValue: function (property) {
|
|
return this._styleProperties && this._styleProperties[property] || getComputedStyle(this).getPropertyValue(property);
|
|
},
|
|
_setupStyleProperties: function () {
|
|
this.customStyle = {};
|
|
this._styleCache = null;
|
|
this._styleProperties = null;
|
|
this._scopeSelector = null;
|
|
this._ownStyleProperties = null;
|
|
this._customStyle = null;
|
|
},
|
|
_needsStyleProperties: function () {
|
|
return Boolean(this._ownStylePropertyNames && this._ownStylePropertyNames.length);
|
|
},
|
|
_beforeAttached: function () {
|
|
if (!this._scopeSelector && this._needsStyleProperties()) {
|
|
this._updateStyleProperties();
|
|
}
|
|
},
|
|
_findStyleHost: function () {
|
|
var e = this, root;
|
|
while (root = Polymer.dom(e).getOwnerRoot()) {
|
|
if (Polymer.isInstance(root.host)) {
|
|
return root.host;
|
|
}
|
|
e = root.host;
|
|
}
|
|
return styleDefaults;
|
|
},
|
|
_updateStyleProperties: function () {
|
|
var info, scope = this._findStyleHost();
|
|
if (!scope._styleCache) {
|
|
scope._styleCache = new Polymer.StyleCache();
|
|
}
|
|
var scopeData = propertyUtils.propertyDataFromStyles(scope._styles, this);
|
|
scopeData.key.customStyle = this.customStyle;
|
|
info = scope._styleCache.retrieve(this.is, scopeData.key, this._styles);
|
|
var scopeCached = Boolean(info);
|
|
if (scopeCached) {
|
|
this._styleProperties = info._styleProperties;
|
|
} else {
|
|
this._computeStyleProperties(scopeData.properties);
|
|
}
|
|
this._computeOwnStyleProperties();
|
|
if (!scopeCached) {
|
|
info = styleCache.retrieve(this.is, this._ownStyleProperties, this._styles);
|
|
}
|
|
var globalCached = Boolean(info) && !scopeCached;
|
|
var style = this._applyStyleProperties(info);
|
|
if (!scopeCached) {
|
|
style = style && nativeShadow ? style.cloneNode(true) : style;
|
|
info = {
|
|
style: style,
|
|
_scopeSelector: this._scopeSelector,
|
|
_styleProperties: this._styleProperties
|
|
};
|
|
scopeData.key.customStyle = {};
|
|
this.mixin(scopeData.key.customStyle, this.customStyle);
|
|
scope._styleCache.store(this.is, info, scopeData.key, this._styles);
|
|
if (!globalCached) {
|
|
styleCache.store(this.is, Object.create(info), this._ownStyleProperties, this._styles);
|
|
}
|
|
}
|
|
},
|
|
_computeStyleProperties: function (scopeProps) {
|
|
var scope = this._findStyleHost();
|
|
if (!scope._styleProperties) {
|
|
scope._computeStyleProperties();
|
|
}
|
|
var props = Object.create(scope._styleProperties);
|
|
this.mixin(props, propertyUtils.hostPropertiesFromStyles(this._styles));
|
|
scopeProps = scopeProps || propertyUtils.propertyDataFromStyles(scope._styles, this).properties;
|
|
this.mixin(props, scopeProps);
|
|
this.mixin(props, propertyUtils.scopePropertiesFromStyles(this._styles));
|
|
propertyUtils.mixinCustomStyle(props, this.customStyle);
|
|
propertyUtils.reify(props);
|
|
this._styleProperties = props;
|
|
},
|
|
_computeOwnStyleProperties: function () {
|
|
var props = {};
|
|
for (var i = 0, n; i < this._ownStylePropertyNames.length; i++) {
|
|
n = this._ownStylePropertyNames[i];
|
|
props[n] = this._styleProperties[n];
|
|
}
|
|
this._ownStyleProperties = props;
|
|
},
|
|
_scopeCount: 0,
|
|
_applyStyleProperties: function (info) {
|
|
var oldScopeSelector = this._scopeSelector;
|
|
this._scopeSelector = info ? info._scopeSelector : this.is + '-' + this.__proto__._scopeCount++;
|
|
var style = propertyUtils.applyElementStyle(this, this._styleProperties, this._scopeSelector, info && info.style);
|
|
if (!nativeShadow) {
|
|
propertyUtils.applyElementScopeSelector(this, this._scopeSelector, oldScopeSelector, this._scopeCssViaAttr);
|
|
}
|
|
return style;
|
|
},
|
|
serializeValueToAttribute: function (value, attribute, node) {
|
|
node = node || this;
|
|
if (attribute === 'class' && !nativeShadow) {
|
|
var host = node === this ? this.domHost || this.dataHost : this;
|
|
if (host) {
|
|
value = host._scopeElementClass(node, value);
|
|
}
|
|
}
|
|
node = this.shadyRoot && this.shadyRoot._hasDistributed ? Polymer.dom(node) : node;
|
|
serializeValueToAttribute.call(this, value, attribute, node);
|
|
},
|
|
_scopeElementClass: function (element, selector) {
|
|
if (!nativeShadow && !this._scopeCssViaAttr) {
|
|
selector = (selector ? selector + ' ' : '') + SCOPE_NAME + ' ' + this.is + (element._scopeSelector ? ' ' + XSCOPE_NAME + ' ' + element._scopeSelector : '');
|
|
}
|
|
return selector;
|
|
},
|
|
updateStyles: function (properties) {
|
|
if (this.isAttached) {
|
|
if (properties) {
|
|
this.mixin(this.customStyle, properties);
|
|
}
|
|
if (this._needsStyleProperties()) {
|
|
this._updateStyleProperties();
|
|
} else {
|
|
this._styleProperties = null;
|
|
}
|
|
if (this._styleCache) {
|
|
this._styleCache.clear();
|
|
}
|
|
this._updateRootStyles();
|
|
}
|
|
},
|
|
_updateRootStyles: function (root) {
|
|
root = root || this.root;
|
|
var c$ = Polymer.dom(root)._query(function (e) {
|
|
return e.shadyRoot || e.shadowRoot;
|
|
});
|
|
for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) {
|
|
if (c.updateStyles) {
|
|
c.updateStyles();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
Polymer.updateStyles = function (properties) {
|
|
styleDefaults.updateStyles(properties);
|
|
Polymer.Base._updateRootStyles(document);
|
|
};
|
|
var styleCache = new Polymer.StyleCache();
|
|
Polymer.customStyleCache = styleCache;
|
|
var SCOPE_NAME = styleTransformer.SCOPE_NAME;
|
|
var XSCOPE_NAME = propertyUtils.XSCOPE_NAME;
|
|
}());
|
|
Polymer.Base._addFeature({
|
|
_registerFeatures: function () {
|
|
this._prepIs();
|
|
this._prepConstructor();
|
|
this._prepStyles();
|
|
},
|
|
_finishRegisterFeatures: function () {
|
|
this._prepTemplate();
|
|
this._prepShimStyles();
|
|
this._prepAnnotations();
|
|
this._prepEffects();
|
|
this._prepBehaviors();
|
|
this._prepPropertyInfo();
|
|
this._prepBindings();
|
|
this._prepShady();
|
|
},
|
|
_prepBehavior: function (b) {
|
|
this._addPropertyEffects(b.properties);
|
|
this._addComplexObserverEffects(b.observers);
|
|
this._addHostAttributes(b.hostAttributes);
|
|
},
|
|
_initFeatures: function () {
|
|
this._setupGestures();
|
|
this._setupConfigure();
|
|
this._setupStyleProperties();
|
|
this._setupDebouncers();
|
|
this._setupShady();
|
|
this._registerHost();
|
|
if (this._template) {
|
|
this._poolContent();
|
|
this._beginHosting();
|
|
this._stampTemplate();
|
|
this._endHosting();
|
|
this._marshalAnnotationReferences();
|
|
}
|
|
this._marshalInstanceEffects();
|
|
this._marshalBehaviors();
|
|
this._marshalHostAttributes();
|
|
this._marshalAttributes();
|
|
this._tryReady();
|
|
},
|
|
_marshalBehavior: function (b) {
|
|
if (b.listeners) {
|
|
this._listenListeners(b.listeners);
|
|
}
|
|
}
|
|
});
|
|
(function () {
|
|
var propertyUtils = Polymer.StyleProperties;
|
|
var styleUtil = Polymer.StyleUtil;
|
|
var cssParse = Polymer.CssParse;
|
|
var styleDefaults = Polymer.StyleDefaults;
|
|
var styleTransformer = Polymer.StyleTransformer;
|
|
Polymer({
|
|
is: 'custom-style',
|
|
extends: 'style',
|
|
_template: null,
|
|
properties: { include: String },
|
|
ready: function () {
|
|
this._tryApply();
|
|
},
|
|
attached: function () {
|
|
this._tryApply();
|
|
},
|
|
_tryApply: function () {
|
|
if (!this._appliesToDocument) {
|
|
if (this.parentNode && this.parentNode.localName !== 'dom-module') {
|
|
this._appliesToDocument = true;
|
|
var e = this.__appliedElement || this;
|
|
styleDefaults.addStyle(e);
|
|
if (e.textContent || this.include) {
|
|
this._apply(true);
|
|
} else {
|
|
var self = this;
|
|
var observer = new MutationObserver(function () {
|
|
observer.disconnect();
|
|
self._apply(true);
|
|
});
|
|
observer.observe(e, { childList: true });
|
|
}
|
|
}
|
|
}
|
|
},
|
|
_apply: function (deferProperties) {
|
|
var e = this.__appliedElement || this;
|
|
if (this.include) {
|
|
e.textContent = styleUtil.cssFromModules(this.include, true) + e.textContent;
|
|
}
|
|
if (e.textContent) {
|
|
styleUtil.forEachRule(styleUtil.rulesForStyle(e), function (rule) {
|
|
styleTransformer.documentRule(rule);
|
|
});
|
|
var self = this;
|
|
var fn = 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) {
|
|
this._computeStyleProperties();
|
|
var props = this._styleProperties;
|
|
var rules = styleUtil.rulesForStyle(element);
|
|
element.textContent = styleUtil.toCssText(rules, function (rule) {
|
|
var css = rule.cssText = rule.parsedCssText;
|
|
if (rule.propertyInfo && rule.propertyInfo.cssText) {
|
|
css = cssParse.removeCustomPropAssignment(css);
|
|
rule.cssText = propertyUtils.valueForProperties(css, props);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}());
|
|
Polymer.Templatizer = {
|
|
properties: { __hideTemplateChildren__: { observer: '_showHideChildren' } },
|
|
_instanceProps: Polymer.nob,
|
|
_parentPropPrefix: '_parent_',
|
|
templatize: function (template) {
|
|
this._templatized = template;
|
|
if (!template._content) {
|
|
template._content = template.content;
|
|
}
|
|
if (template._content._ctor) {
|
|
this.ctor = template._content._ctor;
|
|
this._prepParentProperties(this.ctor.prototype, template);
|
|
return;
|
|
}
|
|
var archetype = Object.create(Polymer.Base);
|
|
this._customPrepAnnotations(archetype, template);
|
|
this._prepParentProperties(archetype, template);
|
|
archetype._prepEffects();
|
|
this._customPrepEffects(archetype);
|
|
archetype._prepBehaviors();
|
|
archetype._prepPropertyInfo();
|
|
archetype._prepBindings();
|
|
archetype._notifyPathUp = this._notifyPathUpImpl;
|
|
archetype._scopeElementClass = this._scopeElementClassImpl;
|
|
archetype.listen = this._listenImpl;
|
|
archetype._showHideChildren = this._showHideChildrenImpl;
|
|
archetype.__setPropertyOrig = this.__setProperty;
|
|
archetype.__setProperty = this.__setPropertyImpl;
|
|
var _constructor = this._constructorImpl;
|
|
var ctor = function TemplateInstance(model, host) {
|
|
_constructor.call(this, model, host);
|
|
};
|
|
ctor.prototype = archetype;
|
|
archetype.constructor = ctor;
|
|
template._content._ctor = ctor;
|
|
this.ctor = ctor;
|
|
},
|
|
_getRootDataHost: function () {
|
|
return this.dataHost && this.dataHost._rootDataHost || this.dataHost;
|
|
},
|
|
_showHideChildrenImpl: function (hide) {
|
|
var c = this._children;
|
|
for (var i = 0; i < c.length; i++) {
|
|
var n = c[i];
|
|
if (Boolean(hide) != Boolean(n.__hideTemplateChildren__)) {
|
|
if (n.nodeType === Node.TEXT_NODE) {
|
|
if (hide) {
|
|
n.__polymerTextContent__ = n.textContent;
|
|
n.textContent = '';
|
|
} else {
|
|
n.textContent = n.__polymerTextContent__;
|
|
}
|
|
} else if (n.style) {
|
|
if (hide) {
|
|
n.__polymerDisplay__ = n.style.display;
|
|
n.style.display = 'none';
|
|
} else {
|
|
n.style.display = n.__polymerDisplay__;
|
|
}
|
|
}
|
|
}
|
|
n.__hideTemplateChildren__ = hide;
|
|
}
|
|
},
|
|
__setPropertyImpl: function (property, value, fromAbove, node) {
|
|
if (node && node.__hideTemplateChildren__ && property == 'textContent') {
|
|
property = '__polymerTextContent__';
|
|
}
|
|
this.__setPropertyOrig(property, value, fromAbove, node);
|
|
},
|
|
_debounceTemplate: function (fn) {
|
|
Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', fn));
|
|
},
|
|
_flushTemplates: function () {
|
|
Polymer.dom.flush();
|
|
},
|
|
_customPrepEffects: function (archetype) {
|
|
var parentProps = archetype._parentProps;
|
|
for (var prop in parentProps) {
|
|
archetype._addPropertyEffect(prop, 'function', this._createHostPropEffector(prop));
|
|
}
|
|
for (prop in this._instanceProps) {
|
|
archetype._addPropertyEffect(prop, 'function', this._createInstancePropEffector(prop));
|
|
}
|
|
},
|
|
_customPrepAnnotations: function (archetype, template) {
|
|
archetype._template = template;
|
|
var c = template._content;
|
|
if (!c._notes) {
|
|
var rootDataHost = archetype._rootDataHost;
|
|
if (rootDataHost) {
|
|
Polymer.Annotations.prepElement = function () {
|
|
rootDataHost._prepElement();
|
|
};
|
|
}
|
|
c._notes = Polymer.Annotations.parseAnnotations(template);
|
|
Polymer.Annotations.prepElement = null;
|
|
this._processAnnotations(c._notes);
|
|
}
|
|
archetype._notes = c._notes;
|
|
archetype._parentProps = c._parentProps;
|
|
},
|
|
_prepParentProperties: function (archetype, template) {
|
|
var parentProps = this._parentProps = archetype._parentProps;
|
|
if (this._forwardParentProp && parentProps) {
|
|
var proto = archetype._parentPropProto;
|
|
var prop;
|
|
if (!proto) {
|
|
for (prop in this._instanceProps) {
|
|
delete parentProps[prop];
|
|
}
|
|
proto = archetype._parentPropProto = Object.create(null);
|
|
if (template != this) {
|
|
Polymer.Bind.prepareModel(proto);
|
|
Polymer.Base.prepareModelNotifyPath(proto);
|
|
}
|
|
for (prop in parentProps) {
|
|
var parentProp = this._parentPropPrefix + prop;
|
|
var effects = [
|
|
{
|
|
kind: 'function',
|
|
effect: this._createForwardPropEffector(prop),
|
|
fn: Polymer.Bind._functionEffect
|
|
},
|
|
{
|
|
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 = function (source, value) {
|
|
self._forwardParentProp(source, value);
|
|
};
|
|
}
|
|
this._extendTemplate(template, proto);
|
|
template._pathEffector = function (path, value, fromAbove) {
|
|
return self._pathEffectorImpl(path, value, fromAbove);
|
|
};
|
|
}
|
|
},
|
|
_createForwardPropEffector: function (prop) {
|
|
return function (source, value) {
|
|
this._forwardParentProp(prop, value);
|
|
};
|
|
},
|
|
_createHostPropEffector: function (prop) {
|
|
var prefix = this._parentPropPrefix;
|
|
return function (source, value) {
|
|
this.dataHost._templatized[prefix + prop] = value;
|
|
};
|
|
},
|
|
_createInstancePropEffector: function (prop) {
|
|
return function (source, value, old, fromAbove) {
|
|
if (!fromAbove) {
|
|
this.dataHost._forwardInstanceProp(this, prop, value);
|
|
}
|
|
};
|
|
},
|
|
_extendTemplate: function (template, proto) {
|
|
var n$ = Object.getOwnPropertyNames(proto);
|
|
if (proto._propertySetter) {
|
|
template._propertySetter = proto._propertySetter;
|
|
}
|
|
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) {
|
|
},
|
|
_forwardInstancePath: function (inst, path, value) {
|
|
},
|
|
_forwardInstanceProp: function (inst, prop, value) {
|
|
},
|
|
_notifyPathUpImpl: function (path, value) {
|
|
var dataHost = this.dataHost;
|
|
var dot = path.indexOf('.');
|
|
var root = dot < 0 ? path : path.slice(0, dot);
|
|
dataHost._forwardInstancePath.call(dataHost, this, path, value);
|
|
if (root in dataHost._parentProps) {
|
|
dataHost._templatized.notifyPath(dataHost._parentPropPrefix + path, value);
|
|
}
|
|
},
|
|
_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._registerHost(host);
|
|
this._beginHosting();
|
|
this.root = this.instanceTemplate(this._template);
|
|
this.root.__noContent = !this._notes._hasContent;
|
|
this.root.__styleScoped = true;
|
|
this._endHosting();
|
|
this._marshalAnnotatedNodes();
|
|
this._marshalInstanceEffects();
|
|
this._marshalAnnotatedListeners();
|
|
var children = [];
|
|
for (var n = this.root.firstChild; n; n = n.nextSibling) {
|
|
children.push(n);
|
|
n._templateInstance = this;
|
|
}
|
|
this._children = children;
|
|
if (host.__hideTemplateChildren__) {
|
|
this._showHideChildren(true);
|
|
}
|
|
this._tryReady();
|
|
},
|
|
_listenImpl: function (node, eventName, methodName) {
|
|
var model = this;
|
|
var host = this._rootDataHost;
|
|
var handler = host._createEventHandler(node, eventName, methodName);
|
|
var decorated = function (e) {
|
|
e.model = model;
|
|
handler(e);
|
|
};
|
|
host._listen(node, eventName, decorated);
|
|
},
|
|
_scopeElementClassImpl: function (node, value) {
|
|
var host = this._rootDataHost;
|
|
if (host) {
|
|
return host._scopeElementClass(node, value);
|
|
}
|
|
},
|
|
stamp: function (model) {
|
|
model = model || {};
|
|
if (this._parentProps) {
|
|
var templatized = this._templatized;
|
|
for (var prop in this._parentProps) {
|
|
if (model[prop] === undefined) {
|
|
model[prop] = templatized[this._parentPropPrefix + prop];
|
|
}
|
|
}
|
|
}
|
|
return new this.ctor(model, this);
|
|
},
|
|
modelForElement: function (el) {
|
|
var model;
|
|
while (el) {
|
|
if (model = el._templateInstance) {
|
|
if (model.dataHost != this) {
|
|
el = model.dataHost;
|
|
} else {
|
|
return model;
|
|
}
|
|
} else {
|
|
el = el.parentNode;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
Polymer({
|
|
is: 'dom-template',
|
|
extends: 'template',
|
|
_template: null,
|
|
behaviors: [Polymer.Templatizer],
|
|
ready: function () {
|
|
this.templatize(this);
|
|
}
|
|
});
|
|
Polymer._collections = new WeakMap();
|
|
Polymer.Collection = function (userArray) {
|
|
Polymer._collections.set(userArray, this);
|
|
this.userArray = userArray;
|
|
this.store = userArray.slice();
|
|
this.initMap();
|
|
};
|
|
Polymer.Collection.prototype = {
|
|
constructor: Polymer.Collection,
|
|
initMap: function () {
|
|
var omap = this.omap = new WeakMap();
|
|
var pmap = this.pmap = {};
|
|
var s = this.store;
|
|
for (var i = 0; i < s.length; i++) {
|
|
var item = s[i];
|
|
if (item && typeof item == 'object') {
|
|
omap.set(item, i);
|
|
} else {
|
|
pmap[item] = i;
|
|
}
|
|
}
|
|
},
|
|
add: function (item) {
|
|
var key = this.store.push(item) - 1;
|
|
if (item && typeof item == 'object') {
|
|
this.omap.set(item, key);
|
|
} else {
|
|
this.pmap[item] = key;
|
|
}
|
|
return '#' + key;
|
|
},
|
|
removeKey: function (key) {
|
|
if (key = this._parseKey(key)) {
|
|
this._removeFromMap(this.store[key]);
|
|
delete this.store[key];
|
|
}
|
|
},
|
|
_removeFromMap: function (item) {
|
|
if (item && typeof item == 'object') {
|
|
this.omap.delete(item);
|
|
} else {
|
|
delete this.pmap[item];
|
|
}
|
|
},
|
|
remove: function (item) {
|
|
var key = this.getKey(item);
|
|
this.removeKey(key);
|
|
return key;
|
|
},
|
|
getKey: function (item) {
|
|
var key;
|
|
if (item && typeof item == 'object') {
|
|
key = this.omap.get(item);
|
|
} else {
|
|
key = this.pmap[item];
|
|
}
|
|
if (key != undefined) {
|
|
return '#' + key;
|
|
}
|
|
},
|
|
getKeys: function () {
|
|
return Object.keys(this.store).map(function (key) {
|
|
return '#' + key;
|
|
});
|
|
},
|
|
_parseKey: function (key) {
|
|
if (key && key[0] == '#') {
|
|
return key.slice(1);
|
|
}
|
|
},
|
|
setItem: function (key, item) {
|
|
if (key = this._parseKey(key)) {
|
|
var old = this.store[key];
|
|
if (old) {
|
|
this._removeFromMap(old);
|
|
}
|
|
if (item && typeof item == 'object') {
|
|
this.omap.set(item, key);
|
|
} else {
|
|
this.pmap[item] = key;
|
|
}
|
|
this.store[key] = item;
|
|
}
|
|
},
|
|
getItem: function (key) {
|
|
if (key = this._parseKey(key)) {
|
|
return this.store[key];
|
|
}
|
|
},
|
|
getItems: function () {
|
|
var items = [], store = this.store;
|
|
for (var key in store) {
|
|
items.push(store[key]);
|
|
}
|
|
return items;
|
|
},
|
|
_applySplices: function (splices) {
|
|
var keyMap = {}, key;
|
|
for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
|
|
s.addedKeys = [];
|
|
for (var j = 0; j < s.removed.length; j++) {
|
|
key = this.getKey(s.removed[j]);
|
|
keyMap[key] = keyMap[key] ? null : -1;
|
|
}
|
|
for (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);
|
|
}
|
|
}
|
|
var removed = [];
|
|
var added = [];
|
|
for (key in keyMap) {
|
|
if (keyMap[key] < 0) {
|
|
this.removeKey(key);
|
|
removed.push(key);
|
|
}
|
|
if (keyMap[key] > 0) {
|
|
added.push(key);
|
|
}
|
|
}
|
|
return [{
|
|
removed: removed,
|
|
added: added
|
|
}];
|
|
}
|
|
};
|
|
Polymer.Collection.get = function (userArray) {
|
|
return Polymer._collections.get(userArray) || new Polymer.Collection(userArray);
|
|
};
|
|
Polymer.Collection.applySplices = function (userArray, splices) {
|
|
var coll = Polymer._collections.get(userArray);
|
|
return coll ? coll._applySplices(splices) : null;
|
|
};
|
|
Polymer({
|
|
is: 'dom-repeat',
|
|
extends: 'template',
|
|
_template: null,
|
|
properties: {
|
|
items: { type: Array },
|
|
as: {
|
|
type: String,
|
|
value: 'item'
|
|
},
|
|
indexAs: {
|
|
type: String,
|
|
value: 'index'
|
|
},
|
|
sort: {
|
|
type: Function,
|
|
observer: '_sortChanged'
|
|
},
|
|
filter: {
|
|
type: Function,
|
|
observer: '_filterChanged'
|
|
},
|
|
observe: {
|
|
type: String,
|
|
observer: '_observeChanged'
|
|
},
|
|
delay: Number,
|
|
renderedItemCount: {
|
|
type: Number,
|
|
notify: true,
|
|
readOnly: true
|
|
},
|
|
initialCount: {
|
|
type: Number,
|
|
observer: '_initializeChunking'
|
|
},
|
|
targetFramerate: {
|
|
type: Number,
|
|
value: 20
|
|
},
|
|
_targetFrameTime: {
|
|
type: Number,
|
|
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 () {
|
|
this.__isDetached = true;
|
|
for (var i = 0; i < this._instances.length; i++) {
|
|
this._detachInstance(i);
|
|
}
|
|
},
|
|
attached: function () {
|
|
if (this.__isDetached) {
|
|
this.__isDetached = false;
|
|
var parent = Polymer.dom(Polymer.dom(this).parentNode);
|
|
for (var i = 0; i < this._instances.length; i++) {
|
|
this._attachInstance(i, parent);
|
|
}
|
|
}
|
|
},
|
|
ready: function () {
|
|
this._instanceProps = { __key__: true };
|
|
this._instanceProps[this.as] = true;
|
|
this._instanceProps[this.indexAs] = true;
|
|
if (!this.ctor) {
|
|
this.templatize(this);
|
|
}
|
|
},
|
|
_sortChanged: function (sort) {
|
|
var dataHost = this._getRootDataHost();
|
|
this._sortFn = sort && (typeof sort == 'function' ? sort : function () {
|
|
return dataHost[sort].apply(dataHost, arguments);
|
|
});
|
|
this._needFullRefresh = true;
|
|
if (this.items) {
|
|
this._debounceTemplate(this._render);
|
|
}
|
|
},
|
|
_filterChanged: function (filter) {
|
|
var dataHost = this._getRootDataHost();
|
|
this._filterFn = filter && (typeof filter == 'function' ? filter : function () {
|
|
return dataHost[filter].apply(dataHost, arguments);
|
|
});
|
|
this._needFullRefresh = true;
|
|
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(' ');
|
|
},
|
|
_itemsChanged: function (change) {
|
|
if (change.path == 'items') {
|
|
if (Array.isArray(this.items)) {
|
|
this.collection = Polymer.Collection.get(this.items);
|
|
} else if (!this.items) {
|
|
this.collection = null;
|
|
} else {
|
|
this._error(this._logf('dom-repeat', 'expected array for `items`,' + ' found', this.items));
|
|
}
|
|
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);
|
|
this._indexSplices = this._indexSplices.concat(change.value.indexSplices);
|
|
this._debounceTemplate(this._render);
|
|
} else {
|
|
var subpath = change.path.slice(6);
|
|
this._forwardItemPath(subpath, change.value);
|
|
this._checkObservedPaths(subpath);
|
|
}
|
|
},
|
|
_checkObservedPaths: function (path) {
|
|
if (this._observePaths) {
|
|
path = path.substring(path.indexOf('.') + 1);
|
|
var paths = this._observePaths;
|
|
for (var i = 0; i < paths.length; i++) {
|
|
if (path.indexOf(paths[i]) === 0) {
|
|
this._needFullRefresh = true;
|
|
if (this.delay) {
|
|
this.debounce('render', this._render, this.delay);
|
|
} else {
|
|
this._debounceTemplate(this._render);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
render: function () {
|
|
this._needFullRefresh = true;
|
|
this._debounceTemplate(this._render);
|
|
this._flushTemplates();
|
|
},
|
|
_render: function () {
|
|
if (this._needFullRefresh) {
|
|
this._applyFullRefresh();
|
|
this._needFullRefresh = false;
|
|
} else if (this._keySplices.length) {
|
|
if (this._sortFn) {
|
|
this._applySplicesUserSort(this._keySplices);
|
|
} else {
|
|
if (this._filterFn) {
|
|
this._applyFullRefresh();
|
|
} else {
|
|
this._applySplicesArrayOrder(this._indexSplices);
|
|
}
|
|
}
|
|
} else {
|
|
}
|
|
this._keySplices = [];
|
|
this._indexSplices = [];
|
|
var keyToIdx = this._keyToInstIdx = {};
|
|
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._setRenderedItemCount(this._instances.length);
|
|
this.fire('dom-change');
|
|
this._tryRenderChunk();
|
|
},
|
|
_applyFullRefresh: function () {
|
|
var c = this.collection;
|
|
var keys;
|
|
if (this._sortFn) {
|
|
keys = c ? c.getKeys() : [];
|
|
} else {
|
|
keys = [];
|
|
var items = this.items;
|
|
if (items) {
|
|
for (var i = 0; i < items.length; i++) {
|
|
keys.push(c.getKey(items[i]));
|
|
}
|
|
}
|
|
}
|
|
var self = this;
|
|
if (this._filterFn) {
|
|
keys = keys.filter(function (a) {
|
|
return self._filterFn(c.getItem(a));
|
|
});
|
|
}
|
|
if (this._sortFn) {
|
|
keys.sort(function (a, b) {
|
|
return self._sortFn(c.getItem(a), c.getItem(b));
|
|
});
|
|
}
|
|
for (i = 0; i < keys.length; i++) {
|
|
var key = keys[i];
|
|
var inst = this._instances[i];
|
|
if (inst) {
|
|
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._insertPlaceholder(i, key);
|
|
}
|
|
}
|
|
for (var j = this._instances.length - 1; j >= i; j--) {
|
|
this._detachAndRemoveInstance(j);
|
|
}
|
|
},
|
|
_numericSort: function (a, b) {
|
|
return a - b;
|
|
},
|
|
_applySplicesUserSort: function (splices) {
|
|
var c = this.collection;
|
|
var keyMap = {};
|
|
var key;
|
|
for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
|
|
for (var j = 0; j < s.removed.length; j++) {
|
|
key = s.removed[j];
|
|
keyMap[key] = keyMap[key] ? null : -1;
|
|
}
|
|
for (j = 0; j < s.added.length; j++) {
|
|
key = s.added[j];
|
|
keyMap[key] = keyMap[key] ? null : 1;
|
|
}
|
|
}
|
|
var removedIdxs = [];
|
|
var addedKeys = [];
|
|
for (key in keyMap) {
|
|
if (keyMap[key] === -1) {
|
|
removedIdxs.push(this._keyToInstIdx[key]);
|
|
}
|
|
if (keyMap[key] === 1) {
|
|
addedKeys.push(key);
|
|
}
|
|
}
|
|
if (removedIdxs.length) {
|
|
removedIdxs.sort(this._numericSort);
|
|
for (i = removedIdxs.length - 1; i >= 0; i--) {
|
|
var idx = removedIdxs[i];
|
|
if (idx !== undefined) {
|
|
this._detachAndRemoveInstance(idx);
|
|
}
|
|
}
|
|
}
|
|
var self = this;
|
|
if (addedKeys.length) {
|
|
if (this._filterFn) {
|
|
addedKeys = addedKeys.filter(function (a) {
|
|
return self._filterFn(c.getItem(a));
|
|
});
|
|
}
|
|
addedKeys.sort(function (a, b) {
|
|
return self._sortFn(c.getItem(a), c.getItem(b));
|
|
});
|
|
var start = 0;
|
|
for (i = 0; i < addedKeys.length; i++) {
|
|
start = this._insertRowUserSort(start, addedKeys[i]);
|
|
}
|
|
}
|
|
},
|
|
_insertRowUserSort: function (start, key) {
|
|
var c = this.collection;
|
|
var item = c.getItem(key);
|
|
var end = this._instances.length - 1;
|
|
var idx = -1;
|
|
while (start <= end) {
|
|
var mid = start + end >> 1;
|
|
var midKey = this._instances[mid].__key__;
|
|
var cmp = this._sortFn(c.getItem(midKey), item);
|
|
if (cmp < 0) {
|
|
start = mid + 1;
|
|
} else if (cmp > 0) {
|
|
end = mid - 1;
|
|
} else {
|
|
idx = mid;
|
|
break;
|
|
}
|
|
}
|
|
if (idx < 0) {
|
|
idx = end + 1;
|
|
}
|
|
this._insertPlaceholder(idx, key);
|
|
return idx;
|
|
},
|
|
_applySplicesArrayOrder: function (splices) {
|
|
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);
|
|
}
|
|
for (j = 0; j < s.addedKeys.length; j++) {
|
|
this._insertPlaceholder(s.index + j, s.addedKeys[j]);
|
|
}
|
|
}
|
|
},
|
|
_detachInstance: function (idx) {
|
|
var inst = this._instances[idx];
|
|
if (!inst.isPlaceholder) {
|
|
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);
|
|
},
|
|
_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._stampInstance(idx, key);
|
|
}
|
|
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;
|
|
},
|
|
_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) {
|
|
for (var i = 0; i < this._instances.length; i++) {
|
|
this._instances[i]._showHideChildren(hidden);
|
|
}
|
|
},
|
|
_forwardInstanceProp: function (inst, prop, value) {
|
|
if (prop == this.as) {
|
|
var idx;
|
|
if (this._sortFn || this._filterFn) {
|
|
idx = this.items.indexOf(this.collection.getItem(inst.__key__));
|
|
} else {
|
|
idx = inst[this.indexAs];
|
|
}
|
|
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);
|
|
}
|
|
},
|
|
_forwardParentProp: function (prop, value) {
|
|
var i$ = this._instances;
|
|
for (var i = 0, inst; i < i$.length && (inst = i$[i]); i++) {
|
|
if (!inst.isPlaceholder) {
|
|
inst.__setProperty(prop, value, true);
|
|
}
|
|
}
|
|
},
|
|
_forwardParentPath: function (path, value) {
|
|
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) {
|
|
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 && !inst.isPlaceholder) {
|
|
if (dot >= 0) {
|
|
path = this.as + '.' + path.substring(dot + 1);
|
|
inst._notifyPath(path, value, true);
|
|
} else {
|
|
inst.__setProperty(this.as, value, true);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
itemForElement: function (el) {
|
|
var instance = this.modelForElement(el);
|
|
return instance && instance[this.as];
|
|
},
|
|
keyForElement: function (el) {
|
|
var instance = this.modelForElement(el);
|
|
return instance && instance.__key__;
|
|
},
|
|
indexForElement: function (el) {
|
|
var instance = this.modelForElement(el);
|
|
return instance && instance[this.indexAs];
|
|
}
|
|
});
|
|
Polymer({
|
|
is: 'array-selector',
|
|
_template: null,
|
|
properties: {
|
|
items: {
|
|
type: Array,
|
|
observer: 'clearSelection'
|
|
},
|
|
multi: {
|
|
type: Boolean,
|
|
value: false,
|
|
observer: 'clearSelection'
|
|
},
|
|
selected: {
|
|
type: Object,
|
|
notify: true
|
|
},
|
|
selectedItem: {
|
|
type: Object,
|
|
notify: true
|
|
},
|
|
toggle: {
|
|
type: Boolean,
|
|
value: false
|
|
}
|
|
},
|
|
clearSelection: function () {
|
|
if (Array.isArray(this.selected)) {
|
|
for (var i = 0; i < this.selected.length; i++) {
|
|
this.unlinkPaths('selected.' + i);
|
|
}
|
|
} else {
|
|
this.unlinkPaths('selected');
|
|
this.unlinkPaths('selectedItem');
|
|
}
|
|
if (this.multi) {
|
|
if (!this.selected || this.selected.length) {
|
|
this.selected = [];
|
|
this._selectedColl = Polymer.Collection.get(this.selected);
|
|
}
|
|
} else {
|
|
this.selected = null;
|
|
this._selectedColl = null;
|
|
}
|
|
this.selectedItem = null;
|
|
},
|
|
isSelected: function (item) {
|
|
if (this.multi) {
|
|
return this._selectedColl.getKey(item) !== undefined;
|
|
} else {
|
|
return this.selected == item;
|
|
}
|
|
},
|
|
deselect: function (item) {
|
|
if (this.multi) {
|
|
if (this.isSelected(item)) {
|
|
var skey = this._selectedColl.getKey(item);
|
|
this.arrayDelete('selected', item);
|
|
this.unlinkPaths('selected.' + skey);
|
|
}
|
|
} else {
|
|
this.selected = null;
|
|
this.selectedItem = null;
|
|
this.unlinkPaths('selected');
|
|
this.unlinkPaths('selectedItem');
|
|
}
|
|
},
|
|
select: function (item) {
|
|
var icol = Polymer.Collection.get(this.items);
|
|
var key = icol.getKey(item);
|
|
if (this.multi) {
|
|
if (this.isSelected(item)) {
|
|
if (this.toggle) {
|
|
this.deselect(item);
|
|
}
|
|
} else {
|
|
this.push('selected', item);
|
|
var skey = this._selectedColl.getKey(item);
|
|
this.linkPaths('selected.' + skey, 'items.' + key);
|
|
}
|
|
} else {
|
|
if (this.toggle && item == this.selected) {
|
|
this.deselect();
|
|
} else {
|
|
this.selected = item;
|
|
this.selectedItem = item;
|
|
this.linkPaths('selected', 'items.' + key);
|
|
this.linkPaths('selectedItem', 'items.' + key);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
Polymer({
|
|
is: 'dom-if',
|
|
extends: 'template',
|
|
_template: null,
|
|
properties: {
|
|
'if': {
|
|
type: Boolean,
|
|
value: false,
|
|
observer: '_queueRender'
|
|
},
|
|
restamp: {
|
|
type: Boolean,
|
|
value: false,
|
|
observer: '_queueRender'
|
|
}
|
|
},
|
|
behaviors: [Polymer.Templatizer],
|
|
_queueRender: function () {
|
|
this._debounceTemplate(this._render);
|
|
},
|
|
detached: function () {
|
|
if (!this.parentNode || this.parentNode.nodeType == Node.DOCUMENT_FRAGMENT_NODE && (!Polymer.Settings.hasShadow || !(this.parentNode instanceof ShadowRoot))) {
|
|
this._teardownInstance();
|
|
}
|
|
},
|
|
attached: function () {
|
|
if (this.if && this.ctor) {
|
|
this.async(this._ensureInstance);
|
|
}
|
|
},
|
|
render: function () {
|
|
this._flushTemplates();
|
|
},
|
|
_render: function () {
|
|
if (this.if) {
|
|
if (!this.ctor) {
|
|
this.templatize(this);
|
|
}
|
|
this._ensureInstance();
|
|
this._showHideChildren();
|
|
} else if (this.restamp) {
|
|
this._teardownInstance();
|
|
}
|
|
if (!this.restamp && this._instance) {
|
|
this._showHideChildren();
|
|
}
|
|
if (this.if != this._lastIf) {
|
|
this.fire('dom-change');
|
|
this._lastIf = this.if;
|
|
}
|
|
},
|
|
_ensureInstance: function () {
|
|
var parentNode = Polymer.dom(this).parentNode;
|
|
if (parentNode) {
|
|
var parent = Polymer.dom(parentNode);
|
|
if (!this._instance) {
|
|
this._instance = this.stamp();
|
|
var root = this._instance.root;
|
|
parent.insertBefore(root, this);
|
|
} else {
|
|
var c$ = this._instance._children;
|
|
if (c$ && c$.length) {
|
|
var lastChild = Polymer.dom(this).previousSibling;
|
|
if (lastChild !== c$[c$.length - 1]) {
|
|
for (var i = 0, n; i < c$.length && (n = c$[i]); i++) {
|
|
parent.insertBefore(n, this);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
_teardownInstance: function () {
|
|
if (this._instance) {
|
|
var c$ = this._instance._children;
|
|
if (c$ && c$.length) {
|
|
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;
|
|
}
|
|
},
|
|
_showHideChildren: function () {
|
|
var hidden = this.__hideTemplateChildren__ || !this.if;
|
|
if (this._instance) {
|
|
this._instance._showHideChildren(hidden);
|
|
}
|
|
},
|
|
_forwardParentProp: function (prop, value) {
|
|
if (this._instance) {
|
|
this._instance[prop] = value;
|
|
}
|
|
},
|
|
_forwardParentPath: function (path, value) {
|
|
if (this._instance) {
|
|
this._instance._notifyPath(path, value, true);
|
|
}
|
|
}
|
|
});
|
|
Polymer({
|
|
is: 'dom-bind',
|
|
extends: 'template',
|
|
_template: null,
|
|
created: function () {
|
|
var self = this;
|
|
Polymer.RenderStatus.whenReady(function () {
|
|
if (document.readyState == 'loading') {
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
self._markImportsReady();
|
|
});
|
|
} else {
|
|
self._markImportsReady();
|
|
}
|
|
});
|
|
},
|
|
_ensureReady: function () {
|
|
if (!this._readied) {
|
|
this._readySelf();
|
|
}
|
|
},
|
|
_markImportsReady: function () {
|
|
this._importsReady = true;
|
|
this._ensureReady();
|
|
},
|
|
_registerFeatures: function () {
|
|
this._prepConstructor();
|
|
},
|
|
_insertChildren: function () {
|
|
var parentDom = Polymer.dom(Polymer.dom(this).parentNode);
|
|
parentDom.insertBefore(this.root, this);
|
|
},
|
|
_removeChildren: function () {
|
|
if (this._children) {
|
|
for (var i = 0; i < this._children.length; i++) {
|
|
this.root.appendChild(this._children[i]);
|
|
}
|
|
}
|
|
},
|
|
_initFeatures: function () {
|
|
},
|
|
_scopeElementClass: function (element, selector) {
|
|
if (this.dataHost) {
|
|
return this.dataHost._scopeElementClass(element, selector);
|
|
} else {
|
|
return selector;
|
|
}
|
|
},
|
|
_prepConfigure: function () {
|
|
var config = {};
|
|
for (var prop in this._propertyEffects) {
|
|
config[prop] = this[prop];
|
|
}
|
|
var setupConfigure = this._setupConfigure;
|
|
this._setupConfigure = function () {
|
|
setupConfigure.call(this, config);
|
|
};
|
|
},
|
|
attached: function () {
|
|
if (this._importsReady) {
|
|
this.render();
|
|
}
|
|
},
|
|
detached: function () {
|
|
this._removeChildren();
|
|
},
|
|
render: function () {
|
|
this._ensureReady();
|
|
if (!this._children) {
|
|
this._template = this;
|
|
this._prepAnnotations();
|
|
this._prepEffects();
|
|
this._prepBehaviors();
|
|
this._prepConfigure();
|
|
this._prepBindings();
|
|
this._prepPropertyInfo();
|
|
Polymer.Base._initFeatures.call(this);
|
|
this._children = Polymer.TreeApi.arrayCopyChildNodes(this.root);
|
|
}
|
|
this._insertChildren();
|
|
this.fire('dom-change');
|
|
}
|
|
});</script>
|