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

Side by Side Diff: pkg/polymer/lib/src/js/polymer/polymer.concat.js

Issue 349313005: update polymer and platform.js (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /** 1 /**
2 * @license 2 * @license
3 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. 3 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
4 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt 4 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
5 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. 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/CON TRIBUTORS.txt 6 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
7 * Code distributed by Google as part of the polymer project is also 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/PA TENTS.txt 8 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
9 */ 9 */
10 window.PolymerGestures = {}; 10 window.PolymerGestures = {
11 hasSDPolyfill: Boolean(window.ShadowDOMPolyfill)
12 };
13 PolymerGestures.wrap = PolymerGestures.hasSDPolyfill ? ShadowDOMPolyfill.wrapIfN eeded : function(a){ return a; };
11 14
12 /* 15 /*
13 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. 16 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
14 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt 17 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
15 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt 18 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
16 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt 19 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
17 * Code distributed by Google as part of the polymer project is also 20 * Code distributed by Google as part of the polymer project is also
18 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt 21 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
19 */ 22 */
20 23
21 (function(scope) { 24 (function(scope) {
25 var HAS_FULL_PATH = false;
26
27 // test for full event path support
28 var pathTest = document.createElement('meta');
29 if (!scope.hasSDPolyfill && pathTest.createShadowRoot) {
30 var sr = pathTest.createShadowRoot();
31 var s = document.createElement('span');
32 sr.appendChild(s);
33 pathTest.addEventListener('testpath', function(ev) {
34 if (ev.path) {
35 // if the span is in the event path, then path[0] is the real source for all events
36 HAS_FULL_PATH = ev.path[0] === s;
37 }
38 ev.stopPropagation();
39 });
40 var ev = new CustomEvent('testpath', {bubbles: true});
41 // must add node to DOM to trigger event listener
42 document.head.appendChild(pathTest);
43 s.dispatchEvent(ev);
44 pathTest.parentNode.removeChild(pathTest);
45 sr = s = null;
46 }
47 pathTest = null;
48
22 var target = { 49 var target = {
23 shadow: function(inEl) { 50 shadow: function(inEl) {
24 if (inEl) { 51 if (inEl) {
25 return inEl.shadowRoot || inEl.webkitShadowRoot; 52 return inEl.shadowRoot || inEl.webkitShadowRoot;
26 } 53 }
27 }, 54 },
28 canTarget: function(shadow) { 55 canTarget: function(shadow) {
29 return shadow && Boolean(shadow.elementFromPoint); 56 return shadow && Boolean(shadow.elementFromPoint);
30 }, 57 },
31 targetingShadow: function(inEl) { 58 targetingShadow: function(inEl) {
(...skipping 14 matching lines...) Expand all
46 }, 73 },
47 allShadows: function(element) { 74 allShadows: function(element) {
48 var shadows = [], s = this.shadow(element); 75 var shadows = [], s = this.shadow(element);
49 while(s) { 76 while(s) {
50 shadows.push(s); 77 shadows.push(s);
51 s = this.olderShadow(s); 78 s = this.olderShadow(s);
52 } 79 }
53 return shadows; 80 return shadows;
54 }, 81 },
55 searchRoot: function(inRoot, x, y) { 82 searchRoot: function(inRoot, x, y) {
83 var t, st, sr, os;
56 if (inRoot) { 84 if (inRoot) {
57 var t = inRoot.elementFromPoint(x, y); 85 t = inRoot.elementFromPoint(x, y);
58 var st, sr, os; 86 if (t) {
59 // is element a shadow host? 87 // found element, check if it has a ShadowRoot
60 sr = this.targetingShadow(t); 88 sr = this.targetingShadow(t);
61 while (sr) { 89 } else if (inRoot !== document) {
62 // find the the element inside the shadow root 90 // check for sibling roots
63 st = sr.elementFromPoint(x, y); 91 sr = this.olderShadow(inRoot);
64 if (!st) {
65 // check for older shadows
66 sr = this.olderShadow(sr);
67 } else {
68 // shadowed element may contain a shadow root
69 var ssr = this.targetingShadow(st);
70 return this.searchRoot(ssr, x, y) || st;
71 }
72 } 92 }
73 // light dom element is the target 93 // search other roots, fall back to light dom element
74 return t; 94 return this.searchRoot(sr, x, y) || t;
75 } 95 }
76 }, 96 },
77 owner: function(element) { 97 owner: function(element) {
78 if (!element) { 98 if (!element) {
79 return document; 99 return document;
80 } 100 }
81 var s = element; 101 var s = element;
82 // walk up until you hit the shadow root or document 102 // walk up until you hit the shadow root or document
83 while (s.parentNode) { 103 while (s.parentNode) {
84 s = s.parentNode; 104 s = s.parentNode;
85 } 105 }
86 // the owner element is expected to be a Document or ShadowRoot 106 // the owner element is expected to be a Document or ShadowRoot
87 if (s.nodeType != Node.DOCUMENT_NODE && s.nodeType != Node.DOCUMENT_FRAGME NT_NODE) { 107 if (s.nodeType != Node.DOCUMENT_NODE && s.nodeType != Node.DOCUMENT_FRAGME NT_NODE) {
88 s = document; 108 s = document;
89 } 109 }
90 return s; 110 return s;
91 }, 111 },
92 findTarget: function(inEvent) { 112 findTarget: function(inEvent) {
113 if (HAS_FULL_PATH && inEvent.path) {
114 return inEvent.path[0];
115 }
93 var x = inEvent.clientX, y = inEvent.clientY; 116 var x = inEvent.clientX, y = inEvent.clientY;
94 // if the listener is in the shadow root, it is much faster to start there 117 // if the listener is in the shadow root, it is much faster to start there
95 var s = this.owner(inEvent.target); 118 var s = this.owner(inEvent.target);
96 // if x, y is not in this root, fall back to document search 119 // if x, y is not in this root, fall back to document search
97 if (!s.elementFromPoint(x, y)) { 120 if (!s.elementFromPoint(x, y)) {
98 s = document; 121 s = document;
99 } 122 }
100 return this.searchRoot(s, x, y); 123 return this.searchRoot(s, x, y);
101 }, 124 },
125 findScrollAxis: function(inEvent) {
126 var n;
127 if (HAS_FULL_PATH && inEvent.path) {
128 var path = inEvent.path;
129 for (var i = 0; i < path.length; i++) {
130 n = path[i];
131 if (n._scrollType) {
132 return n._scrollType;
133 }
134 }
135 } else {
136 n = scope.wrap(inEvent.currentTarget);
137 while(n) {
138 if (n._scrollType) {
139 return n._scrollType;
140 }
141 n = n.parentNode || n.host;
142 }
143 }
144 },
102 LCA: function(a, b) { 145 LCA: function(a, b) {
103 if (a === b) { 146 if (a === b) {
104 return a; 147 return a;
105 } 148 }
106 if (a && !b) { 149 if (a && !b) {
107 return a; 150 return a;
108 } 151 }
109 if (b && !a) { 152 if (b && !a) {
110 return b; 153 return b;
111 } 154 }
112 if (!b && !a) { 155 if (!b && !a) {
113 return document; 156 return document;
114 } 157 }
115 // fast case, a is a direct descendant of b or vice versa 158 // fast case, a is a direct descendant of b or vice versa
116 if (a.contains && a.contains(b)) { 159 if (a.contains && a.contains(b)) {
117 return a; 160 return a;
118 } 161 }
119 if (b.contains && b.contains(a)) { 162 if (b.contains && b.contains(a)) {
120 return b; 163 return b;
121 } 164 }
122 var adepth = this.depth(a); 165 var adepth = this.depth(a);
123 var bdepth = this.depth(b); 166 var bdepth = this.depth(b);
124 var d = adepth - bdepth; 167 var d = adepth - bdepth;
125 if (d > 0) { 168 if (d >= 0) {
126 a = this.walk(a, d); 169 a = this.walk(a, d);
127 } else { 170 } else {
128 b = this.walk(b, -d); 171 b = this.walk(b, -d);
129 } 172 }
130 while(a && b && a !== b) { 173 while (a && b && a !== b) {
131 a = this.walk(a, 1); 174 a = a.parentNode || a.host;
132 b = this.walk(b, 1); 175 b = b.parentNode || b.host;
133 } 176 }
134 return a; 177 return a;
135 }, 178 },
136 walk: function(n, u) { 179 walk: function(n, u) {
137 for (var i = 0; n && (i < u); i++) { 180 for (var i = 0; n && (i < u); i++) {
138 n = n.parentNode || n.host; 181 n = n.parentNode || n.host;
139 } 182 }
140 return n; 183 return n;
141 }, 184 },
142 depth: function(n) { 185 depth: function(n) {
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
222 'none', 265 'none',
223 'auto', 266 'auto',
224 'pan-x', 267 'pan-x',
225 'pan-y', 268 'pan-y',
226 { 269 {
227 rule: 'pan-x pan-y', 270 rule: 'pan-x pan-y',
228 selectors: [ 271 selectors: [
229 'pan-x pan-y', 272 'pan-x pan-y',
230 'pan-y pan-x' 273 'pan-y pan-x'
231 ] 274 ]
232 } 275 },
276 'manipulation'
233 ]; 277 ];
234 var styles = ''; 278 var styles = '';
235 // only install stylesheet if the browser has touch action support 279 // only install stylesheet if the browser has touch action support
236 var head = document.head; 280 var head = document.head;
237 var hasTouchAction = typeof document.head.style.touchAction === 'string'; 281 var hasTouchAction = typeof document.head.style.touchAction === 'string';
238 // only add shadow selectors if shadowdom is supported 282 // only add shadow selectors if shadowdom is supported
239 var hasShadowRoot = !window.ShadowDOMPolyfill && document.head.createShadowRoo t; 283 var hasShadowRoot = !window.ShadowDOMPolyfill && document.head.createShadowRoo t;
240 284
241 if (hasTouchAction) { 285 if (hasTouchAction) {
242 attrib2css.forEach(function(r) { 286 attrib2css.forEach(function(r) {
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
370 // define the properties of the PointerEvent interface 414 // define the properties of the PointerEvent interface
371 e.pointerId = inDict.pointerId || 0; 415 e.pointerId = inDict.pointerId || 0;
372 e.width = inDict.width || 0; 416 e.width = inDict.width || 0;
373 e.height = inDict.height || 0; 417 e.height = inDict.height || 0;
374 e.pressure = pressure; 418 e.pressure = pressure;
375 e.tiltX = inDict.tiltX || 0; 419 e.tiltX = inDict.tiltX || 0;
376 e.tiltY = inDict.tiltY || 0; 420 e.tiltY = inDict.tiltY || 0;
377 e.pointerType = inDict.pointerType || ''; 421 e.pointerType = inDict.pointerType || '';
378 e.hwTimestamp = inDict.hwTimestamp || 0; 422 e.hwTimestamp = inDict.hwTimestamp || 0;
379 e.isPrimary = inDict.isPrimary || false; 423 e.isPrimary = inDict.isPrimary || false;
424 e._source = inDict._source || '';
380 return e; 425 return e;
381 } 426 }
382 }; 427 };
383 428
384 scope.eventFactory = eventFactory; 429 scope.eventFactory = eventFactory;
385 })(window.PolymerGestures); 430 })(window.PolymerGestures);
386 431
387 /* 432 /*
388 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. 433 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
389 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt 434 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
493 // event instance 538 // event instance
494 'type', 539 'type',
495 'target', 540 'target',
496 'currentTarget', 541 'currentTarget',
497 'which', 542 'which',
498 'pageX', 543 'pageX',
499 'pageY', 544 'pageY',
500 'timeStamp', 545 'timeStamp',
501 // gesture addons 546 // gesture addons
502 'preventTap', 547 'preventTap',
503 'tapPrevented' 548 'tapPrevented',
549 '_source'
504 ]; 550 ];
505 551
506 var CLONE_DEFAULTS = [ 552 var CLONE_DEFAULTS = [
507 // MouseEvent 553 // MouseEvent
508 false, 554 false,
509 false, 555 false,
510 null, 556 null,
511 null, 557 null,
512 0, 558 0,
513 0, 559 0,
(...skipping 24 matching lines...) Expand all
538 0, 584 0,
539 0, 585 0,
540 0, 586 0,
541 0, 587 0,
542 function(){}, 588 function(){},
543 false 589 false
544 ]; 590 ];
545 591
546 var HAS_SVG_INSTANCE = (typeof SVGElementInstance !== 'undefined'); 592 var HAS_SVG_INSTANCE = (typeof SVGElementInstance !== 'undefined');
547 593
548 var wrap = window.ShadowDOMPolyfill && ShadowDOMPolyfill.wrapIfNeeded || funct ion(e){ return e; }; 594 var eventFactory = scope.eventFactory;
549 595
550 var eventFactory = scope.eventFactory; 596 var hasSDPolyfill = scope.hasSDPolyfill;
597 var wrap = scope.wrap;
598
551 /** 599 /**
552 * This module is for normalizing events. Mouse and Touch events will be 600 * This module is for normalizing events. Mouse and Touch events will be
553 * collected here, and fire PointerEvents that have the same semantics, no 601 * collected here, and fire PointerEvents that have the same semantics, no
554 * matter the source. 602 * matter the source.
555 * Events fired: 603 * Events fired:
556 * - pointerdown: a pointing is added 604 * - pointerdown: a pointing is added
557 * - pointerup: a pointer is removed 605 * - pointerup: a pointer is removed
558 * - pointermove: a pointer is moved 606 * - pointermove: a pointer is moved
559 * - pointerover: a pointer crosses into an element 607 * - pointerover: a pointer crosses into an element
560 * - pointerout: a pointer leaves an element 608 * - pointerout: a pointer leaves an element
(...skipping 26 matching lines...) Expand all
587 } 635 }
588 }, this); 636 }, this);
589 this.eventSources[name] = s; 637 this.eventSources[name] = s;
590 this.eventSourceList.push(s); 638 this.eventSourceList.push(s);
591 } 639 }
592 }, 640 },
593 registerGesture: function(name, source) { 641 registerGesture: function(name, source) {
594 this.gestures.push(source); 642 this.gestures.push(source);
595 }, 643 },
596 register: function(element) { 644 register: function(element) {
597 // NOTE: Work around for #4, don't add listeners to individual Polymer elm enets in SD Polyfill
598 if (window.ShadowDOMPolyfill && element !== document) {
599 return;
600 }
601 var l = this.eventSourceList.length; 645 var l = this.eventSourceList.length;
602 for (var i = 0, es; (i < l) && (es = this.eventSourceList[i]); i++) { 646 for (var i = 0, es; (i < l) && (es = this.eventSourceList[i]); i++) {
603 // call eventsource register 647 // call eventsource register
604 es.register.call(es, element); 648 es.register.call(es, element);
605 } 649 }
606 }, 650 },
607 unregister: function(element) { 651 unregister: function(element) {
608 var l = this.eventSourceList.length; 652 var l = this.eventSourceList.length;
609 for (var i = 0, es; (i < l) && (es = this.eventSourceList[i]); i++) { 653 for (var i = 0, es; (i < l) && (es = this.eventSourceList[i]); i++) {
610 // call eventsource register 654 // call eventsource register
(...skipping 26 matching lines...) Expand all
637 } 681 }
638 var type = inEvent.type; 682 var type = inEvent.type;
639 var fn = this.eventMap && this.eventMap[type]; 683 var fn = this.eventMap && this.eventMap[type];
640 if (fn) { 684 if (fn) {
641 fn(inEvent); 685 fn(inEvent);
642 } 686 }
643 inEvent._handledByPG = true; 687 inEvent._handledByPG = true;
644 }, 688 },
645 // set up event listeners 689 // set up event listeners
646 listen: function(target, events) { 690 listen: function(target, events) {
647 events.forEach(function(e) { 691 for (var i = 0, l = events.length, e; (i < l) && (e = events[i]); i++) {
648 this.addEvent(target, e); 692 this.addEvent(target, e);
649 }, this); 693 }
650 }, 694 },
651 // remove event listeners 695 // remove event listeners
652 unlisten: function(target, events) { 696 unlisten: function(target, events) {
653 events.forEach(function(e) { 697 for (var i = 0, l = events.length, e; (i < l) && (e = events[i]); i++) {
654 this.removeEvent(target, e); 698 this.removeEvent(target, e);
655 }, this); 699 }
656 }, 700 },
657 addEvent: function(target, eventName) { 701 addEvent: function(target, eventName) {
658 // NOTE: Work around for #4, use native event listener in SD Polyfill 702 // NOTE: Work around for #4, use native event listener in SD Polyfill
659 if (window.ShadowDOMPolyfill) { 703 if (hasSDPolyfill) {
660 target.addEventListener_(eventName, this.boundHandler); 704 target.addEventListener_(eventName, this.boundHandler);
661 } else { 705 } else {
662 target.addEventListener(eventName, this.boundHandler); 706 target.addEventListener(eventName, this.boundHandler);
663 } 707 }
664 }, 708 },
665 removeEvent: function(target, eventName) { 709 removeEvent: function(target, eventName) {
666 // NOTE: Work around for #4, use native event listener in SD Polyfill 710 // NOTE: Work around for #4, use native event listener in SD Polyfill
667 if (window.ShadowDOMPolyfill) { 711 if (hasSDPolyfill) {
668 target.removeEventListener_(eventName, this.boundHandler); 712 target.removeEventListener_(eventName, this.boundHandler);
669 } else { 713 } else {
670 target.removeEventListener(eventName, this.boundHandler); 714 target.removeEventListener(eventName, this.boundHandler);
671 } 715 }
672 }, 716 },
673 // EVENT CREATION AND TRACKING 717 // EVENT CREATION AND TRACKING
674 /** 718 /**
675 * Creates a new Event of type `inType`, based on the information in 719 * Creates a new Event of type `inType`, based on the information in
676 * `inEvent`. 720 * `inEvent`.
677 * 721 *
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
731 // clone after dispatch to pick up gesture prevention code 775 // clone after dispatch to pick up gesture prevention code
732 var clone = this.cloneEvent(inEvent); 776 var clone = this.cloneEvent(inEvent);
733 clone.target = t; 777 clone.target = t;
734 this.fillGestureQueue(clone); 778 this.fillGestureQueue(clone);
735 } 779 }
736 }, 780 },
737 gestureTrigger: function() { 781 gestureTrigger: function() {
738 // process the gesture queue 782 // process the gesture queue
739 for (var i = 0, e; i < this.gestureQueue.length; i++) { 783 for (var i = 0, e; i < this.gestureQueue.length; i++) {
740 e = this.gestureQueue[i]; 784 e = this.gestureQueue[i];
741 for (var j = 0, g; j < this.gestures.length; j++) { 785 for (var j = 0, g, fn; j < this.gestures.length; j++) {
742 g = this.gestures[j]; 786 g = this.gestures[j];
743 if (g.events.indexOf(e.type) >= 0) { 787 fn = g[e.type];
744 g[e.type].call(g, e); 788 if (fn) {
789 fn.call(g, e);
745 } 790 }
746 } 791 }
747 } 792 }
748 this.gestureQueue.length = 0; 793 this.gestureQueue.length = 0;
749 }, 794 },
750 fillGestureQueue: function(ev) { 795 fillGestureQueue: function(ev) {
751 // only trigger the gesture queue once 796 // only trigger the gesture queue once
752 if (!this.gestureQueue.length) { 797 if (!this.gestureQueue.length) {
753 requestAnimationFrame(this.boundGestureTrigger); 798 requestAnimationFrame(this.boundGestureTrigger);
754 } 799 }
755 this.gestureQueue.push(ev); 800 this.gestureQueue.push(ev);
756 } 801 }
757 }; 802 };
758 dispatcher.boundHandler = dispatcher.eventHandler.bind(dispatcher); 803 dispatcher.boundHandler = dispatcher.eventHandler.bind(dispatcher);
759 dispatcher.boundGestureTrigger = dispatcher.gestureTrigger.bind(dispatcher); 804 dispatcher.boundGestureTrigger = dispatcher.gestureTrigger.bind(dispatcher);
760 scope.dispatcher = dispatcher; 805 scope.dispatcher = dispatcher;
761 scope.register = dispatcher.register.bind(dispatcher); 806 scope.register = function(root) {
807 dispatcher.register(root);
808 };
762 scope.unregister = dispatcher.unregister.bind(dispatcher); 809 scope.unregister = dispatcher.unregister.bind(dispatcher);
810 scope.wrap = wrap;
763 })(window.PolymerGestures); 811 })(window.PolymerGestures);
764 812
765 /* 813 /*
766 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. 814 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
767 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt 815 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
768 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt 816 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
769 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt 817 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
770 * Code distributed by Google as part of the polymer project is also 818 * Code distributed by Google as part of the polymer project is also
771 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt 819 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
772 */ 820 */
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
909 HAS_BUTTONS = new MouseEvent('test', {buttons: 1}).buttons === 1; 957 HAS_BUTTONS = new MouseEvent('test', {buttons: 1}).buttons === 1;
910 } catch (e) {} 958 } catch (e) {}
911 959
912 // handler block for native mouse events 960 // handler block for native mouse events
913 var mouseEvents = { 961 var mouseEvents = {
914 POINTER_ID: 1, 962 POINTER_ID: 1,
915 POINTER_TYPE: 'mouse', 963 POINTER_TYPE: 'mouse',
916 events: [ 964 events: [
917 'mousedown', 965 'mousedown',
918 'mousemove', 966 'mousemove',
919 'mouseup', 967 'mouseup'
920 ], 968 ],
921 register: function(target) { 969 register: function(target) {
970 if (target !== document) {
971 return;
972 }
922 dispatcher.listen(target, this.events); 973 dispatcher.listen(target, this.events);
923 }, 974 },
924 unregister: function(target) { 975 unregister: function(target) {
925 dispatcher.unlisten(target, this.events); 976 dispatcher.unlisten(target, this.events);
926 }, 977 },
927 lastTouches: [], 978 lastTouches: [],
928 // collide with the global mouse listener 979 // collide with the global mouse listener
929 isEventSimulatedFromTouch: function(inEvent) { 980 isEventSimulatedFromTouch: function(inEvent) {
930 var lts = this.lastTouches; 981 var lts = this.lastTouches;
931 var x = inEvent.clientX, y = inEvent.clientY; 982 var x = inEvent.clientX, y = inEvent.clientY;
932 for (var i = 0, l = lts.length, t; i < l && (t = lts[i]); i++) { 983 for (var i = 0, l = lts.length, t; i < l && (t = lts[i]); i++) {
933 // simulated mouse events will be swallowed near a primary touchend 984 // simulated mouse events will be swallowed near a primary touchend
934 var dx = Math.abs(x - t.x), dy = Math.abs(y - t.y); 985 var dx = Math.abs(x - t.x), dy = Math.abs(y - t.y);
935 if (dx <= DEDUP_DIST && dy <= DEDUP_DIST) { 986 if (dx <= DEDUP_DIST && dy <= DEDUP_DIST) {
936 return true; 987 return true;
937 } 988 }
938 } 989 }
939 }, 990 },
940 prepareEvent: function(inEvent) { 991 prepareEvent: function(inEvent) {
941 var e = dispatcher.cloneEvent(inEvent); 992 var e = dispatcher.cloneEvent(inEvent);
942 e.pointerId = this.POINTER_ID; 993 e.pointerId = this.POINTER_ID;
943 e.isPrimary = true; 994 e.isPrimary = true;
944 e.pointerType = this.POINTER_TYPE; 995 e.pointerType = this.POINTER_TYPE;
996 e._source = 'mouse';
945 if (!HAS_BUTTONS) { 997 if (!HAS_BUTTONS) {
946 e.buttons = WHICH_TO_BUTTONS[e.which] || 0; 998 e.buttons = WHICH_TO_BUTTONS[e.which] || 0;
947 } 999 }
948 return e; 1000 return e;
949 }, 1001 },
950 mousedown: function(inEvent) { 1002 mousedown: function(inEvent) {
951 if (!this.isEventSimulatedFromTouch(inEvent)) { 1003 if (!this.isEventSimulatedFromTouch(inEvent)) {
952 var p = pointermap.has(this.POINTER_ID); 1004 var p = pointermap.has(this.POINTER_ID);
953 // TODO(dfreedman) workaround for some elements not sending mouseup 1005 // TODO(dfreedman) workaround for some elements not sending mouseup
954 // http://crbug/149091 1006 // http://crbug/149091
955 if (p) { 1007 if (p) {
956 this.mouseup(inEvent); 1008 this.mouseup(inEvent);
957 } 1009 }
958 var e = this.prepareEvent(inEvent); 1010 var e = this.prepareEvent(inEvent);
1011 e.target = scope.wrap(scope.findTarget(inEvent));
959 pointermap.set(this.POINTER_ID, e.target); 1012 pointermap.set(this.POINTER_ID, e.target);
960 dispatcher.down(e); 1013 dispatcher.down(e);
961 } 1014 }
962 }, 1015 },
963 mousemove: function(inEvent) { 1016 mousemove: function(inEvent) {
964 if (!this.isEventSimulatedFromTouch(inEvent)) { 1017 if (!this.isEventSimulatedFromTouch(inEvent)) {
965 var e = this.prepareEvent(inEvent); 1018 var e = this.prepareEvent(inEvent);
966 e.target = pointermap.get(this.POINTER_ID); 1019 e.target = pointermap.get(this.POINTER_ID);
967 dispatcher.move(e); 1020 dispatcher.move(e);
968 } 1021 }
969 }, 1022 },
970 mouseup: function(inEvent) { 1023 mouseup: function(inEvent) {
971 if (!this.isEventSimulatedFromTouch(inEvent)) { 1024 if (!this.isEventSimulatedFromTouch(inEvent)) {
972 var e = this.prepareEvent(inEvent); 1025 var e = this.prepareEvent(inEvent);
973 e.relatedTarget = e.target; 1026 e.relatedTarget = scope.wrap(scope.findTarget(inEvent));
974 e.target = pointermap.get(this.POINTER_ID); 1027 e.target = pointermap.get(this.POINTER_ID);
975 dispatcher.up(e); 1028 dispatcher.up(e);
976 this.cleanupMouse(); 1029 this.cleanupMouse();
977 } 1030 }
978 }, 1031 },
979 cleanupMouse: function() { 1032 cleanupMouse: function() {
980 pointermap['delete'](this.POINTER_ID); 1033 pointermap['delete'](this.POINTER_ID);
981 } 1034 }
982 }; 1035 };
983 1036
(...skipping 10 matching lines...) Expand all
994 */ 1047 */
995 1048
996 (function(scope) { 1049 (function(scope) {
997 var dispatcher = scope.dispatcher; 1050 var dispatcher = scope.dispatcher;
998 var allShadows = scope.targetFinding.allShadows.bind(scope.targetFinding); 1051 var allShadows = scope.targetFinding.allShadows.bind(scope.targetFinding);
999 var pointermap = dispatcher.pointermap; 1052 var pointermap = dispatcher.pointermap;
1000 var touchMap = Array.prototype.map.call.bind(Array.prototype.map); 1053 var touchMap = Array.prototype.map.call.bind(Array.prototype.map);
1001 // This should be long enough to ignore compat mouse events made by touch 1054 // This should be long enough to ignore compat mouse events made by touch
1002 var DEDUP_TIMEOUT = 2500; 1055 var DEDUP_TIMEOUT = 2500;
1003 var CLICK_COUNT_TIMEOUT = 200; 1056 var CLICK_COUNT_TIMEOUT = 200;
1057 var HYSTERESIS = 20;
1004 var ATTRIB = 'touch-action'; 1058 var ATTRIB = 'touch-action';
1005 var INSTALLER; 1059 var INSTALLER;
1006 var HAS_TOUCH_ACTION = typeof document.head.style.touchAction === 'string'; 1060 // maybe one day...
1061 // var CAN_USE_GLOBAL = ATTRIB in document.head.style;
1062 var CAN_USE_GLOBAL = false;
1007 1063
1008 // handler block for native touch events 1064 // handler block for native touch events
1009 var touchEvents = { 1065 var touchEvents = {
1010 events: [ 1066 events: [
1011 'touchstart', 1067 'touchstart',
1012 'touchmove', 1068 'touchmove',
1013 'touchend', 1069 'touchend',
1014 'touchcancel' 1070 'touchcancel'
1015 ], 1071 ],
1016 register: function(target) { 1072 register: function(target) {
1017 if (HAS_TOUCH_ACTION) { 1073 if (CAN_USE_GLOBAL) {
1018 dispatcher.listen(target, this.events); 1074 dispatcher.listen(target, this.events);
1019 } else { 1075 } else {
1020 INSTALLER.enableOnSubtree(target); 1076 INSTALLER.enableOnSubtree(target);
1021 } 1077 }
1022 }, 1078 },
1023 unregister: function(target) { 1079 unregister: function(target) {
1024 if (HAS_TOUCH_ACTION) { 1080 if (CAN_USE_GLOBAL) {
1025 dispatcher.unlisten(target, this.events); 1081 dispatcher.unlisten(target, this.events);
1026 } else { 1082 } else {
1027 // TODO(dfreedman): is it worth it to disconnect the MO? 1083 // TODO(dfreedman): is it worth it to disconnect the MO?
1028 } 1084 }
1029 }, 1085 },
1030 elementAdded: function(el) { 1086 elementAdded: function(el) {
1031 var a = el.getAttribute(ATTRIB); 1087 var a = el.getAttribute(ATTRIB);
1032 var st = this.touchActionToScrollType(a); 1088 var st = this.touchActionToScrollType(a);
1033 if (st) { 1089 if (st) {
1034 el._scrollType = st; 1090 el._scrollType = st;
(...skipping 27 matching lines...) Expand all
1062 } else if (oldSt) { 1118 } else if (oldSt) {
1063 this.elementRemoved(el); 1119 this.elementRemoved(el);
1064 } else if (st) { 1120 } else if (st) {
1065 this.elementAdded(el); 1121 this.elementAdded(el);
1066 } 1122 }
1067 }, 1123 },
1068 scrollTypes: { 1124 scrollTypes: {
1069 EMITTER: 'none', 1125 EMITTER: 'none',
1070 XSCROLLER: 'pan-x', 1126 XSCROLLER: 'pan-x',
1071 YSCROLLER: 'pan-y', 1127 YSCROLLER: 'pan-y',
1072 SCROLLER: /^(?:pan-x pan-y)|(?:pan-y pan-x)|auto$/ 1128 SCROLLER: /^(?:pan-x pan-y)|(?:pan-y pan-x)|auto|manipulation$/
1073 }, 1129 },
1074 touchActionToScrollType: function(touchAction) { 1130 touchActionToScrollType: function(touchAction) {
1075 var t = touchAction; 1131 var t = touchAction;
1076 var st = this.scrollTypes; 1132 var st = this.scrollTypes;
1077 if (t === 'none') { 1133 if (t === 'none') {
1078 return 'none'; 1134 return 'none';
1079 } else if (t === st.XSCROLLER) { 1135 } else if (t === st.XSCROLLER) {
1080 return 'X'; 1136 return 'X';
1081 } else if (t === st.YSCROLLER) { 1137 } else if (t === st.YSCROLLER) {
1082 return 'Y'; 1138 return 'Y';
1083 } else if (st.SCROLLER.exec(t)) { 1139 } else if (st.SCROLLER.exec(t)) {
1084 return 'XY'; 1140 return 'XY';
1085 } 1141 }
1086 }, 1142 },
1087 POINTER_TYPE: 'touch', 1143 POINTER_TYPE: 'touch',
1088 firstTouch: null, 1144 firstTouch: null,
1089 isPrimaryTouch: function(inTouch) { 1145 isPrimaryTouch: function(inTouch) {
1090 return this.firstTouch === inTouch.identifier; 1146 return this.firstTouch === inTouch.identifier;
1091 }, 1147 },
1092 setPrimaryTouch: function(inTouch) { 1148 setPrimaryTouch: function(inTouch) {
1093 // set primary touch if there no pointers, or the only pointer is the mous e 1149 // set primary touch if there no pointers, or the only pointer is the mous e
1094 if (pointermap.pointers() === 0 || (pointermap.pointers() === 1 && pointer map.has(1))) { 1150 if (pointermap.pointers() === 0 || (pointermap.pointers() === 1 && pointer map.has(1))) {
1095 this.firstTouch = inTouch.identifier; 1151 this.firstTouch = inTouch.identifier;
1096 this.firstXY = {X: inTouch.clientX, Y: inTouch.clientY}; 1152 this.firstXY = {X: inTouch.clientX, Y: inTouch.clientY};
1097 this.scrolling = false; 1153 this.scrolling = null;
1098 this.cancelResetClickCount(); 1154 this.cancelResetClickCount();
1099 } 1155 }
1100 }, 1156 },
1101 removePrimaryPointer: function(inPointer) { 1157 removePrimaryPointer: function(inPointer) {
1102 if (inPointer.isPrimary) { 1158 if (inPointer.isPrimary) {
1103 this.firstTouch = null; 1159 this.firstTouch = null;
1104 this.firstXY = null; 1160 this.firstXY = null;
1105 this.resetClickCount(); 1161 this.resetClickCount();
1106 } 1162 }
1107 }, 1163 },
(...skipping 13 matching lines...) Expand all
1121 }, 1177 },
1122 typeToButtons: function(type) { 1178 typeToButtons: function(type) {
1123 var ret = 0; 1179 var ret = 0;
1124 if (type === 'touchstart' || type === 'touchmove') { 1180 if (type === 'touchstart' || type === 'touchmove') {
1125 ret = 1; 1181 ret = 1;
1126 } 1182 }
1127 return ret; 1183 return ret;
1128 }, 1184 },
1129 findTarget: function(touch, id) { 1185 findTarget: function(touch, id) {
1130 if (this.currentTouchEvent.type === 'touchstart') { 1186 if (this.currentTouchEvent.type === 'touchstart') {
1131 return scope.findTarget(touch); 1187 if (this.isPrimaryTouch(touch)) {
1188 var fastPath = {
1189 clientX: touch.clientX,
1190 clientY: touch.clientY,
1191 path: this.currentTouchEvent.path,
1192 target: scope.wrap(this.currentTouchEvent.target)
1193 };
1194 return scope.findTarget(fastPath);
1195 } else {
1196 return scope.findTarget(touch);
1197 }
1132 } 1198 }
1133 // reuse target we found in touchstart 1199 // reuse target we found in touchstart
1134 return pointermap.get(id); 1200 return pointermap.get(id);
1135 }, 1201 },
1136 touchToPointer: function(inTouch) { 1202 touchToPointer: function(inTouch) {
1137 var cte = this.currentTouchEvent; 1203 var cte = this.currentTouchEvent;
1138 var e = dispatcher.cloneEvent(inTouch); 1204 var e = dispatcher.cloneEvent(inTouch);
1139 // Spec specifies that pointerId 1 is reserved for Mouse. 1205 // Spec specifies that pointerId 1 is reserved for Mouse.
1140 // Touch identifiers can start at 0. 1206 // Touch identifiers can start at 0.
1141 // Add 2 to the touch identifier for compatibility. 1207 // Add 2 to the touch identifier for compatibility.
1142 var id = e.pointerId = inTouch.identifier + 2; 1208 var id = e.pointerId = inTouch.identifier + 2;
1143 e.target = this.findTarget(inTouch, id); 1209 e.target = scope.wrap(this.findTarget(inTouch, id));
1144 e.bubbles = true; 1210 e.bubbles = true;
1145 e.cancelable = true; 1211 e.cancelable = true;
1146 e.detail = this.clickCount; 1212 e.detail = this.clickCount;
1147 e.buttons = this.typeToButtons(cte.type); 1213 e.buttons = this.typeToButtons(cte.type);
1148 e.width = inTouch.webkitRadiusX || inTouch.radiusX || 0; 1214 e.width = inTouch.webkitRadiusX || inTouch.radiusX || 0;
1149 e.height = inTouch.webkitRadiusY || inTouch.radiusY || 0; 1215 e.height = inTouch.webkitRadiusY || inTouch.radiusY || 0;
1150 e.pressure = inTouch.webkitForce || inTouch.force || 0.5; 1216 e.pressure = inTouch.webkitForce || inTouch.force || 0.5;
1151 e.isPrimary = this.isPrimaryTouch(inTouch); 1217 e.isPrimary = this.isPrimaryTouch(inTouch);
1152 e.pointerType = this.POINTER_TYPE; 1218 e.pointerType = this.POINTER_TYPE;
1219 e._source = 'touch';
1153 // forward touch preventDefaults 1220 // forward touch preventDefaults
1154 var self = this; 1221 var self = this;
1155 e.preventDefault = function() { 1222 e.preventDefault = function() {
1156 self.scrolling = false; 1223 self.scrolling = false;
1157 self.firstXY = null; 1224 self.firstXY = null;
1158 cte.preventDefault(); 1225 cte.preventDefault();
1159 }; 1226 };
1160 return e; 1227 return e;
1161 }, 1228 },
1162 processTouches: function(inEvent, inFunction) { 1229 processTouches: function(inEvent, inFunction) {
1163 var tl = inEvent.changedTouches; 1230 var tl = inEvent.changedTouches;
1164 this.currentTouchEvent = inEvent; 1231 this.currentTouchEvent = inEvent;
1165 for (var i = 0, t; i < tl.length; i++) { 1232 for (var i = 0, t, p; i < tl.length; i++) {
1166 t = tl[i]; 1233 t = tl[i];
1167 inFunction.call(this, this.touchToPointer(t)); 1234 p = this.touchToPointer(t);
1235 if (inEvent.type === 'touchstart') {
1236 pointermap.set(p.pointerId, p.target);
1237 }
1238 if (pointermap.has(p.pointerId)) {
1239 inFunction.call(this, p);
1240 }
1241 if (inEvent.type === 'touchend' || inEvent._cancel) {
1242 this.cleanUpPointer(p);
1243 }
1168 } 1244 }
1169 }, 1245 },
1170 // For single axis scrollers, determines whether the element should emit 1246 // For single axis scrollers, determines whether the element should emit
1171 // pointer events or behave as a scroller 1247 // pointer events or behave as a scroller
1172 shouldScroll: function(inEvent) { 1248 shouldScroll: function(inEvent) {
1173 if (this.firstXY) { 1249 if (this.firstXY) {
1174 var ret; 1250 var ret;
1175 var scrollAxis = inEvent.currentTarget._scrollType; 1251 var scrollAxis = scope.targetFinding.findScrollAxis(inEvent);
1176 if (scrollAxis === 'none') { 1252 if (scrollAxis === 'none') {
1177 // this element is a touch-action: none, should never scroll 1253 // this element is a touch-action: none, should never scroll
1178 ret = false; 1254 ret = false;
1179 } else if (scrollAxis === 'XY') { 1255 } else if (scrollAxis === 'XY') {
1180 // this element should always scroll 1256 // this element should always scroll
1181 ret = true; 1257 ret = true;
1182 } else { 1258 } else {
1183 var t = inEvent.changedTouches[0]; 1259 var t = inEvent.changedTouches[0];
1184 // check the intended scroll axis, and other axis 1260 // check the intended scroll axis, and other axis
1185 var a = scrollAxis; 1261 var a = scrollAxis;
1186 var oa = scrollAxis === 'Y' ? 'X' : 'Y'; 1262 var oa = scrollAxis === 'Y' ? 'X' : 'Y';
1187 var da = Math.abs(t['client' + a] - this.firstXY[a]); 1263 var da = Math.abs(t['client' + a] - this.firstXY[a]);
1188 var doa = Math.abs(t['client' + oa] - this.firstXY[oa]); 1264 var doa = Math.abs(t['client' + oa] - this.firstXY[oa]);
1189 // if delta in the scroll axis > delta other axis, scroll instead of 1265 // if delta in the scroll axis > delta other axis, scroll instead of
1190 // making events 1266 // making events
1191 ret = da >= doa; 1267 ret = da >= doa;
1192 } 1268 }
1193 this.firstXY = null;
1194 return ret; 1269 return ret;
1195 } 1270 }
1196 }, 1271 },
1197 findTouch: function(inTL, inId) { 1272 findTouch: function(inTL, inId) {
1198 for (var i = 0, l = inTL.length, t; i < l && (t = inTL[i]); i++) { 1273 for (var i = 0, l = inTL.length, t; i < l && (t = inTL[i]); i++) {
1199 if (t.identifier === inId) { 1274 if (t.identifier === inId) {
1200 return true; 1275 return true;
1201 } 1276 }
1202 } 1277 }
1203 }, 1278 },
1204 // In some instances, a touchstart can happen without a touchend. This 1279 // In some instances, a touchstart can happen without a touchend. This
1205 // leaves the pointermap in a broken state. 1280 // leaves the pointermap in a broken state.
1206 // Therefore, on every touchstart, we remove the touches that did not fire a 1281 // Therefore, on every touchstart, we remove the touches that did not fire a
1207 // touchend event. 1282 // touchend event.
1208 // To keep state globally consistent, we fire a 1283 // To keep state globally consistent, we fire a
1209 // pointercancel for this "abandoned" touch 1284 // pointercancel for this "abandoned" touch
1210 vacuumTouches: function(inEvent) { 1285 vacuumTouches: function(inEvent) {
1211 var tl = inEvent.touches; 1286 var tl = inEvent.touches;
1212 // pointermap.pointers() should be < tl.length here, as the touchstart has not 1287 // pointermap.pointers() should be < tl.length here, as the touchstart has not
1213 // been processed yet. 1288 // been processed yet.
1214 if (pointermap.pointers() >= tl.length) { 1289 if (pointermap.pointers() >= tl.length) {
1215 var d = []; 1290 var d = [];
1216 pointermap.forEach(function(value, key) { 1291 pointermap.forEach(function(value, key) {
1217 // Never remove pointerId == 1, which is mouse. 1292 // Never remove pointerId == 1, which is mouse.
1218 // Touch identifiers are 2 smaller than their pointerId, which is the 1293 // Touch identifiers are 2 smaller than their pointerId, which is the
1219 // index in pointermap. 1294 // index in pointermap.
1220 if (key !== 1 && !this.findTouch(tl, key - 2)) { 1295 if (key !== 1 && !this.findTouch(tl, key - 2)) {
1221 var p = value.out; 1296 var p = value;
1222 d.push(p); 1297 d.push(p);
1223 } 1298 }
1224 }, this); 1299 }, this);
1225 d.forEach(this.cancelOut, this); 1300 d.forEach(function(p) {
1301 this.cancel(p);
1302 pointermap.delete(p.pointerId);
1303 });
1226 } 1304 }
1227 }, 1305 },
1228 touchstart: function(inEvent) { 1306 touchstart: function(inEvent) {
1229 this.vacuumTouches(inEvent); 1307 this.vacuumTouches(inEvent);
1230 this.setPrimaryTouch(inEvent.changedTouches[0]); 1308 this.setPrimaryTouch(inEvent.changedTouches[0]);
1231 this.dedupSynthMouse(inEvent); 1309 this.dedupSynthMouse(inEvent);
1232 if (!this.scrolling) { 1310 if (!this.scrolling) {
1233 this.clickCount++; 1311 this.clickCount++;
1234 this.processTouches(inEvent, this.down); 1312 this.processTouches(inEvent, this.down);
1235 } 1313 }
1236 }, 1314 },
1237 down: function(inPointer) { 1315 down: function(inPointer) {
1238 var p = pointermap.set(inPointer.pointerId, inPointer.target);
1239 dispatcher.down(inPointer); 1316 dispatcher.down(inPointer);
1240 }, 1317 },
1241 touchmove: function(inEvent) { 1318 touchmove: function(inEvent) {
1242 if (HAS_TOUCH_ACTION) { 1319 if (CAN_USE_GLOBAL) {
1243 this.processTouches(inEvent, this.move); 1320 this.processTouches(inEvent, this.move);
1244 } else { 1321 } else {
1245 if (!this.scrolling) { 1322 if (!this.scrolling) {
1246 if (this.shouldScroll(inEvent)) { 1323 if (this.scrolling === null && this.shouldScroll(inEvent)) {
1247 this.scrolling = true; 1324 this.scrolling = true;
1248 this.touchcancel(inEvent);
1249 } else { 1325 } else {
1326 this.scrolling = false;
1250 inEvent.preventDefault(); 1327 inEvent.preventDefault();
1251 this.processTouches(inEvent, this.move); 1328 this.processTouches(inEvent, this.move);
1252 } 1329 }
1330 } else if (this.firstXY) {
1331 var t = inEvent.changedTouches[0];
1332 var dx = t.clientX - this.firstXY.X;
1333 var dy = t.clientY - this.firstXY.Y;
1334 var dd = Math.sqrt(dx * dx + dy * dy);
1335 if (dd >= HYSTERESIS) {
1336 this.touchcancel(inEvent);
1337 this.scrolling = true;
1338 this.firstXY = null;
1339 }
1253 } 1340 }
1254 } 1341 }
1255 }, 1342 },
1256 move: function(inPointer) { 1343 move: function(inPointer) {
1257 var pointer = pointermap.get(inPointer.pointerId);
1258 // a finger drifted off the screen, ignore it
1259 if (!pointer) {
1260 return;
1261 }
1262 dispatcher.move(inPointer); 1344 dispatcher.move(inPointer);
1263 }, 1345 },
1264 touchend: function(inEvent) { 1346 touchend: function(inEvent) {
1265 this.dedupSynthMouse(inEvent); 1347 this.dedupSynthMouse(inEvent);
1266 this.processTouches(inEvent, this.up); 1348 this.processTouches(inEvent, this.up);
1267 }, 1349 },
1268 up: function(inPointer) { 1350 up: function(inPointer) {
1269 if (!this.scrolling) { 1351 inPointer.relatedTarget = scope.wrap(scope.findTarget(inPointer));
1270 inPointer.relatedTarget = scope.findTarget(inPointer); 1352 dispatcher.up(inPointer);
1271 dispatcher.up(inPointer);
1272 }
1273 this.cleanUpPointer(inPointer);
1274 }, 1353 },
1275 cancel: function(inPointer) { 1354 cancel: function(inPointer) {
1276 inPointer.relatedTarget = scope.findTarget(inPointer);
1277 dispatcher.cancel(inPointer); 1355 dispatcher.cancel(inPointer);
1278 this.cleanUpPointer(inPointer);
1279 }, 1356 },
1280 touchcancel: function(inEvent) { 1357 touchcancel: function(inEvent) {
1358 inEvent._cancel = true;
1281 this.processTouches(inEvent, this.cancel); 1359 this.processTouches(inEvent, this.cancel);
1282 }, 1360 },
1283 cleanUpPointer: function(inPointer) { 1361 cleanUpPointer: function(inPointer) {
1284 pointermap['delete'](inPointer.pointerId); 1362 pointermap['delete'](inPointer.pointerId);
1285 this.removePrimaryPointer(inPointer); 1363 this.removePrimaryPointer(inPointer);
1286 }, 1364 },
1287 // prevent synth mouse events from creating pointer events 1365 // prevent synth mouse events from creating pointer events
1288 dedupSynthMouse: function(inEvent) { 1366 dedupSynthMouse: function(inEvent) {
1289 var lts = scope.mouseEvents.lastTouches; 1367 var lts = scope.mouseEvents.lastTouches;
1290 var t = inEvent.changedTouches[0]; 1368 var t = inEvent.changedTouches[0];
1291 // only the primary finger will synth mouse events 1369 // only the primary finger will synth mouse events
1292 if (this.isPrimaryTouch(t)) { 1370 if (this.isPrimaryTouch(t)) {
1293 // remember x/y of last touch 1371 // remember x/y of last touch
1294 var lt = {x: t.clientX, y: t.clientY}; 1372 var lt = {x: t.clientX, y: t.clientY};
1295 lts.push(lt); 1373 lts.push(lt);
1296 var fn = (function(lts, lt){ 1374 var fn = (function(lts, lt){
1297 var i = lts.indexOf(lt); 1375 var i = lts.indexOf(lt);
1298 if (i > -1) { 1376 if (i > -1) {
1299 lts.splice(i, 1); 1377 lts.splice(i, 1);
1300 } 1378 }
1301 }).bind(null, lts, lt); 1379 }).bind(null, lts, lt);
1302 setTimeout(fn, DEDUP_TIMEOUT); 1380 setTimeout(fn, DEDUP_TIMEOUT);
1303 } 1381 }
1304 } 1382 }
1305 }; 1383 };
1306 1384
1307 if (!HAS_TOUCH_ACTION) { 1385 if (!CAN_USE_GLOBAL) {
1308 INSTALLER = new scope.Installer(touchEvents.elementAdded, touchEvents.elemen tRemoved, touchEvents.elementChanged, touchEvents); 1386 INSTALLER = new scope.Installer(touchEvents.elementAdded, touchEvents.elemen tRemoved, touchEvents.elementChanged, touchEvents);
1309 } 1387 }
1310 1388
1311 scope.touchEvents = touchEvents; 1389 scope.touchEvents = touchEvents;
1312 })(window.PolymerGestures); 1390 })(window.PolymerGestures);
1313 1391
1314 /* 1392 /*
1315 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. 1393 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
1316 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt 1394 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
1317 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt 1395 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
1318 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt 1396 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
1319 * Code distributed by Google as part of the polymer project is also 1397 * Code distributed by Google as part of the polymer project is also
1320 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt 1398 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
1321 */ 1399 */
1322 1400
1323 (function(scope) { 1401 (function(scope) {
1324 var dispatcher = scope.dispatcher; 1402 var dispatcher = scope.dispatcher;
1325 var pointermap = dispatcher.pointermap; 1403 var pointermap = dispatcher.pointermap;
1326 var HAS_BITMAP_TYPE = window.MSPointerEvent && typeof window.MSPointerEvent.MS POINTER_TYPE_MOUSE === 'number'; 1404 var HAS_BITMAP_TYPE = window.MSPointerEvent && typeof window.MSPointerEvent.MS POINTER_TYPE_MOUSE === 'number';
1327 var msEvents = { 1405 var msEvents = {
1328 events: [ 1406 events: [
1329 'MSPointerDown', 1407 'MSPointerDown',
1330 'MSPointerMove', 1408 'MSPointerMove',
1331 'MSPointerUp', 1409 'MSPointerUp',
1332 'MSPointerCancel', 1410 'MSPointerCancel',
1333 ], 1411 ],
1334 register: function(target) { 1412 register: function(target) {
1413 if (target !== document) {
1414 return;
1415 }
1335 dispatcher.listen(target, this.events); 1416 dispatcher.listen(target, this.events);
1336 }, 1417 },
1337 unregister: function(target) { 1418 unregister: function(target) {
1338 dispatcher.unlisten(target, this.events); 1419 dispatcher.unlisten(target, this.events);
1339 }, 1420 },
1340 POINTER_TYPES: [ 1421 POINTER_TYPES: [
1341 '', 1422 '',
1342 'unavailable', 1423 'unavailable',
1343 'touch', 1424 'touch',
1344 'pen', 1425 'pen',
1345 'mouse' 1426 'mouse'
1346 ], 1427 ],
1347 prepareEvent: function(inEvent) { 1428 prepareEvent: function(inEvent) {
1348 var e = inEvent; 1429 var e = inEvent;
1430 e = dispatcher.cloneEvent(inEvent);
1349 if (HAS_BITMAP_TYPE) { 1431 if (HAS_BITMAP_TYPE) {
1350 e = dispatcher.cloneEvent(inEvent);
1351 e.pointerType = this.POINTER_TYPES[inEvent.pointerType]; 1432 e.pointerType = this.POINTER_TYPES[inEvent.pointerType];
1352 } 1433 }
1434 e._source = 'ms';
1353 return e; 1435 return e;
1354 }, 1436 },
1355 cleanup: function(id) { 1437 cleanup: function(id) {
1356 pointermap['delete'](id); 1438 pointermap['delete'](id);
1357 }, 1439 },
1358 MSPointerDown: function(inEvent) { 1440 MSPointerDown: function(inEvent) {
1359 var e = this.prepareEvent(inEvent); 1441 var e = this.prepareEvent(inEvent);
1442 e.target = scope.wrap(scope.findTarget(inEvent));
1360 pointermap.set(inEvent.pointerId, e.target); 1443 pointermap.set(inEvent.pointerId, e.target);
1361 dispatcher.down(e); 1444 dispatcher.down(e);
1362 }, 1445 },
1363 MSPointerMove: function(inEvent) { 1446 MSPointerMove: function(inEvent) {
1364 var e = this.prepareEvent(inEvent); 1447 var e = this.prepareEvent(inEvent);
1365 e.target = pointermap.get(e.pointerId); 1448 e.target = pointermap.get(e.pointerId);
1366 dispatcher.move(e); 1449 dispatcher.move(e);
1367 }, 1450 },
1368 MSPointerUp: function(inEvent) { 1451 MSPointerUp: function(inEvent) {
1369 var e = this.prepareEvent(inEvent); 1452 var e = this.prepareEvent(inEvent);
1370 e.relatedTarget = e.target; 1453 e.relatedTarget = scope.wrap(scope.findTarget(inEvent));
1371 e.target = pointermap.get(e.pointerId); 1454 e.target = pointermap.get(e.pointerId);
1372 dispatcher.up(e); 1455 dispatcher.up(e);
1373 this.cleanup(inEvent.pointerId); 1456 this.cleanup(inEvent.pointerId);
1374 }, 1457 },
1375 MSPointerCancel: function(inEvent) { 1458 MSPointerCancel: function(inEvent) {
1376 var e = this.prepareEvent(inEvent); 1459 var e = this.prepareEvent(inEvent);
1377 e.relatedTarget = e.target; 1460 e.relatedTarget = scope.wrap(scope.findTarget(inEvent));
1378 e.target = pointermap.get(e.pointerId); 1461 e.target = pointermap.get(e.pointerId);
1379 dispatcher.cancel(e); 1462 dispatcher.cancel(e);
1380 this.cleanup(inEvent.pointerId); 1463 this.cleanup(inEvent.pointerId);
1381 } 1464 }
1382 }; 1465 };
1383 1466
1384 scope.msEvents = msEvents; 1467 scope.msEvents = msEvents;
1385 })(window.PolymerGestures); 1468 })(window.PolymerGestures);
1386 1469
1387 /* 1470 /*
1388 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. 1471 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
1389 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt 1472 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
1390 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt 1473 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
1391 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt 1474 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
1392 * Code distributed by Google as part of the polymer project is also 1475 * Code distributed by Google as part of the polymer project is also
1393 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt 1476 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
1394 */ 1477 */
1395 1478
1396 (function(scope) { 1479 (function(scope) {
1397 var dispatcher = scope.dispatcher; 1480 var dispatcher = scope.dispatcher;
1398 var pointermap = dispatcher.pointermap; 1481 var pointermap = dispatcher.pointermap;
1399 var pointerEvents = { 1482 var pointerEvents = {
1400 events: [ 1483 events: [
1401 'pointerdown', 1484 'pointerdown',
1402 'pointermove', 1485 'pointermove',
1403 'pointerup', 1486 'pointerup',
1404 'pointercancel' 1487 'pointercancel'
1405 ], 1488 ],
1406 prepareEvent: function(inEvent) { 1489 prepareEvent: function(inEvent) {
1407 return dispatcher.cloneEvent(inEvent); 1490 var e = dispatcher.cloneEvent(inEvent);
1491 e._source = 'pointer';
1492 return e;
1408 }, 1493 },
1409 register: function(target) { 1494 register: function(target) {
1495 if (target !== document) {
1496 return;
1497 }
1410 dispatcher.listen(target, this.events); 1498 dispatcher.listen(target, this.events);
1411 }, 1499 },
1412 unregister: function(target) { 1500 unregister: function(target) {
1413 dispatcher.unlisten(target, this.events); 1501 dispatcher.unlisten(target, this.events);
1414 }, 1502 },
1415 cleanup: function(id) { 1503 cleanup: function(id) {
1416 pointermap['delete'](id); 1504 pointermap['delete'](id);
1417 }, 1505 },
1418 pointerdown: function(inEvent) { 1506 pointerdown: function(inEvent) {
1419 var e = this.prepareEvent(inEvent); 1507 var e = this.prepareEvent(inEvent);
1508 e.target = scope.wrap(scope.findTarget(inEvent));
1420 pointermap.set(e.pointerId, e.target); 1509 pointermap.set(e.pointerId, e.target);
1421 dispatcher.down(e); 1510 dispatcher.down(e);
1422 }, 1511 },
1423 pointermove: function(inEvent) { 1512 pointermove: function(inEvent) {
1424 var e = this.prepareEvent(inEvent); 1513 var e = this.prepareEvent(inEvent);
1425 e.target = pointermap.get(e.pointerId); 1514 e.target = pointermap.get(e.pointerId);
1426 dispatcher.move(e); 1515 dispatcher.move(e);
1427 }, 1516 },
1428 pointerup: function(inEvent) { 1517 pointerup: function(inEvent) {
1429 var e = this.prepareEvent(inEvent); 1518 var e = this.prepareEvent(inEvent);
1430 e.relatedTarget = e.target; 1519 e.relatedTarget = scope.wrap(scope.findTarget(inEvent));
1431 e.target = pointermap.get(e.pointerId); 1520 e.target = pointermap.get(e.pointerId);
1432 dispatcher.up(e); 1521 dispatcher.up(e);
1433 this.cleanup(inEvent.pointerId); 1522 this.cleanup(inEvent.pointerId);
1434 }, 1523 },
1435 pointercancel: function(inEvent) { 1524 pointercancel: function(inEvent) {
1436 var e = this.prepareEvent(inEvent); 1525 var e = this.prepareEvent(inEvent);
1437 e.relatedTarget = e.target; 1526 e.relatedTarget = scope.wrap(scope.findTarget(inEvent));
1438 e.target = pointermap.get(e.pointerId); 1527 e.target = pointermap.get(e.pointerId);
1439 dispatcher.cancel(e); 1528 dispatcher.cancel(e);
1440 this.cleanup(inEvent.pointerId); 1529 this.cleanup(inEvent.pointerId);
1441 } 1530 }
1442 }; 1531 };
1443 1532
1444 scope.pointerEvents = pointerEvents; 1533 scope.pointerEvents = pointerEvents;
1445 })(window.PolymerGestures); 1534 })(window.PolymerGestures);
1446 1535
1447 /* 1536 /*
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
1625 clientY: inEvent.clientY, 1714 clientY: inEvent.clientY,
1626 pageX: inEvent.pageX, 1715 pageX: inEvent.pageX,
1627 pageY: inEvent.pageY, 1716 pageY: inEvent.pageY,
1628 screenX: inEvent.screenX, 1717 screenX: inEvent.screenX,
1629 screenY: inEvent.screenY, 1718 screenY: inEvent.screenY,
1630 xDirection: t.xDirection, 1719 xDirection: t.xDirection,
1631 yDirection: t.yDirection, 1720 yDirection: t.yDirection,
1632 trackInfo: t.trackInfo, 1721 trackInfo: t.trackInfo,
1633 relatedTarget: inEvent.relatedTarget, 1722 relatedTarget: inEvent.relatedTarget,
1634 pointerType: inEvent.pointerType, 1723 pointerType: inEvent.pointerType,
1635 pointerId: inEvent.pointerId 1724 pointerId: inEvent.pointerId,
1725 _source: 'track'
1636 }); 1726 });
1637 t.downTarget.dispatchEvent(e); 1727 t.downTarget.dispatchEvent(e);
1638 }, 1728 },
1639 down: function(inEvent) { 1729 down: function(inEvent) {
1640 if (inEvent.isPrimary && (inEvent.pointerType === 'mouse' ? inEvent.butto ns === 1 : true)) { 1730 if (inEvent.isPrimary && (inEvent.pointerType === 'mouse' ? inEvent.butto ns === 1 : true)) {
1641 var p = { 1731 var p = {
1642 downEvent: inEvent, 1732 downEvent: inEvent,
1643 downTarget: inEvent.target, 1733 downTarget: inEvent.target,
1644 trackInfo: {}, 1734 trackInfo: {},
1645 lastMoveEvent: null, 1735 lastMoveEvent: null,
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
1724 * @extends hold 1814 * @extends hold
1725 */ 1815 */
1726 /** 1816 /**
1727 * Milliseconds pointer has been held down. 1817 * Milliseconds pointer has been held down.
1728 * @type Number 1818 * @type Number
1729 * @property holdTime 1819 * @property holdTime
1730 */ 1820 */
1731 /** 1821 /**
1732 * This event is fired when a held pointer is released or moved. 1822 * This event is fired when a held pointer is released or moved.
1733 * 1823 *
1734 * @class released 1824 * @class release
1735 */ 1825 */
1736 1826
1737 (function(scope) { 1827 (function(scope) {
1738 var dispatcher = scope.dispatcher; 1828 var dispatcher = scope.dispatcher;
1739 var eventFactory = scope.eventFactory; 1829 var eventFactory = scope.eventFactory;
1740 var hold = { 1830 var hold = {
1741 // wait at least HOLD_DELAY ms between hold and pulse events 1831 // wait at least HOLD_DELAY ms between hold and pulse events
1742 HOLD_DELAY: 200, 1832 HOLD_DELAY: 200,
1743 // pointer can move WIGGLE_THRESHOLD pixels before not counting as a hold 1833 // pointer can move WIGGLE_THRESHOLD pixels before not counting as a hold
1744 WIGGLE_THRESHOLD: 16, 1834 WIGGLE_THRESHOLD: 16,
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
1786 } 1876 }
1787 } 1877 }
1788 }, 1878 },
1789 fireHold: function(inType, inHoldTime) { 1879 fireHold: function(inType, inHoldTime) {
1790 var p = { 1880 var p = {
1791 bubbles: true, 1881 bubbles: true,
1792 cancelable: true, 1882 cancelable: true,
1793 pointerType: this.heldPointer.pointerType, 1883 pointerType: this.heldPointer.pointerType,
1794 pointerId: this.heldPointer.pointerId, 1884 pointerId: this.heldPointer.pointerId,
1795 x: this.heldPointer.clientX, 1885 x: this.heldPointer.clientX,
1796 y: this.heldPointer.clientY 1886 y: this.heldPointer.clientY,
1887 _source: 'hold'
1797 }; 1888 };
1798 if (inHoldTime) { 1889 if (inHoldTime) {
1799 p.holdTime = inHoldTime; 1890 p.holdTime = inHoldTime;
1800 } 1891 }
1801 var e = eventFactory.makeGestureEvent(inType, p); 1892 var e = eventFactory.makeGestureEvent(inType, p);
1802 this.target.dispatchEvent(e); 1893 this.target.dispatchEvent(e);
1803 } 1894 }
1804 }; 1895 };
1805 dispatcher.registerGesture('hold', hold); 1896 dispatcher.registerGesture('hold', hold);
1806 })(window.PolymerGestures); 1897 })(window.PolymerGestures);
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
1879 bubbles: true, 1970 bubbles: true,
1880 cancelable: true, 1971 cancelable: true,
1881 x: inEvent.clientX, 1972 x: inEvent.clientX,
1882 y: inEvent.clientY, 1973 y: inEvent.clientY,
1883 detail: inEvent.detail, 1974 detail: inEvent.detail,
1884 pointerType: inEvent.pointerType, 1975 pointerType: inEvent.pointerType,
1885 pointerId: inEvent.pointerId, 1976 pointerId: inEvent.pointerId,
1886 altKey: inEvent.altKey, 1977 altKey: inEvent.altKey,
1887 ctrlKey: inEvent.ctrlKey, 1978 ctrlKey: inEvent.ctrlKey,
1888 metaKey: inEvent.metaKey, 1979 metaKey: inEvent.metaKey,
1889 shiftKey: inEvent.shiftKey 1980 shiftKey: inEvent.shiftKey,
1981 _source: 'tap'
1890 }); 1982 });
1891 t.dispatchEvent(e); 1983 t.dispatchEvent(e);
1892 } 1984 }
1893 } 1985 }
1894 pointermap.delete(inEvent.pointerId); 1986 pointermap.delete(inEvent.pointerId);
1895 } 1987 }
1896 }; 1988 };
1897 // patch eventFactory to remove id from tap's pointermap for preventTap calls 1989 // patch eventFactory to remove id from tap's pointermap for preventTap calls
1898 eventFactory.preventTap = function(e) { 1990 eventFactory.preventTap = function(e) {
1899 return function() { 1991 return function() {
(...skipping 751 matching lines...) Expand 10 before | Expand all | Expand 10 after
2651 expect('['); 2743 expect('[');
2652 2744
2653 expr = parseExpression(); 2745 expr = parseExpression();
2654 2746
2655 expect(']'); 2747 expect(']');
2656 2748
2657 return expr; 2749 return expr;
2658 } 2750 }
2659 2751
2660 function parseLeftHandSideExpression() { 2752 function parseLeftHandSideExpression() {
2661 var expr, property; 2753 var expr, args, property;
2662 2754
2663 expr = parsePrimaryExpression(); 2755 expr = parsePrimaryExpression();
2664 2756
2665 while (match('.') || match('[')) { 2757 while (true) {
2666 if (match('[')) { 2758 if (match('[')) {
2667 property = parseComputedMember(); 2759 property = parseComputedMember();
2668 expr = delegate.createMemberExpression('[', expr, property); 2760 expr = delegate.createMemberExpression('[', expr, property);
2669 } else { 2761 } else if (match('.')) {
2670 property = parseNonComputedMember(); 2762 property = parseNonComputedMember();
2671 expr = delegate.createMemberExpression('.', expr, property); 2763 expr = delegate.createMemberExpression('.', expr, property);
2764 } else if (match('(')) {
2765 args = parseArguments();
2766 expr = delegate.createCallExpression(expr, args);
2767 } else {
2768 break;
2672 } 2769 }
2673 } 2770 }
2674 2771
2675 return expr; 2772 return expr;
2676 } 2773 }
2677 2774
2678 // 11.3 Postfix Expressions 2775 // 11.3 Postfix Expressions
2679 2776
2680 var parsePostfixExpression = parseLeftHandSideExpression; 2777 var parsePostfixExpression = parseLeftHandSideExpression;
2681 2778
(...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after
3034 3131
3035 setValue: function(model, newValue) { 3132 setValue: function(model, newValue) {
3036 if (this.path.length == 1); 3133 if (this.path.length == 1);
3037 model = findScope(model, this.path[0]); 3134 model = findScope(model, this.path[0]);
3038 3135
3039 return this.path.setValueFrom(model, newValue); 3136 return this.path.setValueFrom(model, newValue);
3040 } 3137 }
3041 }; 3138 };
3042 3139
3043 function MemberExpression(object, property, accessor) { 3140 function MemberExpression(object, property, accessor) {
3141 this.computed = accessor == '[';
3142
3044 this.dynamicDeps = typeof object == 'function' || 3143 this.dynamicDeps = typeof object == 'function' ||
3045 object.dynamicDeps || 3144 object.dynamicDeps ||
3046 (accessor == '[' && !(property instanceof Literal)); 3145 (this.computed && !(property instanceof Literal));
3047
3048 // convert literal computed property access where literal value is a value
3049 // path to ident dot-access.
3050 if (accessor == '[' &&
3051 property instanceof Literal &&
3052 Path.get(property.value).valid) {
3053 accessor = '.';
3054 property = new IdentPath(property.value);
3055 }
3056 3146
3057 this.simplePath = 3147 this.simplePath =
3058 !this.dynamicDeps && 3148 !this.dynamicDeps &&
3059 property instanceof IdentPath && 3149 (property instanceof IdentPath || property instanceof Literal) &&
3060 (object instanceof MemberExpression || object instanceof IdentPath); 3150 (object instanceof MemberExpression || object instanceof IdentPath);
3061 3151
3062 this.object = this.simplePath ? object : getFn(object); 3152 this.object = this.simplePath ? object : getFn(object);
3063 this.property = accessor == '.' ? property : getFn(property); 3153 this.property = !this.computed || this.simplePath ?
3154 property : getFn(property);
3064 } 3155 }
3065 3156
3066 MemberExpression.prototype = { 3157 MemberExpression.prototype = {
3067 get fullPath() { 3158 get fullPath() {
3068 if (!this.fullPath_) { 3159 if (!this.fullPath_) {
3069 var last = this.object instanceof IdentPath ? 3160
3070 this.object.name : this.object.fullPath; 3161 var parts = this.object instanceof MemberExpression ?
3071 this.fullPath_ = Path.get(last + '.' + this.property.name); 3162 this.object.fullPath.slice() : [this.object.name];
3163 parts.push(this.property instanceof IdentPath ?
3164 this.property.name : this.property.value);
3165 this.fullPath_ = Path.get(parts);
3072 } 3166 }
3073 3167
3074 return this.fullPath_; 3168 return this.fullPath_;
3075 }, 3169 },
3076 3170
3077 valueFn: function() { 3171 valueFn: function() {
3078 if (!this.valueFn_) { 3172 if (!this.valueFn_) {
3079 var object = this.object; 3173 var object = this.object;
3080 3174
3081 if (this.simplePath) { 3175 if (this.simplePath) {
3082 var path = this.fullPath; 3176 var path = this.fullPath;
3083 3177
3084 this.valueFn_ = function(model, observer) { 3178 this.valueFn_ = function(model, observer) {
3085 if (observer) 3179 if (observer)
3086 observer.addPath(model, path); 3180 observer.addPath(model, path);
3087 3181
3088 return path.getValueFrom(model); 3182 return path.getValueFrom(model);
3089 }; 3183 };
3090 } else if (this.property instanceof IdentPath) { 3184 } else if (!this.computed) {
3091 var path = Path.get(this.property.name); 3185 var path = Path.get(this.property.name);
3092 3186
3093 this.valueFn_ = function(model, observer) { 3187 this.valueFn_ = function(model, observer, filterRegistry) {
3094 var context = object(model, observer); 3188 var context = object(model, observer, filterRegistry);
3095 3189
3096 if (observer) 3190 if (observer)
3097 observer.addPath(context, path); 3191 observer.addPath(context, path);
3098 3192
3099 return path.getValueFrom(context); 3193 return path.getValueFrom(context);
3100 } 3194 }
3101 } else { 3195 } else {
3102 // Computed property. 3196 // Computed property.
3103 var property = this.property; 3197 var property = this.property;
3104 3198
3105 this.valueFn_ = function(model, observer) { 3199 this.valueFn_ = function(model, observer, filterRegistry) {
3106 var context = object(model, observer); 3200 var context = object(model, observer, filterRegistry);
3107 var propName = property(model, observer); 3201 var propName = property(model, observer, filterRegistry);
3108 if (observer) 3202 if (observer)
3109 observer.addPath(context, propName); 3203 observer.addPath(context, [propName]);
3110 3204
3111 return context ? context[propName] : undefined; 3205 return context ? context[propName] : undefined;
3112 }; 3206 };
3113 } 3207 }
3114 } 3208 }
3115 return this.valueFn_; 3209 return this.valueFn_;
3116 }, 3210 },
3117 3211
3118 setValue: function(model, newValue) { 3212 setValue: function(model, newValue) {
3119 if (this.simplePath) { 3213 if (this.simplePath) {
(...skipping 10 matching lines...) Expand all
3130 3224
3131 function Filter(name, args) { 3225 function Filter(name, args) {
3132 this.name = name; 3226 this.name = name;
3133 this.args = []; 3227 this.args = [];
3134 for (var i = 0; i < args.length; i++) { 3228 for (var i = 0; i < args.length; i++) {
3135 this.args[i] = getFn(args[i]); 3229 this.args[i] = getFn(args[i]);
3136 } 3230 }
3137 } 3231 }
3138 3232
3139 Filter.prototype = { 3233 Filter.prototype = {
3140 transform: function(value, toModelDirection, filterRegistry, model, 3234 transform: function(model, observer, filterRegistry, toModelDirection,
3141 observer) { 3235 initialArgs) {
3142 var fn = filterRegistry[this.name]; 3236 var fn = filterRegistry[this.name];
3143 var context = model; 3237 var context = model;
3144 if (fn) { 3238 if (fn) {
3145 context = undefined; 3239 context = undefined;
3146 } else { 3240 } else {
3147 fn = context[this.name]; 3241 fn = context[this.name];
3148 if (!fn) { 3242 if (!fn) {
3149 console.error('Cannot find filter: ' + this.name); 3243 console.error('Cannot find function or filter: ' + this.name);
3150 return; 3244 return;
3151 } 3245 }
3152 } 3246 }
3153 3247
3154 // If toModelDirection is falsey, then the "normal" (dom-bound) direction 3248 // If toModelDirection is falsey, then the "normal" (dom-bound) direction
3155 // is used. Otherwise, it looks for a 'toModel' property function on the 3249 // is used. Otherwise, it looks for a 'toModel' property function on the
3156 // object. 3250 // object.
3157 if (toModelDirection) { 3251 if (toModelDirection) {
3158 fn = fn.toModel; 3252 fn = fn.toModel;
3159 } else if (typeof fn.toDOM == 'function') { 3253 } else if (typeof fn.toDOM == 'function') {
3160 fn = fn.toDOM; 3254 fn = fn.toDOM;
3161 } 3255 }
3162 3256
3163 if (typeof fn != 'function') { 3257 if (typeof fn != 'function') {
3164 console.error('No ' + (toModelDirection ? 'toModel' : 'toDOM') + 3258 console.error('Cannot find function or filter: ' + this.name);
3165 ' found on' + this.name);
3166 return; 3259 return;
3167 } 3260 }
3168 3261
3169 var args = [value]; 3262 var args = initialArgs || [];
3170 for (var i = 0; i < this.args.length; i++) { 3263 for (var i = 0; i < this.args.length; i++) {
3171 args[i + 1] = getFn(this.args[i])(model, observer); 3264 args.push(getFn(this.args[i])(model, observer, filterRegistry));
3172 } 3265 }
3173 3266
3174 return fn.apply(context, args); 3267 return fn.apply(context, args);
3175 } 3268 }
3176 }; 3269 };
3177 3270
3178 function notImplemented() { throw Error('Not Implemented'); } 3271 function notImplemented() { throw Error('Not Implemented'); }
3179 3272
3180 var unaryOperators = { 3273 var unaryOperators = {
3181 '+': function(v) { return +v; }, 3274 '+': function(v) { return +v; },
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
3215 this.dynamicDeps = false; 3308 this.dynamicDeps = false;
3216 } 3309 }
3217 3310
3218 ASTDelegate.prototype = { 3311 ASTDelegate.prototype = {
3219 createUnaryExpression: function(op, argument) { 3312 createUnaryExpression: function(op, argument) {
3220 if (!unaryOperators[op]) 3313 if (!unaryOperators[op])
3221 throw Error('Disallowed operator: ' + op); 3314 throw Error('Disallowed operator: ' + op);
3222 3315
3223 argument = getFn(argument); 3316 argument = getFn(argument);
3224 3317
3225 return function(model, observer) { 3318 return function(model, observer, filterRegistry) {
3226 return unaryOperators[op](argument(model, observer)); 3319 return unaryOperators[op](argument(model, observer, filterRegistry));
3227 }; 3320 };
3228 }, 3321 },
3229 3322
3230 createBinaryExpression: function(op, left, right) { 3323 createBinaryExpression: function(op, left, right) {
3231 if (!binaryOperators[op]) 3324 if (!binaryOperators[op])
3232 throw Error('Disallowed operator: ' + op); 3325 throw Error('Disallowed operator: ' + op);
3233 3326
3234 left = getFn(left); 3327 left = getFn(left);
3235 right = getFn(right); 3328 right = getFn(right);
3236 3329
3237 return function(model, observer) { 3330 return function(model, observer, filterRegistry) {
3238 return binaryOperators[op](left(model, observer), 3331 return binaryOperators[op](left(model, observer, filterRegistry),
3239 right(model, observer)); 3332 right(model, observer, filterRegistry));
3240 }; 3333 };
3241 }, 3334 },
3242 3335
3243 createConditionalExpression: function(test, consequent, alternate) { 3336 createConditionalExpression: function(test, consequent, alternate) {
3244 test = getFn(test); 3337 test = getFn(test);
3245 consequent = getFn(consequent); 3338 consequent = getFn(consequent);
3246 alternate = getFn(alternate); 3339 alternate = getFn(alternate);
3247 3340
3248 return function(model, observer) { 3341 return function(model, observer, filterRegistry) {
3249 return test(model, observer) ? 3342 return test(model, observer, filterRegistry) ?
3250 consequent(model, observer) : alternate(model, observer); 3343 consequent(model, observer, filterRegistry) :
3344 alternate(model, observer, filterRegistry);
3251 } 3345 }
3252 }, 3346 },
3253 3347
3254 createIdentifier: function(name) { 3348 createIdentifier: function(name) {
3255 var ident = new IdentPath(name); 3349 var ident = new IdentPath(name);
3256 ident.type = 'Identifier'; 3350 ident.type = 'Identifier';
3257 return ident; 3351 return ident;
3258 }, 3352 },
3259 3353
3260 createMemberExpression: function(accessor, object, property) { 3354 createMemberExpression: function(accessor, object, property) {
3261 var ex = new MemberExpression(object, property, accessor); 3355 var ex = new MemberExpression(object, property, accessor);
3262 if (ex.dynamicDeps) 3356 if (ex.dynamicDeps)
3263 this.dynamicDeps = true; 3357 this.dynamicDeps = true;
3264 return ex; 3358 return ex;
3265 }, 3359 },
3266 3360
3361 createCallExpression: function(expression, args) {
3362 if (!(expression instanceof IdentPath))
3363 throw Error('Only identifier function invocations are allowed');
3364
3365 var filter = new Filter(expression.name, args);
3366
3367 return function(model, observer, filterRegistry) {
3368 return filter.transform(model, observer, filterRegistry, false);
3369 };
3370 },
3371
3267 createLiteral: function(token) { 3372 createLiteral: function(token) {
3268 return new Literal(token.value); 3373 return new Literal(token.value);
3269 }, 3374 },
3270 3375
3271 createArrayExpression: function(elements) { 3376 createArrayExpression: function(elements) {
3272 for (var i = 0; i < elements.length; i++) 3377 for (var i = 0; i < elements.length; i++)
3273 elements[i] = getFn(elements[i]); 3378 elements[i] = getFn(elements[i]);
3274 3379
3275 return function(model, observer) { 3380 return function(model, observer, filterRegistry) {
3276 var arr = [] 3381 var arr = []
3277 for (var i = 0; i < elements.length; i++) 3382 for (var i = 0; i < elements.length; i++)
3278 arr.push(elements[i](model, observer)); 3383 arr.push(elements[i](model, observer, filterRegistry));
3279 return arr; 3384 return arr;
3280 } 3385 }
3281 }, 3386 },
3282 3387
3283 createProperty: function(kind, key, value) { 3388 createProperty: function(kind, key, value) {
3284 return { 3389 return {
3285 key: key instanceof IdentPath ? key.name : key.value, 3390 key: key instanceof IdentPath ? key.name : key.value,
3286 value: value 3391 value: value
3287 }; 3392 };
3288 }, 3393 },
3289 3394
3290 createObjectExpression: function(properties) { 3395 createObjectExpression: function(properties) {
3291 for (var i = 0; i < properties.length; i++) 3396 for (var i = 0; i < properties.length; i++)
3292 properties[i].value = getFn(properties[i].value); 3397 properties[i].value = getFn(properties[i].value);
3293 3398
3294 return function(model, observer) { 3399 return function(model, observer, filterRegistry) {
3295 var obj = {}; 3400 var obj = {};
3296 for (var i = 0; i < properties.length; i++) 3401 for (var i = 0; i < properties.length; i++)
3297 obj[properties[i].key] = properties[i].value(model, observer); 3402 obj[properties[i].key] =
3403 properties[i].value(model, observer, filterRegistry);
3298 return obj; 3404 return obj;
3299 } 3405 }
3300 }, 3406 },
3301 3407
3302 createFilter: function(name, args) { 3408 createFilter: function(name, args) {
3303 this.filters.push(new Filter(name, args)); 3409 this.filters.push(new Filter(name, args));
3304 }, 3410 },
3305 3411
3306 createAsExpression: function(expression, scopeIdent) { 3412 createAsExpression: function(expression, scopeIdent) {
3307 this.expression = expression; 3413 this.expression = expression;
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
3378 3484
3379 function setValueFn(newValue) { 3485 function setValueFn(newValue) {
3380 self.setValue(model, newValue, filterRegistry); 3486 self.setValue(model, newValue, filterRegistry);
3381 return newValue; 3487 return newValue;
3382 } 3488 }
3383 3489
3384 return new ObserverTransform(observer, valueFn, setValueFn, true); 3490 return new ObserverTransform(observer, valueFn, setValueFn, true);
3385 }, 3491 },
3386 3492
3387 getValue: function(model, observer, filterRegistry) { 3493 getValue: function(model, observer, filterRegistry) {
3388 var value = getFn(this.expression)(model, observer); 3494 var value = getFn(this.expression)(model, observer, filterRegistry);
3389 for (var i = 0; i < this.filters.length; i++) { 3495 for (var i = 0; i < this.filters.length; i++) {
3390 value = this.filters[i].transform(value, false, filterRegistry, model, 3496 value = this.filters[i].transform(model, observer, filterRegistry,
3391 observer); 3497 false, [value]);
3392 } 3498 }
3393 3499
3394 return value; 3500 return value;
3395 }, 3501 },
3396 3502
3397 setValue: function(model, newValue, filterRegistry) { 3503 setValue: function(model, newValue, filterRegistry) {
3398 var count = this.filters ? this.filters.length : 0; 3504 var count = this.filters ? this.filters.length : 0;
3399 while (count-- > 0) { 3505 while (count-- > 0) {
3400 newValue = this.filters[count].transform(newValue, true, filterRegistry, 3506 newValue = this.filters[count].transform(model, undefined,
3401 model); 3507 filterRegistry, true, [newValue]);
3402 } 3508 }
3403 3509
3404 if (this.expression.setValue) 3510 if (this.expression.setValue)
3405 return this.expression.setValue(model, newValue); 3511 return this.expression.setValue(model, newValue);
3406 } 3512 }
3407 } 3513 }
3408 3514
3409 /** 3515 /**
3410 * Converts a style property name to a css property name. For example: 3516 * Converts a style property name to a css property name. For example:
3411 * "WebkitUserSelect" to "-webkit-user-select" 3517 * "WebkitUserSelect" to "-webkit-user-select"
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
3503 if (!scopeName) 3609 if (!scopeName)
3504 return; 3610 return;
3505 3611
3506 var parentScope = template.templateInstance ? 3612 var parentScope = template.templateInstance ?
3507 template.templateInstance.model : 3613 template.templateInstance.model :
3508 template.model; 3614 template.model;
3509 3615
3510 var indexName = template.polymerExpressionIndexIdent_; 3616 var indexName = template.polymerExpressionIndexIdent_;
3511 3617
3512 return function(model) { 3618 return function(model) {
3513 var scope = Object.create(parentScope); 3619 return createScopeObject(parentScope, model, scopeName, indexName);
3514 scope[scopeName] = model;
3515 scope[indexName] = undefined;
3516 scope[parentScopeName] = parentScope;
3517 return scope;
3518 }; 3620 };
3519 } 3621 }
3520 }; 3622 };
3521 3623
3624 var createScopeObject = ('__proto__' in {}) ?
3625 function(parentScope, model, scopeName, indexName) {
3626 var scope = {};
3627 scope[scopeName] = model;
3628 scope[indexName] = undefined;
3629 scope[parentScopeName] = parentScope;
3630 scope.__proto__ = parentScope;
3631 return scope;
3632 } :
3633 function(parentScope, model, scopeName, indexName) {
3634 var scope = Object.create(parentScope);
3635 Object.defineProperty(scope, scopeName,
3636 { value: model, configurable: true, writable: true });
3637 Object.defineProperty(scope, indexName,
3638 { value: undefined, configurable: true, writable: true });
3639 Object.defineProperty(scope, parentScopeName,
3640 { value: parentScope, configurable: true, writable: true });
3641 return scope;
3642 };
3643
3522 global.PolymerExpressions = PolymerExpressions; 3644 global.PolymerExpressions = PolymerExpressions;
3523 if (global.exposeGetExpression) 3645 PolymerExpressions.getExpression = getExpression;
3524 global.getExpression_ = getExpression;
3525
3526 })(this); 3646 })(this);
3527 3647
3528 /* 3648 /*
3529 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. 3649 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
3530 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt 3650 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
3531 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt 3651 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
3532 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt 3652 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
3533 * Code distributed by Google as part of the polymer project is also 3653 * Code distributed by Google as part of the polymer project is also
3534 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt 3654 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
3535 */ 3655 */
3536 Polymer = { 3656 Polymer = {
3537 version: '0.3.1-604ba08' 3657 version: '0.3.3-0e73963'
3538 }; 3658 };
3539 3659
3540 /* 3660 /*
3541 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. 3661 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
3542 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt 3662 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
3543 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt 3663 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
3544 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt 3664 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
3545 * Code distributed by Google as part of the polymer project is also 3665 * Code distributed by Google as part of the polymer project is also
3546 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt 3666 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
3547 */ 3667 */
(...skipping 458 matching lines...) Expand 10 before | Expand all | Expand 10 after
4006 * Fire an event asynchronously. 4126 * Fire an event asynchronously.
4007 * @method asyncFire 4127 * @method asyncFire
4008 * @param {string} type An event name. 4128 * @param {string} type An event name.
4009 * @param detail 4129 * @param detail
4010 * @param {Node} toNode Target node. 4130 * @param {Node} toNode Target node.
4011 */ 4131 */
4012 asyncFire: function(/*inType, inDetail*/) { 4132 asyncFire: function(/*inType, inDetail*/) {
4013 this.async("fire", arguments); 4133 this.async("fire", arguments);
4014 }, 4134 },
4015 /** 4135 /**
4016 * Remove class from old, add class to anew, if they exist 4136 * Remove class from old, add class to anew, if they exist.
4017 * @param classFollows 4137 * @param classFollows
4018 * @param anew A node. 4138 * @param anew A node.
4019 * @param old A node 4139 * @param old A node
4020 * @param className 4140 * @param className
4021 */ 4141 */
4022 classFollows: function(anew, old, className) { 4142 classFollows: function(anew, old, className) {
4023 if (old) { 4143 if (old) {
4024 old.classList.remove(className); 4144 old.classList.remove(className);
4025 } 4145 }
4026 if (anew) { 4146 if (anew) {
4027 anew.classList.add(className); 4147 anew.classList.add(className);
4028 } 4148 }
4149 },
4150 /**
4151 * Inject HTML which contains markup bound to this element into
4152 * a target element (replacing target element content).
4153 * @param String html to inject
4154 * @param Element target element
4155 */
4156 injectBoundHTML: function(html, element) {
4157 var template = document.createElement('template');
4158 template.innerHTML = html;
4159 var fragment = this.instanceTemplate(template);
4160 if (element) {
4161 element.textContent = '';
4162 element.appendChild(fragment);
4163 }
4164 return fragment;
4029 } 4165 }
4030 }; 4166 };
4031 4167
4032 // no-operation function for handy stubs 4168 // no-operation function for handy stubs
4033 var nop = function() {}; 4169 var nop = function() {};
4034 4170
4035 // null-object for handy stubs 4171 // null-object for handy stubs
4036 var nob = {}; 4172 var nob = {};
4037 4173
4038 // deprecated 4174 // deprecated
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after
4215 var log = window.logFlags || {}; 4351 var log = window.logFlags || {};
4216 4352
4217 // magic words 4353 // magic words
4218 4354
4219 var OBSERVE_SUFFIX = 'Changed'; 4355 var OBSERVE_SUFFIX = 'Changed';
4220 4356
4221 // element api 4357 // element api
4222 4358
4223 var empty = []; 4359 var empty = [];
4224 4360
4361 var updateRecord = {
4362 object: undefined,
4363 type: 'update',
4364 name: undefined,
4365 oldValue: undefined
4366 };
4367
4368 var numberIsNaN = Number.isNaN || function(value) {
4369 return typeof value === 'number' && isNaN(value);
4370 }
4371
4372 function areSameValue(left, right) {
4373 if (left === right)
4374 return left !== 0 || 1 / left === 1 / right;
4375 if (numberIsNaN(left) && numberIsNaN(right))
4376 return true;
4377
4378 return left !== left && right !== right;
4379 }
4380
4381 // capture A's value if B's value is null or undefined,
4382 // otherwise use B's value
4383 function resolveBindingValue(oldValue, value) {
4384 if (value === undefined && oldValue === null) {
4385 return value;
4386 }
4387 return (value === null || value === undefined) ? oldValue : value;
4388 }
4389
4225 var properties = { 4390 var properties = {
4226 createPropertyObserver: function() { 4391 createPropertyObserver: function() {
4227 var n$ = this._observeNames; 4392 var n$ = this._observeNames;
4228 if (n$ && n$.length) { 4393 if (n$ && n$.length) {
4229 var o = this._propertyObserver = new CompoundObserver(true); 4394 var o = this._propertyObserver = new CompoundObserver(true);
4230 this.registerObservers([o]); 4395 this.registerObserver(o);
4231 // TODO(sorvell): may not be kosher to access the value here (this[n]); 4396 // TODO(sorvell): may not be kosher to access the value here (this[n]);
4232 // previously we looked at the descriptor on the prototype 4397 // previously we looked at the descriptor on the prototype
4233 // this doesn't work for inheritance and not for accessors without 4398 // this doesn't work for inheritance and not for accessors without
4234 // a value property 4399 // a value property
4235 for (var i=0, l=n$.length, n; (i<l) && (n=n$[i]); i++) { 4400 for (var i=0, l=n$.length, n; (i<l) && (n=n$[i]); i++) {
4236 o.addPath(this, n); 4401 o.addPath(this, n);
4237 this.observeArrayValue(n, this[n], null); 4402 this.observeArrayValue(n, this[n], null);
4238 } 4403 }
4239 } 4404 }
4240 }, 4405 },
4241 openPropertyObserver: function() { 4406 openPropertyObserver: function() {
4242 if (this._propertyObserver) { 4407 if (this._propertyObserver) {
4243 this._propertyObserver.open(this.notifyPropertyChanges, this); 4408 this._propertyObserver.open(this.notifyPropertyChanges, this);
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
4290 if (Array.isArray(value)) { 4455 if (Array.isArray(value)) {
4291 log.observe && console.log('[%s] observeArrayValue: register observer [%s]', this.localName, name, value); 4456 log.observe && console.log('[%s] observeArrayValue: register observer [%s]', this.localName, name, value);
4292 var observer = new ArrayObserver(value); 4457 var observer = new ArrayObserver(value);
4293 observer.open(function(value, old) { 4458 observer.open(function(value, old) {
4294 this.invokeMethod(callbackName, [old]); 4459 this.invokeMethod(callbackName, [old]);
4295 }, this); 4460 }, this);
4296 this.registerNamedObserver(name + '__array', observer); 4461 this.registerNamedObserver(name + '__array', observer);
4297 } 4462 }
4298 } 4463 }
4299 }, 4464 },
4465 emitPropertyChangeRecord: function(name, value, oldValue) {
4466 var object = this;
4467 if (areSameValue(value, oldValue))
4468 return;
4469
4470 this.propertyChanged_(name, value, oldValue);
4471
4472 if (!Observer.hasObjectObserve)
4473 return;
4474
4475 var notifier = this.notifier_;
4476 if (!notifier)
4477 notifier = this.notifier_ = Object.getNotifier(this);
4478
4479 updateRecord.object = this;
4480 updateRecord.name = name;
4481 updateRecord.oldValue = oldValue;
4482
4483 notifier.notify(updateRecord);
4484 },
4485 bindToAccessor: function(name, observable, resolveFn) {
4486 var privateName = name + '_';
4487 var privateObservable = name + 'Observable_';
4488
4489 this[privateObservable] = observable;
4490 var oldValue = this[privateName];
4491
4492 var self = this;
4493 var value = observable.open(function(value, oldValue) {
4494 self[privateName] = value;
4495 self.emitPropertyChangeRecord(name, value, oldValue);
4496 });
4497
4498 if (resolveFn && !areSameValue(oldValue, value)) {
4499 var resolvedValue = resolveFn(oldValue, value);
4500 if (!areSameValue(value, resolvedValue)) {
4501 value = resolvedValue;
4502 if (observable.setValue)
4503 observable.setValue(value);
4504 }
4505 }
4506
4507 this[privateName] = value;
4508 this.emitPropertyChangeRecord(name, value, oldValue);
4509
4510 var observer = {
4511 close: function() {
4512 observable.close();
4513 self[privateObservable] = undefined;
4514 }
4515 };
4516 this.registerObserver(observer);
4517 return observer;
4518 },
4519 createComputedProperties: function() {
4520 if (!this._computedNames) {
4521 return;
4522 }
4523
4524 for (var i = 0; i < this._computedNames.length; i++) {
4525 var name = this._computedNames[i];
4526 var expressionText = this.computed[name];
4527 try {
4528 var expression = PolymerExpressions.getExpression(expressionText);
4529 var observable = expression.getBinding(this, this.element.syntax);
4530 this.bindToAccessor(name, observable);
4531 } catch (ex) {
4532 console.error('Failed to create computed property', ex);
4533 }
4534 }
4535 },
4300 bindProperty: function(property, observable, oneTime) { 4536 bindProperty: function(property, observable, oneTime) {
4301 if (oneTime) { 4537 if (oneTime) {
4302 this[property] = observable; 4538 this[property] = observable;
4303 return; 4539 return;
4304 } 4540 }
4305 return bindProperties(this, property, observable); 4541 return this.bindToAccessor(property, observable, resolveBindingValue);
4306 }, 4542 },
4307 invokeMethod: function(method, args) { 4543 invokeMethod: function(method, args) {
4308 var fn = this[method] || method; 4544 var fn = this[method] || method;
4309 if (typeof fn === 'function') { 4545 if (typeof fn === 'function') {
4310 fn.apply(this, args); 4546 fn.apply(this, args);
4311 } 4547 }
4312 }, 4548 },
4313 registerObservers: function(observers) { 4549 registerObserver: function(observer) {
4314 this._observers = this._observers || []; 4550 if (!this._observers) {
4315 this._observers.push(observers); 4551 this._observers = [observer];
4552 return;
4553 }
4554
4555 this._observers.push(observer);
4316 }, 4556 },
4317 // observer array items are arrays of observers. 4557 // observer array items are arrays of observers.
4318 closeObservers: function() { 4558 closeObservers: function() {
4319 if (!this._observers) { 4559 if (!this._observers) {
4320 return; 4560 return;
4321 } 4561 }
4322 for (var i=0, l=this._observers.length; i<l; i++) { 4562
4323 this.closeObserverArray(this._observers[i]); 4563 var observers = this._observers;
4324 } 4564 for (var i = 0; i < observers.length; i++) {
4325 this._observers = []; 4565 var observer = observers[i];
4326 }, 4566 if (observer && typeof observer.close == 'function') {
4327 closeObserverArray: function(observerArray) { 4567 observer.close();
4328 for (var i=0, l=observerArray.length, o; i<l; i++) {
4329 o = observerArray[i];
4330 if (o && o.close) {
4331 o.close();
4332 } 4568 }
4333 } 4569 }
4570
4571 this._observers = [];
4334 }, 4572 },
4335 // bookkeeping observers for memory management 4573 // bookkeeping observers for memory management
4336 registerNamedObserver: function(name, observer) { 4574 registerNamedObserver: function(name, observer) {
4337 var o$ = this._namedObservers || (this._namedObservers = {}); 4575 var o$ = this._namedObservers || (this._namedObservers = {});
4338 o$[name] = observer; 4576 o$[name] = observer;
4339 }, 4577 },
4340 closeNamedObserver: function(name) { 4578 closeNamedObserver: function(name) {
4341 var o$ = this._namedObservers; 4579 var o$ = this._namedObservers;
4342 if (o$ && o$[name]) { 4580 if (o$ && o$[name]) {
4343 o$[name].close(); 4581 o$[name].close();
4344 o$[name] = null; 4582 o$[name] = null;
4345 return true; 4583 return true;
4346 } 4584 }
4347 }, 4585 },
4348 closeNamedObservers: function() { 4586 closeNamedObservers: function() {
4349 if (this._namedObservers) { 4587 if (this._namedObservers) {
4350 for (var i in this._namedObservers) { 4588 for (var i in this._namedObservers) {
4351 this.closeNamedObserver(i); 4589 this.closeNamedObserver(i);
4352 } 4590 }
4353 this._namedObservers = {}; 4591 this._namedObservers = {};
4354 } 4592 }
4355 } 4593 }
4356 }; 4594 };
4357 4595
4358 // property binding
4359 // bind a property in A to a path in B by converting A[property] to a
4360 // getter/setter pair that accesses B[...path...]
4361 function bindProperties(a, property, observable) {
4362 // apply Polymer two-way reference binding
4363 return Observer.bindToInstance(a, property, observable, resolveBindingValue) ;
4364 }
4365
4366 // capture A's value if B's value is null or undefined,
4367 // otherwise use B's value
4368 function resolveBindingValue(oldValue, value) {
4369 if (value === undefined && oldValue === null) {
4370 return value;
4371 }
4372 return (value === null || value === undefined) ? oldValue : value;
4373 }
4374
4375 // logging 4596 // logging
4376 var LOG_OBSERVE = '[%s] watching [%s]'; 4597 var LOG_OBSERVE = '[%s] watching [%s]';
4377 var LOG_OBSERVED = '[%s#%s] watch: [%s] now [%s] was [%s]'; 4598 var LOG_OBSERVED = '[%s#%s] watch: [%s] now [%s] was [%s]';
4378 var LOG_CHANGED = '[%s#%s] propertyChanged: [%s] now [%s] was [%s]'; 4599 var LOG_CHANGED = '[%s#%s] propertyChanged: [%s] now [%s] was [%s]';
4379 4600
4380 // exports 4601 // exports
4381 4602
4382 scope.api.instance.properties = properties; 4603 scope.api.instance.properties = properties;
4383 4604
4384 })(Polymer); 4605 })(Polymer);
(...skipping 13 matching lines...) Expand all
4398 4619
4399 var log = window.logFlags || 0; 4620 var log = window.logFlags || 0;
4400 4621
4401 // element api supporting mdv 4622 // element api supporting mdv
4402 var mdv = { 4623 var mdv = {
4403 instanceTemplate: function(template) { 4624 instanceTemplate: function(template) {
4404 // ensure a default bindingDelegate 4625 // ensure a default bindingDelegate
4405 var syntax = this.syntax || (!template.bindingDelegate && 4626 var syntax = this.syntax || (!template.bindingDelegate &&
4406 this.element.syntax); 4627 this.element.syntax);
4407 var dom = template.createInstance(this, syntax); 4628 var dom = template.createInstance(this, syntax);
4408 this.registerObservers(dom.bindings_); 4629 var observers = dom.bindings_;
4630 for (var i = 0; i < observers.length; i++) {
4631 this.registerObserver(observers[i]);
4632 }
4409 return dom; 4633 return dom;
4410 }, 4634 },
4411 bind: function(name, observable, oneTime) { 4635 bind: function(name, observable, oneTime) {
4412 var property = this.propertyForAttribute(name); 4636 var property = this.propertyForAttribute(name);
4413 if (!property) { 4637 if (!property) {
4414 // TODO(sjmiles): this mixin method must use the special form 4638 // TODO(sjmiles): this mixin method must use the special form
4415 // of `super` installed by `mixinMethod` in declaration/prototype.js 4639 // of `super` installed by `mixinMethod` in declaration/prototype.js
4416 return this.mixinSuper(arguments); 4640 return this.mixinSuper(arguments);
4417 } else { 4641 } else {
4418 // use n-way Polymer binding 4642 // use n-way Polymer binding
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
4551 // process input attributes 4775 // process input attributes
4552 this.takeAttributes(); 4776 this.takeAttributes();
4553 // add event listeners 4777 // add event listeners
4554 this.addHostListeners(); 4778 this.addHostListeners();
4555 }, 4779 },
4556 makeElementReady: function() { 4780 makeElementReady: function() {
4557 if (this._readied) { 4781 if (this._readied) {
4558 return; 4782 return;
4559 } 4783 }
4560 this._readied = true; 4784 this._readied = true;
4785 this.createComputedProperties();
4561 // TODO(sorvell): We could create an entry point here 4786 // TODO(sorvell): We could create an entry point here
4562 // for the user to compute property values. 4787 // for the user to compute property values.
4563 // process declarative resources 4788 // process declarative resources
4564 this.parseDeclarations(this.__proto__); 4789 this.parseDeclarations(this.__proto__);
4565 // TODO(sorvell): CE polyfill uses unresolved attribute to simulate 4790 // TODO(sorvell): CE polyfill uses unresolved attribute to simulate
4566 // :unresolved; remove this attribute to be compatible with native 4791 // :unresolved; remove this attribute to be compatible with native
4567 // CE. 4792 // CE.
4568 this.removeAttribute('unresolved'); 4793 this.removeAttribute('unresolved');
4569 // user entry point 4794 // user entry point
4570 this.ready(); 4795 this.ready();
4571 // TODO (sorvell): temporarily open observer when created 4796 // TODO (sorvell): temporarily open observer when created
4572 // turn on property observation and take any initial changes 4797 // turn on property observation and take any initial changes
4573 //this.openPropertyObserver(); 4798 //this.openPropertyObserver();
4574 }, 4799 },
4575 attachedCallback: function() { 4800 attachedCallback: function() {
4576 this.cancelUnbindAll(); 4801 this.cancelUnbindAll();
4577 // invoke user action 4802 // invoke user action
4578 if (this.attached) { 4803 if (this.attached) {
4579 this.attached(); 4804 this.attached();
4580 } 4805 }
4581 // TODO(sorvell): bc 4806 // TODO(sorvell): bc
4582 if (this.enteredView) { 4807 if (this.enteredView) {
4583 this.enteredView(); 4808 this.enteredView();
4584 } 4809 }
4585 // NOTE: domReady can be used to access elements in dom (descendants, 4810 // NOTE: domReady can be used to access elements in dom (descendants,
4586 // ancestors, siblings) such that the developer is enured to upgrade 4811 // ancestors, siblings) such that the developer is enured to upgrade
4587 // ordering. If the element definitions have loaded, domReady 4812 // ordering. If the element definitions have loaded, domReady
4588 // can be used to access upgraded elements. 4813 // can be used to access upgraded elements.
4589 if (!this.hasBeenAttached) { 4814 if (!this.hasBeenAttached) {
4590 this.hasBeenAttached = true; 4815 this.hasBeenAttached = true;
4591 if (this.domReady) { 4816 if (this.domReady) {
4592 this.async('domReady'); 4817 this.async('domReady');
4593 } 4818 }
4594 } 4819 }
4595 }, 4820 },
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
4640 // return a shadow-root template (if desired), override for custom behavior 4865 // return a shadow-root template (if desired), override for custom behavior
4641 fetchTemplate: function(elementElement) { 4866 fetchTemplate: function(elementElement) {
4642 return elementElement.querySelector('template'); 4867 return elementElement.querySelector('template');
4643 }, 4868 },
4644 // utility function that creates a shadow root from a <template> 4869 // utility function that creates a shadow root from a <template>
4645 shadowFromTemplate: function(template) { 4870 shadowFromTemplate: function(template) {
4646 if (template) { 4871 if (template) {
4647 // make a shadow root 4872 // make a shadow root
4648 var root = this.createShadowRoot(); 4873 var root = this.createShadowRoot();
4649 // stamp template 4874 // stamp template
4650 // which includes parsing and applying MDV bindings before being 4875 // which includes parsing and applying MDV bindings before being
4651 // inserted (to avoid {{}} in attribute values) 4876 // inserted (to avoid {{}} in attribute values)
4652 // e.g. to prevent <img src="images/{{icon}}"> from generating a 404. 4877 // e.g. to prevent <img src="images/{{icon}}"> from generating a 404.
4653 var dom = this.instanceTemplate(template); 4878 var dom = this.instanceTemplate(template);
4654 // append to shadow dom 4879 // append to shadow dom
4655 root.appendChild(dom); 4880 root.appendChild(dom);
4656 // perform post-construction initialization tasks on shadow root 4881 // perform post-construction initialization tasks on shadow root
4657 this.shadowRootReady(root, template); 4882 this.shadowRootReady(root, template);
4658 // return the created shadow root 4883 // return the created shadow root
4659 return root; 4884 return root;
4660 } 4885 }
4661 }, 4886 },
4662 // utility function that stamps a <template> into light-dom 4887 // utility function that stamps a <template> into light-dom
4663 lightFromTemplate: function(template, refNode) { 4888 lightFromTemplate: function(template, refNode) {
4664 if (template) { 4889 if (template) {
4665 // TODO(sorvell): mark this element as an eventController so that 4890 // TODO(sorvell): mark this element as an eventController so that
4666 // event listeners on bound nodes inside it will be called on it. 4891 // event listeners on bound nodes inside it will be called on it.
4667 // Note, the expectation here is that events on all descendants 4892 // Note, the expectation here is that events on all descendants
4668 // should be handled by this element. 4893 // should be handled by this element.
4669 this.eventController = this; 4894 this.eventController = this;
4670 // stamp template 4895 // stamp template
4671 // which includes parsing and applying MDV bindings before being 4896 // which includes parsing and applying MDV bindings before being
4672 // inserted (to avoid {{}} in attribute values) 4897 // inserted (to avoid {{}} in attribute values)
4673 // e.g. to prevent <img src="images/{{icon}}"> from generating a 404. 4898 // e.g. to prevent <img src="images/{{icon}}"> from generating a 404.
4674 var dom = this.instanceTemplate(template); 4899 var dom = this.instanceTemplate(template);
4675 // append to shadow dom 4900 // append to shadow dom
4676 if (refNode) { 4901 if (refNode) {
4677 this.insertBefore(dom, refNode); 4902 this.insertBefore(dom, refNode);
4678 } else { 4903 } else {
4679 this.appendChild(dom); 4904 this.appendChild(dom);
4680 } 4905 }
4681 // perform post-construction initialization tasks on ahem, light root 4906 // perform post-construction initialization tasks on ahem, light root
4682 this.shadowRootReady(this); 4907 this.shadowRootReady(this);
4683 // return the created shadow root 4908 // return the created shadow root
4684 return dom; 4909 return dom;
4685 } 4910 }
4686 }, 4911 },
4687 shadowRootReady: function(root) { 4912 shadowRootReady: function(root) {
(...skipping 27 matching lines...) Expand all
4715 var observer = new MutationObserver(function(mutations) { 4940 var observer = new MutationObserver(function(mutations) {
4716 listener.call(this, observer, mutations); 4941 listener.call(this, observer, mutations);
4717 observer.disconnect(); 4942 observer.disconnect();
4718 }.bind(this)); 4943 }.bind(this));
4719 observer.observe(node, {childList: true, subtree: true}); 4944 observer.observe(node, {childList: true, subtree: true});
4720 } 4945 }
4721 }; 4946 };
4722 4947
4723 // true if object has own PolymerBase api 4948 // true if object has own PolymerBase api
4724 function isBase(object) { 4949 function isBase(object) {
4725 return object.hasOwnProperty('PolymerBase') 4950 return object.hasOwnProperty('PolymerBase')
4726 } 4951 }
4727 4952
4728 // name a base constructor for dev tools 4953 // name a base constructor for dev tools
4729 4954
4730 function PolymerBase() {}; 4955 function PolymerBase() {};
4731 PolymerBase.prototype = base; 4956 PolymerBase.prototype = base;
4732 base.constructor = PolymerBase; 4957 base.constructor = PolymerBase;
4733 4958
4734 // exports 4959 // exports
4735 4960
4736 scope.Base = PolymerBase; 4961 scope.Base = PolymerBase;
4737 scope.isBase = isBase; 4962 scope.isBase = isBase;
4738 scope.api.instance.base = base; 4963 scope.api.instance.base = base;
4739 4964
4740 })(Polymer); 4965 })(Polymer);
4741 4966
4742 /* 4967 /*
4743 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. 4968 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
4744 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt 4969 * This code may only be used under the BSD style license found at http://polyme r.github.io/LICENSE.txt
4745 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt 4970 * The complete set of authors may be found at http://polymer.github.io/AUTHORS. txt
4746 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt 4971 * The complete set of contributors may be found at http://polymer.github.io/CON TRIBUTORS.txt
4747 * Code distributed by Google as part of the polymer project is also 4972 * Code distributed by Google as part of the polymer project is also
4748 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt 4973 * subject to an additional IP rights grant found at http://polymer.github.io/PA TENTS.txt
4749 */ 4974 */
(...skipping 644 matching lines...) Expand 10 before | Expand all | Expand 10 after
5394 } 5619 }
5395 } 5620 }
5396 } 5621 }
5397 if (prototype.publish) { 5622 if (prototype.publish) {
5398 // construct name list 5623 // construct name list
5399 var a = prototype._publishNames = []; 5624 var a = prototype._publishNames = [];
5400 for (var n in prototype.publish) { 5625 for (var n in prototype.publish) {
5401 a.push(n); 5626 a.push(n);
5402 } 5627 }
5403 } 5628 }
5629 if (prototype.computed) {
5630 // construct name list
5631 var a = prototype._computedNames = [];
5632 for (var n in prototype.computed) {
5633 a.push(n);
5634 }
5635 }
5404 }, 5636 },
5405 publishProperties: function(prototype, base) { 5637 publishProperties: function(prototype, base) {
5406 // if we have any properties to publish 5638 // if we have any properties to publish
5407 var publish = prototype.publish; 5639 var publish = prototype.publish;
5408 if (publish) { 5640 if (publish) {
5409 // transcribe `publish` entries onto own prototype 5641 // transcribe `publish` entries onto own prototype
5410 this.requireProperties(publish, prototype, base); 5642 this.requireProperties(publish, prototype, base);
5411 // construct map of lower-cased property names 5643 // construct map of lower-cased property names
5412 prototype._publishLC = this.lowerCaseMap(publish); 5644 prototype._publishLC = this.lowerCaseMap(publish);
5413 } 5645 }
5414 }, 5646 },
5415 // sync prototype to property descriptors; 5647 // sync prototype to property descriptors;
5416 // desriptor format contains default value and optionally a 5648 // desriptor format contains default value and optionally a
5417 // hint for reflecting the property to an attribute. 5649 // hint for reflecting the property to an attribute.
5418 // e.g. {foo: 5, bar: {value: true, reflect: true}} 5650 // e.g. {foo: 5, bar: {value: true, reflect: true}}
5419 // reflect: {foo: true} is also supported 5651 // reflect: {foo: true} is also supported
5420 // 5652 //
5421 requireProperties: function(propertyDescriptors, prototype, base) { 5653 requireProperties: function(propertyDescriptors, prototype, base) {
5422 // reflected properties 5654 // reflected properties
5423 prototype.reflect = prototype.reflect || {}; 5655 prototype.reflect = prototype.reflect || {};
5424 // ensure a prototype value for each property 5656 // ensure a prototype value for each property
5425 // and update the property's reflect to attribute status 5657 // and update the property's reflect to attribute status
5426 for (var n in propertyDescriptors) { 5658 for (var n in propertyDescriptors) {
5427 var propertyDescriptor = propertyDescriptors[n]; 5659 var propertyDescriptor = propertyDescriptors[n];
5428 var reflects = this.reflectHintForDescriptor(propertyDescriptor); 5660 var reflects = this.reflectHintForDescriptor(propertyDescriptor);
5429 if (prototype.reflect[n] === undefined && reflects !== undefined) { 5661 if (prototype.reflect[n] === undefined && reflects !== undefined) {
5430 prototype.reflect[n] = reflects; 5662 prototype.reflect[n] = reflects;
5431 } 5663 }
5432 if (prototype[n] === undefined) { 5664 if (prototype[n] === undefined) {
5433 prototype[n] = this.valueForDescriptor(propertyDescriptor); 5665 prototype[n] = this.valueForDescriptor(propertyDescriptor);
5434 } 5666 }
5435 } 5667 }
5436 }, 5668 },
5437 valueForDescriptor: function(propertyDescriptor) { 5669 valueForDescriptor: function(propertyDescriptor) {
5438 var value = typeof propertyDescriptor === 'object' && 5670 var value = typeof propertyDescriptor === 'object' &&
5439 propertyDescriptor ? propertyDescriptor.value : propertyDescriptor; 5671 propertyDescriptor ? propertyDescriptor.value : propertyDescriptor;
5440 return value !== undefined ? value : null; 5672 return value !== undefined ? value : null;
5441 }, 5673 },
5442 // returns the value of the descriptor's 'reflect' property or undefined 5674 // returns the value of the descriptor's 'reflect' property or undefined
5443 reflectHintForDescriptor: function(propertyDescriptor) { 5675 reflectHintForDescriptor: function(propertyDescriptor) {
5444 if (typeof propertyDescriptor === 'object' && 5676 if (typeof propertyDescriptor === 'object' &&
5445 propertyDescriptor && propertyDescriptor.reflect !== undefined) { 5677 propertyDescriptor && propertyDescriptor.reflect !== undefined) {
5446 return propertyDescriptor.reflect; 5678 return propertyDescriptor.reflect;
5447 } 5679 }
5448 }, 5680 },
5449 lowerCaseMap: function(properties) { 5681 lowerCaseMap: function(properties) {
5450 var map = {}; 5682 var map = {};
5451 for (var n in properties) { 5683 for (var n in properties) {
5452 map[n.toLowerCase()] = n; 5684 map[n.toLowerCase()] = n;
5453 } 5685 }
5454 return map; 5686 return map;
5455 }, 5687 },
5688 createPropertyAccessor: function(name) {
5689 var proto = this.prototype;
5690
5691 var privateName = name + '_';
5692 var privateObservable = name + 'Observable_';
5693 proto[privateName] = proto[name];
5694
5695 Object.defineProperty(proto, name, {
5696 get: function() {
5697 var observable = this[privateObservable];
5698 if (observable)
5699 observable.deliver();
5700
5701 return this[privateName];
5702 },
5703 set: function(value) {
5704 var observable = this[privateObservable];
5705 if (observable) {
5706 observable.setValue(value);
5707 return;
5708 }
5709
5710 var oldValue = this[privateName];
5711 this[privateName] = value;
5712 this.emitPropertyChangeRecord(name, value, oldValue);
5713
5714 return value;
5715 },
5716 configurable: true
5717 });
5718 },
5456 createPropertyAccessors: function(prototype) { 5719 createPropertyAccessors: function(prototype) {
5457 var n$ = prototype._publishNames; 5720 var n$ = prototype._publishNames;
5458 if (n$ && n$.length) { 5721 if (n$ && n$.length) {
5459 for (var i=0, l=n$.length, n, fn; (i<l) && (n=n$[i]); i++) { 5722 for (var i=0, l=n$.length, n, fn; (i<l) && (n=n$[i]); i++) {
5460 Observer.createBindablePrototypeAccessor(prototype, n); 5723 this.createPropertyAccessor(n);
5461 } 5724 }
5462 } 5725 }
5726
5727 var n$ = prototype._computedNames;
5728 if (n$ && n$.length) {
5729 for (var i=0, l=n$.length, n, fn; (i<l) && (n=n$[i]); i++) {
5730 this.createPropertyAccessor(n);
5731 }
5732 }
5733
5463 } 5734 }
5464 }; 5735 };
5465 5736
5466 // exports 5737 // exports
5467 5738
5468 scope.api.declaration.properties = properties; 5739 scope.api.declaration.properties = properties;
5469 5740
5470 })(Polymer); 5741 })(Polymer);
5471 5742
5472 /* 5743 /*
(...skipping 27 matching lines...) Expand all
5500 var attributes = this.getAttribute(ATTRIBUTES_ATTRIBUTE); 5771 var attributes = this.getAttribute(ATTRIBUTES_ATTRIBUTE);
5501 if (attributes) { 5772 if (attributes) {
5502 // get properties to publish 5773 // get properties to publish
5503 var publish = prototype.publish || (prototype.publish = {}); 5774 var publish = prototype.publish || (prototype.publish = {});
5504 // names='a b c' or names='a,b,c' 5775 // names='a b c' or names='a,b,c'
5505 var names = attributes.split(ATTRIBUTES_REGEX); 5776 var names = attributes.split(ATTRIBUTES_REGEX);
5506 // record each name for publishing 5777 // record each name for publishing
5507 for (var i=0, l=names.length, n; i<l; i++) { 5778 for (var i=0, l=names.length, n; i<l; i++) {
5508 // remove excess ws 5779 // remove excess ws
5509 n = names[i].trim(); 5780 n = names[i].trim();
5510 // do not override explicit entries 5781 // if the user hasn't specified a value, we want to use the
5511 if (n && publish[n] === undefined && base[n] === undefined) { 5782 // default, unless a superclass has already chosen one
5783 if (n && publish[n] === undefined) {
5784 // TODO(sjmiles): querying native properties on IE11 (and possibly
5785 // on other browsers) throws an exception because there is no actual
5786 // instance.
5787 // In fact, trying to publish native properties is known bad for thi s
5788 // and other reasons, and we need to solve this problem writ large.
5789 try {
5790 var hasValue = (base[n] !== undefined);
5791 } catch(x) {
5792 hasValue = false;
5793 }
5512 // supply an empty 'descriptor' object and let the publishProperties 5794 // supply an empty 'descriptor' object and let the publishProperties
5513 // code determine a default 5795 // code determine a default
5514 publish[n] = Polymer.nob; 5796 if (!hasValue) {
5797 publish[n] = Polymer.nob;
5798 }
5515 } 5799 }
5516 } 5800 }
5517 } 5801 }
5518 }, 5802 },
5519 5803
5520 // record clonable attributes from <element> 5804 // record clonable attributes from <element>
5521 accumulateInstanceAttributes: function() { 5805 accumulateInstanceAttributes: function() {
5522 // inherit instance attributes 5806 // inherit instance attributes
5523 var clonable = this.prototype._instanceAttributes; 5807 var clonable = this.prototype._instanceAttributes;
5524 // merge attributes from element 5808 // merge attributes from element
(...skipping 773 matching lines...) Expand 10 before | Expand all | Expand 10 after
6298 prepareBinding.call(syntax, pathString, name, node); 6582 prepareBinding.call(syntax, pathString, name, node);
6299 }; 6583 };
6300 return syntax; 6584 return syntax;
6301 } 6585 }
6302 6586
6303 }); 6587 });
6304 6588
6305 })(); 6589 })();
6306 6590
6307 //# sourceMappingURL=polymer.concat.js.map 6591 //# sourceMappingURL=polymer.concat.js.map
OLDNEW
« no previous file with comments | « pkg/polymer/lib/src/js/polymer/polymer.js ('k') | pkg/polymer/lib/src/js/polymer/polymer.concat.js.map » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698