OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |