OLD | NEW |
| (Empty) |
1 <!-- | |
2 @license | |
3 Copyright (c) 2015 The Polymer Project Authors. All rights reserved. | |
4 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt | |
5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt | |
6 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt | |
7 Code distributed by Google as part of the polymer project is also | |
8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt | |
9 --><!-- | |
10 @license | |
11 Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | |
12 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt | |
13 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt | |
14 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt | |
15 Code distributed by Google as part of the polymer project is also | |
16 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt | |
17 --><link rel="import" href="polymer-mini.html"> | |
18 | |
19 <script>Polymer.nar = []; | |
20 Polymer.Annotations = { | |
21 parseAnnotations: function (template) { | |
22 var list = []; | |
23 var content = template._content || template.content; | |
24 this._parseNodeAnnotations(content, list); | |
25 return list; | |
26 }, | |
27 _parseNodeAnnotations: function (node, list) { | |
28 return node.nodeType === Node.TEXT_NODE ? this._parseTextNodeAnnotation(node, li
st) : this._parseElementAnnotations(node, list); | |
29 }, | |
30 _testEscape: function (value) { | |
31 var escape = value.slice(0, 2); | |
32 if (escape === '{{' || escape === '[[') { | |
33 return escape; | |
34 } | |
35 }, | |
36 _parseTextNodeAnnotation: function (node, list) { | |
37 var v = node.textContent; | |
38 var escape = this._testEscape(v); | |
39 if (escape) { | |
40 node.textContent = ' '; | |
41 var annote = { | |
42 bindings: [{ | |
43 kind: 'text', | |
44 mode: escape[0], | |
45 value: v.slice(2, -2).trim() | |
46 }] | |
47 }; | |
48 list.push(annote); | |
49 return annote; | |
50 } | |
51 }, | |
52 _parseElementAnnotations: function (element, list) { | |
53 var annote = { | |
54 bindings: [], | |
55 events: [] | |
56 }; | |
57 if (element.localName === 'content') { | |
58 list._hasContent = true; | |
59 } | |
60 this._parseChildNodesAnnotations(element, annote, list); | |
61 if (element.attributes) { | |
62 this._parseNodeAttributeAnnotations(element, annote, list); | |
63 if (this.prepElement) { | |
64 this.prepElement(element); | |
65 } | |
66 } | |
67 if (annote.bindings.length || annote.events.length || annote.id) { | |
68 list.push(annote); | |
69 } | |
70 return annote; | |
71 }, | |
72 _parseChildNodesAnnotations: function (root, annote, list, callback) { | |
73 if (root.firstChild) { | |
74 for (var i = 0, node = root.firstChild; node; node = node.nextSibling, i++) { | |
75 if (node.localName === 'template' && !node.hasAttribute('preserve-content')) { | |
76 this._parseTemplate(node, i, list, annote); | |
77 } | |
78 if (node.nodeType === Node.TEXT_NODE) { | |
79 var n = node.nextSibling; | |
80 while (n && n.nodeType === Node.TEXT_NODE) { | |
81 node.textContent += n.textContent; | |
82 root.removeChild(n); | |
83 n = n.nextSibling; | |
84 } | |
85 } | |
86 var childAnnotation = this._parseNodeAnnotations(node, list, callback); | |
87 if (childAnnotation) { | |
88 childAnnotation.parent = annote; | |
89 childAnnotation.index = i; | |
90 } | |
91 } | |
92 } | |
93 }, | |
94 _parseTemplate: function (node, index, list, parent) { | |
95 var content = document.createDocumentFragment(); | |
96 content._notes = this.parseAnnotations(node); | |
97 content.appendChild(node.content); | |
98 list.push({ | |
99 bindings: Polymer.nar, | |
100 events: Polymer.nar, | |
101 templateContent: content, | |
102 parent: parent, | |
103 index: index | |
104 }); | |
105 }, | |
106 _parseNodeAttributeAnnotations: function (node, annotation) { | |
107 for (var i = node.attributes.length - 1, a; a = node.attributes[i]; i--) { | |
108 var n = a.name, v = a.value; | |
109 if (n === 'id' && !this._testEscape(v)) { | |
110 annotation.id = v; | |
111 } else if (n.slice(0, 3) === 'on-') { | |
112 node.removeAttribute(n); | |
113 annotation.events.push({ | |
114 name: n.slice(3), | |
115 value: v | |
116 }); | |
117 } else { | |
118 var b = this._parseNodeAttributeAnnotation(node, n, v); | |
119 if (b) { | |
120 annotation.bindings.push(b); | |
121 } | |
122 } | |
123 } | |
124 }, | |
125 _parseNodeAttributeAnnotation: function (node, n, v) { | |
126 var escape = this._testEscape(v); | |
127 if (escape) { | |
128 var customEvent; | |
129 var name = n; | |
130 var mode = escape[0]; | |
131 v = v.slice(2, -2).trim(); | |
132 var not = false; | |
133 if (v[0] == '!') { | |
134 v = v.substring(1); | |
135 not = true; | |
136 } | |
137 var kind = 'property'; | |
138 if (n[n.length - 1] == '$') { | |
139 name = n.slice(0, -1); | |
140 kind = 'attribute'; | |
141 } | |
142 var notifyEvent, colon; | |
143 if (mode == '{' && (colon = v.indexOf('::')) > 0) { | |
144 notifyEvent = v.substring(colon + 2); | |
145 v = v.substring(0, colon); | |
146 customEvent = true; | |
147 } | |
148 if (node.localName == 'input' && n == 'value') { | |
149 node.setAttribute(n, ''); | |
150 } | |
151 node.removeAttribute(n); | |
152 if (kind === 'property') { | |
153 name = Polymer.CaseMap.dashToCamelCase(name); | |
154 } | |
155 return { | |
156 kind: kind, | |
157 mode: mode, | |
158 name: name, | |
159 value: v, | |
160 negate: not, | |
161 event: notifyEvent, | |
162 customEvent: customEvent | |
163 }; | |
164 } | |
165 }, | |
166 _localSubTree: function (node, host) { | |
167 return node === host ? node.childNodes : node._lightChildren || node.childNodes; | |
168 }, | |
169 findAnnotatedNode: function (root, annote) { | |
170 var parent = annote.parent && Polymer.Annotations.findAnnotatedNode(root, annote
.parent); | |
171 return !parent ? root : Polymer.Annotations._localSubTree(parent, root)[annote.i
ndex]; | |
172 } | |
173 }; | |
174 (function () { | |
175 function resolveCss(cssText, ownerDocument) { | |
176 return cssText.replace(CSS_URL_RX, function (m, pre, url, post) { | |
177 return pre + '\'' + resolve(url.replace(/["']/g, ''), ownerDocument) + '\'' + po
st; | |
178 }); | |
179 } | |
180 function resolveAttrs(element, ownerDocument) { | |
181 for (var name in URL_ATTRS) { | |
182 var a$ = URL_ATTRS[name]; | |
183 for (var i = 0, l = a$.length, a, at, v; i < l && (a = a$[i]); i++) { | |
184 if (name === '*' || element.localName === name) { | |
185 at = element.attributes[a]; | |
186 v = at && at.value; | |
187 if (v && v.search(BINDING_RX) < 0) { | |
188 at.value = a === 'style' ? resolveCss(v, ownerDocument) : resolve(v, ownerDocume
nt); | |
189 } | |
190 } | |
191 } | |
192 } | |
193 } | |
194 function resolve(url, ownerDocument) { | |
195 if (url && url[0] === '#') { | |
196 return url; | |
197 } | |
198 var resolver = getUrlResolver(ownerDocument); | |
199 resolver.href = url; | |
200 return resolver.href || url; | |
201 } | |
202 var tempDoc; | |
203 var tempDocBase; | |
204 function resolveUrl(url, baseUri) { | |
205 if (!tempDoc) { | |
206 tempDoc = document.implementation.createHTMLDocument('temp'); | |
207 tempDocBase = tempDoc.createElement('base'); | |
208 tempDoc.head.appendChild(tempDocBase); | |
209 } | |
210 tempDocBase.href = baseUri; | |
211 return resolve(url, tempDoc); | |
212 } | |
213 function getUrlResolver(ownerDocument) { | |
214 return ownerDocument.__urlResolver || (ownerDocument.__urlResolver = ownerDocume
nt.createElement('a')); | |
215 } | |
216 var CSS_URL_RX = /(url\()([^)]*)(\))/g; | |
217 var URL_ATTRS = { | |
218 '*': [ | |
219 'href', | |
220 'src', | |
221 'style', | |
222 'url' | |
223 ], | |
224 form: ['action'] | |
225 }; | |
226 var BINDING_RX = /\{\{|\[\[/; | |
227 Polymer.ResolveUrl = { | |
228 resolveCss: resolveCss, | |
229 resolveAttrs: resolveAttrs, | |
230 resolveUrl: resolveUrl | |
231 }; | |
232 }()); | |
233 Polymer.Base._addFeature({ | |
234 _prepAnnotations: function () { | |
235 if (!this._template) { | |
236 this._notes = []; | |
237 } else { | |
238 Polymer.Annotations.prepElement = this._prepElement.bind(this); | |
239 this._notes = Polymer.Annotations.parseAnnotations(this._template); | |
240 this._processAnnotations(this._notes); | |
241 Polymer.Annotations.prepElement = null; | |
242 } | |
243 }, | |
244 _processAnnotations: function (notes) { | |
245 for (var i = 0; i < notes.length; i++) { | |
246 var note = notes[i]; | |
247 for (var j = 0; j < note.bindings.length; j++) { | |
248 var b = note.bindings[j]; | |
249 b.signature = this._parseMethod(b.value); | |
250 if (!b.signature) { | |
251 b.model = this._modelForPath(b.value); | |
252 } | |
253 } | |
254 if (note.templateContent) { | |
255 this._processAnnotations(note.templateContent._notes); | |
256 var pp = note.templateContent._parentProps = this._discoverTemplateParentProps(n
ote.templateContent._notes); | |
257 var bindings = []; | |
258 for (var prop in pp) { | |
259 bindings.push({ | |
260 index: note.index, | |
261 kind: 'property', | |
262 mode: '{', | |
263 name: '_parent_' + prop, | |
264 model: prop, | |
265 value: prop | |
266 }); | |
267 } | |
268 note.bindings = note.bindings.concat(bindings); | |
269 } | |
270 } | |
271 }, | |
272 _discoverTemplateParentProps: function (notes) { | |
273 var pp = {}; | |
274 notes.forEach(function (n) { | |
275 n.bindings.forEach(function (b) { | |
276 if (b.signature) { | |
277 var args = b.signature.args; | |
278 for (var k = 0; k < args.length; k++) { | |
279 pp[args[k].model] = true; | |
280 } | |
281 } else { | |
282 pp[b.model] = true; | |
283 } | |
284 }); | |
285 if (n.templateContent) { | |
286 var tpp = n.templateContent._parentProps; | |
287 Polymer.Base.mixin(pp, tpp); | |
288 } | |
289 }); | |
290 return pp; | |
291 }, | |
292 _prepElement: function (element) { | |
293 Polymer.ResolveUrl.resolveAttrs(element, this._template.ownerDocument); | |
294 }, | |
295 _findAnnotatedNode: Polymer.Annotations.findAnnotatedNode, | |
296 _marshalAnnotationReferences: function () { | |
297 if (this._template) { | |
298 this._marshalIdNodes(); | |
299 this._marshalAnnotatedNodes(); | |
300 this._marshalAnnotatedListeners(); | |
301 } | |
302 }, | |
303 _configureAnnotationReferences: function () { | |
304 this._configureTemplateContent(); | |
305 }, | |
306 _configureTemplateContent: function () { | |
307 this._notes.forEach(function (note, i) { | |
308 if (note.templateContent) { | |
309 this._nodes[i]._content = note.templateContent; | |
310 } | |
311 }, this); | |
312 }, | |
313 _marshalIdNodes: function () { | |
314 this.$ = {}; | |
315 this._notes.forEach(function (a) { | |
316 if (a.id) { | |
317 this.$[a.id] = this._findAnnotatedNode(this.root, a); | |
318 } | |
319 }, this); | |
320 }, | |
321 _marshalAnnotatedNodes: function () { | |
322 if (this._nodes) { | |
323 this._nodes = this._nodes.map(function (a) { | |
324 return this._findAnnotatedNode(this.root, a); | |
325 }, this); | |
326 } | |
327 }, | |
328 _marshalAnnotatedListeners: function () { | |
329 this._notes.forEach(function (a) { | |
330 if (a.events && a.events.length) { | |
331 var node = this._findAnnotatedNode(this.root, a); | |
332 a.events.forEach(function (e) { | |
333 this.listen(node, e.name, e.value); | |
334 }, this); | |
335 } | |
336 }, this); | |
337 } | |
338 }); | |
339 Polymer.Base._addFeature({ | |
340 listeners: {}, | |
341 _listenListeners: function (listeners) { | |
342 var node, name, key; | |
343 for (key in listeners) { | |
344 if (key.indexOf('.') < 0) { | |
345 node = this; | |
346 name = key; | |
347 } else { | |
348 name = key.split('.'); | |
349 node = this.$[name[0]]; | |
350 name = name[1]; | |
351 } | |
352 this.listen(node, name, listeners[key]); | |
353 } | |
354 }, | |
355 listen: function (node, eventName, methodName) { | |
356 this._listen(node, eventName, this._createEventHandler(node, eventName, methodNa
me)); | |
357 }, | |
358 _boundListenerKey: function (eventName, methodName) { | |
359 return eventName + ':' + methodName; | |
360 }, | |
361 _recordEventHandler: function (host, eventName, target, methodName, handler) { | |
362 var hbl = host.__boundListeners; | |
363 if (!hbl) { | |
364 hbl = host.__boundListeners = new WeakMap(); | |
365 } | |
366 var bl = hbl.get(target); | |
367 if (!bl) { | |
368 bl = {}; | |
369 hbl.set(target, bl); | |
370 } | |
371 var key = this._boundListenerKey(eventName, methodName); | |
372 bl[key] = handler; | |
373 }, | |
374 _recallEventHandler: function (host, eventName, target, methodName) { | |
375 var hbl = host.__boundListeners; | |
376 if (!hbl) { | |
377 return; | |
378 } | |
379 var bl = hbl.get(target); | |
380 if (!bl) { | |
381 return; | |
382 } | |
383 var key = this._boundListenerKey(eventName, methodName); | |
384 return bl[key]; | |
385 }, | |
386 _createEventHandler: function (node, eventName, methodName) { | |
387 var host = this; | |
388 var handler = function (e) { | |
389 if (host[methodName]) { | |
390 host[methodName](e, e.detail); | |
391 } else { | |
392 host._warn(host._logf('_createEventHandler', 'listener method `' + methodName +
'` not defined')); | |
393 } | |
394 }; | |
395 this._recordEventHandler(host, eventName, node, methodName, handler); | |
396 return handler; | |
397 }, | |
398 unlisten: function (node, eventName, methodName) { | |
399 var handler = this._recallEventHandler(this, eventName, node, methodName); | |
400 if (handler) { | |
401 this._unlisten(node, eventName, handler); | |
402 } | |
403 }, | |
404 _listen: function (node, eventName, handler) { | |
405 node.addEventListener(eventName, handler); | |
406 }, | |
407 _unlisten: function (node, eventName, handler) { | |
408 node.removeEventListener(eventName, handler); | |
409 } | |
410 }); | |
411 (function () { | |
412 'use strict'; | |
413 var HAS_NATIVE_TA = typeof document.head.style.touchAction === 'string'; | |
414 var GESTURE_KEY = '__polymerGestures'; | |
415 var HANDLED_OBJ = '__polymerGesturesHandled'; | |
416 var TOUCH_ACTION = '__polymerGesturesTouchAction'; | |
417 var TAP_DISTANCE = 25; | |
418 var TRACK_DISTANCE = 5; | |
419 var TRACK_LENGTH = 2; | |
420 var MOUSE_TIMEOUT = 2500; | |
421 var MOUSE_EVENTS = [ | |
422 'mousedown', | |
423 'mousemove', | |
424 'mouseup', | |
425 'click' | |
426 ]; | |
427 var IS_TOUCH_ONLY = navigator.userAgent.match(/iP(?:[oa]d|hone)|Android/); | |
428 var mouseCanceller = function (mouseEvent) { | |
429 mouseEvent[HANDLED_OBJ] = { skip: true }; | |
430 if (mouseEvent.type === 'click') { | |
431 var path = Polymer.dom(mouseEvent).path; | |
432 for (var i = 0; i < path.length; i++) { | |
433 if (path[i] === POINTERSTATE.mouse.target) { | |
434 return; | |
435 } | |
436 } | |
437 mouseEvent.preventDefault(); | |
438 mouseEvent.stopPropagation(); | |
439 } | |
440 }; | |
441 function setupTeardownMouseCanceller(setup) { | |
442 for (var i = 0, en; i < MOUSE_EVENTS.length; i++) { | |
443 en = MOUSE_EVENTS[i]; | |
444 if (setup) { | |
445 document.addEventListener(en, mouseCanceller, true); | |
446 } else { | |
447 document.removeEventListener(en, mouseCanceller, true); | |
448 } | |
449 } | |
450 } | |
451 function ignoreMouse() { | |
452 if (IS_TOUCH_ONLY) { | |
453 return; | |
454 } | |
455 if (!POINTERSTATE.mouse.mouseIgnoreJob) { | |
456 setupTeardownMouseCanceller(true); | |
457 } | |
458 var unset = function () { | |
459 setupTeardownMouseCanceller(); | |
460 POINTERSTATE.mouse.target = null; | |
461 POINTERSTATE.mouse.mouseIgnoreJob = null; | |
462 }; | |
463 POINTERSTATE.mouse.mouseIgnoreJob = Polymer.Debounce(POINTERSTATE.mouse.mouseIgn
oreJob, unset, MOUSE_TIMEOUT); | |
464 } | |
465 var POINTERSTATE = { | |
466 mouse: { | |
467 target: null, | |
468 mouseIgnoreJob: null | |
469 }, | |
470 touch: { | |
471 x: 0, | |
472 y: 0, | |
473 id: -1, | |
474 scrollDecided: false | |
475 } | |
476 }; | |
477 function firstTouchAction(ev) { | |
478 var path = Polymer.dom(ev).path; | |
479 var ta = 'auto'; | |
480 for (var i = 0, n; i < path.length; i++) { | |
481 n = path[i]; | |
482 if (n[TOUCH_ACTION]) { | |
483 ta = n[TOUCH_ACTION]; | |
484 break; | |
485 } | |
486 } | |
487 return ta; | |
488 } | |
489 var Gestures = { | |
490 gestures: {}, | |
491 recognizers: [], | |
492 deepTargetFind: function (x, y) { | |
493 var node = document.elementFromPoint(x, y); | |
494 var next = node; | |
495 while (next && next.shadowRoot) { | |
496 next = next.shadowRoot.elementFromPoint(x, y); | |
497 if (next) { | |
498 node = next; | |
499 } | |
500 } | |
501 return node; | |
502 }, | |
503 findOriginalTarget: function (ev) { | |
504 if (ev.path) { | |
505 return ev.path[0]; | |
506 } | |
507 return ev.target; | |
508 }, | |
509 handleNative: function (ev) { | |
510 var handled; | |
511 var type = ev.type; | |
512 var node = ev.currentTarget; | |
513 var gobj = node[GESTURE_KEY]; | |
514 var gs = gobj[type]; | |
515 if (!gs) { | |
516 return; | |
517 } | |
518 if (!ev[HANDLED_OBJ]) { | |
519 ev[HANDLED_OBJ] = {}; | |
520 if (type.slice(0, 5) === 'touch') { | |
521 var t = ev.changedTouches[0]; | |
522 if (type === 'touchstart') { | |
523 if (ev.touches.length === 1) { | |
524 POINTERSTATE.touch.id = t.identifier; | |
525 } | |
526 } | |
527 if (POINTERSTATE.touch.id !== t.identifier) { | |
528 return; | |
529 } | |
530 if (!HAS_NATIVE_TA) { | |
531 if (type === 'touchstart' || type === 'touchmove') { | |
532 Gestures.handleTouchAction(ev); | |
533 } | |
534 } | |
535 if (type === 'touchend') { | |
536 POINTERSTATE.mouse.target = Polymer.dom(ev).rootTarget; | |
537 ignoreMouse(true); | |
538 } | |
539 } | |
540 } | |
541 handled = ev[HANDLED_OBJ]; | |
542 if (handled.skip) { | |
543 return; | |
544 } | |
545 var recognizers = Gestures.recognizers; | |
546 for (var i = 0, r; i < recognizers.length; i++) { | |
547 r = recognizers[i]; | |
548 if (gs[r.name] && !handled[r.name]) { | |
549 handled[r.name] = true; | |
550 r[type](ev); | |
551 } | |
552 } | |
553 }, | |
554 handleTouchAction: function (ev) { | |
555 var t = ev.changedTouches[0]; | |
556 var type = ev.type; | |
557 if (type === 'touchstart') { | |
558 POINTERSTATE.touch.x = t.clientX; | |
559 POINTERSTATE.touch.y = t.clientY; | |
560 POINTERSTATE.touch.scrollDecided = false; | |
561 } else if (type === 'touchmove') { | |
562 if (POINTERSTATE.touch.scrollDecided) { | |
563 return; | |
564 } | |
565 POINTERSTATE.touch.scrollDecided = true; | |
566 var ta = firstTouchAction(ev); | |
567 var prevent = false; | |
568 var dx = Math.abs(POINTERSTATE.touch.x - t.clientX); | |
569 var dy = Math.abs(POINTERSTATE.touch.y - t.clientY); | |
570 if (!ev.cancelable) { | |
571 } else if (ta === 'none') { | |
572 prevent = true; | |
573 } else if (ta === 'pan-x') { | |
574 prevent = dy > dx; | |
575 } else if (ta === 'pan-y') { | |
576 prevent = dx > dy; | |
577 } | |
578 if (prevent) { | |
579 ev.preventDefault(); | |
580 } | |
581 } | |
582 }, | |
583 add: function (node, evType, handler) { | |
584 var recognizer = this.gestures[evType]; | |
585 var deps = recognizer.deps; | |
586 var name = recognizer.name; | |
587 var gobj = node[GESTURE_KEY]; | |
588 if (!gobj) { | |
589 node[GESTURE_KEY] = gobj = {}; | |
590 } | |
591 for (var i = 0, dep, gd; i < deps.length; i++) { | |
592 dep = deps[i]; | |
593 if (IS_TOUCH_ONLY && MOUSE_EVENTS.indexOf(dep) > -1) { | |
594 continue; | |
595 } | |
596 gd = gobj[dep]; | |
597 if (!gd) { | |
598 gobj[dep] = gd = { _count: 0 }; | |
599 } | |
600 if (gd._count === 0) { | |
601 node.addEventListener(dep, this.handleNative); | |
602 } | |
603 gd[name] = (gd[name] || 0) + 1; | |
604 gd._count = (gd._count || 0) + 1; | |
605 } | |
606 node.addEventListener(evType, handler); | |
607 if (recognizer.touchAction) { | |
608 this.setTouchAction(node, recognizer.touchAction); | |
609 } | |
610 }, | |
611 remove: function (node, evType, handler) { | |
612 var recognizer = this.gestures[evType]; | |
613 var deps = recognizer.deps; | |
614 var name = recognizer.name; | |
615 var gobj = node[GESTURE_KEY]; | |
616 if (gobj) { | |
617 for (var i = 0, dep, gd; i < deps.length; i++) { | |
618 dep = deps[i]; | |
619 gd = gobj[dep]; | |
620 if (gd && gd[name]) { | |
621 gd[name] = (gd[name] || 1) - 1; | |
622 gd._count = (gd._count || 1) - 1; | |
623 } | |
624 if (gd._count === 0) { | |
625 node.removeEventListener(dep, this.handleNative); | |
626 } | |
627 } | |
628 } | |
629 node.removeEventListener(evType, handler); | |
630 }, | |
631 register: function (recog) { | |
632 this.recognizers.push(recog); | |
633 for (var i = 0; i < recog.emits.length; i++) { | |
634 this.gestures[recog.emits[i]] = recog; | |
635 } | |
636 }, | |
637 findRecognizerByEvent: function (evName) { | |
638 for (var i = 0, r; i < this.recognizers.length; i++) { | |
639 r = this.recognizers[i]; | |
640 for (var j = 0, n; j < r.emits.length; j++) { | |
641 n = r.emits[j]; | |
642 if (n === evName) { | |
643 return r; | |
644 } | |
645 } | |
646 } | |
647 return null; | |
648 }, | |
649 setTouchAction: function (node, value) { | |
650 if (HAS_NATIVE_TA) { | |
651 node.style.touchAction = value; | |
652 } | |
653 node[TOUCH_ACTION] = value; | |
654 }, | |
655 fire: function (target, type, detail) { | |
656 var ev = Polymer.Base.fire(type, detail, { | |
657 node: target, | |
658 bubbles: true, | |
659 cancelable: true | |
660 }); | |
661 if (ev.defaultPrevented) { | |
662 var se = detail.sourceEvent; | |
663 if (se && se.preventDefault) { | |
664 se.preventDefault(); | |
665 } | |
666 } | |
667 }, | |
668 prevent: function (evName) { | |
669 var recognizer = this.findRecognizerByEvent(evName); | |
670 if (recognizer.info) { | |
671 recognizer.info.prevent = true; | |
672 } | |
673 } | |
674 }; | |
675 Gestures.register({ | |
676 name: 'downup', | |
677 deps: [ | |
678 'mousedown', | |
679 'touchstart', | |
680 'touchend' | |
681 ], | |
682 emits: [ | |
683 'down', | |
684 'up' | |
685 ], | |
686 mousedown: function (e) { | |
687 var t = Gestures.findOriginalTarget(e); | |
688 var self = this; | |
689 var upfn = function upfn(e) { | |
690 self.fire('up', t, e); | |
691 document.removeEventListener('mouseup', upfn); | |
692 }; | |
693 document.addEventListener('mouseup', upfn); | |
694 this.fire('down', t, e); | |
695 }, | |
696 touchstart: function (e) { | |
697 this.fire('down', Gestures.findOriginalTarget(e), e.changedTouches[0]); | |
698 }, | |
699 touchend: function (e) { | |
700 this.fire('up', Gestures.findOriginalTarget(e), e.changedTouches[0]); | |
701 }, | |
702 fire: function (type, target, event) { | |
703 var self = this; | |
704 Gestures.fire(target, type, { | |
705 x: event.clientX, | |
706 y: event.clientY, | |
707 sourceEvent: event, | |
708 prevent: Gestures.prevent.bind(Gestures) | |
709 }); | |
710 } | |
711 }); | |
712 Gestures.register({ | |
713 name: 'track', | |
714 touchAction: 'none', | |
715 deps: [ | |
716 'mousedown', | |
717 'touchstart', | |
718 'touchmove', | |
719 'touchend' | |
720 ], | |
721 emits: ['track'], | |
722 info: { | |
723 x: 0, | |
724 y: 0, | |
725 state: 'start', | |
726 started: false, | |
727 moves: [], | |
728 addMove: function (move) { | |
729 if (this.moves.length > TRACK_LENGTH) { | |
730 this.moves.shift(); | |
731 } | |
732 this.moves.push(move); | |
733 }, | |
734 prevent: false | |
735 }, | |
736 clearInfo: function () { | |
737 this.info.state = 'start'; | |
738 this.info.started = false; | |
739 this.info.moves = []; | |
740 this.info.x = 0; | |
741 this.info.y = 0; | |
742 this.info.prevent = false; | |
743 }, | |
744 hasMovedEnough: function (x, y) { | |
745 if (this.info.prevent) { | |
746 return false; | |
747 } | |
748 if (this.info.started) { | |
749 return true; | |
750 } | |
751 var dx = Math.abs(this.info.x - x); | |
752 var dy = Math.abs(this.info.y - y); | |
753 return dx >= TRACK_DISTANCE || dy >= TRACK_DISTANCE; | |
754 }, | |
755 mousedown: function (e) { | |
756 var t = Gestures.findOriginalTarget(e); | |
757 var self = this; | |
758 var movefn = function movefn(e) { | |
759 var x = e.clientX, y = e.clientY; | |
760 if (self.hasMovedEnough(x, y)) { | |
761 self.info.state = self.info.started ? e.type === 'mouseup' ? 'end' : 'track' : '
start'; | |
762 self.info.addMove({ | |
763 x: x, | |
764 y: y | |
765 }); | |
766 self.fire(t, e); | |
767 self.info.started = true; | |
768 } | |
769 }; | |
770 var upfn = function upfn(e) { | |
771 if (self.info.started) { | |
772 Gestures.prevent('tap'); | |
773 movefn(e); | |
774 } | |
775 self.clearInfo(); | |
776 document.removeEventListener('mousemove', movefn); | |
777 document.removeEventListener('mouseup', upfn); | |
778 }; | |
779 document.addEventListener('mousemove', movefn); | |
780 document.addEventListener('mouseup', upfn); | |
781 this.info.x = e.clientX; | |
782 this.info.y = e.clientY; | |
783 }, | |
784 touchstart: function (e) { | |
785 var ct = e.changedTouches[0]; | |
786 this.info.x = ct.clientX; | |
787 this.info.y = ct.clientY; | |
788 }, | |
789 touchmove: function (e) { | |
790 var t = Gestures.findOriginalTarget(e); | |
791 var ct = e.changedTouches[0]; | |
792 var x = ct.clientX, y = ct.clientY; | |
793 if (this.hasMovedEnough(x, y)) { | |
794 this.info.addMove({ | |
795 x: x, | |
796 y: y | |
797 }); | |
798 this.fire(t, ct); | |
799 this.info.state = 'track'; | |
800 this.info.started = true; | |
801 } | |
802 }, | |
803 touchend: function (e) { | |
804 var t = Gestures.findOriginalTarget(e); | |
805 var ct = e.changedTouches[0]; | |
806 if (this.info.started) { | |
807 Gestures.prevent('tap'); | |
808 this.info.state = 'end'; | |
809 this.info.addMove({ | |
810 x: ct.clientX, | |
811 y: ct.clientY | |
812 }); | |
813 this.fire(t, ct); | |
814 } | |
815 this.clearInfo(); | |
816 }, | |
817 fire: function (target, touch) { | |
818 var secondlast = this.info.moves[this.info.moves.length - 2]; | |
819 var lastmove = this.info.moves[this.info.moves.length - 1]; | |
820 var dx = lastmove.x - this.info.x; | |
821 var dy = lastmove.y - this.info.y; | |
822 var ddx, ddy = 0; | |
823 if (secondlast) { | |
824 ddx = lastmove.x - secondlast.x; | |
825 ddy = lastmove.y - secondlast.y; | |
826 } | |
827 return Gestures.fire(target, 'track', { | |
828 state: this.info.state, | |
829 x: touch.clientX, | |
830 y: touch.clientY, | |
831 dx: dx, | |
832 dy: dy, | |
833 ddx: ddx, | |
834 ddy: ddy, | |
835 sourceEvent: touch, | |
836 hover: function () { | |
837 return Gestures.deepTargetFind(touch.clientX, touch.clientY); | |
838 } | |
839 }); | |
840 } | |
841 }); | |
842 Gestures.register({ | |
843 name: 'tap', | |
844 deps: [ | |
845 'mousedown', | |
846 'click', | |
847 'touchstart', | |
848 'touchend' | |
849 ], | |
850 emits: ['tap'], | |
851 info: { | |
852 x: NaN, | |
853 y: NaN, | |
854 prevent: false | |
855 }, | |
856 reset: function () { | |
857 this.info.x = NaN; | |
858 this.info.y = NaN; | |
859 this.info.prevent = false; | |
860 }, | |
861 save: function (e) { | |
862 this.info.x = e.clientX; | |
863 this.info.y = e.clientY; | |
864 }, | |
865 mousedown: function (e) { | |
866 this.save(e); | |
867 }, | |
868 click: function (e) { | |
869 this.forward(e); | |
870 }, | |
871 touchstart: function (e) { | |
872 this.save(e.changedTouches[0]); | |
873 }, | |
874 touchend: function (e) { | |
875 this.forward(e.changedTouches[0]); | |
876 }, | |
877 forward: function (e) { | |
878 var dx = Math.abs(e.clientX - this.info.x); | |
879 var dy = Math.abs(e.clientY - this.info.y); | |
880 var t = Gestures.findOriginalTarget(e); | |
881 if (isNaN(dx) || isNaN(dy) || dx <= TAP_DISTANCE && dy <= TAP_DISTANCE) { | |
882 if (!this.info.prevent) { | |
883 Gestures.fire(t, 'tap', { | |
884 x: e.clientX, | |
885 y: e.clientY, | |
886 sourceEvent: e | |
887 }); | |
888 } | |
889 } | |
890 this.reset(); | |
891 } | |
892 }); | |
893 var DIRECTION_MAP = { | |
894 x: 'pan-x', | |
895 y: 'pan-y', | |
896 none: 'none', | |
897 all: 'auto' | |
898 }; | |
899 Polymer.Base._addFeature({ | |
900 _listen: function (node, eventName, handler) { | |
901 if (Gestures.gestures[eventName]) { | |
902 Gestures.add(node, eventName, handler); | |
903 } else { | |
904 node.addEventListener(eventName, handler); | |
905 } | |
906 }, | |
907 _unlisten: function (node, eventName, handler) { | |
908 if (Gestures.gestures[eventName]) { | |
909 Gestures.remove(node, eventName, handler); | |
910 } else { | |
911 node.removeEventListener(eventName, handler); | |
912 } | |
913 }, | |
914 setScrollDirection: function (direction, node) { | |
915 node = node || this; | |
916 Gestures.setTouchAction(node, DIRECTION_MAP[direction] || 'auto'); | |
917 } | |
918 }); | |
919 Polymer.Gestures = Gestures; | |
920 }()); | |
921 Polymer.Async = { | |
922 _currVal: 0, | |
923 _lastVal: 0, | |
924 _callbacks: [], | |
925 _twiddleContent: 0, | |
926 _twiddle: document.createTextNode(''), | |
927 run: function (callback, waitTime) { | |
928 if (waitTime > 0) { | |
929 return ~setTimeout(callback, waitTime); | |
930 } else { | |
931 this._twiddle.textContent = this._twiddleContent++; | |
932 this._callbacks.push(callback); | |
933 return this._currVal++; | |
934 } | |
935 }, | |
936 cancel: function (handle) { | |
937 if (handle < 0) { | |
938 clearTimeout(~handle); | |
939 } else { | |
940 var idx = handle - this._lastVal; | |
941 if (idx >= 0) { | |
942 if (!this._callbacks[idx]) { | |
943 throw 'invalid async handle: ' + handle; | |
944 } | |
945 this._callbacks[idx] = null; | |
946 } | |
947 } | |
948 }, | |
949 _atEndOfMicrotask: function () { | |
950 var len = this._callbacks.length; | |
951 for (var i = 0; i < len; i++) { | |
952 var cb = this._callbacks[i]; | |
953 if (cb) { | |
954 try { | |
955 cb(); | |
956 } catch (e) { | |
957 i++; | |
958 this._callbacks.splice(0, i); | |
959 this._lastVal += i; | |
960 this._twiddle.textContent = this._twiddleContent++; | |
961 throw e; | |
962 } | |
963 } | |
964 } | |
965 this._callbacks.splice(0, len); | |
966 this._lastVal += len; | |
967 } | |
968 }; | |
969 new (window.MutationObserver || JsMutationObserver)(Polymer.Async._atEndOfMicrot
ask.bind(Polymer.Async)).observe(Polymer.Async._twiddle, { characterData: true }
); | |
970 Polymer.Debounce = function () { | |
971 var Async = Polymer.Async; | |
972 var Debouncer = function (context) { | |
973 this.context = context; | |
974 this.boundComplete = this.complete.bind(this); | |
975 }; | |
976 Debouncer.prototype = { | |
977 go: function (callback, wait) { | |
978 var h; | |
979 this.finish = function () { | |
980 Async.cancel(h); | |
981 }; | |
982 h = Async.run(this.boundComplete, wait); | |
983 this.callback = callback; | |
984 }, | |
985 stop: function () { | |
986 if (this.finish) { | |
987 this.finish(); | |
988 this.finish = null; | |
989 } | |
990 }, | |
991 complete: function () { | |
992 if (this.finish) { | |
993 this.stop(); | |
994 this.callback.call(this.context); | |
995 } | |
996 } | |
997 }; | |
998 function debounce(debouncer, callback, wait) { | |
999 if (debouncer) { | |
1000 debouncer.stop(); | |
1001 } else { | |
1002 debouncer = new Debouncer(this); | |
1003 } | |
1004 debouncer.go(callback, wait); | |
1005 return debouncer; | |
1006 } | |
1007 return debounce; | |
1008 }(); | |
1009 Polymer.Base._addFeature({ | |
1010 $$: function (slctr) { | |
1011 return Polymer.dom(this.root).querySelector(slctr); | |
1012 }, | |
1013 toggleClass: function (name, bool, node) { | |
1014 node = node || this; | |
1015 if (arguments.length == 1) { | |
1016 bool = !node.classList.contains(name); | |
1017 } | |
1018 if (bool) { | |
1019 Polymer.dom(node).classList.add(name); | |
1020 } else { | |
1021 Polymer.dom(node).classList.remove(name); | |
1022 } | |
1023 }, | |
1024 toggleAttribute: function (name, bool, node) { | |
1025 node = node || this; | |
1026 if (arguments.length == 1) { | |
1027 bool = !node.hasAttribute(name); | |
1028 } | |
1029 if (bool) { | |
1030 Polymer.dom(node).setAttribute(name, ''); | |
1031 } else { | |
1032 Polymer.dom(node).removeAttribute(name); | |
1033 } | |
1034 }, | |
1035 classFollows: function (name, toElement, fromElement) { | |
1036 if (fromElement) { | |
1037 Polymer.dom(fromElement).classList.remove(name); | |
1038 } | |
1039 if (toElement) { | |
1040 Polymer.dom(toElement).classList.add(name); | |
1041 } | |
1042 }, | |
1043 attributeFollows: function (name, toElement, fromElement) { | |
1044 if (fromElement) { | |
1045 Polymer.dom(fromElement).removeAttribute(name); | |
1046 } | |
1047 if (toElement) { | |
1048 Polymer.dom(toElement).setAttribute(name, ''); | |
1049 } | |
1050 }, | |
1051 getContentChildNodes: function (slctr) { | |
1052 var content = Polymer.dom(this.root).querySelector(slctr || 'content'); | |
1053 return content ? Polymer.dom(content).getDistributedNodes() : []; | |
1054 }, | |
1055 getContentChildren: function (slctr) { | |
1056 return this.getContentChildNodes(slctr).filter(function (n) { | |
1057 return n.nodeType === Node.ELEMENT_NODE; | |
1058 }); | |
1059 }, | |
1060 fire: function (type, detail, options) { | |
1061 options = options || Polymer.nob; | |
1062 var node = options.node || this; | |
1063 var detail = detail === null || detail === undefined ? Polymer.nob : detail; | |
1064 var bubbles = options.bubbles === undefined ? true : options.bubbles; | |
1065 var cancelable = Boolean(options.cancelable); | |
1066 var event = new CustomEvent(type, { | |
1067 bubbles: Boolean(bubbles), | |
1068 cancelable: cancelable, | |
1069 detail: detail | |
1070 }); | |
1071 node.dispatchEvent(event); | |
1072 return event; | |
1073 }, | |
1074 async: function (callback, waitTime) { | |
1075 return Polymer.Async.run(callback.bind(this), waitTime); | |
1076 }, | |
1077 cancelAsync: function (handle) { | |
1078 Polymer.Async.cancel(handle); | |
1079 }, | |
1080 arrayDelete: function (path, item) { | |
1081 var index; | |
1082 if (Array.isArray(path)) { | |
1083 index = path.indexOf(item); | |
1084 if (index >= 0) { | |
1085 return path.splice(index, 1); | |
1086 } | |
1087 } else { | |
1088 var arr = this.get(path); | |
1089 index = arr.indexOf(item); | |
1090 if (index >= 0) { | |
1091 return this.splice(path, index, 1); | |
1092 } | |
1093 } | |
1094 }, | |
1095 transform: function (transform, node) { | |
1096 node = node || this; | |
1097 node.style.webkitTransform = transform; | |
1098 node.style.transform = transform; | |
1099 }, | |
1100 translate3d: function (x, y, z, node) { | |
1101 node = node || this; | |
1102 this.transform('translate3d(' + x + ',' + y + ',' + z + ')', node); | |
1103 }, | |
1104 importHref: function (href, onload, onerror) { | |
1105 var l = document.createElement('link'); | |
1106 l.rel = 'import'; | |
1107 l.href = href; | |
1108 if (onload) { | |
1109 l.onload = onload.bind(this); | |
1110 } | |
1111 if (onerror) { | |
1112 l.onerror = onerror.bind(this); | |
1113 } | |
1114 document.head.appendChild(l); | |
1115 return l; | |
1116 }, | |
1117 create: function (tag, props) { | |
1118 var elt = document.createElement(tag); | |
1119 if (props) { | |
1120 for (var n in props) { | |
1121 elt[n] = props[n]; | |
1122 } | |
1123 } | |
1124 return elt; | |
1125 } | |
1126 }); | |
1127 Polymer.Bind = { | |
1128 prepareModel: function (model) { | |
1129 model._propertyEffects = {}; | |
1130 model._bindListeners = []; | |
1131 Polymer.Base.mixin(model, this._modelApi); | |
1132 }, | |
1133 _modelApi: { | |
1134 _notifyChange: function (property) { | |
1135 var eventName = Polymer.CaseMap.camelToDashCase(property) + '-changed'; | |
1136 Polymer.Base.fire(eventName, { value: this[property] }, { | |
1137 bubbles: false, | |
1138 node: this | |
1139 }); | |
1140 }, | |
1141 _propertySetter: function (property, value, effects, fromAbove) { | |
1142 var old = this.__data__[property]; | |
1143 if (old !== value && (old === old || value === value)) { | |
1144 this.__data__[property] = value; | |
1145 if (typeof value == 'object') { | |
1146 this._clearPath(property); | |
1147 } | |
1148 if (this._propertyChanged) { | |
1149 this._propertyChanged(property, value, old); | |
1150 } | |
1151 if (effects) { | |
1152 this._effectEffects(property, value, effects, old, fromAbove); | |
1153 } | |
1154 } | |
1155 return old; | |
1156 }, | |
1157 __setProperty: function (property, value, quiet, node) { | |
1158 node = node || this; | |
1159 var effects = node._propertyEffects && node._propertyEffects[property]; | |
1160 if (effects) { | |
1161 node._propertySetter(property, value, effects, quiet); | |
1162 } else { | |
1163 node[property] = value; | |
1164 } | |
1165 }, | |
1166 _effectEffects: function (property, value, effects, old, fromAbove) { | |
1167 effects.forEach(function (fx) { | |
1168 var fn = Polymer.Bind['_' + fx.kind + 'Effect']; | |
1169 if (fn) { | |
1170 fn.call(this, property, value, fx.effect, old, fromAbove); | |
1171 } | |
1172 }, this); | |
1173 }, | |
1174 _clearPath: function (path) { | |
1175 for (var prop in this.__data__) { | |
1176 if (prop.indexOf(path + '.') === 0) { | |
1177 this.__data__[prop] = undefined; | |
1178 } | |
1179 } | |
1180 } | |
1181 }, | |
1182 ensurePropertyEffects: function (model, property) { | |
1183 var fx = model._propertyEffects[property]; | |
1184 if (!fx) { | |
1185 fx = model._propertyEffects[property] = []; | |
1186 } | |
1187 return fx; | |
1188 }, | |
1189 addPropertyEffect: function (model, property, kind, effect) { | |
1190 var fx = this.ensurePropertyEffects(model, property); | |
1191 fx.push({ | |
1192 kind: kind, | |
1193 effect: effect | |
1194 }); | |
1195 }, | |
1196 createBindings: function (model) { | |
1197 var fx$ = model._propertyEffects; | |
1198 if (fx$) { | |
1199 for (var n in fx$) { | |
1200 var fx = fx$[n]; | |
1201 fx.sort(this._sortPropertyEffects); | |
1202 this._createAccessors(model, n, fx); | |
1203 } | |
1204 } | |
1205 }, | |
1206 _sortPropertyEffects: function () { | |
1207 var EFFECT_ORDER = { | |
1208 'compute': 0, | |
1209 'annotation': 1, | |
1210 'computedAnnotation': 2, | |
1211 'reflect': 3, | |
1212 'notify': 4, | |
1213 'observer': 5, | |
1214 'complexObserver': 6, | |
1215 'function': 7 | |
1216 }; | |
1217 return function (a, b) { | |
1218 return EFFECT_ORDER[a.kind] - EFFECT_ORDER[b.kind]; | |
1219 }; | |
1220 }(), | |
1221 _createAccessors: function (model, property, effects) { | |
1222 var defun = { | |
1223 get: function () { | |
1224 return this.__data__[property]; | |
1225 } | |
1226 }; | |
1227 var setter = function (value) { | |
1228 this._propertySetter(property, value, effects); | |
1229 }; | |
1230 var info = model.getPropertyInfo && model.getPropertyInfo(property); | |
1231 if (info && info.readOnly) { | |
1232 if (!info.computed) { | |
1233 model['_set' + this.upper(property)] = setter; | |
1234 } | |
1235 } else { | |
1236 defun.set = setter; | |
1237 } | |
1238 Object.defineProperty(model, property, defun); | |
1239 }, | |
1240 upper: function (name) { | |
1241 return name[0].toUpperCase() + name.substring(1); | |
1242 }, | |
1243 _addAnnotatedListener: function (model, index, property, path, event) { | |
1244 var fn = this._notedListenerFactory(property, path, this._isStructured(path), th
is._isEventBogus); | |
1245 var eventName = event || Polymer.CaseMap.camelToDashCase(property) + '-changed'; | |
1246 model._bindListeners.push({ | |
1247 index: index, | |
1248 property: property, | |
1249 path: path, | |
1250 changedFn: fn, | |
1251 event: eventName | |
1252 }); | |
1253 }, | |
1254 _isStructured: function (path) { | |
1255 return path.indexOf('.') > 0; | |
1256 }, | |
1257 _isEventBogus: function (e, target) { | |
1258 return e.path && e.path[0] !== target; | |
1259 }, | |
1260 _notedListenerFactory: function (property, path, isStructured, bogusTest) { | |
1261 return function (e, target) { | |
1262 if (!bogusTest(e, target)) { | |
1263 if (e.detail && e.detail.path) { | |
1264 this.notifyPath(this._fixPath(path, property, e.detail.path), e.detail.value); | |
1265 } else { | |
1266 var value = target[property]; | |
1267 if (!isStructured) { | |
1268 this[path] = target[property]; | |
1269 } else { | |
1270 if (this.__data__[path] != value) { | |
1271 this.set(path, value); | |
1272 } | |
1273 } | |
1274 } | |
1275 } | |
1276 }; | |
1277 }, | |
1278 prepareInstance: function (inst) { | |
1279 inst.__data__ = Object.create(null); | |
1280 }, | |
1281 setupBindListeners: function (inst) { | |
1282 inst._bindListeners.forEach(function (info) { | |
1283 var node = inst._nodes[info.index]; | |
1284 node.addEventListener(info.event, inst._notifyListener.bind(inst, info.changedFn
)); | |
1285 }); | |
1286 } | |
1287 }; | |
1288 Polymer.Base.extend(Polymer.Bind, { | |
1289 _shouldAddListener: function (effect) { | |
1290 return effect.name && effect.mode === '{' && !effect.negate && effect.kind != 'a
ttribute'; | |
1291 }, | |
1292 _annotationEffect: function (source, value, effect) { | |
1293 if (source != effect.value) { | |
1294 value = this.get(effect.value); | |
1295 this.__data__[effect.value] = value; | |
1296 } | |
1297 var calc = effect.negate ? !value : value; | |
1298 if (!effect.customEvent || this._nodes[effect.index][effect.name] !== calc) { | |
1299 return this._applyEffectValue(calc, effect); | |
1300 } | |
1301 }, | |
1302 _reflectEffect: function (source) { | |
1303 this.reflectPropertyToAttribute(source); | |
1304 }, | |
1305 _notifyEffect: function (source, value, effect, old, fromAbove) { | |
1306 if (!fromAbove) { | |
1307 this._notifyChange(source); | |
1308 } | |
1309 }, | |
1310 _functionEffect: function (source, value, fn, old, fromAbove) { | |
1311 fn.call(this, source, value, old, fromAbove); | |
1312 }, | |
1313 _observerEffect: function (source, value, effect, old) { | |
1314 var fn = this[effect.method]; | |
1315 if (fn) { | |
1316 fn.call(this, value, old); | |
1317 } else { | |
1318 this._warn(this._logf('_observerEffect', 'observer method `' + effect.method + '
` not defined')); | |
1319 } | |
1320 }, | |
1321 _complexObserverEffect: function (source, value, effect) { | |
1322 var fn = this[effect.method]; | |
1323 if (fn) { | |
1324 var args = Polymer.Bind._marshalArgs(this.__data__, effect, source, value); | |
1325 if (args) { | |
1326 fn.apply(this, args); | |
1327 } | |
1328 } else { | |
1329 this._warn(this._logf('_complexObserverEffect', 'observer method `' + effect.met
hod + '` not defined')); | |
1330 } | |
1331 }, | |
1332 _computeEffect: function (source, value, effect) { | |
1333 var args = Polymer.Bind._marshalArgs(this.__data__, effect, source, value); | |
1334 if (args) { | |
1335 var fn = this[effect.method]; | |
1336 if (fn) { | |
1337 this.__setProperty(effect.property, fn.apply(this, args)); | |
1338 } else { | |
1339 this._warn(this._logf('_computeEffect', 'compute method `' + effect.method + '`
not defined')); | |
1340 } | |
1341 } | |
1342 }, | |
1343 _annotatedComputationEffect: function (source, value, effect) { | |
1344 var computedHost = this._rootDataHost || this; | |
1345 var fn = computedHost[effect.method]; | |
1346 if (fn) { | |
1347 var args = Polymer.Bind._marshalArgs(this.__data__, effect, source, value); | |
1348 if (args) { | |
1349 var computedvalue = fn.apply(computedHost, args); | |
1350 if (effect.negate) { | |
1351 computedvalue = !computedvalue; | |
1352 } | |
1353 this._applyEffectValue(computedvalue, effect); | |
1354 } | |
1355 } else { | |
1356 computedHost._warn(computedHost._logf('_annotatedComputationEffect', 'compute me
thod `' + effect.method + '` not defined')); | |
1357 } | |
1358 }, | |
1359 _marshalArgs: function (model, effect, path, value) { | |
1360 var values = []; | |
1361 var args = effect.args; | |
1362 for (var i = 0, l = args.length; i < l; i++) { | |
1363 var arg = args[i]; | |
1364 var name = arg.name; | |
1365 var v; | |
1366 if (arg.literal) { | |
1367 v = arg.value; | |
1368 } else if (arg.structured) { | |
1369 v = Polymer.Base.get(name, model); | |
1370 } else { | |
1371 v = model[name]; | |
1372 } | |
1373 if (args.length > 1 && v === undefined) { | |
1374 return; | |
1375 } | |
1376 if (arg.wildcard) { | |
1377 var baseChanged = name.indexOf(path + '.') === 0; | |
1378 var matches = effect.trigger.name.indexOf(name) === 0 && !baseChanged; | |
1379 values[i] = { | |
1380 path: matches ? path : name, | |
1381 value: matches ? value : v, | |
1382 base: v | |
1383 }; | |
1384 } else { | |
1385 values[i] = v; | |
1386 } | |
1387 } | |
1388 return values; | |
1389 } | |
1390 }); | |
1391 Polymer.Base._addFeature({ | |
1392 _addPropertyEffect: function (property, kind, effect) { | |
1393 Polymer.Bind.addPropertyEffect(this, property, kind, effect); | |
1394 }, | |
1395 _prepEffects: function () { | |
1396 Polymer.Bind.prepareModel(this); | |
1397 this._addAnnotationEffects(this._notes); | |
1398 }, | |
1399 _prepBindings: function () { | |
1400 Polymer.Bind.createBindings(this); | |
1401 }, | |
1402 _addPropertyEffects: function (properties) { | |
1403 if (properties) { | |
1404 for (var p in properties) { | |
1405 var prop = properties[p]; | |
1406 if (prop.observer) { | |
1407 this._addObserverEffect(p, prop.observer); | |
1408 } | |
1409 if (prop.computed) { | |
1410 prop.readOnly = true; | |
1411 this._addComputedEffect(p, prop.computed); | |
1412 } | |
1413 if (prop.notify) { | |
1414 this._addPropertyEffect(p, 'notify'); | |
1415 } | |
1416 if (prop.reflectToAttribute) { | |
1417 this._addPropertyEffect(p, 'reflect'); | |
1418 } | |
1419 if (prop.readOnly) { | |
1420 Polymer.Bind.ensurePropertyEffects(this, p); | |
1421 } | |
1422 } | |
1423 } | |
1424 }, | |
1425 _addComputedEffect: function (name, expression) { | |
1426 var sig = this._parseMethod(expression); | |
1427 sig.args.forEach(function (arg) { | |
1428 this._addPropertyEffect(arg.model, 'compute', { | |
1429 method: sig.method, | |
1430 args: sig.args, | |
1431 trigger: arg, | |
1432 property: name | |
1433 }); | |
1434 }, this); | |
1435 }, | |
1436 _addObserverEffect: function (property, observer) { | |
1437 this._addPropertyEffect(property, 'observer', { | |
1438 method: observer, | |
1439 property: property | |
1440 }); | |
1441 }, | |
1442 _addComplexObserverEffects: function (observers) { | |
1443 if (observers) { | |
1444 observers.forEach(function (observer) { | |
1445 this._addComplexObserverEffect(observer); | |
1446 }, this); | |
1447 } | |
1448 }, | |
1449 _addComplexObserverEffect: function (observer) { | |
1450 var sig = this._parseMethod(observer); | |
1451 sig.args.forEach(function (arg) { | |
1452 this._addPropertyEffect(arg.model, 'complexObserver', { | |
1453 method: sig.method, | |
1454 args: sig.args, | |
1455 trigger: arg | |
1456 }); | |
1457 }, this); | |
1458 }, | |
1459 _addAnnotationEffects: function (notes) { | |
1460 this._nodes = []; | |
1461 notes.forEach(function (note) { | |
1462 var index = this._nodes.push(note) - 1; | |
1463 note.bindings.forEach(function (binding) { | |
1464 this._addAnnotationEffect(binding, index); | |
1465 }, this); | |
1466 }, this); | |
1467 }, | |
1468 _addAnnotationEffect: function (note, index) { | |
1469 if (Polymer.Bind._shouldAddListener(note)) { | |
1470 Polymer.Bind._addAnnotatedListener(this, index, note.name, note.value, note.even
t); | |
1471 } | |
1472 if (note.signature) { | |
1473 this._addAnnotatedComputationEffect(note, index); | |
1474 } else { | |
1475 note.index = index; | |
1476 this._addPropertyEffect(note.model, 'annotation', note); | |
1477 } | |
1478 }, | |
1479 _addAnnotatedComputationEffect: function (note, index) { | |
1480 var sig = note.signature; | |
1481 if (sig.static) { | |
1482 this.__addAnnotatedComputationEffect('__static__', index, note, sig, null); | |
1483 } else { | |
1484 sig.args.forEach(function (arg) { | |
1485 if (!arg.literal) { | |
1486 this.__addAnnotatedComputationEffect(arg.model, index, note, sig, arg); | |
1487 } | |
1488 }, this); | |
1489 } | |
1490 }, | |
1491 __addAnnotatedComputationEffect: function (property, index, note, sig, trigger)
{ | |
1492 this._addPropertyEffect(property, 'annotatedComputation', { | |
1493 index: index, | |
1494 kind: note.kind, | |
1495 property: note.name, | |
1496 negate: note.negate, | |
1497 method: sig.method, | |
1498 args: sig.args, | |
1499 trigger: trigger | |
1500 }); | |
1501 }, | |
1502 _parseMethod: function (expression) { | |
1503 var m = expression.match(/(\w*)\((.*)\)/); | |
1504 if (m) { | |
1505 var sig = { | |
1506 method: m[1], | |
1507 static: true | |
1508 }; | |
1509 if (m[2].trim()) { | |
1510 var args = m[2].replace(/\\,/g, ',').split(','); | |
1511 return this._parseArgs(args, sig); | |
1512 } else { | |
1513 sig.args = Polymer.nar; | |
1514 return sig; | |
1515 } | |
1516 } | |
1517 }, | |
1518 _parseArgs: function (argList, sig) { | |
1519 sig.args = argList.map(function (rawArg) { | |
1520 var arg = this._parseArg(rawArg); | |
1521 if (!arg.literal) { | |
1522 sig.static = false; | |
1523 } | |
1524 return arg; | |
1525 }, this); | |
1526 return sig; | |
1527 }, | |
1528 _parseArg: function (rawArg) { | |
1529 var arg = rawArg.trim().replace(/,/g, ',').replace(/\\(.)/g, '$1'); | |
1530 var a = { | |
1531 name: arg, | |
1532 model: this._modelForPath(arg) | |
1533 }; | |
1534 var fc = arg[0]; | |
1535 if (fc >= '0' && fc <= '9') { | |
1536 fc = '#'; | |
1537 } | |
1538 switch (fc) { | |
1539 case '\'': | |
1540 case '"': | |
1541 a.value = arg.slice(1, -1); | |
1542 a.literal = true; | |
1543 break; | |
1544 case '#': | |
1545 a.value = Number(arg); | |
1546 a.literal = true; | |
1547 break; | |
1548 } | |
1549 if (!a.literal) { | |
1550 a.structured = arg.indexOf('.') > 0; | |
1551 if (a.structured) { | |
1552 a.wildcard = arg.slice(-2) == '.*'; | |
1553 if (a.wildcard) { | |
1554 a.name = arg.slice(0, -2); | |
1555 } | |
1556 } | |
1557 } | |
1558 return a; | |
1559 }, | |
1560 _marshalInstanceEffects: function () { | |
1561 Polymer.Bind.prepareInstance(this); | |
1562 Polymer.Bind.setupBindListeners(this); | |
1563 }, | |
1564 _applyEffectValue: function (value, info) { | |
1565 var node = this._nodes[info.index]; | |
1566 var property = info.property || info.name || 'textContent'; | |
1567 if (info.kind == 'attribute') { | |
1568 this.serializeValueToAttribute(value, property, node); | |
1569 } else { | |
1570 if (property === 'className') { | |
1571 value = this._scopeElementClass(node, value); | |
1572 } | |
1573 if (property === 'textContent' || node.localName == 'input' && property == 'valu
e') { | |
1574 value = value == undefined ? '' : value; | |
1575 } | |
1576 return node[property] = value; | |
1577 } | |
1578 }, | |
1579 _executeStaticEffects: function () { | |
1580 if (this._propertyEffects.__static__) { | |
1581 this._effectEffects('__static__', null, this._propertyEffects.__static__); | |
1582 } | |
1583 } | |
1584 }); | |
1585 Polymer.Base._addFeature({ | |
1586 _setupConfigure: function (initialConfig) { | |
1587 this._config = initialConfig || {}; | |
1588 this._handlers = []; | |
1589 }, | |
1590 _marshalAttributes: function () { | |
1591 this._takeAttributesToModel(this._config); | |
1592 }, | |
1593 _configValue: function (name, value) { | |
1594 this._config[name] = value; | |
1595 }, | |
1596 _beforeClientsReady: function () { | |
1597 this._configure(); | |
1598 }, | |
1599 _configure: function () { | |
1600 this._configureAnnotationReferences(); | |
1601 this._aboveConfig = this.mixin({}, this._config); | |
1602 var config = {}; | |
1603 this.behaviors.forEach(function (b) { | |
1604 this._configureProperties(b.properties, config); | |
1605 }, this); | |
1606 this._configureProperties(this.properties, config); | |
1607 this._mixinConfigure(config, this._aboveConfig); | |
1608 this._config = config; | |
1609 this._distributeConfig(this._config); | |
1610 }, | |
1611 _configureProperties: function (properties, config) { | |
1612 for (var i in properties) { | |
1613 var c = properties[i]; | |
1614 if (c.value !== undefined) { | |
1615 var value = c.value; | |
1616 if (typeof value == 'function') { | |
1617 value = value.call(this, this._config); | |
1618 } | |
1619 config[i] = value; | |
1620 } | |
1621 } | |
1622 }, | |
1623 _mixinConfigure: function (a, b) { | |
1624 for (var prop in b) { | |
1625 if (!this.getPropertyInfo(prop).readOnly) { | |
1626 a[prop] = b[prop]; | |
1627 } | |
1628 } | |
1629 }, | |
1630 _distributeConfig: function (config) { | |
1631 var fx$ = this._propertyEffects; | |
1632 if (fx$) { | |
1633 for (var p in config) { | |
1634 var fx = fx$[p]; | |
1635 if (fx) { | |
1636 for (var i = 0, l = fx.length, x; i < l && (x = fx[i]); i++) { | |
1637 if (x.kind === 'annotation') { | |
1638 var node = this._nodes[x.effect.index]; | |
1639 if (node._configValue) { | |
1640 var value = p === x.effect.value ? config[p] : this.get(x.effect.value, config); | |
1641 node._configValue(x.effect.name, value); | |
1642 } | |
1643 } | |
1644 } | |
1645 } | |
1646 } | |
1647 } | |
1648 }, | |
1649 _afterClientsReady: function () { | |
1650 this._executeStaticEffects(); | |
1651 this._applyConfig(this._config, this._aboveConfig); | |
1652 this._flushHandlers(); | |
1653 }, | |
1654 _applyConfig: function (config, aboveConfig) { | |
1655 for (var n in config) { | |
1656 if (this[n] === undefined) { | |
1657 this.__setProperty(n, config[n], n in aboveConfig); | |
1658 } | |
1659 } | |
1660 }, | |
1661 _notifyListener: function (fn, e) { | |
1662 if (!this._clientsReadied) { | |
1663 this._queueHandler([ | |
1664 fn, | |
1665 e, | |
1666 e.target | |
1667 ]); | |
1668 } else { | |
1669 return fn.call(this, e, e.target); | |
1670 } | |
1671 }, | |
1672 _queueHandler: function (args) { | |
1673 this._handlers.push(args); | |
1674 }, | |
1675 _flushHandlers: function () { | |
1676 var h$ = this._handlers; | |
1677 for (var i = 0, l = h$.length, h; i < l && (h = h$[i]); i++) { | |
1678 h[0].call(this, h[1], h[2]); | |
1679 } | |
1680 } | |
1681 }); | |
1682 (function () { | |
1683 'use strict'; | |
1684 Polymer.Base._addFeature({ | |
1685 notifyPath: function (path, value, fromAbove) { | |
1686 var old = this._propertySetter(path, value); | |
1687 if (old !== value && (old === old || value === value)) { | |
1688 this._pathEffector(path, value); | |
1689 if (!fromAbove) { | |
1690 this._notifyPath(path, value); | |
1691 } | |
1692 return true; | |
1693 } | |
1694 }, | |
1695 _getPathParts: function (path) { | |
1696 if (Array.isArray(path)) { | |
1697 var parts = []; | |
1698 for (var i = 0; i < path.length; i++) { | |
1699 var args = path[i].toString().split('.'); | |
1700 for (var j = 0; j < args.length; j++) { | |
1701 parts.push(args[j]); | |
1702 } | |
1703 } | |
1704 return parts; | |
1705 } else { | |
1706 return path.toString().split('.'); | |
1707 } | |
1708 }, | |
1709 set: function (path, value, root) { | |
1710 var prop = root || this; | |
1711 var parts = this._getPathParts(path); | |
1712 var array; | |
1713 var last = parts[parts.length - 1]; | |
1714 if (parts.length > 1) { | |
1715 for (var i = 0; i < parts.length - 1; i++) { | |
1716 prop = prop[parts[i]]; | |
1717 if (array) { | |
1718 parts[i] = Polymer.Collection.get(array).getKey(prop); | |
1719 } | |
1720 if (!prop) { | |
1721 return; | |
1722 } | |
1723 array = Array.isArray(prop) ? prop : null; | |
1724 } | |
1725 if (array) { | |
1726 var coll = Polymer.Collection.get(array); | |
1727 var old = prop[last]; | |
1728 var key = coll.getKey(old); | |
1729 if (key) { | |
1730 parts[i] = key; | |
1731 coll.setItem(key, value); | |
1732 } | |
1733 } | |
1734 prop[last] = value; | |
1735 if (!root) { | |
1736 this.notifyPath(parts.join('.'), value); | |
1737 } | |
1738 } else { | |
1739 prop[path] = value; | |
1740 } | |
1741 }, | |
1742 get: function (path, root) { | |
1743 var prop = root || this; | |
1744 var parts = this._getPathParts(path); | |
1745 var last = parts.pop(); | |
1746 while (parts.length) { | |
1747 prop = prop[parts.shift()]; | |
1748 if (!prop) { | |
1749 return; | |
1750 } | |
1751 } | |
1752 return prop[last]; | |
1753 }, | |
1754 _pathEffector: function (path, value) { | |
1755 var model = this._modelForPath(path); | |
1756 var fx$ = this._propertyEffects[model]; | |
1757 if (fx$) { | |
1758 fx$.forEach(function (fx) { | |
1759 var fxFn = this['_' + fx.kind + 'PathEffect']; | |
1760 if (fxFn) { | |
1761 fxFn.call(this, path, value, fx.effect); | |
1762 } | |
1763 }, this); | |
1764 } | |
1765 if (this._boundPaths) { | |
1766 this._notifyBoundPaths(path, value); | |
1767 } | |
1768 }, | |
1769 _annotationPathEffect: function (path, value, effect) { | |
1770 if (effect.value === path || effect.value.indexOf(path + '.') === 0) { | |
1771 Polymer.Bind._annotationEffect.call(this, path, value, effect); | |
1772 } else if (path.indexOf(effect.value + '.') === 0 && !effect.negate) { | |
1773 var node = this._nodes[effect.index]; | |
1774 if (node && node.notifyPath) { | |
1775 var p = this._fixPath(effect.name, effect.value, path); | |
1776 node.notifyPath(p, value, true); | |
1777 } | |
1778 } | |
1779 }, | |
1780 _complexObserverPathEffect: function (path, value, effect) { | |
1781 if (this._pathMatchesEffect(path, effect)) { | |
1782 Polymer.Bind._complexObserverEffect.call(this, path, value, effect); | |
1783 } | |
1784 }, | |
1785 _computePathEffect: function (path, value, effect) { | |
1786 if (this._pathMatchesEffect(path, effect)) { | |
1787 Polymer.Bind._computeEffect.call(this, path, value, effect); | |
1788 } | |
1789 }, | |
1790 _annotatedComputationPathEffect: function (path, value, effect) { | |
1791 if (this._pathMatchesEffect(path, effect)) { | |
1792 Polymer.Bind._annotatedComputationEffect.call(this, path, value, effect); | |
1793 } | |
1794 }, | |
1795 _pathMatchesEffect: function (path, effect) { | |
1796 var effectArg = effect.trigger.name; | |
1797 return effectArg == path || effectArg.indexOf(path + '.') === 0 || effect.trigge
r.wildcard && path.indexOf(effectArg) === 0; | |
1798 }, | |
1799 linkPaths: function (to, from) { | |
1800 this._boundPaths = this._boundPaths || {}; | |
1801 if (from) { | |
1802 this._boundPaths[to] = from; | |
1803 } else { | |
1804 this.unbindPath(to); | |
1805 } | |
1806 }, | |
1807 unlinkPaths: function (path) { | |
1808 if (this._boundPaths) { | |
1809 delete this._boundPaths[path]; | |
1810 } | |
1811 }, | |
1812 _notifyBoundPaths: function (path, value) { | |
1813 var from, to; | |
1814 for (var a in this._boundPaths) { | |
1815 var b = this._boundPaths[a]; | |
1816 if (path.indexOf(a + '.') == 0) { | |
1817 from = a; | |
1818 to = b; | |
1819 break; | |
1820 } | |
1821 if (path.indexOf(b + '.') == 0) { | |
1822 from = b; | |
1823 to = a; | |
1824 break; | |
1825 } | |
1826 } | |
1827 if (from && to) { | |
1828 var p = this._fixPath(to, from, path); | |
1829 this.notifyPath(p, value); | |
1830 } | |
1831 }, | |
1832 _fixPath: function (property, root, path) { | |
1833 return property + path.slice(root.length); | |
1834 }, | |
1835 _notifyPath: function (path, value) { | |
1836 var rootName = this._modelForPath(path); | |
1837 var dashCaseName = Polymer.CaseMap.camelToDashCase(rootName); | |
1838 var eventName = dashCaseName + this._EVENT_CHANGED; | |
1839 this.fire(eventName, { | |
1840 path: path, | |
1841 value: value | |
1842 }, { bubbles: false }); | |
1843 }, | |
1844 _modelForPath: function (path) { | |
1845 var dot = path.indexOf('.'); | |
1846 return dot < 0 ? path : path.slice(0, dot); | |
1847 }, | |
1848 _EVENT_CHANGED: '-changed', | |
1849 _notifySplice: function (array, path, index, added, removed) { | |
1850 var splices = [{ | |
1851 index: index, | |
1852 addedCount: added, | |
1853 removed: removed, | |
1854 object: array, | |
1855 type: 'splice' | |
1856 }]; | |
1857 var change = { | |
1858 keySplices: Polymer.Collection.applySplices(array, splices), | |
1859 indexSplices: splices | |
1860 }; | |
1861 this.set(path + '.splices', change); | |
1862 if (added != removed.length) { | |
1863 this.notifyPath(path + '.length', array.length); | |
1864 } | |
1865 change.keySplices = null; | |
1866 change.indexSplices = null; | |
1867 }, | |
1868 push: function (path) { | |
1869 var array = this.get(path); | |
1870 var args = Array.prototype.slice.call(arguments, 1); | |
1871 var len = array.length; | |
1872 var ret = array.push.apply(array, args); | |
1873 this._notifySplice(array, path, len, args.length, []); | |
1874 return ret; | |
1875 }, | |
1876 pop: function (path) { | |
1877 var array = this.get(path); | |
1878 var args = Array.prototype.slice.call(arguments, 1); | |
1879 var rem = array.slice(-1); | |
1880 var ret = array.pop.apply(array, args); | |
1881 this._notifySplice(array, path, array.length, 0, rem); | |
1882 return ret; | |
1883 }, | |
1884 splice: function (path, start, deleteCount) { | |
1885 var array = this.get(path); | |
1886 var args = Array.prototype.slice.call(arguments, 1); | |
1887 var ret = array.splice.apply(array, args); | |
1888 this._notifySplice(array, path, start, args.length - 2, ret); | |
1889 return ret; | |
1890 }, | |
1891 shift: function (path) { | |
1892 var array = this.get(path); | |
1893 var args = Array.prototype.slice.call(arguments, 1); | |
1894 var ret = array.shift.apply(array, args); | |
1895 this._notifySplice(array, path, 0, 0, [ret]); | |
1896 return ret; | |
1897 }, | |
1898 unshift: function (path) { | |
1899 var array = this.get(path); | |
1900 var args = Array.prototype.slice.call(arguments, 1); | |
1901 var ret = array.unshift.apply(array, args); | |
1902 this._notifySplice(array, path, 0, args.length, []); | |
1903 return ret; | |
1904 } | |
1905 }); | |
1906 }()); | |
1907 Polymer.Base._addFeature({ | |
1908 resolveUrl: function (url) { | |
1909 var module = Polymer.DomModule.import(this.is); | |
1910 var root = ''; | |
1911 if (module) { | |
1912 var assetPath = module.getAttribute('assetpath') || ''; | |
1913 root = Polymer.ResolveUrl.resolveUrl(assetPath, module.ownerDocument.baseURI); | |
1914 } | |
1915 return Polymer.ResolveUrl.resolveUrl(url, root); | |
1916 } | |
1917 }); | |
1918 Polymer.CssParse = function () { | |
1919 var api = { | |
1920 parse: function (text) { | |
1921 text = this._clean(text); | |
1922 return this._parseCss(this._lex(text), text); | |
1923 }, | |
1924 _clean: function (cssText) { | |
1925 return cssText.replace(rx.comments, '').replace(rx.port, ''); | |
1926 }, | |
1927 _lex: function (text) { | |
1928 var root = { | |
1929 start: 0, | |
1930 end: text.length | |
1931 }; | |
1932 var n = root; | |
1933 for (var i = 0, s = 0, l = text.length; i < l; i++) { | |
1934 switch (text[i]) { | |
1935 case this.OPEN_BRACE: | |
1936 if (!n.rules) { | |
1937 n.rules = []; | |
1938 } | |
1939 var p = n; | |
1940 var previous = p.rules[p.rules.length - 1]; | |
1941 n = { | |
1942 start: i + 1, | |
1943 parent: p, | |
1944 previous: previous | |
1945 }; | |
1946 p.rules.push(n); | |
1947 break; | |
1948 case this.CLOSE_BRACE: | |
1949 n.end = i + 1; | |
1950 n = n.parent || root; | |
1951 break; | |
1952 } | |
1953 } | |
1954 return root; | |
1955 }, | |
1956 _parseCss: function (node, text) { | |
1957 var t = text.substring(node.start, node.end - 1); | |
1958 node.parsedCssText = node.cssText = t.trim(); | |
1959 if (node.parent) { | |
1960 var ss = node.previous ? node.previous.end : node.parent.start; | |
1961 t = text.substring(ss, node.start - 1); | |
1962 t = t.substring(t.lastIndexOf(';') + 1); | |
1963 var s = node.parsedSelector = node.selector = t.trim(); | |
1964 node.atRule = s.indexOf(AT_START) === 0; | |
1965 if (node.atRule) { | |
1966 if (s.indexOf(MEDIA_START) === 0) { | |
1967 node.type = this.types.MEDIA_RULE; | |
1968 } else if (s.match(rx.keyframesRule)) { | |
1969 node.type = this.types.KEYFRAMES_RULE; | |
1970 } | |
1971 } else { | |
1972 if (s.indexOf(VAR_START) === 0) { | |
1973 node.type = this.types.MIXIN_RULE; | |
1974 } else { | |
1975 node.type = this.types.STYLE_RULE; | |
1976 } | |
1977 } | |
1978 } | |
1979 var r$ = node.rules; | |
1980 if (r$) { | |
1981 for (var i = 0, l = r$.length, r; i < l && (r = r$[i]); i++) { | |
1982 this._parseCss(r, text); | |
1983 } | |
1984 } | |
1985 return node; | |
1986 }, | |
1987 stringify: function (node, preserveProperties, text) { | |
1988 text = text || ''; | |
1989 var cssText = ''; | |
1990 if (node.cssText || node.rules) { | |
1991 var r$ = node.rules; | |
1992 if (r$ && (preserveProperties || !hasMixinRules(r$))) { | |
1993 for (var i = 0, l = r$.length, r; i < l && (r = r$[i]); i++) { | |
1994 cssText = this.stringify(r, preserveProperties, cssText); | |
1995 } | |
1996 } else { | |
1997 cssText = preserveProperties ? node.cssText : removeCustomProps(node.cssText); | |
1998 cssText = cssText.trim(); | |
1999 if (cssText) { | |
2000 cssText = ' ' + cssText + '\n'; | |
2001 } | |
2002 } | |
2003 } | |
2004 if (cssText) { | |
2005 if (node.selector) { | |
2006 text += node.selector + ' ' + this.OPEN_BRACE + '\n'; | |
2007 } | |
2008 text += cssText; | |
2009 if (node.selector) { | |
2010 text += this.CLOSE_BRACE + '\n\n'; | |
2011 } | |
2012 } | |
2013 return text; | |
2014 }, | |
2015 types: { | |
2016 STYLE_RULE: 1, | |
2017 KEYFRAMES_RULE: 7, | |
2018 MEDIA_RULE: 4, | |
2019 MIXIN_RULE: 1000 | |
2020 }, | |
2021 OPEN_BRACE: '{', | |
2022 CLOSE_BRACE: '}' | |
2023 }; | |
2024 function hasMixinRules(rules) { | |
2025 return rules[0].selector.indexOf(VAR_START) >= 0; | |
2026 } | |
2027 function removeCustomProps(cssText) { | |
2028 return cssText.replace(rx.customProp, '').replace(rx.mixinProp, '').replace(rx.m
ixinApply, '').replace(rx.varApply, ''); | |
2029 } | |
2030 var VAR_START = '--'; | |
2031 var MEDIA_START = '@media'; | |
2032 var AT_START = '@'; | |
2033 var rx = { | |
2034 comments: /\/\*[^*]*\*+([^\/*][^*]*\*+)*\//gim, | |
2035 port: /@import[^;]*;/gim, | |
2036 customProp: /(?:^|[\s;])--[^;{]*?:[^{};]*?(?:[;\n]|$)/gim, | |
2037 mixinProp: /(?:^|[\s;])--[^;{]*?:[^{;]*?{[^}]*?}(?:[;\n]|$)?/gim, | |
2038 mixinApply: /@apply[\s]*\([^)]*?\)[\s]*(?:[;\n]|$)?/gim, | |
2039 varApply: /[^;:]*?:[^;]*var[^;]*(?:[;\n]|$)?/gim, | |
2040 keyframesRule: /^@[^\s]*keyframes/ | |
2041 }; | |
2042 return api; | |
2043 }(); | |
2044 Polymer.StyleUtil = function () { | |
2045 return { | |
2046 MODULE_STYLES_SELECTOR: 'style, link[rel=import][type~=css]', | |
2047 toCssText: function (rules, callback, preserveProperties) { | |
2048 if (typeof rules === 'string') { | |
2049 rules = this.parser.parse(rules); | |
2050 } | |
2051 if (callback) { | |
2052 this.forEachStyleRule(rules, callback); | |
2053 } | |
2054 return this.parser.stringify(rules, preserveProperties); | |
2055 }, | |
2056 forRulesInStyles: function (styles, callback) { | |
2057 if (styles) { | |
2058 for (var i = 0, l = styles.length, s; i < l && (s = styles[i]); i++) { | |
2059 this.forEachStyleRule(this.rulesForStyle(s), callback); | |
2060 } | |
2061 } | |
2062 }, | |
2063 rulesForStyle: function (style) { | |
2064 if (!style.__cssRules && style.textContent) { | |
2065 style.__cssRules = this.parser.parse(style.textContent); | |
2066 } | |
2067 return style.__cssRules; | |
2068 }, | |
2069 clearStyleRules: function (style) { | |
2070 style.__cssRules = null; | |
2071 }, | |
2072 forEachStyleRule: function (node, callback) { | |
2073 var s = node.selector; | |
2074 var skipRules = false; | |
2075 if (node.type === this.ruleTypes.STYLE_RULE) { | |
2076 callback(node); | |
2077 } else if (node.type === this.ruleTypes.KEYFRAMES_RULE || node.type === this.rul
eTypes.MIXIN_RULE) { | |
2078 skipRules = true; | |
2079 } | |
2080 var r$ = node.rules; | |
2081 if (r$ && !skipRules) { | |
2082 for (var i = 0, l = r$.length, r; i < l && (r = r$[i]); i++) { | |
2083 this.forEachStyleRule(r, callback); | |
2084 } | |
2085 } | |
2086 }, | |
2087 applyCss: function (cssText, moniker, target, afterNode) { | |
2088 var style = document.createElement('style'); | |
2089 if (moniker) { | |
2090 style.setAttribute('scope', moniker); | |
2091 } | |
2092 style.textContent = cssText; | |
2093 target = target || document.head; | |
2094 if (!afterNode) { | |
2095 var n$ = target.querySelectorAll('style[scope]'); | |
2096 afterNode = n$[n$.length - 1]; | |
2097 } | |
2098 target.insertBefore(style, afterNode && afterNode.nextSibling || target.firstChi
ld); | |
2099 return style; | |
2100 }, | |
2101 cssFromModule: function (moduleId) { | |
2102 var m = Polymer.DomModule.import(moduleId); | |
2103 if (m && !m._cssText) { | |
2104 var cssText = ''; | |
2105 var e$ = Array.prototype.slice.call(m.querySelectorAll(this.MODULE_STYLES_SELECT
OR)); | |
2106 for (var i = 0, e; i < e$.length; i++) { | |
2107 e = e$[i]; | |
2108 if (e.localName === 'style') { | |
2109 e = e.__appliedElement || e; | |
2110 e.parentNode.removeChild(e); | |
2111 } else { | |
2112 e = e.import && e.import.body; | |
2113 } | |
2114 if (e) { | |
2115 cssText += Polymer.ResolveUrl.resolveCss(e.textContent, e.ownerDocument); | |
2116 } | |
2117 } | |
2118 m._cssText = cssText; | |
2119 } | |
2120 return m && m._cssText || ''; | |
2121 }, | |
2122 parser: Polymer.CssParse, | |
2123 ruleTypes: Polymer.CssParse.types | |
2124 }; | |
2125 }(); | |
2126 Polymer.StyleTransformer = function () { | |
2127 var nativeShadow = Polymer.Settings.useNativeShadow; | |
2128 var styleUtil = Polymer.StyleUtil; | |
2129 var api = { | |
2130 dom: function (node, scope, useAttr, shouldRemoveScope) { | |
2131 this._transformDom(node, scope || '', useAttr, shouldRemoveScope); | |
2132 }, | |
2133 _transformDom: function (node, selector, useAttr, shouldRemoveScope) { | |
2134 if (node.setAttribute) { | |
2135 this.element(node, selector, useAttr, shouldRemoveScope); | |
2136 } | |
2137 var c$ = Polymer.dom(node).childNodes; | |
2138 for (var i = 0; i < c$.length; i++) { | |
2139 this._transformDom(c$[i], selector, useAttr, shouldRemoveScope); | |
2140 } | |
2141 }, | |
2142 element: function (element, scope, useAttr, shouldRemoveScope) { | |
2143 if (useAttr) { | |
2144 if (shouldRemoveScope) { | |
2145 element.removeAttribute(SCOPE_NAME); | |
2146 } else { | |
2147 element.setAttribute(SCOPE_NAME, scope); | |
2148 } | |
2149 } else { | |
2150 if (scope) { | |
2151 if (element.classList) { | |
2152 if (shouldRemoveScope) { | |
2153 element.classList.remove(SCOPE_NAME); | |
2154 element.classList.remove(scope); | |
2155 } else { | |
2156 element.classList.add(SCOPE_NAME); | |
2157 element.classList.add(scope); | |
2158 } | |
2159 } else if (element.getAttribute) { | |
2160 var c = element.getAttribute(CLASS); | |
2161 if (shouldRemoveScope) { | |
2162 if (c) { | |
2163 element.setAttribute(CLASS, c.replace(SCOPE_NAME, '').replace(scope, '')); | |
2164 } | |
2165 } else { | |
2166 element.setAttribute(CLASS, c + (c ? ' ' : '') + SCOPE_NAME + ' ' + scope); | |
2167 } | |
2168 } | |
2169 } | |
2170 } | |
2171 }, | |
2172 elementStyles: function (element, callback) { | |
2173 var styles = element._styles; | |
2174 var cssText = ''; | |
2175 for (var i = 0, l = styles.length, s, text; i < l && (s = styles[i]); i++) { | |
2176 var rules = styleUtil.rulesForStyle(s); | |
2177 cssText += nativeShadow ? styleUtil.toCssText(rules, callback) : this.css(rules,
element.is, element.extends, callback, element._scopeCssViaAttr) + '\n\n'; | |
2178 } | |
2179 return cssText.trim(); | |
2180 }, | |
2181 css: function (rules, scope, ext, callback, useAttr) { | |
2182 var hostScope = this._calcHostScope(scope, ext); | |
2183 scope = this._calcElementScope(scope, useAttr); | |
2184 var self = this; | |
2185 return styleUtil.toCssText(rules, function (rule) { | |
2186 if (!rule.isScoped) { | |
2187 self.rule(rule, scope, hostScope); | |
2188 rule.isScoped = true; | |
2189 } | |
2190 if (callback) { | |
2191 callback(rule, scope, hostScope); | |
2192 } | |
2193 }); | |
2194 }, | |
2195 _calcElementScope: function (scope, useAttr) { | |
2196 if (scope) { | |
2197 return useAttr ? CSS_ATTR_PREFIX + scope + CSS_ATTR_SUFFIX : CSS_CLASS_PREFIX +
scope; | |
2198 } else { | |
2199 return ''; | |
2200 } | |
2201 }, | |
2202 _calcHostScope: function (scope, ext) { | |
2203 return ext ? '[is=' + scope + ']' : scope; | |
2204 }, | |
2205 rule: function (rule, scope, hostScope) { | |
2206 this._transformRule(rule, this._transformComplexSelector, scope, hostScope); | |
2207 }, | |
2208 _transformRule: function (rule, transformer, scope, hostScope) { | |
2209 var p$ = rule.selector.split(COMPLEX_SELECTOR_SEP); | |
2210 for (var i = 0, l = p$.length, p; i < l && (p = p$[i]); i++) { | |
2211 p$[i] = transformer.call(this, p, scope, hostScope); | |
2212 } | |
2213 rule.selector = p$.join(COMPLEX_SELECTOR_SEP); | |
2214 }, | |
2215 _transformComplexSelector: function (selector, scope, hostScope) { | |
2216 var stop = false; | |
2217 var hostContext = false; | |
2218 var self = this; | |
2219 selector = selector.replace(SIMPLE_SELECTOR_SEP, function (m, c, s) { | |
2220 if (!stop) { | |
2221 var info = self._transformCompoundSelector(s, c, scope, hostScope); | |
2222 stop = stop || info.stop; | |
2223 hostContext = hostContext || info.hostContext; | |
2224 c = info.combinator; | |
2225 s = info.value; | |
2226 } else { | |
2227 s = s.replace(SCOPE_JUMP, ' '); | |
2228 } | |
2229 return c + s; | |
2230 }); | |
2231 if (hostContext) { | |
2232 selector = selector.replace(HOST_CONTEXT_PAREN, function (m, pre, paren, post) { | |
2233 return pre + paren + ' ' + hostScope + post + COMPLEX_SELECTOR_SEP + ' ' + pre +
hostScope + paren + post; | |
2234 }); | |
2235 } | |
2236 return selector; | |
2237 }, | |
2238 _transformCompoundSelector: function (selector, combinator, scope, hostScope) { | |
2239 var jumpIndex = selector.search(SCOPE_JUMP); | |
2240 var hostContext = false; | |
2241 if (selector.indexOf(HOST_CONTEXT) >= 0) { | |
2242 hostContext = true; | |
2243 } else if (selector.indexOf(HOST) >= 0) { | |
2244 selector = selector.replace(HOST_PAREN, function (m, host, paren) { | |
2245 return hostScope + paren; | |
2246 }); | |
2247 selector = selector.replace(HOST, hostScope); | |
2248 } else if (jumpIndex !== 0) { | |
2249 selector = scope ? this._transformSimpleSelector(selector, scope) : selector; | |
2250 } | |
2251 if (selector.indexOf(CONTENT) >= 0) { | |
2252 combinator = ''; | |
2253 } | |
2254 var stop; | |
2255 if (jumpIndex >= 0) { | |
2256 selector = selector.replace(SCOPE_JUMP, ' '); | |
2257 stop = true; | |
2258 } | |
2259 return { | |
2260 value: selector, | |
2261 combinator: combinator, | |
2262 stop: stop, | |
2263 hostContext: hostContext | |
2264 }; | |
2265 }, | |
2266 _transformSimpleSelector: function (selector, scope) { | |
2267 var p$ = selector.split(PSEUDO_PREFIX); | |
2268 p$[0] += scope; | |
2269 return p$.join(PSEUDO_PREFIX); | |
2270 }, | |
2271 documentRule: function (rule) { | |
2272 rule.selector = rule.parsedSelector; | |
2273 this.normalizeRootSelector(rule); | |
2274 if (!nativeShadow) { | |
2275 this._transformRule(rule, this._transformDocumentSelector); | |
2276 } | |
2277 }, | |
2278 normalizeRootSelector: function (rule) { | |
2279 if (rule.selector === ROOT) { | |
2280 rule.selector = 'body'; | |
2281 } | |
2282 }, | |
2283 _transformDocumentSelector: function (selector) { | |
2284 return selector.match(SCOPE_JUMP) ? this._transformComplexSelector(selector, SCO
PE_DOC_SELECTOR) : this._transformSimpleSelector(selector.trim(), SCOPE_DOC_SELE
CTOR); | |
2285 }, | |
2286 SCOPE_NAME: 'style-scope' | |
2287 }; | |
2288 var SCOPE_NAME = api.SCOPE_NAME; | |
2289 var SCOPE_DOC_SELECTOR = ':not([' + SCOPE_NAME + '])' + ':not(.' + SCOPE_NAME +
')'; | |
2290 var COMPLEX_SELECTOR_SEP = ','; | |
2291 var SIMPLE_SELECTOR_SEP = /(^|[\s>+~]+)([^\s>+~]+)/g; | |
2292 var HOST = ':host'; | |
2293 var ROOT = ':root'; | |
2294 var HOST_PAREN = /(\:host)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/g; | |
2295 var HOST_CONTEXT = ':host-context'; | |
2296 var HOST_CONTEXT_PAREN = /(.*)(?:\:host-context)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\)
)(.*)/; | |
2297 var CONTENT = '::content'; | |
2298 var SCOPE_JUMP = /\:\:content|\:\:shadow|\/deep\//; | |
2299 var CSS_CLASS_PREFIX = '.'; | |
2300 var CSS_ATTR_PREFIX = '[' + SCOPE_NAME + '~='; | |
2301 var CSS_ATTR_SUFFIX = ']'; | |
2302 var PSEUDO_PREFIX = ':'; | |
2303 var CLASS = 'class'; | |
2304 return api; | |
2305 }(); | |
2306 Polymer.StyleExtends = function () { | |
2307 var styleUtil = Polymer.StyleUtil; | |
2308 return { | |
2309 hasExtends: function (cssText) { | |
2310 return Boolean(cssText.match(this.rx.EXTEND)); | |
2311 }, | |
2312 transform: function (style) { | |
2313 var rules = styleUtil.rulesForStyle(style); | |
2314 var self = this; | |
2315 styleUtil.forEachStyleRule(rules, function (rule) { | |
2316 var map = self._mapRule(rule); | |
2317 if (rule.parent) { | |
2318 var m; | |
2319 while (m = self.rx.EXTEND.exec(rule.cssText)) { | |
2320 var extend = m[1]; | |
2321 var extendor = self._findExtendor(extend, rule); | |
2322 if (extendor) { | |
2323 self._extendRule(rule, extendor); | |
2324 } | |
2325 } | |
2326 } | |
2327 rule.cssText = rule.cssText.replace(self.rx.EXTEND, ''); | |
2328 }); | |
2329 return styleUtil.toCssText(rules, function (rule) { | |
2330 if (rule.selector.match(self.rx.STRIP)) { | |
2331 rule.cssText = ''; | |
2332 } | |
2333 }, true); | |
2334 }, | |
2335 _mapRule: function (rule) { | |
2336 if (rule.parent) { | |
2337 var map = rule.parent.map || (rule.parent.map = {}); | |
2338 var parts = rule.selector.split(','); | |
2339 for (var i = 0, p; i < parts.length; i++) { | |
2340 p = parts[i]; | |
2341 map[p.trim()] = rule; | |
2342 } | |
2343 return map; | |
2344 } | |
2345 }, | |
2346 _findExtendor: function (extend, rule) { | |
2347 return rule.parent && rule.parent.map && rule.parent.map[extend] || this._findEx
tendor(extend, rule.parent); | |
2348 }, | |
2349 _extendRule: function (target, source) { | |
2350 if (target.parent !== source.parent) { | |
2351 this._cloneAndAddRuleToParent(source, target.parent); | |
2352 } | |
2353 target.extends = target.extends || (target.extends = []); | |
2354 target.extends.push(source); | |
2355 source.selector = source.selector.replace(this.rx.STRIP, ''); | |
2356 source.selector = (source.selector && source.selector + ',\n') + target.selector
; | |
2357 if (source.extends) { | |
2358 source.extends.forEach(function (e) { | |
2359 this._extendRule(target, e); | |
2360 }, this); | |
2361 } | |
2362 }, | |
2363 _cloneAndAddRuleToParent: function (rule, parent) { | |
2364 rule = Object.create(rule); | |
2365 rule.parent = parent; | |
2366 if (rule.extends) { | |
2367 rule.extends = rule.extends.slice(); | |
2368 } | |
2369 parent.rules.push(rule); | |
2370 }, | |
2371 rx: { | |
2372 EXTEND: /@extends\(([^)]*)\)\s*?;/gim, | |
2373 STRIP: /%[^,]*$/ | |
2374 } | |
2375 }; | |
2376 }(); | |
2377 (function () { | |
2378 var prepElement = Polymer.Base._prepElement; | |
2379 var nativeShadow = Polymer.Settings.useNativeShadow; | |
2380 var styleUtil = Polymer.StyleUtil; | |
2381 var styleTransformer = Polymer.StyleTransformer; | |
2382 var styleExtends = Polymer.StyleExtends; | |
2383 Polymer.Base._addFeature({ | |
2384 _prepElement: function (element) { | |
2385 if (this._encapsulateStyle) { | |
2386 styleTransformer.element(element, this.is, this._scopeCssViaAttr); | |
2387 } | |
2388 prepElement.call(this, element); | |
2389 }, | |
2390 _prepStyles: function () { | |
2391 if (this._encapsulateStyle === undefined) { | |
2392 this._encapsulateStyle = !nativeShadow && Boolean(this._template); | |
2393 } | |
2394 this._styles = this._collectStyles(); | |
2395 var cssText = styleTransformer.elementStyles(this); | |
2396 if (cssText && this._template) { | |
2397 var style = styleUtil.applyCss(cssText, this.is, nativeShadow ? this._template.c
ontent : null); | |
2398 if (!nativeShadow) { | |
2399 this._scopeStyle = style; | |
2400 } | |
2401 } | |
2402 }, | |
2403 _collectStyles: function () { | |
2404 var styles = []; | |
2405 var cssText = '', m$ = this.styleModules; | |
2406 if (m$) { | |
2407 for (var i = 0, l = m$.length, m; i < l && (m = m$[i]); i++) { | |
2408 cssText += styleUtil.cssFromModule(m); | |
2409 } | |
2410 } | |
2411 cssText += styleUtil.cssFromModule(this.is); | |
2412 if (cssText) { | |
2413 var style = document.createElement('style'); | |
2414 style.textContent = cssText; | |
2415 if (styleExtends.hasExtends(style.textContent)) { | |
2416 cssText = styleExtends.transform(style); | |
2417 } | |
2418 styles.push(style); | |
2419 } | |
2420 return styles; | |
2421 }, | |
2422 _elementAdd: function (node) { | |
2423 if (this._encapsulateStyle) { | |
2424 if (node.__styleScoped) { | |
2425 node.__styleScoped = false; | |
2426 } else { | |
2427 styleTransformer.dom(node, this.is, this._scopeCssViaAttr); | |
2428 } | |
2429 } | |
2430 }, | |
2431 _elementRemove: function (node) { | |
2432 if (this._encapsulateStyle) { | |
2433 styleTransformer.dom(node, this.is, this._scopeCssViaAttr, true); | |
2434 } | |
2435 }, | |
2436 scopeSubtree: function (container, shouldObserve) { | |
2437 if (nativeShadow) { | |
2438 return; | |
2439 } | |
2440 var self = this; | |
2441 var scopify = function (node) { | |
2442 if (node.nodeType === Node.ELEMENT_NODE) { | |
2443 node.className = self._scopeElementClass(node, node.className); | |
2444 var n$ = node.querySelectorAll('*'); | |
2445 Array.prototype.forEach.call(n$, function (n) { | |
2446 n.className = self._scopeElementClass(n, n.className); | |
2447 }); | |
2448 } | |
2449 }; | |
2450 scopify(container); | |
2451 if (shouldObserve) { | |
2452 var mo = new MutationObserver(function (mxns) { | |
2453 mxns.forEach(function (m) { | |
2454 if (m.addedNodes) { | |
2455 for (var i = 0; i < m.addedNodes.length; i++) { | |
2456 scopify(m.addedNodes[i]); | |
2457 } | |
2458 } | |
2459 }); | |
2460 }); | |
2461 mo.observe(container, { | |
2462 childList: true, | |
2463 subtree: true | |
2464 }); | |
2465 return mo; | |
2466 } | |
2467 } | |
2468 }); | |
2469 }()); | |
2470 Polymer.StyleProperties = function () { | |
2471 'use strict'; | |
2472 var nativeShadow = Polymer.Settings.useNativeShadow; | |
2473 var matchesSelector = Polymer.DomApi.matchesSelector; | |
2474 var styleUtil = Polymer.StyleUtil; | |
2475 var styleTransformer = Polymer.StyleTransformer; | |
2476 return { | |
2477 decorateStyles: function (styles) { | |
2478 var self = this, props = {}; | |
2479 styleUtil.forRulesInStyles(styles, function (rule) { | |
2480 self.decorateRule(rule); | |
2481 self.collectPropertiesInCssText(rule.propertyInfo.cssText, props); | |
2482 }); | |
2483 var names = []; | |
2484 for (var i in props) { | |
2485 names.push(i); | |
2486 } | |
2487 return names; | |
2488 }, | |
2489 decorateRule: function (rule) { | |
2490 if (rule.propertyInfo) { | |
2491 return rule.propertyInfo; | |
2492 } | |
2493 var info = {}, properties = {}; | |
2494 var hasProperties = this.collectProperties(rule, properties); | |
2495 if (hasProperties) { | |
2496 info.properties = properties; | |
2497 rule.rules = null; | |
2498 } | |
2499 info.cssText = this.collectCssText(rule); | |
2500 rule.propertyInfo = info; | |
2501 return info; | |
2502 }, | |
2503 collectProperties: function (rule, properties) { | |
2504 var info = rule.propertyInfo; | |
2505 if (info) { | |
2506 if (info.properties) { | |
2507 Polymer.Base.mixin(properties, info.properties); | |
2508 return true; | |
2509 } | |
2510 } else { | |
2511 var m, rx = this.rx.VAR_ASSIGN; | |
2512 var cssText = rule.parsedCssText; | |
2513 var any; | |
2514 while (m = rx.exec(cssText)) { | |
2515 properties[m[1]] = (m[2] || m[3]).trim(); | |
2516 any = true; | |
2517 } | |
2518 return any; | |
2519 } | |
2520 }, | |
2521 collectCssText: function (rule) { | |
2522 var customCssText = ''; | |
2523 var cssText = rule.parsedCssText; | |
2524 cssText = cssText.replace(this.rx.BRACKETED, '').replace(this.rx.VAR_ASSIGN, '')
; | |
2525 var parts = cssText.split(';'); | |
2526 for (var i = 0, p; i < parts.length; i++) { | |
2527 p = parts[i]; | |
2528 if (p.match(this.rx.MIXIN_MATCH) || p.match(this.rx.VAR_MATCH)) { | |
2529 customCssText += p + ';\n'; | |
2530 } | |
2531 } | |
2532 return customCssText; | |
2533 }, | |
2534 collectPropertiesInCssText: function (cssText, props) { | |
2535 var m; | |
2536 while (m = this.rx.VAR_CAPTURE.exec(cssText)) { | |
2537 props[m[1]] = true; | |
2538 var def = m[2]; | |
2539 if (def && def.match(this.rx.IS_VAR)) { | |
2540 props[def] = true; | |
2541 } | |
2542 } | |
2543 }, | |
2544 reify: function (props) { | |
2545 var names = Object.getOwnPropertyNames(props); | |
2546 for (var i = 0, n; i < names.length; i++) { | |
2547 n = names[i]; | |
2548 props[n] = this.valueForProperty(props[n], props); | |
2549 } | |
2550 }, | |
2551 valueForProperty: function (property, props) { | |
2552 if (property) { | |
2553 if (property.indexOf(';') >= 0) { | |
2554 property = this.valueForProperties(property, props); | |
2555 } else { | |
2556 var self = this; | |
2557 var fn = function (all, prefix, value, fallback) { | |
2558 var propertyValue = self.valueForProperty(props[value], props) || (props[fallbac
k] ? self.valueForProperty(props[fallback], props) : fallback); | |
2559 return prefix + (propertyValue || ''); | |
2560 }; | |
2561 property = property.replace(this.rx.VAR_MATCH, fn); | |
2562 } | |
2563 } | |
2564 return property && property.trim() || ''; | |
2565 }, | |
2566 valueForProperties: function (property, props) { | |
2567 var parts = property.split(';'); | |
2568 for (var i = 0, p, m; i < parts.length && (p = parts[i]); i++) { | |
2569 m = p.match(this.rx.MIXIN_MATCH); | |
2570 if (m) { | |
2571 p = this.valueForProperty(props[m[1]], props); | |
2572 } else { | |
2573 var pp = p.split(':'); | |
2574 if (pp[1]) { | |
2575 pp[1] = pp[1].trim(); | |
2576 pp[1] = this.valueForProperty(pp[1], props) || pp[1]; | |
2577 } | |
2578 p = pp.join(':'); | |
2579 } | |
2580 parts[i] = p && p.lastIndexOf(';') === p.length - 1 ? p.slice(0, -1) : p || ''; | |
2581 } | |
2582 return parts.join(';'); | |
2583 }, | |
2584 applyProperties: function (rule, props) { | |
2585 var output = ''; | |
2586 if (!rule.propertyInfo) { | |
2587 this.decorateRule(rule); | |
2588 } | |
2589 if (rule.propertyInfo.cssText) { | |
2590 output = this.valueForProperties(rule.propertyInfo.cssText, props); | |
2591 } | |
2592 rule.cssText = output; | |
2593 }, | |
2594 propertyDataFromStyles: function (styles, element) { | |
2595 var props = {}, self = this; | |
2596 var o = [], i = 0; | |
2597 styleUtil.forRulesInStyles(styles, function (rule) { | |
2598 if (!rule.propertyInfo) { | |
2599 self.decorateRule(rule); | |
2600 } | |
2601 if (element && rule.propertyInfo.properties && matchesSelector.call(element, rul
e.selector)) { | |
2602 self.collectProperties(rule, props); | |
2603 addToBitMask(i, o); | |
2604 } | |
2605 i++; | |
2606 }); | |
2607 return { | |
2608 properties: props, | |
2609 key: o | |
2610 }; | |
2611 }, | |
2612 scopePropertiesFromStyles: function (styles) { | |
2613 if (!styles._scopeStyleProperties) { | |
2614 styles._scopeStyleProperties = this.selectedPropertiesFromStyles(styles, this.SC
OPE_SELECTORS); | |
2615 } | |
2616 return styles._scopeStyleProperties; | |
2617 }, | |
2618 hostPropertiesFromStyles: function (styles) { | |
2619 if (!styles._hostStyleProperties) { | |
2620 styles._hostStyleProperties = this.selectedPropertiesFromStyles(styles, this.HOS
T_SELECTORS); | |
2621 } | |
2622 return styles._hostStyleProperties; | |
2623 }, | |
2624 selectedPropertiesFromStyles: function (styles, selectors) { | |
2625 var props = {}, self = this; | |
2626 styleUtil.forRulesInStyles(styles, function (rule) { | |
2627 if (!rule.propertyInfo) { | |
2628 self.decorateRule(rule); | |
2629 } | |
2630 for (var i = 0; i < selectors.length; i++) { | |
2631 if (rule.parsedSelector === selectors[i]) { | |
2632 self.collectProperties(rule, props); | |
2633 return; | |
2634 } | |
2635 } | |
2636 }); | |
2637 return props; | |
2638 }, | |
2639 transformStyles: function (element, properties, scopeSelector) { | |
2640 var self = this; | |
2641 var hostSelector = styleTransformer._calcHostScope(element.is, element.extends); | |
2642 var rxHostSelector = element.extends ? '\\' + hostSelector.slice(0, -1) + '\\]'
: hostSelector; | |
2643 var hostRx = new RegExp(this.rx.HOST_PREFIX + rxHostSelector + this.rx.HOST_SUFF
IX); | |
2644 return styleTransformer.elementStyles(element, function (rule) { | |
2645 self.applyProperties(rule, properties); | |
2646 if (rule.cssText && !nativeShadow) { | |
2647 self._scopeSelector(rule, hostRx, hostSelector, element._scopeCssViaAttr, scopeS
elector); | |
2648 } | |
2649 }); | |
2650 }, | |
2651 _scopeSelector: function (rule, hostRx, hostSelector, viaAttr, scopeId) { | |
2652 rule.transformedSelector = rule.transformedSelector || rule.selector; | |
2653 var selector = rule.transformedSelector; | |
2654 var scope = viaAttr ? '[' + styleTransformer.SCOPE_NAME + '~=' + scopeId + ']' :
'.' + scopeId; | |
2655 var parts = selector.split(','); | |
2656 for (var i = 0, l = parts.length, p; i < l && (p = parts[i]); i++) { | |
2657 parts[i] = p.match(hostRx) ? p.replace(hostSelector, hostSelector + scope) : sco
pe + ' ' + p; | |
2658 } | |
2659 rule.selector = parts.join(','); | |
2660 }, | |
2661 applyElementScopeSelector: function (element, selector, old, viaAttr) { | |
2662 var c = viaAttr ? element.getAttribute(styleTransformer.SCOPE_NAME) : element.cl
assName; | |
2663 var v = old ? c.replace(old, selector) : (c ? c + ' ' : '') + this.XSCOPE_NAME +
' ' + selector; | |
2664 if (c !== v) { | |
2665 if (viaAttr) { | |
2666 element.setAttribute(styleTransformer.SCOPE_NAME, v); | |
2667 } else { | |
2668 element.className = v; | |
2669 } | |
2670 } | |
2671 }, | |
2672 applyElementStyle: function (element, properties, selector, style) { | |
2673 var cssText = style ? style.textContent || '' : this.transformStyles(element, pr
operties, selector); | |
2674 var s = element._customStyle; | |
2675 if (s && !nativeShadow && s !== style) { | |
2676 s._useCount--; | |
2677 if (s._useCount <= 0 && s.parentNode) { | |
2678 s.parentNode.removeChild(s); | |
2679 } | |
2680 } | |
2681 if (nativeShadow || (!style || !style.parentNode)) { | |
2682 if (nativeShadow && element._customStyle) { | |
2683 element._customStyle.textContent = cssText; | |
2684 style = element._customStyle; | |
2685 } else if (cssText) { | |
2686 style = styleUtil.applyCss(cssText, selector, nativeShadow ? element.root : null
, element._scopeStyle); | |
2687 } | |
2688 } | |
2689 if (style) { | |
2690 style._useCount = style._useCount || 0; | |
2691 if (element._customStyle != style) { | |
2692 style._useCount++; | |
2693 } | |
2694 element._customStyle = style; | |
2695 } | |
2696 return style; | |
2697 }, | |
2698 mixinCustomStyle: function (props, customStyle) { | |
2699 var v; | |
2700 for (var i in customStyle) { | |
2701 v = customStyle[i]; | |
2702 if (v || v === 0) { | |
2703 props[i] = v; | |
2704 } | |
2705 } | |
2706 }, | |
2707 rx: { | |
2708 VAR_ASSIGN: /(?:^|[;\n]\s*)(--[\w-]*?):\s*(?:([^;{]*)|{([^}]*)})(?:(?=[;\n])|$)/
gi, | |
2709 MIXIN_MATCH: /(?:^|\W+)@apply[\s]*\(([^)]*)\)/i, | |
2710 VAR_MATCH: /(^|\W+)var\([\s]*([^,)]*)[\s]*,?[\s]*((?:[^,)]*)|(?:[^;]*\([^;)]*\))
)[\s]*?\)/gi, | |
2711 VAR_CAPTURE: /\([\s]*(--[^,\s)]*)(?:,[\s]*(--[^,\s)]*))?(?:\)|,)/gi, | |
2712 IS_VAR: /^--/, | |
2713 BRACKETED: /\{[^}]*\}/g, | |
2714 HOST_PREFIX: '(?:^|[^.#[:])', | |
2715 HOST_SUFFIX: '($|[.:[\\s>+~])' | |
2716 }, | |
2717 HOST_SELECTORS: [':host'], | |
2718 SCOPE_SELECTORS: [':root'], | |
2719 XSCOPE_NAME: 'x-scope' | |
2720 }; | |
2721 function addToBitMask(n, bits) { | |
2722 var o = parseInt(n / 32); | |
2723 var v = 1 << n % 32; | |
2724 bits[o] = (bits[o] || 0) | v; | |
2725 } | |
2726 }(); | |
2727 (function () { | |
2728 Polymer.StyleCache = function () { | |
2729 this.cache = {}; | |
2730 }; | |
2731 Polymer.StyleCache.prototype = { | |
2732 MAX: 100, | |
2733 store: function (is, data, keyValues, keyStyles) { | |
2734 data.keyValues = keyValues; | |
2735 data.styles = keyStyles; | |
2736 var s$ = this.cache[is] = this.cache[is] || []; | |
2737 s$.push(data); | |
2738 if (s$.length > this.MAX) { | |
2739 s$.shift(); | |
2740 } | |
2741 }, | |
2742 retrieve: function (is, keyValues, keyStyles) { | |
2743 var cache = this.cache[is]; | |
2744 if (cache) { | |
2745 for (var i = cache.length - 1, data; i >= 0; i--) { | |
2746 data = cache[i]; | |
2747 if (keyStyles === data.styles && this._objectsEqual(keyValues, data.keyValues))
{ | |
2748 return data; | |
2749 } | |
2750 } | |
2751 } | |
2752 }, | |
2753 clear: function () { | |
2754 this.cache = {}; | |
2755 }, | |
2756 _objectsEqual: function (target, source) { | |
2757 var t, s; | |
2758 for (var i in target) { | |
2759 t = target[i], s = source[i]; | |
2760 if (!(typeof t === 'object' && t ? this._objectsStrictlyEqual(t, s) : t === s))
{ | |
2761 return false; | |
2762 } | |
2763 } | |
2764 if (Array.isArray(target)) { | |
2765 return target.length === source.length; | |
2766 } | |
2767 return true; | |
2768 }, | |
2769 _objectsStrictlyEqual: function (target, source) { | |
2770 return this._objectsEqual(target, source) && this._objectsEqual(source, target); | |
2771 } | |
2772 }; | |
2773 }()); | |
2774 Polymer.StyleDefaults = function () { | |
2775 var styleProperties = Polymer.StyleProperties; | |
2776 var styleUtil = Polymer.StyleUtil; | |
2777 var StyleCache = Polymer.StyleCache; | |
2778 var api = { | |
2779 _styles: [], | |
2780 _properties: null, | |
2781 customStyle: {}, | |
2782 _styleCache: new StyleCache(), | |
2783 addStyle: function (style) { | |
2784 this._styles.push(style); | |
2785 this._properties = null; | |
2786 }, | |
2787 get _styleProperties() { | |
2788 if (!this._properties) { | |
2789 styleProperties.decorateStyles(this._styles); | |
2790 this._styles._scopeStyleProperties = null; | |
2791 this._properties = styleProperties.scopePropertiesFromStyles(this._styles); | |
2792 styleProperties.mixinCustomStyle(this._properties, this.customStyle); | |
2793 styleProperties.reify(this._properties); | |
2794 } | |
2795 return this._properties; | |
2796 }, | |
2797 _needsStyleProperties: function () { | |
2798 }, | |
2799 _computeStyleProperties: function () { | |
2800 return this._styleProperties; | |
2801 }, | |
2802 updateStyles: function (properties) { | |
2803 this._properties = null; | |
2804 if (properties) { | |
2805 Polymer.Base.mixin(this.customStyle, properties); | |
2806 } | |
2807 this._styleCache.clear(); | |
2808 for (var i = 0, s; i < this._styles.length; i++) { | |
2809 s = this._styles[i]; | |
2810 s = s.__importElement || s; | |
2811 s._apply(); | |
2812 } | |
2813 } | |
2814 }; | |
2815 return api; | |
2816 }(); | |
2817 (function () { | |
2818 'use strict'; | |
2819 var serializeValueToAttribute = Polymer.Base.serializeValueToAttribute; | |
2820 var propertyUtils = Polymer.StyleProperties; | |
2821 var styleTransformer = Polymer.StyleTransformer; | |
2822 var styleUtil = Polymer.StyleUtil; | |
2823 var styleDefaults = Polymer.StyleDefaults; | |
2824 var nativeShadow = Polymer.Settings.useNativeShadow; | |
2825 Polymer.Base._addFeature({ | |
2826 _prepStyleProperties: function () { | |
2827 this._ownStylePropertyNames = this._styles ? propertyUtils.decorateStyles(this._
styles) : []; | |
2828 }, | |
2829 _setupStyleProperties: function () { | |
2830 this.customStyle = {}; | |
2831 }, | |
2832 _needsStyleProperties: function () { | |
2833 return Boolean(this._ownStylePropertyNames && this._ownStylePropertyNames.length
); | |
2834 }, | |
2835 _beforeAttached: function () { | |
2836 if (!this._scopeSelector && this._needsStyleProperties()) { | |
2837 this._updateStyleProperties(); | |
2838 } | |
2839 }, | |
2840 _findStyleHost: function () { | |
2841 var e = this, root; | |
2842 while (root = Polymer.dom(e).getOwnerRoot()) { | |
2843 if (Polymer.isInstance(root.host)) { | |
2844 return root.host; | |
2845 } | |
2846 e = root.host; | |
2847 } | |
2848 return styleDefaults; | |
2849 }, | |
2850 _updateStyleProperties: function () { | |
2851 var info, scope = this._findStyleHost(); | |
2852 if (!scope._styleCache) { | |
2853 scope._styleCache = new Polymer.StyleCache(); | |
2854 } | |
2855 var scopeData = propertyUtils.propertyDataFromStyles(scope._styles, this); | |
2856 scopeData.key.customStyle = this.customStyle; | |
2857 info = scope._styleCache.retrieve(this.is, scopeData.key, this._styles); | |
2858 var scopeCached = Boolean(info); | |
2859 if (scopeCached) { | |
2860 this._styleProperties = info._styleProperties; | |
2861 } else { | |
2862 this._computeStyleProperties(scopeData.properties); | |
2863 } | |
2864 this._computeOwnStyleProperties(); | |
2865 if (!scopeCached) { | |
2866 info = styleCache.retrieve(this.is, this._ownStyleProperties, this._styles); | |
2867 } | |
2868 var globalCached = Boolean(info) && !scopeCached; | |
2869 var style = this._applyStyleProperties(info); | |
2870 if (!scopeCached) { | |
2871 style = style && nativeShadow ? style.cloneNode(true) : style; | |
2872 info = { | |
2873 style: style, | |
2874 _scopeSelector: this._scopeSelector, | |
2875 _styleProperties: this._styleProperties | |
2876 }; | |
2877 scopeData.key.customStyle = {}; | |
2878 this.mixin(scopeData.key.customStyle, this.customStyle); | |
2879 scope._styleCache.store(this.is, info, scopeData.key, this._styles); | |
2880 if (!globalCached) { | |
2881 styleCache.store(this.is, Object.create(info), this._ownStyleProperties, this._s
tyles); | |
2882 } | |
2883 } | |
2884 }, | |
2885 _computeStyleProperties: function (scopeProps) { | |
2886 var scope = this._findStyleHost(); | |
2887 if (!scope._styleProperties) { | |
2888 scope._computeStyleProperties(); | |
2889 } | |
2890 var props = Object.create(scope._styleProperties); | |
2891 this.mixin(props, propertyUtils.hostPropertiesFromStyles(this._styles)); | |
2892 scopeProps = scopeProps || propertyUtils.propertyDataFromStyles(scope._styles, t
his).properties; | |
2893 this.mixin(props, scopeProps); | |
2894 this.mixin(props, propertyUtils.scopePropertiesFromStyles(this._styles)); | |
2895 propertyUtils.mixinCustomStyle(props, this.customStyle); | |
2896 propertyUtils.reify(props); | |
2897 this._styleProperties = props; | |
2898 }, | |
2899 _computeOwnStyleProperties: function () { | |
2900 var props = {}; | |
2901 for (var i = 0, n; i < this._ownStylePropertyNames.length; i++) { | |
2902 n = this._ownStylePropertyNames[i]; | |
2903 props[n] = this._styleProperties[n]; | |
2904 } | |
2905 this._ownStyleProperties = props; | |
2906 }, | |
2907 _scopeCount: 0, | |
2908 _applyStyleProperties: function (info) { | |
2909 var oldScopeSelector = this._scopeSelector; | |
2910 this._scopeSelector = info ? info._scopeSelector : this.is + '-' + this.__proto_
_._scopeCount++; | |
2911 var style = propertyUtils.applyElementStyle(this, this._styleProperties, this._s
copeSelector, info && info.style); | |
2912 if (!nativeShadow) { | |
2913 propertyUtils.applyElementScopeSelector(this, this._scopeSelector, oldScopeSelec
tor, this._scopeCssViaAttr); | |
2914 } | |
2915 return style; | |
2916 }, | |
2917 serializeValueToAttribute: function (value, attribute, node) { | |
2918 node = node || this; | |
2919 if (attribute === 'class' && !nativeShadow) { | |
2920 var host = node === this ? this.domHost || this.dataHost : this; | |
2921 if (host) { | |
2922 value = host._scopeElementClass(node, value); | |
2923 } | |
2924 } | |
2925 node = Polymer.dom(node); | |
2926 serializeValueToAttribute.call(this, value, attribute, node); | |
2927 }, | |
2928 _scopeElementClass: function (element, selector) { | |
2929 if (!nativeShadow && !this._scopeCssViaAttr) { | |
2930 selector += (selector ? ' ' : '') + SCOPE_NAME + ' ' + this.is + (element._scope
Selector ? ' ' + XSCOPE_NAME + ' ' + element._scopeSelector : ''); | |
2931 } | |
2932 return selector; | |
2933 }, | |
2934 updateStyles: function (properties) { | |
2935 if (this.isAttached) { | |
2936 if (properties) { | |
2937 this.mixin(this.customStyle, properties); | |
2938 } | |
2939 if (this._needsStyleProperties()) { | |
2940 this._updateStyleProperties(); | |
2941 } else { | |
2942 this._styleProperties = null; | |
2943 } | |
2944 if (this._styleCache) { | |
2945 this._styleCache.clear(); | |
2946 } | |
2947 this._updateRootStyles(); | |
2948 } | |
2949 }, | |
2950 _updateRootStyles: function (root) { | |
2951 root = root || this.root; | |
2952 var c$ = Polymer.dom(root)._query(function (e) { | |
2953 return e.shadyRoot || e.shadowRoot; | |
2954 }); | |
2955 for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) { | |
2956 if (c.updateStyles) { | |
2957 c.updateStyles(); | |
2958 } | |
2959 } | |
2960 } | |
2961 }); | |
2962 Polymer.updateStyles = function (properties) { | |
2963 styleDefaults.updateStyles(properties); | |
2964 Polymer.Base._updateRootStyles(document); | |
2965 }; | |
2966 var styleCache = new Polymer.StyleCache(); | |
2967 Polymer.customStyleCache = styleCache; | |
2968 var SCOPE_NAME = styleTransformer.SCOPE_NAME; | |
2969 var XSCOPE_NAME = propertyUtils.XSCOPE_NAME; | |
2970 }()); | |
2971 Polymer.Base._addFeature({ | |
2972 _registerFeatures: function () { | |
2973 this._prepIs(); | |
2974 this._prepAttributes(); | |
2975 this._prepConstructor(); | |
2976 this._prepTemplate(); | |
2977 this._prepStyles(); | |
2978 this._prepStyleProperties(); | |
2979 this._prepAnnotations(); | |
2980 this._prepEffects(); | |
2981 this._prepBehaviors(); | |
2982 this._prepBindings(); | |
2983 this._prepShady(); | |
2984 }, | |
2985 _prepBehavior: function (b) { | |
2986 this._addPropertyEffects(b.properties); | |
2987 this._addComplexObserverEffects(b.observers); | |
2988 this._addHostAttributes(b.hostAttributes); | |
2989 }, | |
2990 _initFeatures: function () { | |
2991 this._poolContent(); | |
2992 this._setupConfigure(); | |
2993 this._setupStyleProperties(); | |
2994 this._pushHost(); | |
2995 this._stampTemplate(); | |
2996 this._popHost(); | |
2997 this._marshalAnnotationReferences(); | |
2998 this._marshalHostAttributes(); | |
2999 this._setupDebouncers(); | |
3000 this._marshalInstanceEffects(); | |
3001 this._marshalBehaviors(); | |
3002 this._marshalAttributes(); | |
3003 this._tryReady(); | |
3004 }, | |
3005 _marshalBehavior: function (b) { | |
3006 this._listenListeners(b.listeners); | |
3007 } | |
3008 }); | |
3009 (function () { | |
3010 var nativeShadow = Polymer.Settings.useNativeShadow; | |
3011 var propertyUtils = Polymer.StyleProperties; | |
3012 var styleUtil = Polymer.StyleUtil; | |
3013 var styleDefaults = Polymer.StyleDefaults; | |
3014 var styleTransformer = Polymer.StyleTransformer; | |
3015 Polymer({ | |
3016 is: 'custom-style', | |
3017 extends: 'style', | |
3018 created: function () { | |
3019 this._tryApply(); | |
3020 }, | |
3021 attached: function () { | |
3022 this._tryApply(); | |
3023 }, | |
3024 _tryApply: function () { | |
3025 if (!this._appliesToDocument) { | |
3026 if (this.parentNode && this.parentNode.localName !== 'dom-module') { | |
3027 this._appliesToDocument = true; | |
3028 var e = this.__appliedElement || this; | |
3029 styleDefaults.addStyle(e); | |
3030 if (e.textContent) { | |
3031 this._apply(); | |
3032 } else { | |
3033 var observer = new MutationObserver(function () { | |
3034 observer.disconnect(); | |
3035 this._apply(); | |
3036 }.bind(this)); | |
3037 observer.observe(e, { childList: true }); | |
3038 } | |
3039 } | |
3040 } | |
3041 }, | |
3042 _apply: function () { | |
3043 var e = this.__appliedElement || this; | |
3044 this._computeStyleProperties(); | |
3045 var props = this._styleProperties; | |
3046 var self = this; | |
3047 e.textContent = styleUtil.toCssText(styleUtil.rulesForStyle(e), function (rule)
{ | |
3048 var css = rule.cssText = rule.parsedCssText; | |
3049 if (rule.propertyInfo && rule.propertyInfo.cssText) { | |
3050 css = css.replace(propertyUtils.rx.VAR_ASSIGN, ''); | |
3051 rule.cssText = propertyUtils.valueForProperties(css, props); | |
3052 } | |
3053 styleTransformer.documentRule(rule); | |
3054 }); | |
3055 } | |
3056 }); | |
3057 }()); | |
3058 Polymer.Templatizer = { | |
3059 properties: { __hideTemplateChildren__: { observer: '_showHideChildren' } }, | |
3060 _templatizerStatic: { | |
3061 count: 0, | |
3062 callbacks: {}, | |
3063 debouncer: null | |
3064 }, | |
3065 _instanceProps: Polymer.nob, | |
3066 created: function () { | |
3067 this._templatizerId = this._templatizerStatic.count++; | |
3068 }, | |
3069 templatize: function (template) { | |
3070 if (!template._content) { | |
3071 template._content = template.content; | |
3072 } | |
3073 if (template._content._ctor) { | |
3074 this.ctor = template._content._ctor; | |
3075 this._prepParentProperties(this.ctor.prototype, template); | |
3076 return; | |
3077 } | |
3078 var archetype = Object.create(Polymer.Base); | |
3079 this._customPrepAnnotations(archetype, template); | |
3080 archetype._prepEffects(); | |
3081 this._customPrepEffects(archetype); | |
3082 archetype._prepBehaviors(); | |
3083 archetype._prepBindings(); | |
3084 this._prepParentProperties(archetype, template); | |
3085 archetype._notifyPath = this._notifyPathImpl; | |
3086 archetype._scopeElementClass = this._scopeElementClassImpl; | |
3087 archetype.listen = this._listenImpl; | |
3088 archetype._showHideChildren = this._showHideChildrenImpl; | |
3089 var _constructor = this._constructorImpl; | |
3090 var ctor = function TemplateInstance(model, host) { | |
3091 _constructor.call(this, model, host); | |
3092 }; | |
3093 ctor.prototype = archetype; | |
3094 archetype.constructor = ctor; | |
3095 template._content._ctor = ctor; | |
3096 this.ctor = ctor; | |
3097 }, | |
3098 _getRootDataHost: function () { | |
3099 return this.dataHost && this.dataHost._rootDataHost || this.dataHost; | |
3100 }, | |
3101 _showHideChildrenImpl: function (hide) { | |
3102 var c = this._children; | |
3103 for (var i = 0; i < c.length; i++) { | |
3104 var n = c[i]; | |
3105 if (n.style) { | |
3106 n.style.display = hide ? 'none' : ''; | |
3107 n.__hideTemplateChildren__ = hide; | |
3108 } | |
3109 } | |
3110 }, | |
3111 _debounceTemplate: function (fn) { | |
3112 this._templatizerStatic.callbacks[this._templatizerId] = fn.bind(this); | |
3113 this._templatizerStatic.debouncer = Polymer.Debounce(this._templatizerStatic.deb
ouncer, this._flushTemplates.bind(this, true)); | |
3114 }, | |
3115 _flushTemplates: function (debouncerExpired) { | |
3116 var db = this._templatizerStatic.debouncer; | |
3117 while (debouncerExpired || db && db.finish) { | |
3118 db.stop(); | |
3119 var cbs = this._templatizerStatic.callbacks; | |
3120 this._templatizerStatic.callbacks = {}; | |
3121 for (var id in cbs) { | |
3122 cbs[id](); | |
3123 } | |
3124 debouncerExpired = false; | |
3125 } | |
3126 }, | |
3127 _customPrepEffects: function (archetype) { | |
3128 var parentProps = archetype._parentProps; | |
3129 for (var prop in parentProps) { | |
3130 archetype._addPropertyEffect(prop, 'function', this._createHostPropEffector(prop
)); | |
3131 } | |
3132 for (var prop in this._instanceProps) { | |
3133 archetype._addPropertyEffect(prop, 'function', this._createInstancePropEffector(
prop)); | |
3134 } | |
3135 }, | |
3136 _customPrepAnnotations: function (archetype, template) { | |
3137 archetype._template = template; | |
3138 var c = template._content; | |
3139 if (!c._notes) { | |
3140 var rootDataHost = archetype._rootDataHost; | |
3141 if (rootDataHost) { | |
3142 Polymer.Annotations.prepElement = rootDataHost._prepElement.bind(rootDataHost); | |
3143 } | |
3144 c._notes = Polymer.Annotations.parseAnnotations(template); | |
3145 Polymer.Annotations.prepElement = null; | |
3146 this._processAnnotations(c._notes); | |
3147 } | |
3148 archetype._notes = c._notes; | |
3149 archetype._parentProps = c._parentProps; | |
3150 }, | |
3151 _prepParentProperties: function (archetype, template) { | |
3152 var parentProps = this._parentProps = archetype._parentProps; | |
3153 if (this._forwardParentProp && parentProps) { | |
3154 var proto = archetype._parentPropProto; | |
3155 var prop; | |
3156 if (!proto) { | |
3157 for (prop in this._instanceProps) { | |
3158 delete parentProps[prop]; | |
3159 } | |
3160 proto = archetype._parentPropProto = Object.create(null); | |
3161 if (template != this) { | |
3162 Polymer.Bind.prepareModel(proto); | |
3163 } | |
3164 for (prop in parentProps) { | |
3165 var parentProp = '_parent_' + prop; | |
3166 var effects = [ | |
3167 { | |
3168 kind: 'function', | |
3169 effect: this._createForwardPropEffector(prop) | |
3170 }, | |
3171 { kind: 'notify' } | |
3172 ]; | |
3173 Polymer.Bind._createAccessors(proto, parentProp, effects); | |
3174 } | |
3175 } | |
3176 if (template != this) { | |
3177 Polymer.Bind.prepareInstance(template); | |
3178 template._forwardParentProp = this._forwardParentProp.bind(this); | |
3179 } | |
3180 this._extendTemplate(template, proto); | |
3181 } | |
3182 }, | |
3183 _createForwardPropEffector: function (prop) { | |
3184 return function (source, value) { | |
3185 this._forwardParentProp(prop, value); | |
3186 }; | |
3187 }, | |
3188 _createHostPropEffector: function (prop) { | |
3189 return function (source, value) { | |
3190 this.dataHost['_parent_' + prop] = value; | |
3191 }; | |
3192 }, | |
3193 _createInstancePropEffector: function (prop) { | |
3194 return function (source, value, old, fromAbove) { | |
3195 if (!fromAbove) { | |
3196 this.dataHost._forwardInstanceProp(this, prop, value); | |
3197 } | |
3198 }; | |
3199 }, | |
3200 _extendTemplate: function (template, proto) { | |
3201 Object.getOwnPropertyNames(proto).forEach(function (n) { | |
3202 var val = template[n]; | |
3203 var pd = Object.getOwnPropertyDescriptor(proto, n); | |
3204 Object.defineProperty(template, n, pd); | |
3205 if (val !== undefined) { | |
3206 template._propertySetter(n, val); | |
3207 } | |
3208 }); | |
3209 }, | |
3210 _showHideChildren: function (hidden) { | |
3211 }, | |
3212 _forwardInstancePath: function (inst, path, value) { | |
3213 }, | |
3214 _forwardInstanceProp: function (inst, prop, value) { | |
3215 }, | |
3216 _notifyPathImpl: function (path, value) { | |
3217 var dataHost = this.dataHost; | |
3218 var dot = path.indexOf('.'); | |
3219 var root = dot < 0 ? path : path.slice(0, dot); | |
3220 dataHost._forwardInstancePath.call(dataHost, this, path, value); | |
3221 if (root in dataHost._parentProps) { | |
3222 dataHost.notifyPath('_parent_' + path, value); | |
3223 } | |
3224 }, | |
3225 _pathEffector: function (path, value, fromAbove) { | |
3226 if (this._forwardParentPath) { | |
3227 if (path.indexOf('_parent_') === 0) { | |
3228 this._forwardParentPath(path.substring(8), value); | |
3229 } | |
3230 } | |
3231 Polymer.Base._pathEffector.apply(this, arguments); | |
3232 }, | |
3233 _constructorImpl: function (model, host) { | |
3234 this._rootDataHost = host._getRootDataHost(); | |
3235 this._setupConfigure(model); | |
3236 this._pushHost(host); | |
3237 this.root = this.instanceTemplate(this._template); | |
3238 this.root.__noContent = !this._notes._hasContent; | |
3239 this.root.__styleScoped = true; | |
3240 this._popHost(); | |
3241 this._marshalAnnotatedNodes(); | |
3242 this._marshalInstanceEffects(); | |
3243 this._marshalAnnotatedListeners(); | |
3244 var children = []; | |
3245 for (var n = this.root.firstChild; n; n = n.nextSibling) { | |
3246 children.push(n); | |
3247 n._templateInstance = this; | |
3248 } | |
3249 this._children = children; | |
3250 if (host.__hideTemplateChildren__) { | |
3251 this._showHideChildren(true); | |
3252 } | |
3253 this._tryReady(); | |
3254 }, | |
3255 _listenImpl: function (node, eventName, methodName) { | |
3256 var model = this; | |
3257 var host = this._rootDataHost; | |
3258 var handler = host._createEventHandler(node, eventName, methodName); | |
3259 var decorated = function (e) { | |
3260 e.model = model; | |
3261 handler(e); | |
3262 }; | |
3263 host._listen(node, eventName, decorated); | |
3264 }, | |
3265 _scopeElementClassImpl: function (node, value) { | |
3266 var host = this._rootDataHost; | |
3267 if (host) { | |
3268 return host._scopeElementClass(node, value); | |
3269 } | |
3270 }, | |
3271 stamp: function (model) { | |
3272 model = model || {}; | |
3273 if (this._parentProps) { | |
3274 for (var prop in this._parentProps) { | |
3275 model[prop] = this['_parent_' + prop]; | |
3276 } | |
3277 } | |
3278 return new this.ctor(model, this); | |
3279 }, | |
3280 modelForElement: function (el) { | |
3281 var model; | |
3282 while (el) { | |
3283 if (model = el._templateInstance) { | |
3284 if (model.dataHost != this) { | |
3285 el = model.dataHost; | |
3286 } else { | |
3287 return model; | |
3288 } | |
3289 } else { | |
3290 el = el.parentNode; | |
3291 } | |
3292 } | |
3293 } | |
3294 }; | |
3295 Polymer({ | |
3296 is: 'dom-template', | |
3297 extends: 'template', | |
3298 behaviors: [Polymer.Templatizer], | |
3299 ready: function () { | |
3300 this.templatize(this); | |
3301 } | |
3302 }); | |
3303 Polymer._collections = new WeakMap(); | |
3304 Polymer.Collection = function (userArray) { | |
3305 Polymer._collections.set(userArray, this); | |
3306 this.userArray = userArray; | |
3307 this.store = userArray.slice(); | |
3308 this.initMap(); | |
3309 }; | |
3310 Polymer.Collection.prototype = { | |
3311 constructor: Polymer.Collection, | |
3312 initMap: function () { | |
3313 var omap = this.omap = new WeakMap(); | |
3314 var pmap = this.pmap = {}; | |
3315 var s = this.store; | |
3316 for (var i = 0; i < s.length; i++) { | |
3317 var item = s[i]; | |
3318 if (item && typeof item == 'object') { | |
3319 omap.set(item, i); | |
3320 } else { | |
3321 pmap[item] = i; | |
3322 } | |
3323 } | |
3324 }, | |
3325 add: function (item) { | |
3326 var key = this.store.push(item) - 1; | |
3327 if (item && typeof item == 'object') { | |
3328 this.omap.set(item, key); | |
3329 } else { | |
3330 this.pmap[item] = key; | |
3331 } | |
3332 return key; | |
3333 }, | |
3334 removeKey: function (key) { | |
3335 this._removeFromMap(this.store[key]); | |
3336 delete this.store[key]; | |
3337 }, | |
3338 _removeFromMap: function (item) { | |
3339 if (item && typeof item == 'object') { | |
3340 this.omap.delete(item); | |
3341 } else { | |
3342 delete this.pmap[item]; | |
3343 } | |
3344 }, | |
3345 remove: function (item) { | |
3346 var key = this.getKey(item); | |
3347 this.removeKey(key); | |
3348 return key; | |
3349 }, | |
3350 getKey: function (item) { | |
3351 if (item && typeof item == 'object') { | |
3352 return this.omap.get(item); | |
3353 } else { | |
3354 return this.pmap[item]; | |
3355 } | |
3356 }, | |
3357 getKeys: function () { | |
3358 return Object.keys(this.store); | |
3359 }, | |
3360 setItem: function (key, item) { | |
3361 var old = this.store[key]; | |
3362 if (old) { | |
3363 this._removeFromMap(old); | |
3364 } | |
3365 if (item && typeof item == 'object') { | |
3366 this.omap.set(item, key); | |
3367 } else { | |
3368 this.pmap[item] = key; | |
3369 } | |
3370 this.store[key] = item; | |
3371 }, | |
3372 getItem: function (key) { | |
3373 return this.store[key]; | |
3374 }, | |
3375 getItems: function () { | |
3376 var items = [], store = this.store; | |
3377 for (var key in store) { | |
3378 items.push(store[key]); | |
3379 } | |
3380 return items; | |
3381 }, | |
3382 _applySplices: function (splices) { | |
3383 var keySplices = []; | |
3384 for (var i = 0; i < splices.length; i++) { | |
3385 var j, o, key, s = splices[i]; | |
3386 var removed = []; | |
3387 for (j = 0; j < s.removed.length; j++) { | |
3388 o = s.removed[j]; | |
3389 key = this.remove(o); | |
3390 removed.push(key); | |
3391 } | |
3392 var added = []; | |
3393 for (j = 0; j < s.addedCount; j++) { | |
3394 o = this.userArray[s.index + j]; | |
3395 key = this.add(o); | |
3396 added.push(key); | |
3397 } | |
3398 keySplices.push({ | |
3399 index: s.index, | |
3400 removed: removed, | |
3401 removedItems: s.removed, | |
3402 added: added | |
3403 }); | |
3404 } | |
3405 return keySplices; | |
3406 } | |
3407 }; | |
3408 Polymer.Collection.get = function (userArray) { | |
3409 return Polymer._collections.get(userArray) || new Polymer.Collection(userArray); | |
3410 }; | |
3411 Polymer.Collection.applySplices = function (userArray, splices) { | |
3412 var coll = Polymer._collections.get(userArray); | |
3413 return coll ? coll._applySplices(splices) : null; | |
3414 }; | |
3415 Polymer({ | |
3416 is: 'dom-repeat', | |
3417 extends: 'template', | |
3418 properties: { | |
3419 items: { type: Array }, | |
3420 as: { | |
3421 type: String, | |
3422 value: 'item' | |
3423 }, | |
3424 indexAs: { | |
3425 type: String, | |
3426 value: 'index' | |
3427 }, | |
3428 sort: { | |
3429 type: Function, | |
3430 observer: '_sortChanged' | |
3431 }, | |
3432 filter: { | |
3433 type: Function, | |
3434 observer: '_filterChanged' | |
3435 }, | |
3436 observe: { | |
3437 type: String, | |
3438 observer: '_observeChanged' | |
3439 }, | |
3440 delay: Number | |
3441 }, | |
3442 behaviors: [Polymer.Templatizer], | |
3443 observers: ['_itemsChanged(items.*)'], | |
3444 created: function () { | |
3445 this._instances = []; | |
3446 }, | |
3447 detached: function () { | |
3448 for (var i = 0; i < this._instances.length; i++) { | |
3449 this._detachRow(i); | |
3450 } | |
3451 }, | |
3452 attached: function () { | |
3453 var parentNode = Polymer.dom(this).parentNode; | |
3454 for (var i = 0; i < this._instances.length; i++) { | |
3455 Polymer.dom(parentNode).insertBefore(this._instances[i].root, this); | |
3456 } | |
3457 }, | |
3458 ready: function () { | |
3459 this._instanceProps = { __key__: true }; | |
3460 this._instanceProps[this.as] = true; | |
3461 this._instanceProps[this.indexAs] = true; | |
3462 if (!this.ctor) { | |
3463 this.templatize(this); | |
3464 } | |
3465 }, | |
3466 _sortChanged: function () { | |
3467 var dataHost = this._getRootDataHost(); | |
3468 var sort = this.sort; | |
3469 this._sortFn = sort && (typeof sort == 'function' ? sort : function () { | |
3470 return dataHost[sort].apply(dataHost, arguments); | |
3471 }); | |
3472 this._needFullRefresh = true; | |
3473 if (this.items) { | |
3474 this._debounceTemplate(this._render); | |
3475 } | |
3476 }, | |
3477 _filterChanged: function () { | |
3478 var dataHost = this._getRootDataHost(); | |
3479 var filter = this.filter; | |
3480 this._filterFn = filter && (typeof filter == 'function' ? filter : function () { | |
3481 return dataHost[filter].apply(dataHost, arguments); | |
3482 }); | |
3483 this._needFullRefresh = true; | |
3484 if (this.items) { | |
3485 this._debounceTemplate(this._render); | |
3486 } | |
3487 }, | |
3488 _observeChanged: function () { | |
3489 this._observePaths = this.observe && this.observe.replace('.*', '.').split(' '); | |
3490 }, | |
3491 _itemsChanged: function (change) { | |
3492 if (change.path == 'items') { | |
3493 if (Array.isArray(this.items)) { | |
3494 this.collection = Polymer.Collection.get(this.items); | |
3495 } else if (!this.items) { | |
3496 this.collection = null; | |
3497 } else { | |
3498 this._error(this._logf('dom-repeat', 'expected array for `items`,' + ' found', t
his.items)); | |
3499 } | |
3500 this._splices = []; | |
3501 this._needFullRefresh = true; | |
3502 this._debounceTemplate(this._render); | |
3503 } else if (change.path == 'items.splices') { | |
3504 this._splices = this._splices.concat(change.value.keySplices); | |
3505 this._debounceTemplate(this._render); | |
3506 } else { | |
3507 var subpath = change.path.slice(6); | |
3508 this._forwardItemPath(subpath, change.value); | |
3509 this._checkObservedPaths(subpath); | |
3510 } | |
3511 }, | |
3512 _checkObservedPaths: function (path) { | |
3513 if (this._observePaths) { | |
3514 path = path.substring(path.indexOf('.') + 1); | |
3515 var paths = this._observePaths; | |
3516 for (var i = 0; i < paths.length; i++) { | |
3517 if (path.indexOf(paths[i]) === 0) { | |
3518 this._needFullRefresh = true; | |
3519 if (this.delay) { | |
3520 this.debounce('render', this._render, this.delay); | |
3521 } else { | |
3522 this._debounceTemplate(this._render); | |
3523 } | |
3524 return; | |
3525 } | |
3526 } | |
3527 } | |
3528 }, | |
3529 render: function () { | |
3530 this._needFullRefresh = true; | |
3531 this._debounceTemplate(this._render); | |
3532 this._flushTemplates(); | |
3533 }, | |
3534 _render: function () { | |
3535 var c = this.collection; | |
3536 if (this._needFullRefresh) { | |
3537 this._applyFullRefresh(); | |
3538 this._needFullRefresh = false; | |
3539 } else { | |
3540 if (this._sortFn) { | |
3541 this._applySplicesUserSort(this._splices); | |
3542 } else { | |
3543 if (this._filterFn) { | |
3544 this._applyFullRefresh(); | |
3545 } else { | |
3546 this._applySplicesArrayOrder(this._splices); | |
3547 } | |
3548 } | |
3549 } | |
3550 this._splices = []; | |
3551 var keyToIdx = this._keyToInstIdx = {}; | |
3552 for (var i = 0; i < this._instances.length; i++) { | |
3553 var inst = this._instances[i]; | |
3554 keyToIdx[inst.__key__] = i; | |
3555 inst.__setProperty(this.indexAs, i, true); | |
3556 } | |
3557 this.fire('dom-change'); | |
3558 }, | |
3559 _applyFullRefresh: function () { | |
3560 var c = this.collection; | |
3561 var keys; | |
3562 if (this._sortFn) { | |
3563 keys = c ? c.getKeys() : []; | |
3564 } else { | |
3565 keys = []; | |
3566 var items = this.items; | |
3567 if (items) { | |
3568 for (var i = 0; i < items.length; i++) { | |
3569 keys.push(c.getKey(items[i])); | |
3570 } | |
3571 } | |
3572 } | |
3573 if (this._filterFn) { | |
3574 keys = keys.filter(function (a) { | |
3575 return this._filterFn(c.getItem(a)); | |
3576 }, this); | |
3577 } | |
3578 if (this._sortFn) { | |
3579 keys.sort(function (a, b) { | |
3580 return this._sortFn(c.getItem(a), c.getItem(b)); | |
3581 }.bind(this)); | |
3582 } | |
3583 for (var i = 0; i < keys.length; i++) { | |
3584 var key = keys[i]; | |
3585 var inst = this._instances[i]; | |
3586 if (inst) { | |
3587 inst.__setProperty('__key__', key, true); | |
3588 inst.__setProperty(this.as, c.getItem(key), true); | |
3589 } else { | |
3590 this._instances.push(this._insertRow(i, key)); | |
3591 } | |
3592 } | |
3593 for (; i < this._instances.length; i++) { | |
3594 this._detachRow(i); | |
3595 } | |
3596 this._instances.splice(keys.length, this._instances.length - keys.length); | |
3597 }, | |
3598 _keySort: function (a, b) { | |
3599 return this.collection.getKey(a) - this.collection.getKey(b); | |
3600 }, | |
3601 _applySplicesUserSort: function (splices) { | |
3602 var c = this.collection; | |
3603 var instances = this._instances; | |
3604 var keyMap = {}; | |
3605 var pool = []; | |
3606 var sortFn = this._sortFn || this._keySort.bind(this); | |
3607 splices.forEach(function (s) { | |
3608 for (var i = 0; i < s.removed.length; i++) { | |
3609 var key = s.removed[i]; | |
3610 keyMap[key] = keyMap[key] ? null : -1; | |
3611 } | |
3612 for (var i = 0; i < s.added.length; i++) { | |
3613 var key = s.added[i]; | |
3614 keyMap[key] = keyMap[key] ? null : 1; | |
3615 } | |
3616 }, this); | |
3617 var removedIdxs = []; | |
3618 var addedKeys = []; | |
3619 for (var key in keyMap) { | |
3620 if (keyMap[key] === -1) { | |
3621 removedIdxs.push(this._keyToInstIdx[key]); | |
3622 } | |
3623 if (keyMap[key] === 1) { | |
3624 addedKeys.push(key); | |
3625 } | |
3626 } | |
3627 if (removedIdxs.length) { | |
3628 removedIdxs.sort(); | |
3629 for (var i = removedIdxs.length - 1; i >= 0; i--) { | |
3630 var idx = removedIdxs[i]; | |
3631 if (idx !== undefined) { | |
3632 pool.push(this._detachRow(idx)); | |
3633 instances.splice(idx, 1); | |
3634 } | |
3635 } | |
3636 } | |
3637 if (addedKeys.length) { | |
3638 if (this._filterFn) { | |
3639 addedKeys = addedKeys.filter(function (a) { | |
3640 return this._filterFn(c.getItem(a)); | |
3641 }, this); | |
3642 } | |
3643 addedKeys.sort(function (a, b) { | |
3644 return this._sortFn(c.getItem(a), c.getItem(b)); | |
3645 }.bind(this)); | |
3646 var start = 0; | |
3647 for (var i = 0; i < addedKeys.length; i++) { | |
3648 start = this._insertRowUserSort(start, addedKeys[i], pool); | |
3649 } | |
3650 } | |
3651 }, | |
3652 _insertRowUserSort: function (start, key, pool) { | |
3653 var c = this.collection; | |
3654 var item = c.getItem(key); | |
3655 var end = this._instances.length - 1; | |
3656 var idx = -1; | |
3657 var sortFn = this._sortFn || this._keySort.bind(this); | |
3658 while (start <= end) { | |
3659 var mid = start + end >> 1; | |
3660 var midKey = this._instances[mid].__key__; | |
3661 var cmp = sortFn(c.getItem(midKey), item); | |
3662 if (cmp < 0) { | |
3663 start = mid + 1; | |
3664 } else if (cmp > 0) { | |
3665 end = mid - 1; | |
3666 } else { | |
3667 idx = mid; | |
3668 break; | |
3669 } | |
3670 } | |
3671 if (idx < 0) { | |
3672 idx = end + 1; | |
3673 } | |
3674 this._instances.splice(idx, 0, this._insertRow(idx, key, pool)); | |
3675 return idx; | |
3676 }, | |
3677 _applySplicesArrayOrder: function (splices) { | |
3678 var pool = []; | |
3679 var c = this.collection; | |
3680 splices.forEach(function (s) { | |
3681 for (var i = 0; i < s.removed.length; i++) { | |
3682 var inst = this._detachRow(s.index + i); | |
3683 if (!inst.isPlaceholder) { | |
3684 pool.push(inst); | |
3685 } | |
3686 } | |
3687 this._instances.splice(s.index, s.removed.length); | |
3688 for (var i = 0; i < s.added.length; i++) { | |
3689 var inst = { | |
3690 isPlaceholder: true, | |
3691 key: s.added[i] | |
3692 }; | |
3693 this._instances.splice(s.index + i, 0, inst); | |
3694 } | |
3695 }, this); | |
3696 for (var i = this._instances.length - 1; i >= 0; i--) { | |
3697 var inst = this._instances[i]; | |
3698 if (inst.isPlaceholder) { | |
3699 this._instances[i] = this._insertRow(i, inst.key, pool, true); | |
3700 } | |
3701 } | |
3702 }, | |
3703 _detachRow: function (idx) { | |
3704 var inst = this._instances[idx]; | |
3705 if (!inst.isPlaceholder) { | |
3706 var parentNode = Polymer.dom(this).parentNode; | |
3707 for (var i = 0; i < inst._children.length; i++) { | |
3708 var el = inst._children[i]; | |
3709 Polymer.dom(inst.root).appendChild(el); | |
3710 } | |
3711 } | |
3712 return inst; | |
3713 }, | |
3714 _insertRow: function (idx, key, pool, replace) { | |
3715 var inst; | |
3716 if (inst = pool && pool.pop()) { | |
3717 inst.__setProperty(this.as, this.collection.getItem(key), true); | |
3718 inst.__setProperty('__key__', key, true); | |
3719 } else { | |
3720 inst = this._generateRow(idx, key); | |
3721 } | |
3722 var beforeRow = this._instances[replace ? idx + 1 : idx]; | |
3723 var beforeNode = beforeRow ? beforeRow._children[0] : this; | |
3724 var parentNode = Polymer.dom(this).parentNode; | |
3725 Polymer.dom(parentNode).insertBefore(inst.root, beforeNode); | |
3726 return inst; | |
3727 }, | |
3728 _generateRow: function (idx, key) { | |
3729 var model = { __key__: key }; | |
3730 model[this.as] = this.collection.getItem(key); | |
3731 model[this.indexAs] = idx; | |
3732 var inst = this.stamp(model); | |
3733 return inst; | |
3734 }, | |
3735 _showHideChildren: function (hidden) { | |
3736 for (var i = 0; i < this._instances.length; i++) { | |
3737 this._instances[i]._showHideChildren(hidden); | |
3738 } | |
3739 }, | |
3740 _forwardInstanceProp: function (inst, prop, value) { | |
3741 if (prop == this.as) { | |
3742 var idx; | |
3743 if (this._sortFn || this._filterFn) { | |
3744 idx = this.items.indexOf(this.collection.getItem(inst.__key__)); | |
3745 } else { | |
3746 idx = inst[this.indexAs]; | |
3747 } | |
3748 this.set('items.' + idx, value); | |
3749 } | |
3750 }, | |
3751 _forwardInstancePath: function (inst, path, value) { | |
3752 if (path.indexOf(this.as + '.') === 0) { | |
3753 this.notifyPath('items.' + inst.__key__ + '.' + path.slice(this.as.length + 1),
value); | |
3754 } | |
3755 }, | |
3756 _forwardParentProp: function (prop, value) { | |
3757 this._instances.forEach(function (inst) { | |
3758 inst.__setProperty(prop, value, true); | |
3759 }, this); | |
3760 }, | |
3761 _forwardParentPath: function (path, value) { | |
3762 this._instances.forEach(function (inst) { | |
3763 inst.notifyPath(path, value, true); | |
3764 }, this); | |
3765 }, | |
3766 _forwardItemPath: function (path, value) { | |
3767 if (this._keyToInstIdx) { | |
3768 var dot = path.indexOf('.'); | |
3769 var key = path.substring(0, dot < 0 ? path.length : dot); | |
3770 var idx = this._keyToInstIdx[key]; | |
3771 var inst = this._instances[idx]; | |
3772 if (inst) { | |
3773 if (dot >= 0) { | |
3774 path = this.as + '.' + path.substring(dot + 1); | |
3775 inst.notifyPath(path, value, true); | |
3776 } else { | |
3777 inst.__setProperty(this.as, value, true); | |
3778 } | |
3779 } | |
3780 } | |
3781 }, | |
3782 itemForElement: function (el) { | |
3783 var instance = this.modelForElement(el); | |
3784 return instance && instance[this.as]; | |
3785 }, | |
3786 keyForElement: function (el) { | |
3787 var instance = this.modelForElement(el); | |
3788 return instance && instance.__key__; | |
3789 }, | |
3790 indexForElement: function (el) { | |
3791 var instance = this.modelForElement(el); | |
3792 return instance && instance[this.indexAs]; | |
3793 } | |
3794 }); | |
3795 Polymer({ | |
3796 is: 'array-selector', | |
3797 properties: { | |
3798 items: { | |
3799 type: Array, | |
3800 observer: '_itemsChanged' | |
3801 }, | |
3802 selected: { | |
3803 type: Object, | |
3804 notify: true | |
3805 }, | |
3806 toggle: Boolean, | |
3807 multi: Boolean | |
3808 }, | |
3809 _itemsChanged: function () { | |
3810 if (Array.isArray(this.selected)) { | |
3811 for (var i = 0; i < this.selected.length; i++) { | |
3812 this.unlinkPaths('selected.' + i); | |
3813 } | |
3814 } else { | |
3815 this.unlinkPaths('selected'); | |
3816 } | |
3817 if (this.multi) { | |
3818 this.selected = []; | |
3819 } else { | |
3820 this.selected = null; | |
3821 } | |
3822 }, | |
3823 deselect: function (item) { | |
3824 if (this.multi) { | |
3825 var scol = Polymer.Collection.get(this.selected); | |
3826 var sidx = this.selected.indexOf(item); | |
3827 if (sidx >= 0) { | |
3828 var skey = scol.getKey(item); | |
3829 this.splice('selected', sidx, 1); | |
3830 this.unlinkPaths('selected.' + skey); | |
3831 return true; | |
3832 } | |
3833 } else { | |
3834 this.selected = null; | |
3835 this.unlinkPaths('selected'); | |
3836 } | |
3837 }, | |
3838 select: function (item) { | |
3839 var icol = Polymer.Collection.get(this.items); | |
3840 var key = icol.getKey(item); | |
3841 if (this.multi) { | |
3842 var scol = Polymer.Collection.get(this.selected); | |
3843 var skey = scol.getKey(item); | |
3844 if (skey >= 0) { | |
3845 if (this.toggle) { | |
3846 this.deselect(item); | |
3847 } | |
3848 } else { | |
3849 this.push('selected', item); | |
3850 this.async(function () { | |
3851 skey = scol.getKey(item); | |
3852 this.linkPaths('selected.' + skey, 'items.' + key); | |
3853 }); | |
3854 } | |
3855 } else { | |
3856 if (this.toggle && item == this.selected) { | |
3857 this.deselect(); | |
3858 } else { | |
3859 this.linkPaths('selected', 'items.' + key); | |
3860 this.selected = item; | |
3861 } | |
3862 } | |
3863 } | |
3864 }); | |
3865 Polymer({ | |
3866 is: 'dom-if', | |
3867 extends: 'template', | |
3868 properties: { | |
3869 'if': { | |
3870 type: Boolean, | |
3871 value: false, | |
3872 observer: '_queueRender' | |
3873 }, | |
3874 restamp: { | |
3875 type: Boolean, | |
3876 value: false, | |
3877 observer: '_queueRender' | |
3878 } | |
3879 }, | |
3880 behaviors: [Polymer.Templatizer], | |
3881 _queueRender: function () { | |
3882 this._debounceTemplate(this._render); | |
3883 }, | |
3884 detached: function () { | |
3885 this._teardownInstance(); | |
3886 }, | |
3887 attached: function () { | |
3888 if (this.if && this.ctor) { | |
3889 this.async(this._ensureInstance); | |
3890 } | |
3891 }, | |
3892 render: function () { | |
3893 this._flushTemplates(); | |
3894 }, | |
3895 _render: function () { | |
3896 if (this.if) { | |
3897 if (!this.ctor) { | |
3898 this._wrapTextNodes(this._content || this.content); | |
3899 this.templatize(this); | |
3900 } | |
3901 this._ensureInstance(); | |
3902 this._showHideChildren(); | |
3903 } else if (this.restamp) { | |
3904 this._teardownInstance(); | |
3905 } | |
3906 if (!this.restamp && this._instance) { | |
3907 this._showHideChildren(); | |
3908 } | |
3909 if (this.if != this._lastIf) { | |
3910 this.fire('dom-change'); | |
3911 this._lastIf = this.if; | |
3912 } | |
3913 }, | |
3914 _ensureInstance: function () { | |
3915 if (!this._instance) { | |
3916 this._instance = this.stamp(); | |
3917 var root = this._instance.root; | |
3918 var parent = Polymer.dom(Polymer.dom(this).parentNode); | |
3919 parent.insertBefore(root, this); | |
3920 } | |
3921 }, | |
3922 _teardownInstance: function () { | |
3923 if (this._instance) { | |
3924 var c = this._instance._children; | |
3925 if (c) { | |
3926 var parent = Polymer.dom(Polymer.dom(c[0]).parentNode); | |
3927 c.forEach(function (n) { | |
3928 parent.removeChild(n); | |
3929 }); | |
3930 } | |
3931 this._instance = null; | |
3932 } | |
3933 }, | |
3934 _wrapTextNodes: function (root) { | |
3935 for (var n = root.firstChild; n; n = n.nextSibling) { | |
3936 if (n.nodeType === Node.TEXT_NODE && n.textContent.trim()) { | |
3937 var s = document.createElement('span'); | |
3938 root.insertBefore(s, n); | |
3939 s.appendChild(n); | |
3940 n = s; | |
3941 } | |
3942 } | |
3943 }, | |
3944 _showHideChildren: function () { | |
3945 var hidden = this.__hideTemplateChildren__ || !this.if; | |
3946 if (this._instance) { | |
3947 this._instance._showHideChildren(hidden); | |
3948 } | |
3949 }, | |
3950 _forwardParentProp: function (prop, value) { | |
3951 if (this._instance) { | |
3952 this._instance[prop] = value; | |
3953 } | |
3954 }, | |
3955 _forwardParentPath: function (path, value) { | |
3956 if (this._instance) { | |
3957 this._instance.notifyPath(path, value, true); | |
3958 } | |
3959 } | |
3960 }); | |
3961 Polymer.ImportStatus = { | |
3962 _ready: false, | |
3963 _callbacks: [], | |
3964 whenLoaded: function (cb) { | |
3965 if (this._ready) { | |
3966 cb(); | |
3967 } else { | |
3968 this._callbacks.push(cb); | |
3969 } | |
3970 }, | |
3971 _importsLoaded: function () { | |
3972 this._ready = true; | |
3973 this._callbacks.forEach(function (cb) { | |
3974 cb(); | |
3975 }); | |
3976 this._callbacks = []; | |
3977 } | |
3978 }; | |
3979 window.addEventListener('load', function () { | |
3980 Polymer.ImportStatus._importsLoaded(); | |
3981 }); | |
3982 if (window.HTMLImports) { | |
3983 HTMLImports.whenReady(function () { | |
3984 Polymer.ImportStatus._importsLoaded(); | |
3985 }); | |
3986 } | |
3987 Polymer({ | |
3988 is: 'dom-bind', | |
3989 extends: 'template', | |
3990 created: function () { | |
3991 Polymer.ImportStatus.whenLoaded(this._readySelf.bind(this)); | |
3992 }, | |
3993 _registerFeatures: function () { | |
3994 this._prepConstructor(); | |
3995 }, | |
3996 _insertChildren: function () { | |
3997 var parentDom = Polymer.dom(Polymer.dom(this).parentNode); | |
3998 parentDom.insertBefore(this.root, this); | |
3999 }, | |
4000 _removeChildren: function () { | |
4001 if (this._children) { | |
4002 for (var i = 0; i < this._children.length; i++) { | |
4003 this.root.appendChild(this._children[i]); | |
4004 } | |
4005 } | |
4006 }, | |
4007 _initFeatures: function () { | |
4008 }, | |
4009 _scopeElementClass: function (element, selector) { | |
4010 if (this.dataHost) { | |
4011 return this.dataHost._scopeElementClass(element, selector); | |
4012 } else { | |
4013 return selector; | |
4014 } | |
4015 }, | |
4016 _prepConfigure: function () { | |
4017 var config = {}; | |
4018 for (var prop in this._propertyEffects) { | |
4019 config[prop] = this[prop]; | |
4020 } | |
4021 this._setupConfigure = this._setupConfigure.bind(this, config); | |
4022 }, | |
4023 attached: function () { | |
4024 if (!this._children) { | |
4025 this._template = this; | |
4026 this._prepAnnotations(); | |
4027 this._prepEffects(); | |
4028 this._prepBehaviors(); | |
4029 this._prepConfigure(); | |
4030 this._prepBindings(); | |
4031 Polymer.Base._initFeatures.call(this); | |
4032 this._children = Array.prototype.slice.call(this.root.childNodes); | |
4033 } | |
4034 this._insertChildren(); | |
4035 this.fire('dom-change'); | |
4036 }, | |
4037 detached: function () { | |
4038 this._removeChildren(); | |
4039 } | |
4040 });</script> | |
OLD | NEW |