Index: polymer_1.2.3/bower_components/polymer/polymer.html |
diff --git a/polymer_1.0.4/bower_components/polymer/polymer.html b/polymer_1.2.3/bower_components/polymer/polymer.html |
similarity index 64% |
copy from polymer_1.0.4/bower_components/polymer/polymer.html |
copy to polymer_1.2.3/bower_components/polymer/polymer.html |
index 9d59e33d25954a42b32dc7e8aff5b71bdfed8fe3..8caf5ed230849ddd0f44864ba0ba1cd448bec0c9 100644 |
--- a/polymer_1.0.4/bower_components/polymer/polymer.html |
+++ b/polymer_1.2.3/bower_components/polymer/polymer.html |
@@ -21,40 +21,87 @@ Polymer.Annotations = { |
parseAnnotations: function (template) { |
var list = []; |
var content = template._content || template.content; |
-this._parseNodeAnnotations(content, list); |
+this._parseNodeAnnotations(content, list, template.hasAttribute('strip-whitespace')); |
return list; |
}, |
-_parseNodeAnnotations: function (node, list) { |
-return node.nodeType === Node.TEXT_NODE ? this._parseTextNodeAnnotation(node, list) : this._parseElementAnnotations(node, list); |
+_parseNodeAnnotations: function (node, list, stripWhiteSpace) { |
+return node.nodeType === Node.TEXT_NODE ? this._parseTextNodeAnnotation(node, list) : this._parseElementAnnotations(node, list, stripWhiteSpace); |
}, |
-_testEscape: function (value) { |
-var escape = value.slice(0, 2); |
-if (escape === '{{' || escape === '[[') { |
-return escape; |
+_bindingRegex: /([^{[]*)(\{\{|\[\[)(?!\}\}|\]\])(.+?)(?:\]\]|\}\})/g, |
+_parseBindings: function (text) { |
+var re = this._bindingRegex; |
+var parts = []; |
+var m, lastIndex; |
+while ((m = re.exec(text)) !== null) { |
+if (m[1]) { |
+parts.push({ literal: m[1] }); |
+} |
+var mode = m[2][0]; |
+var value = m[3].trim(); |
+var negate = false; |
+if (value[0] == '!') { |
+negate = true; |
+value = value.substring(1).trim(); |
+} |
+var customEvent, notifyEvent, colon; |
+if (mode == '{' && (colon = value.indexOf('::')) > 0) { |
+notifyEvent = value.substring(colon + 2); |
+value = value.substring(0, colon); |
+customEvent = true; |
+} |
+parts.push({ |
+compoundIndex: parts.length, |
+value: value, |
+mode: mode, |
+negate: negate, |
+event: notifyEvent, |
+customEvent: customEvent |
+}); |
+lastIndex = re.lastIndex; |
+} |
+if (lastIndex && lastIndex < text.length) { |
+var literal = text.substring(lastIndex); |
+if (literal) { |
+parts.push({ literal: literal }); |
} |
+} |
+if (parts.length) { |
+return parts; |
+} |
+}, |
+_literalFromParts: function (parts) { |
+var s = ''; |
+for (var i = 0; i < parts.length; i++) { |
+var literal = parts[i].literal; |
+s += literal || ''; |
+} |
+return s; |
}, |
_parseTextNodeAnnotation: function (node, list) { |
-var v = node.textContent; |
-var escape = this._testEscape(v); |
-if (escape) { |
-node.textContent = ' '; |
+var parts = this._parseBindings(node.textContent); |
+if (parts) { |
+node.textContent = this._literalFromParts(parts) || ' '; |
var annote = { |
bindings: [{ |
kind: 'text', |
-mode: escape[0], |
-value: v.slice(2, -2).trim() |
+name: 'textContent', |
+parts: parts, |
+isCompound: parts.length !== 1 |
}] |
}; |
list.push(annote); |
return annote; |
} |
}, |
-_parseElementAnnotations: function (element, list) { |
+_parseElementAnnotations: function (element, list, stripWhiteSpace) { |
var annote = { |
bindings: [], |
events: [] |
}; |
-this._parseChildNodesAnnotations(element, annote, list); |
+if (element.localName === 'content') { |
+list._hasContent = true; |
+} |
+this._parseChildNodesAnnotations(element, annote, list, stripWhiteSpace); |
if (element.attributes) { |
this._parseNodeAttributeAnnotations(element, annote, list); |
if (this.prepElement) { |
@@ -66,18 +113,38 @@ list.push(annote); |
} |
return annote; |
}, |
-_parseChildNodesAnnotations: function (root, annote, list, callback) { |
+_parseChildNodesAnnotations: function (root, annote, list, stripWhiteSpace) { |
if (root.firstChild) { |
-for (var i = 0, node = root.firstChild; node; node = node.nextSibling, i++) { |
+var node = root.firstChild; |
+var i = 0; |
+while (node) { |
+var next = node.nextSibling; |
if (node.localName === 'template' && !node.hasAttribute('preserve-content')) { |
this._parseTemplate(node, i, list, annote); |
} |
-var childAnnotation = this._parseNodeAnnotations(node, list, callback); |
+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) { |
@@ -93,62 +160,50 @@ index: index |
}); |
}, |
_parseNodeAttributeAnnotations: function (node, annotation) { |
-for (var i = node.attributes.length - 1, a; a = node.attributes[i]; i--) { |
-var n = a.name, v = a.value; |
-if (n === 'id' && !this._testEscape(v)) { |
-annotation.id = v; |
-} else if (n.slice(0, 3) === 'on-') { |
+var attrs = Array.prototype.slice.call(node.attributes); |
+for (var i = attrs.length - 1, a; a = attrs[i]; i--) { |
+var n = a.name; |
+var v = a.value; |
+var b; |
+if (n.slice(0, 3) === 'on-') { |
node.removeAttribute(n); |
annotation.events.push({ |
name: n.slice(3), |
value: v |
}); |
-} else { |
-var b = this._parseNodeAttributeAnnotation(node, n, v); |
-if (b) { |
+} else if (b = this._parseNodeAttributeAnnotation(node, n, v)) { |
annotation.bindings.push(b); |
-} |
+} else if (n === 'id') { |
+annotation.id = v; |
} |
} |
}, |
-_parseNodeAttributeAnnotation: function (node, n, v) { |
-var escape = this._testEscape(v); |
-if (escape) { |
-var customEvent; |
-var name = n; |
-var mode = escape[0]; |
-v = v.slice(2, -2).trim(); |
-var not = false; |
-if (v[0] == '!') { |
-v = v.substring(1); |
-not = true; |
-} |
+_parseNodeAttributeAnnotation: function (node, name, value) { |
+var parts = this._parseBindings(value); |
+if (parts) { |
+var origName = name; |
var kind = 'property'; |
-if (n[n.length - 1] == '$') { |
-name = n.slice(0, -1); |
+if (name[name.length - 1] == '$') { |
+name = name.slice(0, -1); |
kind = 'attribute'; |
} |
-var notifyEvent, colon; |
-if (mode == '{' && (colon = v.indexOf('::')) > 0) { |
-notifyEvent = v.substring(colon + 2); |
-v = v.substring(0, colon); |
-customEvent = true; |
+var literal = this._literalFromParts(parts); |
+if (literal && kind == 'attribute') { |
+node.setAttribute(name, literal); |
} |
-if (node.localName == 'input' && n == 'value') { |
-node.setAttribute(n, ''); |
+if (node.localName == 'input' && name == 'value') { |
+node.setAttribute(origName, ''); |
} |
-node.removeAttribute(n); |
+node.removeAttribute(origName); |
if (kind === 'property') { |
name = Polymer.CaseMap.dashToCamelCase(name); |
} |
return { |
kind: kind, |
-mode: mode, |
name: name, |
-value: v, |
-negate: not, |
-event: notifyEvent, |
-customEvent: customEvent |
+parts: parts, |
+literal: literal, |
+isCompound: parts.length !== 1 |
}; |
} |
}, |
@@ -224,8 +279,15 @@ _prepAnnotations: function () { |
if (!this._template) { |
this._notes = []; |
} else { |
-Polymer.Annotations.prepElement = this._prepElement.bind(this); |
+var self = this; |
+Polymer.Annotations.prepElement = function (element) { |
+self._prepElement(element); |
+}; |
+if (this._template._content && this._template._content._notes) { |
+this._notes = this._template._content._notes; |
+} else { |
this._notes = Polymer.Annotations.parseAnnotations(this._template); |
+} |
this._processAnnotations(this._notes); |
Polymer.Annotations.prepElement = null; |
} |
@@ -235,9 +297,14 @@ for (var i = 0; i < notes.length; i++) { |
var note = notes[i]; |
for (var j = 0; j < note.bindings.length; j++) { |
var b = note.bindings[j]; |
-b.signature = this._parseMethod(b.value); |
-if (!b.signature) { |
-b.model = this._modelForPath(b.value); |
+for (var k = 0; k < b.parts.length; k++) { |
+var p = b.parts[k]; |
+if (!p.literal) { |
+p.signature = this._parseMethod(p.value); |
+if (!p.signature) { |
+p.model = this._modelForPath(p.value); |
+} |
+} |
} |
} |
if (note.templateContent) { |
@@ -248,10 +315,12 @@ for (var prop in pp) { |
bindings.push({ |
index: note.index, |
kind: 'property', |
-mode: '{', |
name: '_parent_' + prop, |
+parts: [{ |
+mode: '{', |
model: prop, |
value: prop |
+}] |
}); |
} |
note.bindings = note.bindings.concat(bindings); |
@@ -260,22 +329,24 @@ note.bindings = note.bindings.concat(bindings); |
}, |
_discoverTemplateParentProps: function (notes) { |
var pp = {}; |
-notes.forEach(function (n) { |
-n.bindings.forEach(function (b) { |
-if (b.signature) { |
-var args = b.signature.args; |
-for (var k = 0; k < args.length; k++) { |
-pp[args[k].model] = true; |
+for (var i = 0, n; i < notes.length && (n = notes[i]); i++) { |
+for (var j = 0, b$ = n.bindings, b; j < b$.length && (b = b$[j]); j++) { |
+for (var k = 0, p$ = b.parts, p; k < p$.length && (p = p$[k]); k++) { |
+if (p.signature) { |
+var args = p.signature.args; |
+for (var kk = 0; kk < args.length; kk++) { |
+pp[args[kk].model] = true; |
} |
} else { |
-pp[b.model] = true; |
+pp[p.model] = true; |
+} |
+} |
} |
-}); |
if (n.templateContent) { |
var tpp = n.templateContent._parentProps; |
Polymer.Base.mixin(pp, tpp); |
} |
-}); |
+} |
return pp; |
}, |
_prepElement: function (element) { |
@@ -289,60 +360,98 @@ this._marshalAnnotatedNodes(); |
this._marshalAnnotatedListeners(); |
} |
}, |
-_configureAnnotationReferences: function () { |
-this._configureTemplateContent(); |
+_configureAnnotationReferences: function (config) { |
+var notes = this._notes; |
+var nodes = this._nodes; |
+for (var i = 0; i < notes.length; i++) { |
+var note = notes[i]; |
+var node = nodes[i]; |
+this._configureTemplateContent(note, node); |
+this._configureCompoundBindings(note, node); |
+} |
}, |
-_configureTemplateContent: function () { |
-this._notes.forEach(function (note, i) { |
+_configureTemplateContent: function (note, node) { |
if (note.templateContent) { |
-this._nodes[i]._content = note.templateContent; |
+node._content = note.templateContent; |
+} |
+}, |
+_configureCompoundBindings: function (note, node) { |
+var bindings = note.bindings; |
+for (var i = 0; i < bindings.length; i++) { |
+var binding = bindings[i]; |
+if (binding.isCompound) { |
+var storage = node.__compoundStorage__ || (node.__compoundStorage__ = {}); |
+var parts = binding.parts; |
+var literals = new Array(parts.length); |
+for (var j = 0; j < parts.length; j++) { |
+literals[j] = parts[j].literal; |
+} |
+var name = binding.name; |
+storage[name] = literals; |
+if (binding.literal && binding.kind == 'property') { |
+if (node._configValue) { |
+node._configValue(name, binding.literal); |
+} else { |
+node[name] = binding.literal; |
+} |
+} |
+} |
} |
-}, this); |
}, |
_marshalIdNodes: function () { |
this.$ = {}; |
-this._notes.forEach(function (a) { |
+for (var i = 0, l = this._notes.length, a; i < l && (a = this._notes[i]); i++) { |
if (a.id) { |
this.$[a.id] = this._findAnnotatedNode(this.root, a); |
} |
-}, this); |
+} |
}, |
_marshalAnnotatedNodes: function () { |
-if (this._nodes) { |
-this._nodes = this._nodes.map(function (a) { |
-return this._findAnnotatedNode(this.root, a); |
-}, this); |
+if (this._notes && this._notes.length) { |
+var r = new Array(this._notes.length); |
+for (var i = 0; i < this._notes.length; i++) { |
+r[i] = this._findAnnotatedNode(this.root, this._notes[i]); |
+} |
+this._nodes = r; |
} |
}, |
_marshalAnnotatedListeners: function () { |
-this._notes.forEach(function (a) { |
+for (var i = 0, l = this._notes.length, a; i < l && (a = this._notes[i]); i++) { |
if (a.events && a.events.length) { |
var node = this._findAnnotatedNode(this.root, a); |
-a.events.forEach(function (e) { |
+for (var j = 0, e$ = a.events, e; j < e$.length && (e = e$[j]); j++) { |
this.listen(node, e.name, e.value); |
-}, this); |
} |
-}, this); |
+} |
+} |
} |
}); |
Polymer.Base._addFeature({ |
listeners: {}, |
_listenListeners: function (listeners) { |
-var node, name, key; |
-for (key in listeners) { |
-if (key.indexOf('.') < 0) { |
+var node, name, eventName; |
+for (eventName in listeners) { |
+if (eventName.indexOf('.') < 0) { |
node = this; |
-name = key; |
+name = eventName; |
} else { |
-name = key.split('.'); |
+name = eventName.split('.'); |
node = this.$[name[0]]; |
name = name[1]; |
} |
-this.listen(node, name, listeners[key]); |
+this.listen(node, name, listeners[eventName]); |
} |
}, |
listen: function (node, eventName, methodName) { |
-this._listen(node, eventName, this._createEventHandler(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; |
@@ -381,6 +490,7 @@ host[methodName](e, e.detail); |
host._warn(host._logf('_createEventHandler', 'listener method `' + methodName + '` not defined')); |
} |
}; |
+handler._listening = false; |
this._recordEventHandler(host, eventName, node, methodName, handler); |
return handler; |
}, |
@@ -388,6 +498,7 @@ 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) { |
@@ -399,6 +510,7 @@ node.removeEventListener(eventName, handler); |
}); |
(function () { |
'use strict'; |
+var wrap = Polymer.DomApi.wrap; |
var HAS_NATIVE_TA = typeof document.head.style.touchAction === 'string'; |
var GESTURE_KEY = '__polymerGestures'; |
var HANDLED_OBJ = '__polymerGesturesHandled'; |
@@ -413,6 +525,20 @@ var MOUSE_EVENTS = [ |
'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') { |
@@ -437,6 +563,9 @@ document.removeEventListener(en, mouseCanceller, true); |
} |
} |
function ignoreMouse() { |
+if (IS_TOUCH_ONLY) { |
+return; |
+} |
if (!POINTERSTATE.mouse.mouseIgnoreJob) { |
setupTeardownMouseCanceller(true); |
} |
@@ -447,6 +576,34 @@ 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, |
@@ -471,6 +628,16 @@ 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); |
+} |
var Gestures = { |
gestures: {}, |
recognizers: [], |
@@ -485,11 +652,20 @@ 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 = ev.currentTarget; |
+var node = wrap(ev.currentTarget); |
var gobj = node[GESTURE_KEY]; |
+if (!gobj) { |
+return; |
+} |
var gs = gobj[type]; |
if (!gs) { |
return; |
@@ -525,6 +701,16 @@ 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) { |
+if (r.reset) { |
+r.reset(); |
+} |
+} |
+} |
+} |
+for (var i = 0, r; i < recognizers.length; i++) { |
+r = recognizers[i]; |
+if (gs[r.name] && !handled[r.name]) { |
handled[r.name] = true; |
r[type](ev); |
} |
@@ -556,10 +742,13 @@ 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; |
@@ -569,12 +758,18 @@ 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 = {}; |
+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) { |
@@ -582,6 +777,7 @@ this.setTouchAction(node, recognizer.touchAction); |
} |
}, |
remove: function (node, evType, handler) { |
+node = wrap(node); |
var recognizer = this.gestures[evType]; |
var deps = recognizer.deps; |
var name = recognizer.name; |
@@ -592,7 +788,8 @@ dep = deps[i]; |
gd = gobj[dep]; |
if (gd && gd[name]) { |
gd[name] = (gd[name] || 1) - 1; |
-if (gd[name] === 0) { |
+gd._count = (gd._count || 1) - 1; |
+if (gd._count === 0) { |
node.removeEventListener(dep, this.handleNative); |
} |
} |
@@ -651,25 +848,55 @@ deps: [ |
'touchstart', |
'touchend' |
], |
+flow: { |
+start: [ |
+'mousedown', |
+'touchstart' |
+], |
+end: [ |
+'mouseup', |
+'touchend' |
+] |
+}, |
emits: [ |
'down', |
'up' |
], |
+info: { |
+movefn: function () { |
+}, |
+upfn: function () { |
+} |
+}, |
+reset: function () { |
+untrackDocument(this.info); |
+}, |
mousedown: function (e) { |
-var t = e.currentTarget; |
+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); |
-document.removeEventListener('mouseup', upfn); |
+} |
+untrackDocument(self.info); |
}; |
-document.addEventListener('mouseup', upfn); |
+trackDocument(this.info, movefn, upfn); |
this.fire('down', t, e); |
}, |
touchstart: function (e) { |
-this.fire('down', e.currentTarget, e.changedTouches[0]); |
+this.fire('down', Gestures.findOriginalTarget(e), e.changedTouches[0]); |
}, |
touchend: function (e) { |
-this.fire('up', e.currentTarget, e.changedTouches[0]); |
+this.fire('up', Gestures.findOriginalTarget(e), e.changedTouches[0]); |
}, |
fire: function (type, target, event) { |
var self = this; |
@@ -677,7 +904,9 @@ Gestures.fire(target, type, { |
x: event.clientX, |
y: event.clientY, |
sourceEvent: event, |
-prevent: Gestures.prevent.bind(Gestures) |
+prevent: function (e) { |
+return Gestures.prevent(e); |
+} |
}); |
} |
}); |
@@ -690,6 +919,16 @@ deps: [ |
'touchmove', |
'touchend' |
], |
+flow: { |
+start: [ |
+'mousedown', |
+'touchstart' |
+], |
+end: [ |
+'mouseup', |
+'touchend' |
+] |
+}, |
emits: ['track'], |
info: { |
x: 0, |
@@ -703,15 +942,20 @@ this.moves.shift(); |
} |
this.moves.push(move); |
}, |
+movefn: function () { |
+}, |
+upfn: function () { |
+}, |
prevent: false |
}, |
-clearInfo: function () { |
+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) { |
@@ -725,7 +969,10 @@ var dy = Math.abs(this.info.y - y); |
return dx >= TRACK_DISTANCE || dy >= TRACK_DISTANCE; |
}, |
mousedown: function (e) { |
-var t = e.currentTarget; |
+if (!hasLeftMouseButton(e)) { |
+return; |
+} |
+var t = Gestures.findOriginalTarget(e); |
var self = this; |
var movefn = function movefn(e) { |
var x = e.clientX, y = e.clientY; |
@@ -735,6 +982,10 @@ 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; |
} |
@@ -744,12 +995,9 @@ if (self.info.started) { |
Gestures.prevent('tap'); |
movefn(e); |
} |
-self.clearInfo(); |
-document.removeEventListener('mousemove', movefn); |
-document.removeEventListener('mouseup', upfn); |
+untrackDocument(self.info); |
}; |
-document.addEventListener('mousemove', movefn); |
-document.addEventListener('mouseup', upfn); |
+trackDocument(this.info, movefn, upfn); |
this.info.x = e.clientX; |
this.info.y = e.clientY; |
}, |
@@ -759,7 +1007,7 @@ this.info.x = ct.clientX; |
this.info.y = ct.clientY; |
}, |
touchmove: function (e) { |
-var t = e.currentTarget; |
+var t = Gestures.findOriginalTarget(e); |
var ct = e.changedTouches[0]; |
var x = ct.clientX, y = ct.clientY; |
if (this.hasMovedEnough(x, y)) { |
@@ -773,7 +1021,7 @@ this.info.started = true; |
} |
}, |
touchend: function (e) { |
-var t = e.currentTarget; |
+var t = Gestures.findOriginalTarget(e); |
var ct = e.changedTouches[0]; |
if (this.info.started) { |
Gestures.prevent('tap'); |
@@ -784,7 +1032,6 @@ y: ct.clientY |
}); |
this.fire(t, ct); |
} |
-this.clearInfo(); |
}, |
fire: function (target, touch) { |
var secondlast = this.info.moves[this.info.moves.length - 2]; |
@@ -819,6 +1066,16 @@ deps: [ |
'touchstart', |
'touchend' |
], |
+flow: { |
+start: [ |
+'mousedown', |
+'touchstart' |
+], |
+end: [ |
+'click', |
+'touchend' |
+] |
+}, |
emits: ['tap'], |
info: { |
x: NaN, |
@@ -835,10 +1092,14 @@ 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]); |
@@ -849,16 +1110,16 @@ 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); |
-if (isNaN(dx) || isNaN(dy) || dx <= TAP_DISTANCE && dy <= TAP_DISTANCE) { |
+var t = Gestures.findOriginalTarget(e); |
+if (isNaN(dx) || isNaN(dy) || dx <= TAP_DISTANCE && dy <= TAP_DISTANCE || isSyntheticClick(e)) { |
if (!this.info.prevent) { |
-Gestures.fire(e.target, 'tap', { |
+Gestures.fire(t, 'tap', { |
x: e.clientX, |
y: e.clientY, |
sourceEvent: e |
}); |
} |
} |
-this.reset(); |
} |
}); |
var DIRECTION_MAP = { |
@@ -889,55 +1150,65 @@ Gestures.setTouchAction(node, DIRECTION_MAP[direction] || 'auto'); |
}); |
Polymer.Gestures = Gestures; |
}()); |
-Polymer.Async = function () { |
-var currVal = 0; |
-var lastVal = 0; |
-var callbacks = []; |
-var twiddle = document.createTextNode(''); |
-function runAsync(callback, waitTime) { |
+Polymer.Async = { |
+_currVal: 0, |
+_lastVal: 0, |
+_callbacks: [], |
+_twiddleContent: 0, |
+_twiddle: document.createTextNode(''), |
+run: function (callback, waitTime) { |
if (waitTime > 0) { |
return ~setTimeout(callback, waitTime); |
} else { |
-twiddle.textContent = currVal++; |
-callbacks.push(callback); |
-return currVal - 1; |
-} |
+this._twiddle.textContent = this._twiddleContent++; |
+this._callbacks.push(callback); |
+return this._currVal++; |
} |
-function cancelAsync(handle) { |
+}, |
+cancel: function (handle) { |
if (handle < 0) { |
clearTimeout(~handle); |
} else { |
-var idx = handle - lastVal; |
+var idx = handle - this._lastVal; |
if (idx >= 0) { |
-if (!callbacks[idx]) { |
+if (!this._callbacks[idx]) { |
throw 'invalid async handle: ' + handle; |
} |
-callbacks[idx] = null; |
-} |
+this._callbacks[idx] = null; |
} |
} |
-function atEndOfMicrotask() { |
-var len = callbacks.length; |
+}, |
+_atEndOfMicrotask: function () { |
+var len = this._callbacks.length; |
for (var i = 0; i < len; i++) { |
-var cb = callbacks[i]; |
+var cb = this._callbacks[i]; |
if (cb) { |
+try { |
cb(); |
+} catch (e) { |
+i++; |
+this._callbacks.splice(0, i); |
+this._lastVal += i; |
+this._twiddle.textContent = this._twiddleContent++; |
+throw e; |
} |
} |
-callbacks.splice(0, len); |
-lastVal += len; |
} |
-new (window.MutationObserver || JsMutationObserver)(atEndOfMicrotask).observe(twiddle, { characterData: true }); |
-return { |
-run: runAsync, |
-cancel: cancelAsync |
+this._callbacks.splice(0, len); |
+this._lastVal += len; |
+} |
}; |
-}(); |
+new window.MutationObserver(function () { |
+Polymer.Async._atEndOfMicrotask(); |
+}).observe(Polymer.Async._twiddle, { characterData: true }); |
Polymer.Debounce = function () { |
var Async = Polymer.Async; |
var Debouncer = function (context) { |
this.context = context; |
-this.boundComplete = this.complete.bind(this); |
+var self = this; |
+this.boundComplete = function () { |
+self.complete(); |
+}; |
}; |
Debouncer.prototype = { |
go: function (callback, wait) { |
@@ -1014,8 +1285,35 @@ 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) { |
-return Polymer.dom(Polymer.dom(this.root).querySelector(slctr || 'content')).getDistributedNodes(); |
+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) { |
@@ -1025,19 +1323,37 @@ return n.nodeType === Node.ELEMENT_NODE; |
fire: function (type, detail, options) { |
options = options || Polymer.nob; |
var node = options.node || this; |
-var detail = detail === null || detail === undefined ? Polymer.nob : detail; |
+var detail = detail === null || detail === undefined ? {} : detail; |
var bubbles = options.bubbles === undefined ? true : options.bubbles; |
var cancelable = Boolean(options.cancelable); |
-var event = new CustomEvent(type, { |
+var useCache = options._useCache; |
+var event = this._getEvent(type, bubbles, cancelable, useCache); |
+event.detail = detail; |
+if (useCache) { |
+this.__eventCache[type] = null; |
+} |
+node.dispatchEvent(event); |
+if (useCache) { |
+this.__eventCache[type] = event; |
+} |
+return event; |
+}, |
+__eventCache: {}, |
+_getEvent: function (type, bubbles, cancelable, useCache) { |
+var event = useCache && this.__eventCache[type]; |
+if (!event || (event.bubbles != bubbles || event.cancelable != cancelable)) { |
+event = new Event(type, { |
bubbles: Boolean(bubbles), |
-cancelable: cancelable, |
-detail: detail |
+cancelable: cancelable |
}); |
-node.dispatchEvent(event); |
+} |
return event; |
}, |
async: function (callback, waitTime) { |
-return Polymer.Async.run(callback.bind(this), waitTime); |
+var self = this; |
+return Polymer.Async.run(function () { |
+callback.call(self); |
+}, waitTime); |
}, |
cancelAsync: function (handle) { |
Polymer.Async.cancel(handle); |
@@ -1050,7 +1366,7 @@ if (index >= 0) { |
return path.splice(index, 1); |
} |
} else { |
-var arr = this.get(path); |
+var arr = this._get(path); |
index = arr.indexOf(item); |
if (index >= 0) { |
return this.splice(path, index, 1); |
@@ -1070,11 +1386,16 @@ importHref: function (href, onload, onerror) { |
var l = document.createElement('link'); |
l.rel = 'import'; |
l.href = href; |
+var self = this; |
if (onload) { |
-l.onload = onload.bind(this); |
+l.onload = function (e) { |
+return onload.call(self, e); |
+}; |
} |
if (onerror) { |
-l.onerror = onerror.bind(this); |
+l.onerror = function (e) { |
+return onerror.call(self, e); |
+}; |
} |
document.head.appendChild(l); |
return l; |
@@ -1088,27 +1409,29 @@ elt[n] = props[n]; |
} |
return elt; |
}, |
-mixin: function (target, source) { |
-for (var i in source) { |
-target[i] = source[i]; |
-} |
+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) { |
-model._propertyEffects = {}; |
-model._bindListeners = []; |
-var api = this._modelApi; |
-for (var n in api) { |
-model[n] = api[n]; |
-} |
+Polymer.Base.mixin(model, this._modelApi); |
}, |
_modelApi: { |
-_notifyChange: function (property) { |
-var eventName = Polymer.CaseMap.camelToDashCase(property) + '-changed'; |
-this.fire(eventName, { value: this[property] }, { bubbles: false }); |
+_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 |
+}); |
}, |
-_propertySet: function (property, value, effects) { |
+_propertySetter: function (property, value, effects, fromAbove) { |
var old = this.__data__[property]; |
if (old !== value && (old === old || value === value)) { |
this.__data__[property] = value; |
@@ -1119,18 +1442,24 @@ if (this._propertyChanged) { |
this._propertyChanged(property, value, old); |
} |
if (effects) { |
-this._effectEffects(property, value, effects, old); |
+this._effectEffects(property, value, effects, old, fromAbove); |
} |
} |
return old; |
}, |
-_effectEffects: function (property, value, effects, old) { |
-effects.forEach(function (fx) { |
-var fn = Polymer.Bind['_' + fx.kind + 'Effect']; |
-if (fn) { |
-fn.call(this, property, value, fx.effect, 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); |
} |
-}, this); |
}, |
_clearPath: function (path) { |
for (var prop in this.__data__) { |
@@ -1141,6 +1470,9 @@ this.__data__[prop] = undefined; |
} |
}, |
ensurePropertyEffects: function (model, property) { |
+if (!model._propertyEffects) { |
+model._propertyEffects = {}; |
+} |
var fx = model._propertyEffects[property]; |
if (!fx) { |
fx = model._propertyEffects[property] = []; |
@@ -1149,10 +1481,13 @@ return fx; |
}, |
addPropertyEffect: function (model, property, kind, effect) { |
var fx = this.ensurePropertyEffects(model, property); |
-fx.push({ |
+var propEffect = { |
kind: kind, |
-effect: effect |
-}); |
+effect: effect, |
+fn: Polymer.Bind['_' + kind + 'Effect'] |
+}; |
+fx.push(propEffect); |
+return propEffect; |
}, |
createBindings: function (model) { |
var fx$ = model._propertyEffects; |
@@ -1186,10 +1521,13 @@ return this.__data__[property]; |
} |
}; |
var setter = function (value) { |
-this._propertySet(property, value, effects); |
+this._propertySetter(property, value, effects); |
}; |
-if (model.getPropertyInfo && model.getPropertyInfo(property).readOnly) { |
+var info = model.getPropertyInfo && model.getPropertyInfo(property); |
+if (info && info.readOnly) { |
+if (!info.computed) { |
model['_set' + this.upper(property)] = setter; |
+} |
} else { |
defun.set = setter; |
} |
@@ -1199,7 +1537,10 @@ upper: function (name) { |
return name[0].toUpperCase() + name.substring(1); |
}, |
_addAnnotatedListener: function (model, index, property, path, event) { |
-var fn = this._notedListenerFactory(property, path, this._isStructured(path), this._isEventBogus); |
+if (!model._bindListeners) { |
+model._bindListeners = []; |
+} |
+var fn = this._notedListenerFactory(property, path, this._isStructured(path)); |
var eventName = event || Polymer.CaseMap.camelToDashCase(property) + '-changed'; |
model._bindListeners.push({ |
index: index, |
@@ -1215,56 +1556,63 @@ return path.indexOf('.') > 0; |
_isEventBogus: function (e, target) { |
return e.path && e.path[0] !== target; |
}, |
-_notedListenerFactory: function (property, path, isStructured, bogusTest) { |
-return function (e, target) { |
-if (!bogusTest(e, target)) { |
-if (e.detail && e.detail.path) { |
-this.notifyPath(this._fixPath(path, property, e.detail.path), e.detail.value); |
+_notedListenerFactory: function (property, path, isStructured) { |
+return function (target, value, targetPath) { |
+if (targetPath) { |
+this._notifyPath(this._fixPath(path, property, targetPath), value); |
} else { |
-var value = target[property]; |
+value = target[property]; |
if (!isStructured) { |
-this[path] = target[property]; |
+this[path] = value; |
} else { |
if (this.__data__[path] != value) { |
this.set(path, value); |
} |
} |
} |
-} |
}; |
}, |
prepareInstance: function (inst) { |
inst.__data__ = Object.create(null); |
}, |
setupBindListeners: function (inst) { |
-inst._bindListeners.forEach(function (info) { |
+var b$ = inst._bindListeners; |
+for (var i = 0, l = b$.length, info; i < l && (info = b$[i]); i++) { |
var node = inst._nodes[info.index]; |
-node.addEventListener(info.event, inst._notifyListener.bind(inst, info.changedFn)); |
+this._addNotifyListener(node, inst, info.event, info.changedFn); |
+} |
+; |
+}, |
+_addNotifyListener: function (element, context, event, changedFn) { |
+element.addEventListener(event, function (e) { |
+return context._notifyListener(changedFn, e); |
}); |
} |
}; |
Polymer.Base.extend(Polymer.Bind, { |
_shouldAddListener: function (effect) { |
-return effect.name && effect.mode === '{' && !effect.negate && effect.kind != 'attribute'; |
+return effect.name && effect.kind != 'attribute' && effect.kind != 'text' && !effect.isCompound && effect.parts[0].mode === '{' && !effect.parts[0].negate; |
}, |
_annotationEffect: function (source, value, effect) { |
if (source != effect.value) { |
-value = this.get(effect.value); |
+value = this._get(effect.value); |
this.__data__[effect.value] = value; |
} |
var calc = effect.negate ? !value : value; |
if (!effect.customEvent || this._nodes[effect.index][effect.name] !== calc) { |
-return this._applyEffectValue(calc, effect); |
+return this._applyEffectValue(effect, calc); |
} |
}, |
-_reflectEffect: function (source) { |
-this.reflectPropertyToAttribute(source); |
+_reflectEffect: function (source, value, effect) { |
+this.reflectPropertyToAttribute(source, effect.attribute, value); |
}, |
-_notifyEffect: function (source) { |
-this._notifyChange(source); |
+_notifyEffect: function (source, value, effect, old, fromAbove) { |
+if (!fromAbove) { |
+this._notifyChange(source, effect.event, value); |
+} |
}, |
-_functionEffect: function (source, value, fn, old) { |
-fn.call(this, source, value, old); |
+_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]; |
@@ -1290,7 +1638,7 @@ var args = Polymer.Bind._marshalArgs(this.__data__, effect, source, value); |
if (args) { |
var fn = this[effect.method]; |
if (fn) { |
-this[effect.property] = fn.apply(this, args); |
+this.__setProperty(effect.name, fn.apply(this, args)); |
} else { |
this._warn(this._logf('_computeEffect', 'compute method `' + effect.method + '` not defined')); |
} |
@@ -1306,7 +1654,7 @@ var computedvalue = fn.apply(computedHost, args); |
if (effect.negate) { |
computedvalue = !computedvalue; |
} |
-this._applyEffectValue(computedvalue, effect); |
+this._applyEffectValue(effect, computedvalue); |
} |
} else { |
computedHost._warn(computedHost._logf('_annotatedComputationEffect', 'compute method `' + effect.method + '` not defined')); |
@@ -1322,7 +1670,7 @@ var v; |
if (arg.literal) { |
v = arg.value; |
} else if (arg.structured) { |
-v = Polymer.Base.get(name, model); |
+v = Polymer.Base._get(name, model); |
} else { |
v = model[name]; |
} |
@@ -1346,7 +1694,8 @@ return values; |
}); |
Polymer.Base._addFeature({ |
_addPropertyEffect: function (property, kind, effect) { |
-Polymer.Bind.addPropertyEffect(this, property, kind, effect); |
+var prop = Polymer.Bind.addPropertyEffect(this, property, kind, effect); |
+prop.pathFn = this['_' + prop.kind + 'PathEffect']; |
}, |
_prepEffects: function () { |
Polymer.Bind.prepareModel(this); |
@@ -1363,13 +1712,14 @@ 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'); |
+this._addPropertyEffect(p, 'notify', { event: Polymer.CaseMap.camelToDashCase(p) + '-changed' }); |
} |
if (prop.reflectToAttribute) { |
-this._addPropertyEffect(p, 'reflect'); |
+this._addPropertyEffect(p, 'reflect', { attribute: Polymer.CaseMap.camelToDashCase(p) }); |
} |
if (prop.readOnly) { |
Polymer.Bind.ensurePropertyEffects(this, p); |
@@ -1379,14 +1729,14 @@ Polymer.Bind.ensurePropertyEffects(this, p); |
}, |
_addComputedEffect: function (name, expression) { |
var sig = this._parseMethod(expression); |
-sig.args.forEach(function (arg) { |
+for (var i = 0, arg; i < sig.args.length && (arg = sig.args[i]); i++) { |
this._addPropertyEffect(arg.model, 'compute', { |
method: sig.method, |
args: sig.args, |
trigger: arg, |
-property: name |
+name: name |
}); |
-}, this); |
+} |
}, |
_addObserverEffect: function (property, observer) { |
this._addPropertyEffect(property, 'observer', { |
@@ -1396,66 +1746,79 @@ property: property |
}, |
_addComplexObserverEffects: function (observers) { |
if (observers) { |
-observers.forEach(function (observer) { |
-this._addComplexObserverEffect(observer); |
-}, this); |
+for (var i = 0, o; i < observers.length && (o = observers[i]); i++) { |
+this._addComplexObserverEffect(o); |
+} |
} |
}, |
_addComplexObserverEffect: function (observer) { |
var sig = this._parseMethod(observer); |
-sig.args.forEach(function (arg) { |
+for (var i = 0, arg; i < sig.args.length && (arg = sig.args[i]); i++) { |
this._addPropertyEffect(arg.model, 'complexObserver', { |
method: sig.method, |
args: sig.args, |
trigger: arg |
}); |
-}, this); |
+} |
}, |
_addAnnotationEffects: function (notes) { |
-this._nodes = []; |
-notes.forEach(function (note) { |
-var index = this._nodes.push(note) - 1; |
-note.bindings.forEach(function (binding) { |
-this._addAnnotationEffect(binding, index); |
-}, this); |
-}, this); |
+for (var i = 0, note; i < notes.length && (note = notes[i]); i++) { |
+var b$ = note.bindings; |
+for (var j = 0, binding; j < b$.length && (binding = b$[j]); j++) { |
+this._addAnnotationEffect(binding, i); |
+} |
+} |
}, |
_addAnnotationEffect: function (note, index) { |
if (Polymer.Bind._shouldAddListener(note)) { |
-Polymer.Bind._addAnnotatedListener(this, index, note.name, note.value, note.event); |
+Polymer.Bind._addAnnotatedListener(this, index, note.name, note.parts[0].value, note.parts[0].event); |
+} |
+for (var i = 0; i < note.parts.length; i++) { |
+var part = note.parts[i]; |
+if (part.signature) { |
+this._addAnnotatedComputationEffect(note, part, index); |
+} else if (!part.literal) { |
+this._addPropertyEffect(part.model, 'annotation', { |
+kind: note.kind, |
+index: index, |
+name: note.name, |
+value: part.value, |
+isCompound: note.isCompound, |
+compoundIndex: part.compoundIndex, |
+event: part.event, |
+customEvent: part.customEvent, |
+negate: part.negate |
+}); |
} |
-if (note.signature) { |
-this._addAnnotatedComputationEffect(note, index); |
-} else { |
-note.index = index; |
-this._addPropertyEffect(note.model, 'annotation', note); |
} |
}, |
-_addAnnotatedComputationEffect: function (note, index) { |
-var sig = note.signature; |
+_addAnnotatedComputationEffect: function (note, part, index) { |
+var sig = part.signature; |
if (sig.static) { |
-this.__addAnnotatedComputationEffect('__static__', index, note, sig, null); |
+this.__addAnnotatedComputationEffect('__static__', index, note, part, null); |
} else { |
-sig.args.forEach(function (arg) { |
+for (var i = 0, arg; i < sig.args.length && (arg = sig.args[i]); i++) { |
if (!arg.literal) { |
-this.__addAnnotatedComputationEffect(arg.model, index, note, sig, arg); |
+this.__addAnnotatedComputationEffect(arg.model, index, note, part, arg); |
+} |
} |
-}, this); |
} |
}, |
-__addAnnotatedComputationEffect: function (property, index, note, sig, trigger) { |
+__addAnnotatedComputationEffect: function (property, index, note, part, trigger) { |
this._addPropertyEffect(property, 'annotatedComputation', { |
index: index, |
+isCompound: note.isCompound, |
+compoundIndex: part.compoundIndex, |
kind: note.kind, |
-property: note.name, |
-negate: note.negate, |
-method: sig.method, |
-args: sig.args, |
+name: note.name, |
+negate: part.negate, |
+method: part.signature.method, |
+args: part.signature.args, |
trigger: trigger |
}); |
}, |
_parseMethod: function (expression) { |
-var m = expression.match(/(\w*)\((.*)\)/); |
+var m = expression.match(/([^\s]+)\((.*)\)/); |
if (m) { |
var sig = { |
method: m[1], |
@@ -1487,6 +1850,9 @@ name: arg, |
model: this._modelForPath(arg) |
}; |
var fc = arg[0]; |
+if (fc === '-') { |
+fc = arg[1]; |
+} |
if (fc >= '0' && fc <= '9') { |
fc = '#'; |
} |
@@ -1514,11 +1880,18 @@ return a; |
}, |
_marshalInstanceEffects: function () { |
Polymer.Bind.prepareInstance(this); |
+if (this._bindListeners) { |
Polymer.Bind.setupBindListeners(this); |
+} |
}, |
-_applyEffectValue: function (value, info) { |
+_applyEffectValue: function (info, value) { |
var node = this._nodes[info.index]; |
-var property = info.property || info.name || 'textContent'; |
+var property = info.name; |
+if (info.isCompound) { |
+var storage = node.__compoundStorage__[property]; |
+storage[info.compoundIndex] = value; |
+value = storage.join(''); |
+} |
if (info.kind == 'attribute') { |
this.serializeValueToAttribute(value, property, node); |
} else { |
@@ -1528,39 +1901,59 @@ value = this._scopeElementClass(node, value); |
if (property === 'textContent' || node.localName == 'input' && property == 'value') { |
value = value == undefined ? '' : value; |
} |
-return node[property] = value; |
+var pinfo; |
+if (!node._propertyInfo || !(pinfo = node._propertyInfo[property]) || !pinfo.readOnly) { |
+this.__setProperty(property, value, true, node); |
+} |
} |
}, |
_executeStaticEffects: function () { |
-if (this._propertyEffects.__static__) { |
+if (this._propertyEffects && this._propertyEffects.__static__) { |
this._effectEffects('__static__', null, this._propertyEffects.__static__); |
} |
} |
}); |
Polymer.Base._addFeature({ |
_setupConfigure: function (initialConfig) { |
-this._config = initialConfig || {}; |
+this._config = {}; |
this._handlers = []; |
+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 = {}; |
-this.behaviors.forEach(function (b) { |
-this._configureProperties(b.properties, config); |
-}, this); |
+for (var i = 0; i < this.behaviors.length; i++) { |
+this._configureProperties(this.behaviors[i].properties, config); |
+} |
this._configureProperties(this.properties, config); |
-this._mixinConfigure(config, this._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) { |
@@ -1574,13 +1967,6 @@ config[i] = value; |
} |
} |
}, |
-_mixinConfigure: function (a, b) { |
-for (var prop in b) { |
-if (!this.getPropertyInfo(prop).readOnly) { |
-a[prop] = b[prop]; |
-} |
-} |
-}, |
_distributeConfig: function (config) { |
var fx$ = this._propertyEffects; |
if (fx$) { |
@@ -1588,10 +1974,10 @@ for (var p in config) { |
var fx = fx$[p]; |
if (fx) { |
for (var i = 0, l = fx.length, x; i < l && (x = fx[i]); i++) { |
-if (x.kind === 'annotation') { |
+if (x.kind === 'annotation' && !x.isCompound) { |
var node = this._nodes[x.effect.index]; |
if (node._configValue) { |
-var value = p === x.effect.value ? config[p] : this.get(x.effect.value, config); |
+var value = p === x.effect.value ? config[p] : this._get(x.effect.value, config); |
node._configValue(x.effect.name, value); |
} |
} |
@@ -1602,30 +1988,33 @@ node._configValue(x.effect.name, value); |
}, |
_afterClientsReady: function () { |
this._executeStaticEffects(); |
-this._applyConfig(this._config); |
+this._applyConfig(this._config, this._aboveConfig); |
this._flushHandlers(); |
}, |
-_applyConfig: function (config) { |
+_applyConfig: function (config, aboveConfig) { |
for (var n in config) { |
if (this[n] === undefined) { |
-var effects = this._propertyEffects[n]; |
-if (effects) { |
-this._propertySet(n, config[n], effects); |
-} else { |
-this[n] = config[n]; |
-} |
+this.__setProperty(n, config[n], n in aboveConfig); |
} |
} |
}, |
_notifyListener: function (fn, e) { |
+if (!Polymer.Bind._isEventBogus(e, e.target)) { |
+var value, path; |
+if (e.detail) { |
+value = e.detail.value; |
+path = e.detail.path; |
+} |
if (!this._clientsReadied) { |
this._queueHandler([ |
fn, |
-e, |
-e.target |
+e.target, |
+value, |
+path |
]); |
} else { |
-return fn.call(this, e, e.target); |
+return fn.call(this, e.target, value, path); |
+} |
} |
}, |
_queueHandler: function (args) { |
@@ -1634,20 +2023,27 @@ this._handlers.push(args); |
_flushHandlers: function () { |
var h$ = this._handlers; |
for (var i = 0, l = h$.length, h; i < l && (h = h$[i]); i++) { |
-h[0].call(this, h[1], h[2]); |
+h[0].call(this, h[1], h[2], h[3]); |
} |
+this._handlers = []; |
} |
}); |
(function () { |
'use strict'; |
Polymer.Base._addFeature({ |
notifyPath: function (path, value, fromAbove) { |
-var old = this._propertySet(path, value); |
+var info = {}; |
+this._get(path, this, info); |
+this._notifyPath(info.path, value, fromAbove); |
+}, |
+_notifyPath: function (path, value, fromAbove) { |
+var old = this._propertySetter(path, value); |
if (old !== value && (old === old || value === value)) { |
this._pathEffector(path, value); |
if (!fromAbove) { |
-this._notifyPath(path, value); |
+this._notifyPathUp(path, value); |
} |
+return true; |
} |
}, |
_getPathParts: function (path) { |
@@ -1671,45 +2067,79 @@ var array; |
var last = parts[parts.length - 1]; |
if (parts.length > 1) { |
for (var i = 0; i < parts.length - 1; i++) { |
-prop = prop[parts[i]]; |
-if (array) { |
+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); |
+if (last[0] == '#') { |
+var key = last; |
+var old = coll.getItem(key); |
+last = array.indexOf(old); |
+coll.setItem(key, value); |
+} else if (parseInt(last, 10) == last) { |
+var old = prop[last]; |
+var key = coll.getKey(old); |
+parts[i] = key; |
+coll.setItem(key, value); |
+} |
+} |
prop[last] = value; |
if (!root) { |
-this.notifyPath(parts.join('.'), value); |
+this._notifyPath(parts.join('.'), value); |
} |
} else { |
prop[path] = value; |
} |
}, |
get: function (path, root) { |
+return this._get(path, root); |
+}, |
+_get: function (path, root, info) { |
var prop = root || this; |
var parts = this._getPathParts(path); |
-var last = parts.pop(); |
-while (parts.length) { |
-prop = prop[parts.shift()]; |
+var array; |
+for (var i = 0; i < parts.length; i++) { |
if (!prop) { |
return; |
} |
+var part = parts[i]; |
+if (array && part[0] == '#') { |
+prop = Polymer.Collection.get(array).getItem(part); |
+} else { |
+prop = prop[part]; |
+if (info && array && parseInt(part, 10) == part) { |
+parts[i] = Polymer.Collection.get(array).getKey(prop); |
+} |
+} |
+array = Array.isArray(prop) ? prop : null; |
+} |
+if (info) { |
+info.path = parts.join('.'); |
} |
-return prop[last]; |
+return prop; |
}, |
_pathEffector: function (path, value) { |
var model = this._modelForPath(path); |
-var fx$ = this._propertyEffects[model]; |
+var fx$ = this._propertyEffects && this._propertyEffects[model]; |
if (fx$) { |
-fx$.forEach(function (fx) { |
-var fxFn = this['_' + fx.kind + 'PathEffect']; |
+for (var i = 0, fx; i < fx$.length && (fx = fx$[i]); i++) { |
+var fxFn = fx.pathFn; |
if (fxFn) { |
fxFn.call(this, path, value, fx.effect); |
} |
-}, this); |
+} |
} |
if (this._boundPaths) { |
this._notifyBoundPaths(path, value); |
@@ -1720,9 +2150,9 @@ if (effect.value === path || effect.value.indexOf(path + '.') === 0) { |
Polymer.Bind._annotationEffect.call(this, path, value, effect); |
} else if (path.indexOf(effect.value + '.') === 0 && !effect.negate) { |
var node = this._nodes[effect.index]; |
-if (node && node.notifyPath) { |
+if (node && node._notifyPath) { |
var p = this._fixPath(effect.name, effect.value, path); |
-node.notifyPath(p, value, true); |
+node._notifyPath(p, value, true); |
} |
} |
}, |
@@ -1750,7 +2180,7 @@ this._boundPaths = this._boundPaths || {}; |
if (from) { |
this._boundPaths[to] = from; |
} else { |
-this.unbindPath(to); |
+this.unlinkPaths(to); |
} |
}, |
unlinkPaths: function (path) { |
@@ -1759,98 +2189,148 @@ delete this._boundPaths[path]; |
} |
}, |
_notifyBoundPaths: function (path, value) { |
-var from, to; |
for (var a in this._boundPaths) { |
var b = this._boundPaths[a]; |
if (path.indexOf(a + '.') == 0) { |
-from = a; |
-to = b; |
-break; |
-} |
-if (path.indexOf(b + '.') == 0) { |
-from = b; |
-to = a; |
-break; |
-} |
+this._notifyPath(this._fixPath(b, a, path), value); |
+} else if (path.indexOf(b + '.') == 0) { |
+this._notifyPath(this._fixPath(a, b, path), value); |
} |
-if (from && to) { |
-var p = this._fixPath(to, from, path); |
-this.notifyPath(p, value); |
} |
}, |
_fixPath: function (property, root, path) { |
return property + path.slice(root.length); |
}, |
-_notifyPath: function (path, value) { |
+_notifyPathUp: function (path, value) { |
var rootName = this._modelForPath(path); |
var dashCaseName = Polymer.CaseMap.camelToDashCase(rootName); |
var eventName = dashCaseName + this._EVENT_CHANGED; |
this.fire(eventName, { |
path: path, |
value: value |
-}, { bubbles: false }); |
+}, { |
+bubbles: false, |
+_useCache: true |
+}); |
}, |
_modelForPath: function (path) { |
var dot = path.indexOf('.'); |
return dot < 0 ? path : path.slice(0, dot); |
}, |
_EVENT_CHANGED: '-changed', |
-_notifySplice: function (array, path, index, added, removed) { |
-var splices = [{ |
-index: index, |
-addedCount: added, |
-removed: removed, |
-object: array, |
-type: 'splice' |
-}]; |
+notifySplices: function (path, splices) { |
+var info = {}; |
+var array = this._get(path, this, info); |
+this._notifySplices(array, info.path, splices); |
+}, |
+_notifySplices: function (array, path, splices) { |
var change = { |
keySplices: Polymer.Collection.applySplices(array, splices), |
indexSplices: splices |
}; |
-this.set(path + '.splices', change); |
-if (added != removed.length) { |
-this.notifyPath(path + '.length', array.length); |
+if (!array.hasOwnProperty('splices')) { |
+Object.defineProperty(array, 'splices', { |
+configurable: true, |
+writable: true |
+}); |
} |
+array.splices = change; |
+this._notifyPath(path + '.splices', change); |
+this._notifyPath(path + '.length', array.length); |
change.keySplices = null; |
change.indexSplices = null; |
}, |
+_notifySplice: function (array, path, index, added, removed) { |
+this._notifySplices(array, path, [{ |
+index: index, |
+addedCount: added, |
+removed: removed, |
+object: array, |
+type: 'splice' |
+}]); |
+}, |
push: function (path) { |
-var array = this.get(path); |
+var info = {}; |
+var array = this._get(path, this, info); |
var args = Array.prototype.slice.call(arguments, 1); |
var len = array.length; |
var ret = array.push.apply(array, args); |
-this._notifySplice(array, path, len, args.length, []); |
+if (args.length) { |
+this._notifySplice(array, info.path, len, args.length, []); |
+} |
return ret; |
}, |
pop: function (path) { |
-var array = this.get(path); |
+var info = {}; |
+var array = this._get(path, this, info); |
+var hadLength = Boolean(array.length); |
var args = Array.prototype.slice.call(arguments, 1); |
-var rem = array.slice(-1); |
var ret = array.pop.apply(array, args); |
-this._notifySplice(array, path, array.length, 0, rem); |
+if (hadLength) { |
+this._notifySplice(array, info.path, array.length, 0, [ret]); |
+} |
return ret; |
}, |
splice: function (path, start, deleteCount) { |
-var array = this.get(path); |
+var info = {}; |
+var array = this._get(path, this, info); |
+if (start < 0) { |
+start = array.length - Math.floor(-start); |
+} else { |
+start = Math.floor(start); |
+} |
+if (!start) { |
+start = 0; |
+} |
var args = Array.prototype.slice.call(arguments, 1); |
-var rem = array.slice(start, start + deleteCount); |
var ret = array.splice.apply(array, args); |
-this._notifySplice(array, path, start, args.length - 2, rem); |
+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 array = this.get(path); |
+var info = {}; |
+var array = this._get(path, this, info); |
+var hadLength = Boolean(array.length); |
var args = Array.prototype.slice.call(arguments, 1); |
var ret = array.shift.apply(array, args); |
-this._notifySplice(array, path, 0, 0, [ret]); |
+if (hadLength) { |
+this._notifySplice(array, info.path, 0, 0, [ret]); |
+} |
return ret; |
}, |
unshift: function (path) { |
-var array = this.get(path); |
+var info = {}; |
+var array = this._get(path, this, info); |
var args = Array.prototype.slice.call(arguments, 1); |
var ret = array.unshift.apply(array, args); |
-this._notifySplice(array, path, 0, args.length, []); |
+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 |
+}); |
} |
}); |
}()); |
@@ -1872,7 +2352,7 @@ text = this._clean(text); |
return this._parseCss(this._lex(text), text); |
}, |
_clean: function (cssText) { |
-return cssText.replace(rx.comments, '').replace(rx.port, ''); |
+return cssText.replace(this._rx.comments, '').replace(this._rx.port, ''); |
}, |
_lex: function (text) { |
var root = { |
@@ -1909,17 +2389,19 @@ 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(AT_START) === 0; |
+node.atRule = s.indexOf(this.AT_START) === 0; |
if (node.atRule) { |
-if (s.indexOf(MEDIA_START) === 0) { |
+if (s.indexOf(this.MEDIA_START) === 0) { |
node.type = this.types.MEDIA_RULE; |
-} else if (s.match(rx.keyframesRule)) { |
+} else if (s.match(this._rx.keyframesRule)) { |
node.type = this.types.KEYFRAMES_RULE; |
} |
} else { |
-if (s.indexOf(VAR_START) === 0) { |
+if (s.indexOf(this.VAR_START) === 0) { |
node.type = this.types.MIXIN_RULE; |
} else { |
node.type = this.types.STYLE_RULE; |
@@ -1934,17 +2416,26 @@ 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 || !hasMixinRules(r$))) { |
+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 : removeCustomProps(node.cssText); |
+cssText = preserveProperties ? node.cssText : this.removeCustomProps(node.cssText); |
cssText = cssText.trim(); |
if (cssText) { |
cssText = ' ' + cssText + '\n'; |
@@ -1962,6 +2453,19 @@ 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, |
@@ -1969,31 +2473,27 @@ MEDIA_RULE: 4, |
MIXIN_RULE: 1000 |
}, |
OPEN_BRACE: '{', |
-CLOSE_BRACE: '}' |
-}; |
-function hasMixinRules(rules) { |
-return rules[0].selector.indexOf(VAR_START) >= 0; |
-} |
-function removeCustomProps(cssText) { |
-return cssText.replace(rx.customProp, '').replace(rx.mixinProp, '').replace(rx.mixinApply, '').replace(rx.varApply, ''); |
-} |
-var VAR_START = '--'; |
-var MEDIA_START = '@media'; |
-var AT_START = '@'; |
-var rx = { |
-comments: /\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim, |
+CLOSE_BRACE: '}', |
+_rx: { |
+comments: /\/\*[^*]*\*+([^\/*][^*]*\*+)*\//gim, |
port: /@import[^;]*;/gim, |
-customProp: /(?:^|[\s;])--[^;{]*?:[^{};]*?;/gim, |
-mixinProp: /(?:^|[\s;])--[^;{]*?:[^{;]*?{[^}]*?};?/gim, |
-mixinApply: /@apply[\s]*\([^)]*?\)[\s]*;/gim, |
-varApply: /[^;:]*?:[^;]*var[^;]*;/gim, |
-keyframesRule: /^@[^\s]*keyframes/ |
+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: '@' |
}; |
return api; |
}(); |
Polymer.StyleUtil = function () { |
return { |
-MODULE_STYLES_SELECTOR: 'style, link[rel=import][type~=css]', |
+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); |
@@ -2004,9 +2504,11 @@ this.forEachStyleRule(rules, callback); |
return this.parser.stringify(rules, preserveProperties); |
}, |
forRulesInStyles: function (styles, callback) { |
+if (styles) { |
for (var i = 0, l = styles.length, s; i < l && (s = styles[i]); i++) { |
this.forEachStyleRule(this.rulesForStyle(s), callback); |
} |
+} |
}, |
rulesForStyle: function (style) { |
if (!style.__cssRules && style.textContent) { |
@@ -2018,7 +2520,10 @@ clearStyleRules: function (style) { |
style.__cssRules = null; |
}, |
forEachStyleRule: function (node, callback) { |
-var s = node.selector; |
+if (!node) { |
+return; |
+} |
+var s = node.parsedSelector; |
var skipRules = false; |
if (node.type === this.ruleTypes.STYLE_RULE) { |
callback(node); |
@@ -2046,27 +2551,49 @@ afterNode = n$[n$.length - 1]; |
target.insertBefore(style, afterNode && afterNode.nextSibling || target.firstChild); |
return style; |
}, |
-cssFromModule: function (moduleId) { |
+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 e$ = Array.prototype.slice.call(m.querySelectorAll(this.MODULE_STYLES_SELECTOR)); |
+var content = element.content || element; |
+var e$ = Polymer.DomApi.arrayCopy(content.querySelectorAll(this.MODULE_STYLES_SELECTOR)); |
for (var i = 0, e; i < e$.length; i++) { |
e = e$[i]; |
+if (e.localName === 'template') { |
+cssText += this.cssFromElement(e); |
+} 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); |
-} else { |
-e = e.import && e.import.body; |
-} |
-if (e) { |
-cssText += Polymer.ResolveUrl.resolveCss(e.textContent, e.ownerDocument); |
+cssText += this.resolveCss(e.textContent, element.ownerDocument); |
+} else if (e.import && e.import.body) { |
+cssText += this.resolveCss(e.import.body.textContent, e.import); |
} |
} |
-m._cssText = cssText; |
} |
-return m && m._cssText || ''; |
+return cssText; |
}, |
+resolveCss: Polymer.ResolveUrl.resolveCss, |
parser: Polymer.CssParse, |
ruleTypes: Polymer.CssParse.types |
}; |
@@ -2158,29 +2685,37 @@ var p$ = rule.selector.split(COMPLEX_SELECTOR_SEP); |
for (var i = 0, l = p$.length, p; i < l && (p = p$[i]); i++) { |
p$[i] = transformer.call(this, p, scope, hostScope); |
} |
-rule.selector = p$.join(COMPLEX_SELECTOR_SEP); |
+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(SIMPLE_SELECTOR_SEP, function (m, c, s) { |
if (!stop) { |
-var o = self._transformCompoundSelector(s, c, scope, hostScope); |
-if (o.stop) { |
-stop = true; |
-} |
-c = o.combinator; |
-s = o.value; |
+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); |
-if (selector.indexOf(HOST) >= 0) { |
+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; |
}); |
@@ -2199,7 +2734,8 @@ stop = true; |
return { |
value: selector, |
combinator: combinator, |
-stop: stop |
+stop: stop, |
+hostContext: hostContext |
}; |
}, |
_transformSimpleSelector: function (selector, scope) { |
@@ -2231,6 +2767,8 @@ 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 = '.'; |
@@ -2287,7 +2825,7 @@ _extendRule: function (target, source) { |
if (target.parent !== source.parent) { |
this._cloneAndAddRuleToParent(source, target.parent); |
} |
-target.extends = target.extends || (target.extends = []); |
+target.extends = target.extends || []; |
target.extends.push(source); |
source.selector = source.selector.replace(this.rx.STRIP, ''); |
source.selector = (source.selector && source.selector + ',\n') + target.selector; |
@@ -2328,14 +2866,18 @@ _prepStyles: function () { |
if (this._encapsulateStyle === undefined) { |
this._encapsulateStyle = !nativeShadow && Boolean(this._template); |
} |
+if (this._template) { |
this._styles = this._collectStyles(); |
var cssText = styleTransformer.elementStyles(this); |
-if (cssText && this._template) { |
+if (cssText) { |
var style = styleUtil.applyCss(cssText, this.is, nativeShadow ? this._template.content : null); |
if (!nativeShadow) { |
this._scopeStyle = style; |
} |
} |
+} else { |
+this._styles = []; |
+} |
}, |
_collectStyles: function () { |
var styles = []; |
@@ -2346,6 +2888,10 @@ cssText += styleUtil.cssFromModule(m); |
} |
} |
cssText += styleUtil.cssFromModule(this.is); |
+var p = this._template && this._template.parentNode; |
+if (this._template && (!p || p.id.toLowerCase() !== this.is)) { |
+cssText += styleUtil.cssFromElement(this._template); |
+} |
if (cssText) { |
var style = document.createElement('style'); |
style.textContent = cssText; |
@@ -2379,21 +2925,21 @@ var scopify = function (node) { |
if (node.nodeType === Node.ELEMENT_NODE) { |
node.className = self._scopeElementClass(node, node.className); |
var n$ = node.querySelectorAll('*'); |
-Array.prototype.forEach.call(n$, function (n) { |
+for (var i = 0, n; i < n$.length && (n = n$[i]); i++) { |
n.className = self._scopeElementClass(n, n.className); |
-}); |
+} |
} |
}; |
scopify(container); |
if (shouldObserve) { |
var mo = new MutationObserver(function (mxns) { |
-mxns.forEach(function (m) { |
+for (var i = 0, m; i < mxns.length && (m = mxns[i]); i++) { |
if (m.addedNodes) { |
-for (var i = 0; i < m.addedNodes.length; i++) { |
-scopify(m.addedNodes[i]); |
+for (var j = 0; j < m.addedNodes.length; j++) { |
+scopify(m.addedNodes[j]); |
+} |
} |
} |
-}); |
}); |
mo.observe(container, { |
childList: true, |
@@ -2502,7 +3048,8 @@ return property && property.trim() || ''; |
}, |
valueForProperties: function (property, props) { |
var parts = property.split(';'); |
-for (var i = 0, p, m; i < parts.length && (p = parts[i]); i++) { |
+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); |
@@ -2516,7 +3063,10 @@ p = pp.join(':'); |
} |
parts[i] = p && p.lastIndexOf(';') === p.length - 1 ? p.slice(0, -1) : p || ''; |
} |
-return parts.join(';'); |
+} |
+return parts.filter(function (v) { |
+return v; |
+}).join(';'); |
}, |
applyProperties: function (rule, props) { |
var output = ''; |
@@ -2535,7 +3085,7 @@ styleUtil.forRulesInStyles(styles, function (rule) { |
if (!rule.propertyInfo) { |
self.decorateRule(rule); |
} |
-if (element && rule.propertyInfo.properties && matchesSelector.call(element, rule.selector)) { |
+if (element && rule.propertyInfo.properties && matchesSelector.call(element, rule.transformedSelector || rule.parsedSelector)) { |
self.collectProperties(rule, props); |
addToBitMask(i, o); |
} |
@@ -2611,7 +3161,7 @@ var cssText = style ? style.textContent || '' : this.transformStyles(element, pr |
var s = element._customStyle; |
if (s && !nativeShadow && s !== style) { |
s._useCount--; |
-if (s._useCount <= 0) { |
+if (s._useCount <= 0 && s.parentNode) { |
s.parentNode.removeChild(s); |
} |
} |
@@ -2632,14 +3182,23 @@ 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*?(?:([^;{]*?)|{([^}]*)})(?=;)/gim, |
-MIXIN_MATCH: /(?:^|\W+)@apply[\s]*\(([^)]*)\);?/im, |
-VAR_MATCH: /(^|\W+)var\([\s]*([^,)]*)[\s]*,?[\s]*((?:[^,)]*)|(?:[^;]*\([^;)]*\)))[\s]*?\)/gim, |
-VAR_CAPTURE: /\([\s]*(--[^,\s)]*)(?:,[\s]*(--[^,\s)]*))?(?:\)|,)/gim, |
+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, |
IS_VAR: /^--/, |
BRACKETED: /\{[^}]*\}/g, |
-HOST_PREFIX: '(?:^|[^.])', |
+HOST_PREFIX: '(?:^|[^.#[:])', |
HOST_SUFFIX: '($|[.:[\\s>+~])' |
}, |
HOST_SELECTORS: [':host'], |
@@ -2652,41 +3211,6 @@ var v = 1 << n % 32; |
bits[o] = (bits[o] || 0) | v; |
} |
}(); |
-Polymer.StyleDefaults = function () { |
-var styleProperties = Polymer.StyleProperties; |
-var styleUtil = Polymer.StyleUtil; |
-var api = { |
-_styles: [], |
-_properties: null, |
-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.reify(this._properties); |
-} |
-return this._properties; |
-}, |
-_needsStyleProperties: function () { |
-}, |
-_computeStyleProperties: function () { |
-return this._styleProperties; |
-}, |
-updateStyles: function () { |
-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 () { |
Polymer.StyleCache = function () { |
this.cache = {}; |
@@ -2717,8 +3241,10 @@ clear: function () { |
this.cache = {}; |
}, |
_objectsEqual: function (target, source) { |
+var t, s; |
for (var i in target) { |
-if (target[i] !== source[i]) { |
+t = target[i], s = source[i]; |
+if (!(typeof t === 'object' && t ? this._objectsStrictlyEqual(t, s) : t === s)) { |
return false; |
} |
} |
@@ -2726,9 +3252,55 @@ 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 styleUtil = Polymer.StyleUtil; |
+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; |
@@ -2739,7 +3311,11 @@ var styleDefaults = Polymer.StyleDefaults; |
var nativeShadow = Polymer.Settings.useNativeShadow; |
Polymer.Base._addFeature({ |
_prepStyleProperties: function () { |
-this._ownStylePropertyNames = this._styles ? propertyUtils.decorateStyles(this._styles) : []; |
+this._ownStylePropertyNames = this._styles ? propertyUtils.decorateStyles(this._styles) : null; |
+}, |
+customStyle: null, |
+getComputedStyleValue: function (property) { |
+return this._styleProperties && this._styleProperties[property] || getComputedStyle(this).getPropertyValue(property); |
}, |
_setupStyleProperties: function () { |
this.customStyle = {}; |
@@ -2752,12 +3328,23 @@ 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.domHost || styleDefaults; |
+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) { |
@@ -2772,15 +3359,14 @@ info = styleCache.retrieve(this.is, this._ownStyleProperties, this._styles); |
var globalCached = Boolean(info) && !scopeCached; |
var style = this._applyStyleProperties(info); |
if (!scopeCached) { |
-var cacheableStyle = style; |
-if (nativeShadow) { |
-cacheableStyle = style.cloneNode ? style.cloneNode(true) : Object.create(style || null); |
-} |
+style = style && nativeShadow ? style.cloneNode(true) : style; |
info = { |
-style: cacheableStyle, |
+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); |
@@ -2788,7 +3374,7 @@ styleCache.store(this.is, Object.create(info), this._ownStyleProperties, this._s |
} |
}, |
_computeStyleProperties: function (scopeProps) { |
-var scope = this.domHost || styleDefaults; |
+var scope = this._findStyleHost(); |
if (!scope._styleProperties) { |
scope._computeStyleProperties(); |
} |
@@ -2797,7 +3383,7 @@ 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)); |
-this.mixin(props, this.customStyle); |
+propertyUtils.mixinCustomStyle(props, this.customStyle); |
propertyUtils.reify(props); |
this._styleProperties = props; |
}, |
@@ -2814,20 +3400,20 @@ _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 ((style || oldScopeSelector) && !nativeShadow) { |
+if (!nativeShadow) { |
propertyUtils.applyElementScopeSelector(this, this._scopeSelector, oldScopeSelector, this._scopeCssViaAttr); |
} |
-return style || {}; |
+return style; |
}, |
serializeValueToAttribute: function (value, attribute, node) { |
node = node || this; |
-if (attribute === 'class') { |
+if (attribute === 'class' && !nativeShadow) { |
var host = node === this ? this.domHost || this.dataHost : this; |
if (host) { |
value = host._scopeElementClass(node, value); |
} |
} |
-node = Polymer.dom(node); |
+node = this.shadyRoot && this.shadyRoot._hasDistributed ? Polymer.dom(node) : node; |
serializeValueToAttribute.call(this, value, attribute, node); |
}, |
_scopeElementClass: function (element, selector) { |
@@ -2836,8 +3422,11 @@ selector += (selector ? ' ' : '') + SCOPE_NAME + ' ' + this.is + (element._scope |
} |
return selector; |
}, |
-updateStyles: function () { |
+updateStyles: function (properties) { |
if (this.isAttached) { |
+if (properties) { |
+this.mixin(this.customStyle, properties); |
+} |
if (this._needsStyleProperties()) { |
this._updateStyleProperties(); |
} else { |
@@ -2861,8 +3450,8 @@ c.updateStyles(); |
} |
} |
}); |
-Polymer.updateStyles = function () { |
-styleDefaults.updateStyles(); |
+Polymer.updateStyles = function (properties) { |
+styleDefaults.updateStyles(properties); |
Polymer.Base._updateRootStyles(document); |
}; |
var styleCache = new Polymer.StyleCache(); |
@@ -2873,8 +3462,6 @@ var XSCOPE_NAME = propertyUtils.XSCOPE_NAME; |
Polymer.Base._addFeature({ |
_registerFeatures: function () { |
this._prepIs(); |
-this._prepAttributes(); |
-this._prepExtends(); |
this._prepConstructor(); |
this._prepTemplate(); |
this._prepStyles(); |
@@ -2882,6 +3469,7 @@ this._prepStyleProperties(); |
this._prepAnnotations(); |
this._prepEffects(); |
this._prepBehaviors(); |
+this._prepPropertyInfo(); |
this._prepBindings(); |
this._prepShady(); |
}, |
@@ -2891,34 +3479,42 @@ this._addComplexObserverEffects(b.observers); |
this._addHostAttributes(b.hostAttributes); |
}, |
_initFeatures: function () { |
-this._poolContent(); |
this._setupConfigure(); |
this._setupStyleProperties(); |
-this._pushHost(); |
+this._setupDebouncers(); |
+this._registerHost(); |
+if (this._template) { |
+this._poolContent(); |
+this._beginHosting(); |
this._stampTemplate(); |
-this._popHost(); |
+this._endHosting(); |
this._marshalAnnotationReferences(); |
-this._marshalHostAttributes(); |
-this._setupDebouncers(); |
+} |
this._marshalInstanceEffects(); |
this._marshalBehaviors(); |
+this._marshalHostAttributes(); |
this._marshalAttributes(); |
this._tryReady(); |
}, |
_marshalBehavior: function (b) { |
+if (b.listeners) { |
this._listenListeners(b.listeners); |
} |
+} |
}); |
(function () { |
var nativeShadow = Polymer.Settings.useNativeShadow; |
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', |
-created: function () { |
+_template: null, |
+properties: { include: String }, |
+ready: function () { |
this._tryApply(); |
}, |
attached: function () { |
@@ -2930,46 +3526,63 @@ if (this.parentNode && this.parentNode.localName !== 'dom-module') { |
this._appliesToDocument = true; |
var e = this.__appliedElement || this; |
styleDefaults.addStyle(e); |
-if (e.textContent) { |
-this._apply(); |
+if (e.textContent || this.include) { |
+this._apply(true); |
} else { |
+var self = this; |
var observer = new MutationObserver(function () { |
observer.disconnect(); |
-this._apply(); |
-}.bind(this)); |
+self._apply(true); |
+}); |
observer.observe(e, { childList: true }); |
} |
} |
} |
}, |
-_apply: function () { |
+_apply: function (deferProperties) { |
var e = this.__appliedElement || this; |
+if (this.include) { |
+e.textContent = styleUtil.cssFromModules(this.include, true) + e.textContent; |
+} |
+if (e.textContent) { |
+styleUtil.forEachStyleRule(styleUtil.rulesForStyle(e), function (rule) { |
+styleTransformer.documentRule(rule); |
+}); |
+var self = this; |
+function fn() { |
+self._applyCustomProperties(e); |
+} |
+if (this._pendingApplyProperties) { |
+cancelAnimationFrame(this._pendingApplyProperties); |
+this._pendingApplyProperties = null; |
+} |
+if (deferProperties) { |
+this._pendingApplyProperties = requestAnimationFrame(fn); |
+} else { |
+fn(); |
+} |
+} |
+}, |
+_applyCustomProperties: function (element) { |
this._computeStyleProperties(); |
var props = this._styleProperties; |
-var self = this; |
-e.textContent = styleUtil.toCssText(styleUtil.rulesForStyle(e), function (rule) { |
+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 = css.replace(propertyUtils.rx.VAR_ASSIGN, ''); |
+css = cssParse.removeCustomPropAssignment(css); |
rule.cssText = propertyUtils.valueForProperties(css, props); |
} |
-styleTransformer.documentRule(rule); |
}); |
} |
}); |
}()); |
Polymer.Templatizer = { |
-properties: { _hideTemplateChildren: { observer: '_showHideChildren' } }, |
-_templatizerStatic: { |
-count: 0, |
-callbacks: {}, |
-debouncer: null |
-}, |
+properties: { __hideTemplateChildren__: { observer: '_showHideChildren' } }, |
_instanceProps: Polymer.nob, |
-created: function () { |
-this._templatizerId = this._templatizerStatic.count++; |
-}, |
+_parentPropPrefix: '_parent_', |
templatize: function (template) { |
+this._templatized = template; |
if (!template._content) { |
template._content = template.content; |
} |
@@ -2980,14 +3593,16 @@ 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(); |
-this._prepParentProperties(archetype, template); |
-archetype._notifyPath = this._notifyPathImpl; |
+archetype._notifyPathUp = this._notifyPathUpImpl; |
archetype._scopeElementClass = this._scopeElementClassImpl; |
archetype.listen = this._listenImpl; |
+archetype._showHideChildren = this._showHideChildrenImpl; |
var _constructor = this._constructorImpl; |
var ctor = function TemplateInstance(model, host) { |
_constructor.call(this, model, host); |
@@ -3000,29 +3615,44 @@ this.ctor = ctor; |
_getRootDataHost: function () { |
return this.dataHost && this.dataHost._rootDataHost || this.dataHost; |
}, |
-_showHideChildren: function (hidden) { |
+_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; |
+} |
}, |
_debounceTemplate: function (fn) { |
-this._templatizerStatic.callbacks[this._templatizerId] = fn.bind(this); |
-this._templatizerStatic.debouncer = Polymer.Debounce(this._templatizerStatic.debouncer, this._flushTemplates.bind(this, true)); |
+Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', fn)); |
}, |
_flushTemplates: function (debouncerExpired) { |
-var db = this._templatizerStatic.debouncer; |
-while (debouncerExpired || db && db.finish) { |
-db.stop(); |
-var cbs = this._templatizerStatic.callbacks; |
-this._templatizerStatic.callbacks = {}; |
-for (var id in cbs) { |
-cbs[id](); |
-} |
-debouncerExpired = false; |
-} |
+Polymer.dom.flush(); |
}, |
_customPrepEffects: function (archetype) { |
var parentProps = archetype._parentProps; |
for (var prop in parentProps) { |
archetype._addPropertyEffect(prop, 'function', this._createHostPropEffector(prop)); |
} |
+for (var prop in this._instanceProps) { |
+archetype._addPropertyEffect(prop, 'function', this._createInstancePropEffector(prop)); |
+} |
}, |
_customPrepAnnotations: function (archetype, template) { |
archetype._template = template; |
@@ -3030,7 +3660,9 @@ var c = template._content; |
if (!c._notes) { |
var rootDataHost = archetype._rootDataHost; |
if (rootDataHost) { |
-Polymer.Annotations.prepElement = rootDataHost._prepElement.bind(rootDataHost); |
+Polymer.Annotations.prepElement = function () { |
+rootDataHost._prepElement(); |
+}; |
} |
c._notes = Polymer.Annotations.parseAnnotations(template); |
Polymer.Annotations.prepElement = null; |
@@ -3051,24 +3683,36 @@ 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 = '_parent_' + prop; |
+var parentProp = this._parentPropPrefix + prop; |
var effects = [ |
{ |
kind: 'function', |
-effect: this._createForwardPropEffector(prop) |
+effect: this._createForwardPropEffector(prop), |
+fn: Polymer.Bind._functionEffect |
}, |
-{ kind: 'notify' } |
+{ |
+kind: 'notify', |
+fn: Polymer.Bind._notifyEffect, |
+effect: { event: Polymer.CaseMap.camelToDashCase(parentProp) + '-changed' } |
+} |
]; |
Polymer.Bind._createAccessors(proto, parentProp, effects); |
} |
} |
+var self = this; |
if (template != this) { |
Polymer.Bind.prepareInstance(template); |
-template._forwardParentProp = this._forwardParentProp.bind(this); |
+template._forwardParentProp = function (source, value) { |
+self._forwardParentProp(source, value); |
+}; |
} |
this._extendTemplate(template, proto); |
+template._pathEffector = function (path, value, fromAbove) { |
+return self._pathEffectorImpl(path, value, fromAbove); |
+}; |
} |
}, |
_createForwardPropEffector: function (prop) { |
@@ -3077,46 +3721,65 @@ this._forwardParentProp(prop, value); |
}; |
}, |
_createHostPropEffector: function (prop) { |
+var prefix = this._parentPropPrefix; |
return function (source, value) { |
-this.dataHost['_parent_' + prop] = 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) { |
-Object.getOwnPropertyNames(proto).forEach(function (n) { |
+var n$ = Object.getOwnPropertyNames(proto); |
+for (var i = 0, n; i < n$.length && (n = n$[i]); i++) { |
var val = template[n]; |
var pd = Object.getOwnPropertyDescriptor(proto, n); |
Object.defineProperty(template, n, pd); |
if (val !== undefined) { |
-template._propertySet(n, val); |
+template._propertySetter(n, val); |
} |
-}); |
+} |
+}, |
+_showHideChildren: function (hidden) { |
}, |
_forwardInstancePath: function (inst, path, value) { |
}, |
-_notifyPathImpl: function (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.notifyPath('_parent_' + path, value); |
+dataHost._templatized.notifyPath(dataHost._parentPropPrefix + path, value); |
} |
}, |
-_pathEffector: function (path, value, fromAbove) { |
+_pathEffectorImpl: function (path, value, fromAbove) { |
if (this._forwardParentPath) { |
-if (path.indexOf('_parent_') === 0) { |
-this._forwardParentPath(path.substring(8), value); |
+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.apply(this, arguments); |
+Polymer.Base._pathEffector.call(this._templatized, path, value, fromAbove); |
}, |
_constructorImpl: function (model, host) { |
this._rootDataHost = host._getRootDataHost(); |
this._setupConfigure(model); |
-this._pushHost(host); |
+this._registerHost(host); |
+this._beginHosting(); |
this.root = this.instanceTemplate(this._template); |
+this.root.__noContent = !this._notes._hasContent; |
this.root.__styleScoped = true; |
-this._popHost(); |
+this._endHosting(); |
this._marshalAnnotatedNodes(); |
this._marshalInstanceEffects(); |
this._marshalAnnotatedListeners(); |
@@ -3126,6 +3789,9 @@ children.push(n); |
n._templateInstance = this; |
} |
this._children = children; |
+if (host.__hideTemplateChildren__) { |
+this._showHideChildren(true); |
+} |
this._tryReady(); |
}, |
_listenImpl: function (node, eventName, methodName) { |
@@ -3147,16 +3813,32 @@ return host._scopeElementClass(node, value); |
stamp: function (model) { |
model = model || {}; |
if (this._parentProps) { |
+var templatized = this._templatized; |
for (var prop in this._parentProps) { |
-model[prop] = this['_parent_' + prop]; |
+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); |
@@ -3191,14 +3873,15 @@ this.omap.set(item, key); |
} else { |
this.pmap[item] = key; |
} |
-return key; |
+return '#' + key; |
}, |
removeKey: function (key) { |
+key = this._parseKey(key); |
this._removeFromMap(this.store[key]); |
delete this.store[key]; |
}, |
_removeFromMap: function (item) { |
-if (typeof item == 'object') { |
+if (item && typeof item == 'object') { |
this.omap.delete(item); |
} else { |
delete this.pmap[item]; |
@@ -3210,19 +3893,42 @@ this.removeKey(key); |
return key; |
}, |
getKey: function (item) { |
-if (typeof item == 'object') { |
-return this.omap.get(item); |
+var key; |
+if (item && typeof item == 'object') { |
+key = this.omap.get(item); |
} else { |
-return this.pmap[item]; |
+key = this.pmap[item]; |
+} |
+if (key != undefined) { |
+return '#' + key; |
} |
}, |
getKeys: function () { |
-return Object.keys(this.store); |
+return Object.keys(this.store).map(function (key) { |
+return '#' + key; |
+}); |
}, |
-setItem: function (key, value) { |
-this.store[key] = value; |
+_parseKey: function (key) { |
+if (key[0] == '#') { |
+return key.slice(1); |
+} |
+throw new Error('unexpected key ' + key); |
+}, |
+setItem: function (key, item) { |
+key = this._parseKey(key); |
+var old = this.store[key]; |
+if (old) { |
+this._removeFromMap(old); |
+} |
+if (item && typeof item == 'object') { |
+this.omap.set(item, key); |
+} else { |
+this.pmap[item] = key; |
+} |
+this.store[key] = item; |
}, |
getItem: function (key) { |
+key = this._parseKey(key); |
return this.store[key]; |
}, |
getItems: function () { |
@@ -3233,29 +3939,36 @@ items.push(store[key]); |
return items; |
}, |
_applySplices: function (splices) { |
-var keySplices = []; |
-for (var i = 0; i < splices.length; i++) { |
-var j, o, key, s = splices[i]; |
+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 (var j = 0; j < s.addedCount; j++) { |
+var item = this.userArray[s.index + j]; |
+key = this.getKey(item); |
+key = key === undefined ? this.add(item) : key; |
+keyMap[key] = keyMap[key] ? null : 1; |
+s.addedKeys.push(key); |
+} |
+} |
var removed = []; |
-for (j = 0; j < s.removed.length; j++) { |
-o = s.removed[j]; |
-key = this.remove(o); |
+var added = []; |
+for (var key in keyMap) { |
+if (keyMap[key] < 0) { |
+this.removeKey(key); |
removed.push(key); |
} |
-var added = []; |
-for (j = 0; j < s.addedCount; j++) { |
-o = this.userArray[s.index + j]; |
-key = this.add(o); |
+if (keyMap[key] > 0) { |
added.push(key); |
} |
-keySplices.push({ |
-index: s.index, |
+} |
+return [{ |
removed: removed, |
-removedItems: s.removed, |
added: added |
-}); |
-} |
-return keySplices; |
+}]; |
} |
}; |
Polymer.Collection.get = function (userArray) { |
@@ -3268,6 +3981,7 @@ return coll ? coll._applySplices(splices) : null; |
Polymer({ |
is: 'dom-repeat', |
extends: 'template', |
+_template: null, |
properties: { |
items: { type: Array }, |
as: { |
@@ -3290,23 +4004,37 @@ observe: { |
type: String, |
observer: '_observeChanged' |
}, |
-delay: Number |
+delay: Number, |
+initialCount: { |
+type: Number, |
+observer: '_initializeChunking' |
+}, |
+targetFramerate: { |
+type: Number, |
+value: 20 |
+}, |
+_targetFrameTime: { computed: '_computeFrameTime(targetFramerate)' } |
}, |
behaviors: [Polymer.Templatizer], |
observers: ['_itemsChanged(items.*)'], |
+created: function () { |
+this._instances = []; |
+this._pool = []; |
+this._limit = Infinity; |
+var self = this; |
+this._boundRenderChunk = function () { |
+self._renderChunk(); |
+}; |
+}, |
detached: function () { |
-if (this.rows) { |
-for (var i = 0; i < this.rows.length; i++) { |
-this._detachRow(i); |
-} |
+for (var i = 0; i < this._instances.length; i++) { |
+this._detachInstance(i); |
} |
}, |
attached: function () { |
-if (this.rows) { |
-var parentNode = Polymer.dom(this).parentNode; |
-for (var i = 0; i < this.rows.length; i++) { |
-Polymer.dom(parentNode).insertBefore(this.rows[i].root, this); |
-} |
+var parent = Polymer.dom(Polymer.dom(this).parentNode); |
+for (var i = 0; i < this._instances.length; i++) { |
+this._attachInstance(i, parent); |
} |
}, |
ready: function () { |
@@ -3317,28 +4045,52 @@ if (!this.ctor) { |
this.templatize(this); |
} |
}, |
-_sortChanged: function () { |
+_sortChanged: function (sort) { |
var dataHost = this._getRootDataHost(); |
-var sort = this.sort; |
this._sortFn = sort && (typeof sort == 'function' ? sort : function () { |
return dataHost[sort].apply(dataHost, arguments); |
}); |
-this._fullRefresh = true; |
+this._needFullRefresh = true; |
if (this.items) { |
this._debounceTemplate(this._render); |
} |
}, |
-_filterChanged: function () { |
+_filterChanged: function (filter) { |
var dataHost = this._getRootDataHost(); |
-var filter = this.filter; |
this._filterFn = filter && (typeof filter == 'function' ? filter : function () { |
return dataHost[filter].apply(dataHost, arguments); |
}); |
-this._fullRefresh = true; |
+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(' '); |
}, |
@@ -3351,11 +4103,14 @@ this.collection = null; |
} else { |
this._error(this._logf('dom-repeat', 'expected array for `items`,' + ' found', this.items)); |
} |
-this._splices = []; |
-this._fullRefresh = true; |
+this._keySplices = []; |
+this._indexSplices = []; |
+this._needFullRefresh = true; |
+this._initializeChunking(); |
this._debounceTemplate(this._render); |
} else if (change.path == 'items.splices') { |
-this._splices = this._splices.concat(change.value.keySplices); |
+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); |
@@ -3369,7 +4124,7 @@ 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._fullRefresh = true; |
+this._needFullRefresh = true; |
if (this.delay) { |
this.debounce('render', this._render, this.delay); |
} else { |
@@ -3381,129 +4136,150 @@ return; |
} |
}, |
render: function () { |
-this._fullRefresh = true; |
-this.debounce('render', this._render); |
+this._needFullRefresh = true; |
+this._debounceTemplate(this._render); |
this._flushTemplates(); |
}, |
_render: function () { |
var c = this.collection; |
-if (!this._fullRefresh) { |
+if (this._needFullRefresh) { |
+this._applyFullRefresh(); |
+this._needFullRefresh = false; |
+} else if (this._keySplices.length) { |
if (this._sortFn) { |
-this._applySplicesViewSort(this._splices); |
+this._applySplicesUserSort(this._keySplices); |
} else { |
if (this._filterFn) { |
-this._fullRefresh = true; |
+this._applyFullRefresh(); |
} else { |
-this._applySplicesArraySort(this._splices); |
+this._applySplicesArrayOrder(this._indexSplices); |
} |
} |
+} else { |
} |
-if (this._fullRefresh) { |
-this._sortAndFilter(); |
-this._fullRefresh = false; |
-} |
-this._splices = []; |
-var rowForKey = this._rowForKey = {}; |
-var keys = this._orderedKeys; |
-this.rows = this.rows || []; |
-for (var i = 0; i < keys.length; i++) { |
-var key = keys[i]; |
-var item = c.getItem(key); |
-var row = this.rows[i]; |
-rowForKey[key] = i; |
-if (!row) { |
-this.rows.push(row = this._insertRow(i, null, item)); |
+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__); |
} |
-row[this.as] = item; |
-row.__key__ = key; |
-row[this.indexAs] = i; |
+keyToIdx[inst.__key__] = i; |
+if (!inst.isPlaceholder) { |
+inst.__setProperty(this.indexAs, i, true); |
} |
-for (; i < this.rows.length; i++) { |
-this._detachRow(i); |
} |
-this.rows.splice(keys.length, this.rows.length - keys.length); |
+this._pool.length = 0; |
this.fire('dom-change'); |
+this._tryRenderChunk(); |
}, |
-_sortAndFilter: function () { |
+_applyFullRefresh: function () { |
var c = this.collection; |
-if (!this._sortFn) { |
-this._orderedKeys = []; |
+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++) { |
-this._orderedKeys.push(c.getKey(items[i])); |
+keys.push(c.getKey(items[i])); |
} |
} |
-} else { |
-this._orderedKeys = c ? c.getKeys() : []; |
} |
+var self = this; |
if (this._filterFn) { |
-this._orderedKeys = this._orderedKeys.filter(function (a) { |
-return this._filterFn(c.getItem(a)); |
-}, this); |
+keys = keys.filter(function (a) { |
+return self._filterFn(c.getItem(a)); |
+}); |
} |
if (this._sortFn) { |
-this._orderedKeys.sort(function (a, b) { |
-return this._sortFn(c.getItem(a), c.getItem(b)); |
-}.bind(this)); |
+keys.sort(function (a, b) { |
+return self._sortFn(c.getItem(a), c.getItem(b)); |
+}); |
+} |
+for (var i = 0; i < keys.length; i++) { |
+var key = keys[i]; |
+var inst = this._instances[i]; |
+if (inst) { |
+inst.__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); |
} |
}, |
-_keySort: function (a, b) { |
-return this.collection.getKey(a) - this.collection.getKey(b); |
+_numericSort: function (a, b) { |
+return a - b; |
}, |
-_applySplicesViewSort: function (splices) { |
+_applySplicesUserSort: function (splices) { |
var c = this.collection; |
-var keys = this._orderedKeys; |
-var rows = this.rows; |
-var removedRows = []; |
+var instances = this._instances; |
+var keyMap = {}; |
+for (var i = 0, s; i < splices.length && (s = splices[i]); i++) { |
+for (var j = 0; j < s.removed.length; j++) { |
+var key = s.removed[j]; |
+keyMap[key] = keyMap[key] ? null : -1; |
+} |
+for (var j = 0; j < s.added.length; j++) { |
+var key = s.added[j]; |
+keyMap[key] = keyMap[key] ? null : 1; |
+} |
+} |
+var removedIdxs = []; |
var addedKeys = []; |
-var pool = []; |
-var sortFn = this._sortFn || this._keySort.bind(this); |
-splices.forEach(function (s) { |
-for (var i = 0; i < s.removed.length; i++) { |
-var idx = this._rowForKey[s.removed[i]]; |
-if (idx != null) { |
-removedRows.push(idx); |
+for (var key in keyMap) { |
+if (keyMap[key] === -1) { |
+removedIdxs.push(this._keyToInstIdx[key]); |
} |
+if (keyMap[key] === 1) { |
+addedKeys.push(key); |
} |
-for (var i = 0; i < s.added.length; i++) { |
-addedKeys.push(s.added[i]); |
} |
-}, this); |
-if (removedRows.length) { |
-removedRows.sort(); |
-for (var i = removedRows.length - 1; i >= 0; i--) { |
-var idx = removedRows[i]; |
-pool.push(this._detachRow(idx)); |
-rows.splice(idx, 1); |
-keys.splice(idx, 1); |
+if (removedIdxs.length) { |
+removedIdxs.sort(this._numericSort); |
+for (var 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 this._filterFn(c.getItem(a)); |
-}, this); |
+return self._filterFn(c.getItem(a)); |
+}); |
} |
addedKeys.sort(function (a, b) { |
-return this._sortFn(c.getItem(a), c.getItem(b)); |
-}.bind(this)); |
+return self._sortFn(c.getItem(a), c.getItem(b)); |
+}); |
var start = 0; |
for (var i = 0; i < addedKeys.length; i++) { |
-start = this._insertRowIntoViewSort(start, addedKeys[i], pool); |
+start = this._insertRowUserSort(start, addedKeys[i]); |
} |
} |
}, |
-_insertRowIntoViewSort: function (start, key, pool) { |
+_insertRowUserSort: function (start, key) { |
var c = this.collection; |
var item = c.getItem(key); |
-var end = this.rows.length - 1; |
+var end = this._instances.length - 1; |
var idx = -1; |
-var sortFn = this._sortFn || this._keySort.bind(this); |
while (start <= end) { |
var mid = start + end >> 1; |
-var midKey = this._orderedKeys[mid]; |
-var cmp = sortFn(c.getItem(midKey), item); |
+var midKey = this._instances[mid].__key__; |
+var cmp = this._sortFn(c.getItem(midKey), item); |
if (cmp < 0) { |
start = mid + 1; |
} else if (cmp > 0) { |
@@ -3516,121 +4292,135 @@ break; |
if (idx < 0) { |
idx = end + 1; |
} |
-this._orderedKeys.splice(idx, 0, key); |
-this.rows.splice(idx, 0, this._insertRow(idx, pool, c.getItem(key))); |
+this._insertPlaceholder(idx, key); |
return idx; |
}, |
-_applySplicesArraySort: function (splices) { |
-var keys = this._orderedKeys; |
-var pool = []; |
-splices.forEach(function (s) { |
-for (var i = 0; i < s.removed.length; i++) { |
-pool.push(this._detachRow(s.index + i)); |
-} |
-this.rows.splice(s.index, s.removed.length); |
-}, this); |
+_applySplicesArrayOrder: function (splices) { |
var c = this.collection; |
-splices.forEach(function (s) { |
-var args = [ |
-s.index, |
-s.removed.length |
-].concat(s.added); |
-keys.splice.apply(keys, args); |
-for (var i = 0; i < s.added.length; i++) { |
-var item = c.getItem(s.added[i]); |
-var row = this._insertRow(s.index + i, pool, item); |
-this.rows.splice(s.index + i, 0, row); |
+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 (var j = 0; j < s.addedKeys.length; j++) { |
+this._insertPlaceholder(s.index + j, s.addedKeys[j]); |
+} |
} |
-}, this); |
}, |
-_detachRow: function (idx) { |
-var row = this.rows[idx]; |
-var parentNode = Polymer.dom(this).parentNode; |
-for (var i = 0; i < row._children.length; i++) { |
-var el = row._children[i]; |
-Polymer.dom(row.root).appendChild(el); |
+_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; |
} |
-return row; |
}, |
-_insertRow: function (idx, pool, item) { |
-var row = pool && pool.pop() || this._generateRow(idx, item); |
-var beforeRow = this.rows[idx]; |
-var beforeNode = beforeRow ? beforeRow._children[0] : this; |
-var parentNode = Polymer.dom(this).parentNode; |
-Polymer.dom(parentNode).insertBefore(row.root, beforeNode); |
-return row; |
+_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); |
}, |
-_generateRow: function (idx, item) { |
-var model = { __key__: this.collection.getKey(item) }; |
-model[this.as] = item; |
+_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; |
-var row = this.stamp(model); |
-return row; |
+return this.stamp(model); |
}, |
-_showHideChildren: function (hidden) { |
-if (this.rows) { |
-for (var i = 0; i < this.rows.length; i++) { |
-var c$ = this.rows[i]._children; |
-for (var j = 0; j < c$.length; j++) { |
-var c = c$[j]; |
-if (c.style) { |
-c.style.display = hidden ? 'none' : ''; |
+_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); |
} |
-c._hideTemplateChildren = hidden; |
+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 (row, path, value) { |
+_forwardInstancePath: function (inst, path, value) { |
if (path.indexOf(this.as + '.') === 0) { |
-this.notifyPath('items.' + row.__key__ + '.' + path.slice(this.as.length + 1), value); |
-return true; |
+this._notifyPath('items.' + inst.__key__ + '.' + path.slice(this.as.length + 1), value); |
} |
}, |
_forwardParentProp: function (prop, value) { |
-if (this.rows) { |
-this.rows.forEach(function (row) { |
-row[prop] = value; |
-}, this); |
+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) { |
-if (this.rows) { |
-this.rows.forEach(function (row) { |
-row.notifyPath(path, value, true); |
-}, this); |
+var i$ = this._instances; |
+for (var i = 0, inst; i < i$.length && (inst = i$[i]); i++) { |
+if (!inst.isPlaceholder) { |
+inst._notifyPath(path, value, true); |
+} |
} |
}, |
_forwardItemPath: function (path, value) { |
-if (this._rowForKey) { |
+if (this._keyToInstIdx) { |
var dot = path.indexOf('.'); |
var key = path.substring(0, dot < 0 ? path.length : dot); |
-var idx = this._rowForKey[key]; |
-var row = this.rows[idx]; |
-if (row) { |
+var idx = this._keyToInstIdx[key]; |
+var inst = this._instances[idx]; |
+if (inst && !inst.isPlaceholder) { |
if (dot >= 0) { |
path = this.as + '.' + path.substring(dot + 1); |
-row.notifyPath(path, value, true); |
+inst._notifyPath(path, value, true); |
} else { |
-row[this.as] = value; |
+inst.__setProperty(this.as, value, true); |
} |
} |
} |
}, |
-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; |
-} |
-} |
-}, |
itemForElement: function (el) { |
var instance = this.modelForElement(el); |
return instance && instance[this.as]; |
@@ -3646,70 +4436,92 @@ return instance && instance[this.indexAs]; |
}); |
Polymer({ |
is: 'array-selector', |
+_template: null, |
properties: { |
items: { |
type: Array, |
-observer: '_itemsChanged' |
+observer: 'clearSelection' |
+}, |
+multi: { |
+type: Boolean, |
+value: false, |
+observer: 'clearSelection' |
}, |
selected: { |
type: Object, |
notify: true |
}, |
-toggle: Boolean, |
-multi: Boolean |
+selectedItem: { |
+type: Object, |
+notify: true |
+}, |
+toggle: { |
+type: Boolean, |
+value: false |
+} |
}, |
-_itemsChanged: function () { |
+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) { |
-var scol = Polymer.Collection.get(this.selected); |
-var sidx = this.selected.indexOf(item); |
-if (sidx >= 0) { |
-var skey = scol.getKey(item); |
-this.splice('selected', sidx, 1); |
+if (this.isSelected(item)) { |
+var skey = this._selectedColl.getKey(item); |
+this.arrayDelete('selected', item); |
this.unlinkPaths('selected.' + skey); |
-return true; |
} |
} 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) { |
-var scol = Polymer.Collection.get(this.selected); |
-var skey = scol.getKey(item); |
-if (skey >= 0) { |
+if (this.isSelected(item)) { |
if (this.toggle) { |
this.deselect(item); |
} |
} else { |
this.push('selected', item); |
-this.async(function () { |
-skey = scol.getKey(item); |
+var skey = this._selectedColl.getKey(item); |
this.linkPaths('selected.' + skey, 'items.' + key); |
-}); |
} |
} else { |
if (this.toggle && item == this.selected) { |
this.deselect(); |
} else { |
-this.linkPaths('selected', 'items.' + key); |
this.selected = item; |
+this.selectedItem = item; |
+this.linkPaths('selected', 'items.' + key); |
+this.linkPaths('selectedItem', 'items.' + key); |
} |
} |
} |
@@ -3717,18 +4529,20 @@ this.selected = item; |
Polymer({ |
is: 'dom-if', |
extends: 'template', |
+_template: null, |
properties: { |
'if': { |
type: Boolean, |
-value: false |
+value: false, |
+observer: '_queueRender' |
}, |
restamp: { |
type: Boolean, |
-value: false |
+value: false, |
+observer: '_queueRender' |
} |
}, |
behaviors: [Polymer.Templatizer], |
-observers: ['_queueRender(if, restamp)'], |
_queueRender: function () { |
this._debounceTemplate(this._render); |
}, |
@@ -3746,7 +4560,6 @@ this._flushTemplates(); |
_render: function () { |
if (this.if) { |
if (!this.ctor) { |
-this._wrapTextNodes(this._content || this.content); |
this.templatize(this); |
} |
this._ensureInstance(); |
@@ -3764,43 +4577,31 @@ this._lastIf = this.if; |
}, |
_ensureInstance: function () { |
if (!this._instance) { |
+var parentNode = Polymer.dom(this).parentNode; |
+if (parentNode) { |
+var parent = Polymer.dom(parentNode); |
this._instance = this.stamp(); |
var root = this._instance.root; |
-var parent = Polymer.dom(Polymer.dom(this).parentNode); |
parent.insertBefore(root, this); |
} |
+} |
}, |
_teardownInstance: function () { |
if (this._instance) { |
-var c = this._instance._children; |
-if (c) { |
-var parent = Polymer.dom(Polymer.dom(c[0]).parentNode); |
-c.forEach(function (n) { |
+var c$ = this._instance._children; |
+if (c$) { |
+var parent = Polymer.dom(Polymer.dom(c$[0]).parentNode); |
+for (var i = 0, n; i < c$.length && (n = c$[i]); i++) { |
parent.removeChild(n); |
-}); |
-} |
-this._instance = null; |
} |
-}, |
-_wrapTextNodes: function (root) { |
-for (var n = root.firstChild; n; n = n.nextSibling) { |
-if (n.nodeType === Node.TEXT_NODE) { |
-var s = document.createElement('span'); |
-root.insertBefore(s, n); |
-s.appendChild(n); |
-n = s; |
} |
+this._instance = null; |
} |
}, |
_showHideChildren: function () { |
-var hidden = this._hideTemplateChildren || !this.if; |
+var hidden = this.__hideTemplateChildren__ || !this.if; |
if (this._instance) { |
-var c$ = this._instance._children; |
-for (var i = 0; i < c$.length; i++) { |
-var c = c$[i]; |
-c.style.display = hidden ? 'none' : ''; |
-c._hideTemplateChildren = hidden; |
-} |
+this._instance._showHideChildren(hidden); |
} |
}, |
_forwardParentProp: function (prop, value) { |
@@ -3810,44 +4611,30 @@ this._instance[prop] = value; |
}, |
_forwardParentPath: function (path, value) { |
if (this._instance) { |
-this._instance.notifyPath(path, value, true); |
-} |
-} |
-}); |
-Polymer.ImportStatus = { |
-_ready: false, |
-_callbacks: [], |
-whenLoaded: function (cb) { |
-if (this._ready) { |
-cb(); |
-} else { |
-this._callbacks.push(cb); |
+this._instance._notifyPath(path, value, true); |
} |
-}, |
-_importsLoaded: function () { |
-this._ready = true; |
-this._callbacks.forEach(function (cb) { |
-cb(); |
-}); |
-this._callbacks = []; |
} |
-}; |
-window.addEventListener('load', function () { |
-Polymer.ImportStatus._importsLoaded(); |
-}); |
-if (window.HTMLImports) { |
-HTMLImports.whenReady(function () { |
-Polymer.ImportStatus._importsLoaded(); |
}); |
-} |
Polymer({ |
is: 'dom-bind', |
extends: 'template', |
+_template: null, |
created: function () { |
-Polymer.ImportStatus.whenLoaded(this._readySelf.bind(this)); |
+var self = this; |
+Polymer.RenderStatus.whenReady(function () { |
+self._markImportsReady(); |
+}); |
+}, |
+_ensureReady: function () { |
+if (!this._readied) { |
+this._readySelf(); |
+} |
+}, |
+_markImportsReady: function () { |
+this._importsReady = true; |
+this._ensureReady(); |
}, |
_registerFeatures: function () { |
-this._prepExtends(); |
this._prepConstructor(); |
}, |
_insertChildren: function () { |
@@ -3875,9 +4662,21 @@ var config = {}; |
for (var prop in this._propertyEffects) { |
config[prop] = this[prop]; |
} |
-this._setupConfigure = this._setupConfigure.bind(this, config); |
+var setupConfigure = this._setupConfigure; |
+this._setupConfigure = function () { |
+setupConfigure.call(this, config); |
+}; |
}, |
attached: function () { |
+if (this._importsReady) { |
+this.render(); |
+} |
+}, |
+detached: function () { |
+this._removeChildren(); |
+}, |
+render: function () { |
+this._ensureReady(); |
if (!this._children) { |
this._template = this; |
this._prepAnnotations(); |
@@ -3885,13 +4684,11 @@ this._prepEffects(); |
this._prepBehaviors(); |
this._prepConfigure(); |
this._prepBindings(); |
+this._prepPropertyInfo(); |
Polymer.Base._initFeatures.call(this); |
-this._children = Array.prototype.slice.call(this.root.childNodes); |
+this._children = Polymer.DomApi.arrayCopyChildNodes(this.root); |
} |
this._insertChildren(); |
this.fire('dom-change'); |
-}, |
-detached: function () { |
-this._removeChildren(); |
} |
});</script> |