OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 The Polymer Authors. All rights reserved. | 2 * Copyright 2012 The Polymer Authors. All rights reserved. |
3 * Use of this source code is governed by a BSD-style | 3 * Use of this source code is governed by a BSD-style |
4 * license that can be found in the LICENSE file. | 4 * license that can be found in the LICENSE file. |
5 */ | 5 */ |
6 | 6 |
7 if (typeof WeakMap === 'undefined') { | 7 if (typeof WeakMap === 'undefined') { |
8 (function() { | 8 (function() { |
9 var defineProperty = Object.defineProperty; | 9 var defineProperty = Object.defineProperty; |
10 var counter = Date.now() % 1e9; | 10 var counter = Date.now() % 1e9; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
45 // | 45 // |
46 // Unless required by applicable law or agreed to in writing, software | 46 // Unless required by applicable law or agreed to in writing, software |
47 // distributed under the License is distributed on an "AS IS" BASIS, | 47 // distributed under the License is distributed on an "AS IS" BASIS, |
48 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 48 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
49 // See the License for the specific language governing permissions and | 49 // See the License for the specific language governing permissions and |
50 // limitations under the License. | 50 // limitations under the License. |
51 | 51 |
52 (function(global) { | 52 (function(global) { |
53 'use strict'; | 53 'use strict'; |
54 | 54 |
| 55 var PROP_ADD_TYPE = 'add'; |
| 56 var PROP_UPDATE_TYPE = 'update'; |
| 57 var PROP_RECONFIGURE_TYPE = 'reconfigure'; |
| 58 var PROP_DELETE_TYPE = 'delete'; |
| 59 var ARRAY_SPLICE_TYPE = 'splice'; |
| 60 |
55 // Detect and do basic sanity checking on Object/Array.observe. | 61 // Detect and do basic sanity checking on Object/Array.observe. |
56 function detectObjectObserve() { | 62 function detectObjectObserve() { |
57 if (typeof Object.observe !== 'function' || | 63 if (typeof Object.observe !== 'function' || |
58 typeof Array.observe !== 'function') { | 64 typeof Array.observe !== 'function') { |
59 return false; | 65 return false; |
60 } | 66 } |
61 | 67 |
62 var records = []; | 68 var records = []; |
63 | 69 |
64 function callback(recs) { | 70 function callback(recs) { |
65 records = recs; | 71 records = recs; |
66 } | 72 } |
67 | 73 |
68 var test = {}; | 74 var test = {}; |
69 var arr = []; | |
70 Object.observe(test, callback); | 75 Object.observe(test, callback); |
71 Array.observe(arr, callback); | |
72 test.id = 1; | 76 test.id = 1; |
73 test.id = 2; | 77 test.id = 2; |
74 delete test.id; | 78 delete test.id; |
75 arr.push(1, 2); | |
76 arr.length = 0; | |
77 | |
78 Object.deliverChangeRecords(callback); | 79 Object.deliverChangeRecords(callback); |
79 if (records.length !== 5) | 80 if (records.length !== 3) |
80 return false; | 81 return false; |
81 | 82 |
82 if (records[0].type != 'add' || | 83 // TODO(rafaelw): Remove this when new change record type names make it to |
83 records[1].type != 'update' || | 84 // chrome release. |
84 records[2].type != 'delete' || | 85 if (records[0].type == 'new' && |
85 records[3].type != 'splice' || | 86 records[1].type == 'updated' && |
86 records[4].type != 'splice') { | 87 records[2].type == 'deleted') { |
| 88 PROP_ADD_TYPE = 'new'; |
| 89 PROP_UPDATE_TYPE = 'updated'; |
| 90 PROP_RECONFIGURE_TYPE = 'reconfigured'; |
| 91 PROP_DELETE_TYPE = 'deleted'; |
| 92 } else if (records[0].type != 'add' || |
| 93 records[1].type != 'update' || |
| 94 records[2].type != 'delete') { |
| 95 console.error('Unexpected change record names for Object.observe. ' + |
| 96 'Using dirty-checking instead'); |
87 return false; | 97 return false; |
88 } | 98 } |
| 99 Object.unobserve(test, callback); |
89 | 100 |
90 Object.unobserve(test, callback); | 101 test = [0]; |
91 Array.unobserve(arr, callback); | 102 Array.observe(test, callback); |
| 103 test[1] = 1; |
| 104 test.length = 0; |
| 105 Object.deliverChangeRecords(callback); |
| 106 if (records.length != 2) |
| 107 return false; |
| 108 if (records[0].type != ARRAY_SPLICE_TYPE || |
| 109 records[1].type != ARRAY_SPLICE_TYPE) { |
| 110 return false; |
| 111 } |
| 112 Array.unobserve(test, callback); |
92 | 113 |
93 return true; | 114 return true; |
94 } | 115 } |
95 | 116 |
96 var hasObserve = detectObjectObserve(); | 117 var hasObserve = detectObjectObserve(); |
97 | 118 |
98 function detectEval() { | 119 function detectEval() { |
99 // don't test for eval if document has CSP securityPolicy object and we can
see that | 120 // don't test for eval if document has CSP securityPolicy object and we can
see that |
100 // eval is not supported. This avoids an error message in console even when
the exception | 121 // eval is not supported. This avoids an error message in console even when
the exception |
101 // is caught | 122 // is caught |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
240 return; | 261 return; |
241 obj = obj[this[i]]; | 262 obj = obj[this[i]]; |
242 } | 263 } |
243 return obj; | 264 return obj; |
244 }, | 265 }, |
245 | 266 |
246 iterateObjects: function(obj, observe) { | 267 iterateObjects: function(obj, observe) { |
247 for (var i = 0; i < this.length; i++) { | 268 for (var i = 0; i < this.length; i++) { |
248 if (i) | 269 if (i) |
249 obj = obj[this[i - 1]]; | 270 obj = obj[this[i - 1]]; |
250 if (!isObject(obj)) | 271 if (!obj) |
251 return; | 272 return; |
252 observe(obj); | 273 observe(obj); |
253 } | 274 } |
254 }, | 275 }, |
255 | 276 |
256 compiledGetValueFromFn: function() { | 277 compiledGetValueFromFn: function() { |
257 var accessors = this.map(function(ident) { | 278 var accessors = this.map(function(ident) { |
258 return isIndex(ident) ? '["' + ident + '"]' : '.' + ident; | 279 return isIndex(ident) ? '["' + ident + '"]' : '.' + ident; |
259 }); | 280 }); |
260 | 281 |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
450 | 471 |
451 function newObservedSet() { | 472 function newObservedSet() { |
452 var observers = []; | 473 var observers = []; |
453 var observerCount = 0; | 474 var observerCount = 0; |
454 var objects = []; | 475 var objects = []; |
455 var toRemove = emptyArray; | 476 var toRemove = emptyArray; |
456 var resetNeeded = false; | 477 var resetNeeded = false; |
457 var resetScheduled = false; | 478 var resetScheduled = false; |
458 | 479 |
459 function observe(obj) { | 480 function observe(obj) { |
460 if (!obj) | 481 if (!isObject(obj)) |
461 return; | 482 return; |
462 | 483 |
463 var index = toRemove.indexOf(obj); | 484 var index = toRemove.indexOf(obj); |
464 if (index >= 0) { | 485 if (index >= 0) { |
465 toRemove[index] = undefined; | 486 toRemove[index] = undefined; |
466 objects.push(obj); | 487 objects.push(obj); |
467 } else if (objects.indexOf(obj) < 0) { | 488 } else if (objects.indexOf(obj) < 0) { |
468 objects.push(obj); | 489 objects.push(obj); |
469 Object.observe(obj, callback); | 490 Object.observe(obj, callback); |
470 } | 491 } |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
651 | 672 |
652 allObservers.push(observer); | 673 allObservers.push(observer); |
653 } | 674 } |
654 | 675 |
655 function removeFromAll(observer) { | 676 function removeFromAll(observer) { |
656 Observer._allObserversCount--; | 677 Observer._allObserversCount--; |
657 } | 678 } |
658 | 679 |
659 var runningMicrotaskCheckpoint = false; | 680 var runningMicrotaskCheckpoint = false; |
660 | 681 |
661 var hasDebugForceFullDelivery = hasObserve && (function() { | 682 var hasDebugForceFullDelivery = typeof Object.deliverAllChangeRecords == 'func
tion'; |
662 try { | |
663 eval('%RunMicrotasks()'); | |
664 return true; | |
665 } catch (ex) { | |
666 return false; | |
667 } | |
668 })(); | |
669 | 683 |
670 global.Platform = global.Platform || {}; | 684 global.Platform = global.Platform || {}; |
671 | 685 |
672 global.Platform.performMicrotaskCheckpoint = function() { | 686 global.Platform.performMicrotaskCheckpoint = function() { |
673 if (runningMicrotaskCheckpoint) | 687 if (runningMicrotaskCheckpoint) |
674 return; | 688 return; |
675 | 689 |
676 if (hasDebugForceFullDelivery) { | 690 if (hasDebugForceFullDelivery) { |
677 eval('%RunMicrotasks()'); | 691 Object.deliverAllChangeRecords(); |
678 return; | 692 return; |
679 } | 693 } |
680 | 694 |
681 if (!collectObservers) | 695 if (!collectObservers) |
682 return; | 696 return; |
683 | 697 |
684 runningMicrotaskCheckpoint = true; | 698 runningMicrotaskCheckpoint = true; |
685 | 699 |
686 var cycles = 0; | 700 var cycles = 0; |
687 var anyChanged, toCheck; | 701 var anyChanged, toCheck; |
(...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1097 this.observable_.close(); | 1111 this.observable_.close(); |
1098 this.callback_ = undefined; | 1112 this.callback_ = undefined; |
1099 this.target_ = undefined; | 1113 this.target_ = undefined; |
1100 this.observable_ = undefined; | 1114 this.observable_ = undefined; |
1101 this.value_ = undefined; | 1115 this.value_ = undefined; |
1102 this.getValueFn_ = undefined; | 1116 this.getValueFn_ = undefined; |
1103 this.setValueFn_ = undefined; | 1117 this.setValueFn_ = undefined; |
1104 } | 1118 } |
1105 } | 1119 } |
1106 | 1120 |
1107 var expectedRecordTypes = { | 1121 var expectedRecordTypes = {}; |
1108 add: true, | 1122 expectedRecordTypes[PROP_ADD_TYPE] = true; |
1109 update: true, | 1123 expectedRecordTypes[PROP_UPDATE_TYPE] = true; |
1110 delete: true | 1124 expectedRecordTypes[PROP_DELETE_TYPE] = true; |
1111 }; | |
1112 | 1125 |
1113 function notifyFunction(object, name) { | 1126 function notifyFunction(object, name) { |
1114 if (typeof Object.observe !== 'function') | 1127 if (typeof Object.observe !== 'function') |
1115 return; | 1128 return; |
1116 | 1129 |
1117 var notifier = Object.getNotifier(object); | 1130 var notifier = Object.getNotifier(object); |
1118 return function(type, oldValue) { | 1131 return function(type, oldValue) { |
1119 var changeRecord = { | 1132 var changeRecord = { |
1120 object: object, | 1133 object: object, |
1121 type: type, | 1134 type: type, |
1122 name: name | 1135 name: name |
1123 }; | 1136 }; |
1124 if (arguments.length === 2) | 1137 if (arguments.length === 2) |
1125 changeRecord.oldValue = oldValue; | 1138 changeRecord.oldValue = oldValue; |
1126 notifier.notify(changeRecord); | 1139 notifier.notify(changeRecord); |
1127 } | 1140 } |
1128 } | 1141 } |
1129 | 1142 |
1130 Observer.defineComputedProperty = function(target, name, observable) { | 1143 Observer.defineComputedProperty = function(target, name, observable) { |
1131 var notify = notifyFunction(target, name); | 1144 var notify = notifyFunction(target, name); |
1132 var value = observable.open(function(newValue, oldValue) { | 1145 var value = observable.open(function(newValue, oldValue) { |
1133 value = newValue; | 1146 value = newValue; |
1134 if (notify) | 1147 if (notify) |
1135 notify('update', oldValue); | 1148 notify(PROP_UPDATE_TYPE, oldValue); |
1136 }); | 1149 }); |
1137 | 1150 |
1138 Object.defineProperty(target, name, { | 1151 Object.defineProperty(target, name, { |
1139 get: function() { | 1152 get: function() { |
1140 observable.deliver(); | 1153 observable.deliver(); |
1141 return value; | 1154 return value; |
1142 }, | 1155 }, |
1143 set: function(newValue) { | 1156 set: function(newValue) { |
1144 observable.setValue(newValue); | 1157 observable.setValue(newValue); |
1145 return newValue; | 1158 return newValue; |
(...skipping 21 matching lines...) Expand all Loading... |
1167 var record = changeRecords[i]; | 1180 var record = changeRecords[i]; |
1168 if (!expectedRecordTypes[record.type]) { | 1181 if (!expectedRecordTypes[record.type]) { |
1169 console.error('Unknown changeRecord type: ' + record.type); | 1182 console.error('Unknown changeRecord type: ' + record.type); |
1170 console.error(record); | 1183 console.error(record); |
1171 continue; | 1184 continue; |
1172 } | 1185 } |
1173 | 1186 |
1174 if (!(record.name in oldValues)) | 1187 if (!(record.name in oldValues)) |
1175 oldValues[record.name] = record.oldValue; | 1188 oldValues[record.name] = record.oldValue; |
1176 | 1189 |
1177 if (record.type == 'update') | 1190 if (record.type == PROP_UPDATE_TYPE) |
1178 continue; | 1191 continue; |
1179 | 1192 |
1180 if (record.type == 'add') { | 1193 if (record.type == PROP_ADD_TYPE) { |
1181 if (record.name in removed) | 1194 if (record.name in removed) |
1182 delete removed[record.name]; | 1195 delete removed[record.name]; |
1183 else | 1196 else |
1184 added[record.name] = true; | 1197 added[record.name] = true; |
1185 | 1198 |
1186 continue; | 1199 continue; |
1187 } | 1200 } |
1188 | 1201 |
1189 // type = 'delete' | 1202 // type = 'delete' |
1190 if (record.name in added) { | 1203 if (record.name in added) { |
(...skipping 376 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1567 if (!inserted) | 1580 if (!inserted) |
1568 splices.push(splice); | 1581 splices.push(splice); |
1569 } | 1582 } |
1570 | 1583 |
1571 function createInitialSplices(array, changeRecords) { | 1584 function createInitialSplices(array, changeRecords) { |
1572 var splices = []; | 1585 var splices = []; |
1573 | 1586 |
1574 for (var i = 0; i < changeRecords.length; i++) { | 1587 for (var i = 0; i < changeRecords.length; i++) { |
1575 var record = changeRecords[i]; | 1588 var record = changeRecords[i]; |
1576 switch(record.type) { | 1589 switch(record.type) { |
1577 case 'splice': | 1590 case ARRAY_SPLICE_TYPE: |
1578 mergeSplice(splices, record.index, record.removed.slice(), record.adde
dCount); | 1591 mergeSplice(splices, record.index, record.removed.slice(), record.adde
dCount); |
1579 break; | 1592 break; |
1580 case 'add': | 1593 case PROP_ADD_TYPE: |
1581 case 'update': | 1594 case PROP_UPDATE_TYPE: |
1582 case 'delete': | 1595 case PROP_DELETE_TYPE: |
1583 if (!isIndex(record.name)) | 1596 if (!isIndex(record.name)) |
1584 continue; | 1597 continue; |
1585 var index = toNumber(record.name); | 1598 var index = toNumber(record.name); |
1586 if (index < 0) | 1599 if (index < 0) |
1587 continue; | 1600 continue; |
1588 mergeSplice(splices, index, [record.oldValue], 1); | 1601 mergeSplice(splices, index, [record.oldValue], 1); |
1589 break; | 1602 break; |
1590 default: | 1603 default: |
1591 console.error('Unexpected record type: ' + JSON.stringify(record)); | 1604 console.error('Unexpected record type: ' + JSON.stringify(record)); |
1592 break; | 1605 break; |
(...skipping 28 matching lines...) Expand all Loading... |
1621 global.ArrayObserver.calculateSplices = function(current, previous) { | 1634 global.ArrayObserver.calculateSplices = function(current, previous) { |
1622 return arraySplice.calculateSplices(current, previous); | 1635 return arraySplice.calculateSplices(current, previous); |
1623 }; | 1636 }; |
1624 | 1637 |
1625 global.ArraySplice = ArraySplice; | 1638 global.ArraySplice = ArraySplice; |
1626 global.ObjectObserver = ObjectObserver; | 1639 global.ObjectObserver = ObjectObserver; |
1627 global.PathObserver = PathObserver; | 1640 global.PathObserver = PathObserver; |
1628 global.CompoundObserver = CompoundObserver; | 1641 global.CompoundObserver = CompoundObserver; |
1629 global.Path = Path; | 1642 global.Path = Path; |
1630 global.ObserverTransform = ObserverTransform; | 1643 global.ObserverTransform = ObserverTransform; |
| 1644 |
| 1645 // TODO(rafaelw): Only needed for testing until new change record names |
| 1646 // make it to release. |
| 1647 global.Observer.changeRecordTypes = { |
| 1648 add: PROP_ADD_TYPE, |
| 1649 update: PROP_UPDATE_TYPE, |
| 1650 reconfigure: PROP_RECONFIGURE_TYPE, |
| 1651 'delete': PROP_DELETE_TYPE, |
| 1652 splice: ARRAY_SPLICE_TYPE |
| 1653 }; |
1631 })(typeof global !== 'undefined' && global && typeof module !== 'undefined' && m
odule ? global : this || window); | 1654 })(typeof global !== 'undefined' && global && typeof module !== 'undefined' && m
odule ? global : this || window); |
1632 | 1655 |
1633 // prepoulate window.Platform.flags for default controls | 1656 // prepoulate window.Platform.flags for default controls |
1634 window.Platform = window.Platform || {}; | 1657 window.Platform = window.Platform || {}; |
1635 // prepopulate window.logFlags if necessary | 1658 // prepopulate window.logFlags if necessary |
1636 window.logFlags = window.logFlags || {}; | 1659 window.logFlags = window.logFlags || {}; |
1637 // process flags | 1660 // process flags |
1638 (function(scope){ | 1661 (function(scope){ |
1639 // import | 1662 // import |
1640 var flags = scope.flags || {}; | 1663 var flags = scope.flags || {}; |
1641 // populate flags from location | 1664 // populate flags from location |
1642 location.search.slice(1).split('&').forEach(function(o) { | 1665 location.search.slice(1).split('&').forEach(function(o) { |
1643 o = o.split('='); | 1666 o = o.split('='); |
1644 o[0] && (flags[o[0]] = o[1] || true); | 1667 o[0] && (flags[o[0]] = o[1] || true); |
1645 }); | 1668 }); |
1646 var entryPoint = document.currentScript || | 1669 var entryPoint = document.currentScript || document.querySelector('script[src*
="platform.js"]'); |
1647 document.querySelector('script[src*="platform.js"]'); | |
1648 if (entryPoint) { | 1670 if (entryPoint) { |
1649 var a = entryPoint.attributes; | 1671 var a = entryPoint.attributes; |
1650 for (var i = 0, n; i < a.length; i++) { | 1672 for (var i = 0, n; i < a.length; i++) { |
1651 n = a[i]; | 1673 n = a[i]; |
1652 if (n.name !== 'src') { | 1674 if (n.name !== 'src') { |
1653 flags[n.name] = n.value || true; | 1675 flags[n.name] = n.value || true; |
1654 } | 1676 } |
1655 } | 1677 } |
1656 } | 1678 } |
1657 if (flags.log) { | 1679 if (flags.log) { |
1658 flags.log.split(',').forEach(function(f) { | 1680 flags.log.split(',').forEach(function(f) { |
1659 window.logFlags[f] = true; | 1681 window.logFlags[f] = true; |
1660 }); | 1682 }); |
1661 } | 1683 } |
1662 // If any of these flags match 'native', then force native ShadowDOM; any | 1684 // If any of these flags match 'native', then force native ShadowDOM; any |
1663 // other truthy value, or failure to detect native | 1685 // other truthy value, or failure to detect native |
1664 // ShadowDOM, results in polyfill | 1686 // ShadowDOM, results in polyfill |
1665 flags.shadow = flags.shadow || flags.shadowdom || flags.polyfill; | 1687 flags.shadow = (flags.shadow || flags.shadowdom || flags.polyfill); |
1666 if (flags.shadow === 'native') { | 1688 if (flags.shadow === 'native') { |
1667 flags.shadow = false; | 1689 flags.shadow = false; |
1668 } else { | 1690 } else { |
1669 flags.shadow = flags.shadow || !HTMLElement.prototype.createShadowRoot; | 1691 flags.shadow = flags.shadow || !HTMLElement.prototype.createShadowRoot; |
1670 } | 1692 } |
1671 | 1693 |
1672 if (flags.shadow && document.querySelectorAll('script').length > 1) { | |
1673 console.warn('platform.js is not the first script on the page. ' + | |
1674 'See http://www.polymer-project.org/docs/start/platform.html#setup ' + | |
1675 'for details.'); | |
1676 } | |
1677 | |
1678 // CustomElements polyfill flag | 1694 // CustomElements polyfill flag |
1679 if (flags.register) { | 1695 if (flags.register) { |
1680 window.CustomElements = window.CustomElements || {flags: {}}; | 1696 window.CustomElements = window.CustomElements || {flags: {}}; |
1681 window.CustomElements.flags.register = flags.register; | 1697 window.CustomElements.flags.register = flags.register; |
1682 } | 1698 } |
1683 | 1699 |
1684 if (flags.imports) { | 1700 if (flags.imports) { |
1685 window.HTMLImports = window.HTMLImports || {flags: {}}; | 1701 window.HTMLImports = window.HTMLImports || {flags: {}}; |
1686 window.HTMLImports.flags.imports = flags.imports; | 1702 window.HTMLImports.flags.imports = flags.imports; |
1687 } | 1703 } |
(...skipping 859 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2547 if (treeScope === this) | 2563 if (treeScope === this) |
2548 return true; | 2564 return true; |
2549 } | 2565 } |
2550 return false; | 2566 return false; |
2551 } | 2567 } |
2552 }; | 2568 }; |
2553 | 2569 |
2554 function setTreeScope(node, treeScope) { | 2570 function setTreeScope(node, treeScope) { |
2555 if (node.treeScope_ !== treeScope) { | 2571 if (node.treeScope_ !== treeScope) { |
2556 node.treeScope_ = treeScope; | 2572 node.treeScope_ = treeScope; |
2557 for (var sr = node.shadowRoot; sr; sr = sr.olderShadowRoot) { | |
2558 sr.treeScope_.parent = treeScope; | |
2559 } | |
2560 for (var child = node.firstChild; child; child = child.nextSibling) { | 2573 for (var child = node.firstChild; child; child = child.nextSibling) { |
2561 setTreeScope(child, treeScope); | 2574 setTreeScope(child, treeScope); |
2562 } | 2575 } |
2563 } | 2576 } |
2564 } | 2577 } |
2565 | 2578 |
2566 function getTreeScope(node) { | 2579 function getTreeScope(node) { |
2567 if (node.treeScope_) | 2580 if (node.treeScope_) |
2568 return node.treeScope_; | 2581 return node.treeScope_; |
2569 var parent = node.parentNode; | 2582 var parent = node.parentNode; |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2746 | 2759 |
2747 function inSameTree(a, b) { | 2760 function inSameTree(a, b) { |
2748 return getTreeScope(a) === getTreeScope(b); | 2761 return getTreeScope(a) === getTreeScope(b); |
2749 } | 2762 } |
2750 | 2763 |
2751 function dispatchOriginalEvent(originalEvent) { | 2764 function dispatchOriginalEvent(originalEvent) { |
2752 // Make sure this event is only dispatched once. | 2765 // Make sure this event is only dispatched once. |
2753 if (handledEventsTable.get(originalEvent)) | 2766 if (handledEventsTable.get(originalEvent)) |
2754 return; | 2767 return; |
2755 handledEventsTable.set(originalEvent, true); | 2768 handledEventsTable.set(originalEvent, true); |
2756 dispatchEvent(wrap(originalEvent), wrap(originalEvent.target)); | |
2757 } | |
2758 | 2769 |
2759 function isLoadLikeEvent(event) { | 2770 return dispatchEvent(wrap(originalEvent), wrap(originalEvent.target)); |
2760 switch (event.type) { | |
2761 case 'beforeunload': | |
2762 case 'load': | |
2763 case 'unload': | |
2764 return true; | |
2765 } | |
2766 return false; | |
2767 } | 2771 } |
2768 | 2772 |
2769 function dispatchEvent(event, originalWrapperTarget) { | 2773 function dispatchEvent(event, originalWrapperTarget) { |
2770 if (currentlyDispatchingEvents.get(event)) | 2774 if (currentlyDispatchingEvents.get(event)) |
2771 throw new Error('InvalidStateError') | 2775 throw new Error('InvalidStateError') |
2772 currentlyDispatchingEvents.set(event, true); | 2776 currentlyDispatchingEvents.set(event, true); |
2773 | 2777 |
2774 // Render to ensure that the event path is correct. | 2778 // Render to ensure that the event path is correct. |
2775 scope.renderAllPending(); | 2779 scope.renderAllPending(); |
2776 var eventPath = retarget(originalWrapperTarget); | 2780 var eventPath = retarget(originalWrapperTarget); |
2777 | 2781 |
2778 // For window "load" events the "load" event is dispatched at the window but | 2782 // For window load events the load event is dispatched at the window but |
2779 // the target is set to the document. | 2783 // the target is set to the document. |
2780 // | 2784 // |
2781 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#
the-end | 2785 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#
the-end |
2782 // | 2786 // |
2783 // TODO(arv): Find a less hacky way to do this. | 2787 // TODO(arv): Find a less hacky way to do this. |
2784 if (eventPath.length === 2 && | 2788 if (event.type === 'load' && |
2785 eventPath[0].target instanceof wrappers.Document && | 2789 eventPath.length === 2 && |
2786 isLoadLikeEvent(event)) { | 2790 eventPath[0].target instanceof wrappers.Document) { |
2787 eventPath.shift(); | 2791 eventPath.shift(); |
2788 } | 2792 } |
2789 | 2793 |
2790 eventPathTable.set(event, eventPath); | 2794 eventPathTable.set(event, eventPath); |
2791 | 2795 |
2792 if (dispatchCapturing(event, eventPath)) { | 2796 if (dispatchCapturing(event, eventPath)) { |
2793 if (dispatchAtTarget(event, eventPath)) { | 2797 if (dispatchAtTarget(event, eventPath)) { |
2794 dispatchBubbling(event, eventPath); | 2798 dispatchBubbling(event, eventPath); |
2795 } | 2799 } |
2796 } | 2800 } |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2846 function invoke(tuple, event, phase) { | 2850 function invoke(tuple, event, phase) { |
2847 var target = tuple.target; | 2851 var target = tuple.target; |
2848 var currentTarget = tuple.currentTarget; | 2852 var currentTarget = tuple.currentTarget; |
2849 | 2853 |
2850 var listeners = listenersTable.get(currentTarget); | 2854 var listeners = listenersTable.get(currentTarget); |
2851 if (!listeners) | 2855 if (!listeners) |
2852 return true; | 2856 return true; |
2853 | 2857 |
2854 if ('relatedTarget' in event) { | 2858 if ('relatedTarget' in event) { |
2855 var originalEvent = unwrap(event); | 2859 var originalEvent = unwrap(event); |
2856 var unwrappedRelatedTarget = originalEvent.relatedTarget; | |
2857 | |
2858 // X-Tag sets relatedTarget on a CustomEvent. If they do that there is no | 2860 // X-Tag sets relatedTarget on a CustomEvent. If they do that there is no |
2859 // way to have relatedTarget return the adjusted target but worse is that | 2861 // way to have relatedTarget return the adjusted target but worse is that |
2860 // the originalEvent might not have a relatedTarget so we hit an assert | 2862 // the originalEvent might not have a relatedTarget so we hit an assert |
2861 // when we try to wrap it. | 2863 // when we try to wrap it. |
2862 if (unwrappedRelatedTarget) { | 2864 if (originalEvent.relatedTarget) { |
2863 // In IE we can get objects that are not EventTargets at this point. | 2865 var relatedTarget = wrap(originalEvent.relatedTarget); |
2864 // Safari does not have an EventTarget interface so revert to checking | |
2865 // for addEventListener as an approximation. | |
2866 if (unwrappedRelatedTarget instanceof Object && | |
2867 unwrappedRelatedTarget.addEventListener) { | |
2868 var relatedTarget = wrap(unwrappedRelatedTarget); | |
2869 | 2866 |
2870 var adjusted = adjustRelatedTarget(currentTarget, relatedTarget); | 2867 var adjusted = adjustRelatedTarget(currentTarget, relatedTarget); |
2871 if (adjusted === target) | 2868 if (adjusted === target) |
2872 return true; | 2869 return true; |
2873 } else { | 2870 |
2874 adjusted = null; | |
2875 } | |
2876 relatedTargetTable.set(event, adjusted); | 2871 relatedTargetTable.set(event, adjusted); |
2877 } | 2872 } |
2878 } | 2873 } |
2879 | 2874 |
2880 eventPhaseTable.set(event, phase); | 2875 eventPhaseTable.set(event, phase); |
2881 var type = event.type; | 2876 var type = event.type; |
2882 | 2877 |
2883 var anyRemoved = false; | 2878 var anyRemoved = false; |
2884 targetTable.set(event, target); | 2879 targetTable.set(event, target); |
2885 currentTargetTable.set(event, currentTarget); | 2880 currentTargetTable.set(event, currentTarget); |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2952 keyLocation: true | 2947 keyLocation: true |
2953 }; | 2948 }; |
2954 | 2949 |
2955 /** | 2950 /** |
2956 * Creates a new Event wrapper or wraps an existin native Event object. | 2951 * Creates a new Event wrapper or wraps an existin native Event object. |
2957 * @param {string|Event} type | 2952 * @param {string|Event} type |
2958 * @param {Object=} options | 2953 * @param {Object=} options |
2959 * @constructor | 2954 * @constructor |
2960 */ | 2955 */ |
2961 function Event(type, options) { | 2956 function Event(type, options) { |
2962 if (type instanceof OriginalEvent) { | 2957 if (type instanceof OriginalEvent) |
2963 var impl = type; | 2958 this.impl = type; |
2964 if (!OriginalBeforeUnloadEvent && impl.type === 'beforeunload') | 2959 else |
2965 return new BeforeUnloadEvent(impl); | |
2966 this.impl = impl; | |
2967 } else { | |
2968 return wrap(constructEvent(OriginalEvent, 'Event', type, options)); | 2960 return wrap(constructEvent(OriginalEvent, 'Event', type, options)); |
2969 } | |
2970 } | 2961 } |
2971 Event.prototype = { | 2962 Event.prototype = { |
2972 get target() { | 2963 get target() { |
2973 return targetTable.get(this); | 2964 return targetTable.get(this); |
2974 }, | 2965 }, |
2975 get currentTarget() { | 2966 get currentTarget() { |
2976 return currentTargetTable.get(this); | 2967 return currentTargetTable.get(this); |
2977 }, | 2968 }, |
2978 get eventPhase() { | 2969 get eventPhase() { |
2979 return eventPhaseTable.get(this); | 2970 return eventPhaseTable.get(this); |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3042 } | 3033 } |
3043 } | 3034 } |
3044 return GenericEvent; | 3035 return GenericEvent; |
3045 } | 3036 } |
3046 | 3037 |
3047 var UIEvent = registerGenericEvent('UIEvent', Event); | 3038 var UIEvent = registerGenericEvent('UIEvent', Event); |
3048 var CustomEvent = registerGenericEvent('CustomEvent', Event); | 3039 var CustomEvent = registerGenericEvent('CustomEvent', Event); |
3049 | 3040 |
3050 var relatedTargetProto = { | 3041 var relatedTargetProto = { |
3051 get relatedTarget() { | 3042 get relatedTarget() { |
3052 var relatedTarget = relatedTargetTable.get(this); | 3043 return relatedTargetTable.get(this) || wrap(unwrap(this).relatedTarget); |
3053 // relatedTarget can be null. | |
3054 if (relatedTarget !== undefined) | |
3055 return relatedTarget; | |
3056 return wrap(unwrap(this).relatedTarget); | |
3057 } | 3044 } |
3058 }; | 3045 }; |
3059 | 3046 |
3060 function getInitFunction(name, relatedTargetIndex) { | 3047 function getInitFunction(name, relatedTargetIndex) { |
3061 return function() { | 3048 return function() { |
3062 arguments[relatedTargetIndex] = unwrap(arguments[relatedTargetIndex]); | 3049 arguments[relatedTargetIndex] = unwrap(arguments[relatedTargetIndex]); |
3063 var impl = unwrap(this); | 3050 var impl = unwrap(this); |
3064 impl[name].apply(impl, arguments); | 3051 impl[name].apply(impl, arguments); |
3065 }; | 3052 }; |
3066 } | 3053 } |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3135 ctrlKey: false, | 3122 ctrlKey: false, |
3136 altKey: false, | 3123 altKey: false, |
3137 shiftKey: false, | 3124 shiftKey: false, |
3138 metaKey: false, | 3125 metaKey: false, |
3139 button: 0, | 3126 button: 0, |
3140 relatedTarget: null | 3127 relatedTarget: null |
3141 }, 'UIEvent'); | 3128 }, 'UIEvent'); |
3142 configureEventConstructor('FocusEvent', {relatedTarget: null}, 'UIEvent'); | 3129 configureEventConstructor('FocusEvent', {relatedTarget: null}, 'UIEvent'); |
3143 } | 3130 } |
3144 | 3131 |
3145 // Safari 7 does not yet have BeforeUnloadEvent. | |
3146 // https://bugs.webkit.org/show_bug.cgi?id=120849 | |
3147 var OriginalBeforeUnloadEvent = window.BeforeUnloadEvent; | |
3148 | |
3149 function BeforeUnloadEvent(impl) { | 3132 function BeforeUnloadEvent(impl) { |
3150 Event.call(this, impl); | 3133 Event.call(this); |
3151 } | 3134 } |
3152 BeforeUnloadEvent.prototype = Object.create(Event.prototype); | 3135 BeforeUnloadEvent.prototype = Object.create(Event.prototype); |
3153 mixin(BeforeUnloadEvent.prototype, { | 3136 mixin(BeforeUnloadEvent.prototype, { |
3154 get returnValue() { | 3137 get returnValue() { |
3155 return this.impl.returnValue; | 3138 return this.impl.returnValue; |
3156 }, | 3139 }, |
3157 set returnValue(v) { | 3140 set returnValue(v) { |
3158 this.impl.returnValue = v; | 3141 this.impl.returnValue = v; |
3159 } | 3142 } |
3160 }); | 3143 }); |
3161 | 3144 |
3162 if (OriginalBeforeUnloadEvent) | |
3163 registerWrapper(OriginalBeforeUnloadEvent, BeforeUnloadEvent); | |
3164 | |
3165 function isValidListener(fun) { | 3145 function isValidListener(fun) { |
3166 if (typeof fun === 'function') | 3146 if (typeof fun === 'function') |
3167 return true; | 3147 return true; |
3168 return fun && fun.handleEvent; | 3148 return fun && fun.handleEvent; |
3169 } | 3149 } |
3170 | 3150 |
3171 function isMutationEvent(type) { | 3151 function isMutationEvent(type) { |
3172 switch (type) { | 3152 switch (type) { |
3173 case 'DOMAttrModified': | 3153 case 'DOMAttrModified': |
3174 case 'DOMAttributeNameChanged': | 3154 case 'DOMAttributeNameChanged': |
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3483 var assert = scope.assert; | 3463 var assert = scope.assert; |
3484 var defineWrapGetter = scope.defineWrapGetter; | 3464 var defineWrapGetter = scope.defineWrapGetter; |
3485 var enqueueMutation = scope.enqueueMutation; | 3465 var enqueueMutation = scope.enqueueMutation; |
3486 var getTreeScope = scope.getTreeScope; | 3466 var getTreeScope = scope.getTreeScope; |
3487 var isWrapper = scope.isWrapper; | 3467 var isWrapper = scope.isWrapper; |
3488 var mixin = scope.mixin; | 3468 var mixin = scope.mixin; |
3489 var registerTransientObservers = scope.registerTransientObservers; | 3469 var registerTransientObservers = scope.registerTransientObservers; |
3490 var registerWrapper = scope.registerWrapper; | 3470 var registerWrapper = scope.registerWrapper; |
3491 var setTreeScope = scope.setTreeScope; | 3471 var setTreeScope = scope.setTreeScope; |
3492 var unwrap = scope.unwrap; | 3472 var unwrap = scope.unwrap; |
3493 var unwrapIfNeeded = scope.unwrapIfNeeded; | |
3494 var wrap = scope.wrap; | 3473 var wrap = scope.wrap; |
3495 var wrapIfNeeded = scope.wrapIfNeeded; | 3474 var wrapIfNeeded = scope.wrapIfNeeded; |
3496 var wrappers = scope.wrappers; | 3475 var wrappers = scope.wrappers; |
3497 | 3476 |
3498 function assertIsNodeWrapper(node) { | 3477 function assertIsNodeWrapper(node) { |
3499 assert(node instanceof Node); | 3478 assert(node instanceof Node); |
3500 } | 3479 } |
3501 | 3480 |
3502 function createOneElementNodeList(node) { | 3481 function createOneElementNodeList(node) { |
3503 var nodes = new NodeList(); | 3482 var nodes = new NodeList(); |
(...skipping 628 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4132 return cloneNode(this, deep); | 4111 return cloneNode(this, deep); |
4133 }, | 4112 }, |
4134 | 4113 |
4135 contains: function(child) { | 4114 contains: function(child) { |
4136 return contains(this, wrapIfNeeded(child)); | 4115 return contains(this, wrapIfNeeded(child)); |
4137 }, | 4116 }, |
4138 | 4117 |
4139 compareDocumentPosition: function(otherNode) { | 4118 compareDocumentPosition: function(otherNode) { |
4140 // This only wraps, it therefore only operates on the composed DOM and not | 4119 // This only wraps, it therefore only operates on the composed DOM and not |
4141 // the logical DOM. | 4120 // the logical DOM. |
4142 return originalCompareDocumentPosition.call(this.impl, | 4121 return originalCompareDocumentPosition.call(this.impl, unwrap(otherNode)); |
4143 unwrapIfNeeded(otherNode)); | |
4144 }, | 4122 }, |
4145 | 4123 |
4146 normalize: function() { | 4124 normalize: function() { |
4147 var nodes = snapshotNodeList(this.childNodes); | 4125 var nodes = snapshotNodeList(this.childNodes); |
4148 var remNodes = []; | 4126 var remNodes = []; |
4149 var s = ''; | 4127 var s = ''; |
4150 var modNode; | 4128 var modNode; |
4151 | 4129 |
4152 for (var i = 0, n; i < nodes.length; i++) { | 4130 for (var i = 0, n; i < nodes.length; i++) { |
4153 n = nodes[i]; | 4131 n = nodes[i]; |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4320 get children() { | 4298 get children() { |
4321 var wrapperList = new NodeList(); | 4299 var wrapperList = new NodeList(); |
4322 var i = 0; | 4300 var i = 0; |
4323 for (var child = this.firstElementChild; | 4301 for (var child = this.firstElementChild; |
4324 child; | 4302 child; |
4325 child = child.nextElementSibling) { | 4303 child = child.nextElementSibling) { |
4326 wrapperList[i++] = child; | 4304 wrapperList[i++] = child; |
4327 } | 4305 } |
4328 wrapperList.length = i; | 4306 wrapperList.length = i; |
4329 return wrapperList; | 4307 return wrapperList; |
4330 }, | |
4331 | |
4332 remove: function() { | |
4333 var p = this.parentNode; | |
4334 if (p) | |
4335 p.removeChild(this); | |
4336 } | 4308 } |
4337 }; | 4309 }; |
4338 | 4310 |
4339 var ChildNodeInterface = { | 4311 var ChildNodeInterface = { |
4340 get nextElementSibling() { | 4312 get nextElementSibling() { |
4341 return forwardElement(this.nextSibling); | 4313 return forwardElement(this.nextSibling); |
4342 }, | 4314 }, |
4343 | 4315 |
4344 get previousElementSibling() { | 4316 get previousElementSibling() { |
4345 return backwardsElement(this.previousSibling); | 4317 return backwardsElement(this.previousSibling); |
(...skipping 922 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5268 mixin(HTMLSelectElement.prototype, { | 5240 mixin(HTMLSelectElement.prototype, { |
5269 add: function(element, before) { | 5241 add: function(element, before) { |
5270 if (typeof before === 'object') // also includes null | 5242 if (typeof before === 'object') // also includes null |
5271 before = unwrap(before); | 5243 before = unwrap(before); |
5272 unwrap(this).add(unwrap(element), before); | 5244 unwrap(this).add(unwrap(element), before); |
5273 }, | 5245 }, |
5274 | 5246 |
5275 remove: function(indexOrNode) { | 5247 remove: function(indexOrNode) { |
5276 // Spec only allows index but implementations allow index or node. | 5248 // Spec only allows index but implementations allow index or node. |
5277 // remove() is also allowed which is same as remove(undefined) | 5249 // remove() is also allowed which is same as remove(undefined) |
5278 if (indexOrNode === undefined) { | |
5279 HTMLElement.prototype.remove.call(this); | |
5280 return; | |
5281 } | |
5282 | |
5283 if (typeof indexOrNode === 'object') | 5250 if (typeof indexOrNode === 'object') |
5284 indexOrNode = unwrap(indexOrNode); | 5251 indexOrNode = unwrap(indexOrNode); |
5285 | |
5286 unwrap(this).remove(indexOrNode); | 5252 unwrap(this).remove(indexOrNode); |
5287 }, | 5253 }, |
5288 | 5254 |
5289 get form() { | 5255 get form() { |
5290 return wrap(unwrap(this).form); | 5256 return wrap(unwrap(this).form); |
5291 } | 5257 } |
5292 }); | 5258 }); |
5293 | 5259 |
5294 registerWrapper(OriginalHTMLSelectElement, HTMLSelectElement, | 5260 registerWrapper(OriginalHTMLSelectElement, HTMLSelectElement, |
5295 document.createElement('select')); | 5261 document.createElement('select')); |
(...skipping 1499 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6795 }, | 6761 }, |
6796 getSelection: function() { | 6762 getSelection: function() { |
6797 renderAllPending(); | 6763 renderAllPending(); |
6798 return new Selection(originalGetSelection.call(unwrap(this))); | 6764 return new Selection(originalGetSelection.call(unwrap(this))); |
6799 } | 6765 } |
6800 }); | 6766 }); |
6801 | 6767 |
6802 if (document.registerElement) { | 6768 if (document.registerElement) { |
6803 var originalRegisterElement = document.registerElement; | 6769 var originalRegisterElement = document.registerElement; |
6804 Document.prototype.registerElement = function(tagName, object) { | 6770 Document.prototype.registerElement = function(tagName, object) { |
6805 var prototype, extendsOption; | 6771 var prototype = object.prototype; |
6806 if (object !== undefined) { | |
6807 prototype = object.prototype; | |
6808 extendsOption = object.extends; | |
6809 } | |
6810 | |
6811 if (!prototype) | |
6812 prototype = Object.create(HTMLElement.prototype); | |
6813 | |
6814 | 6772 |
6815 // If we already used the object as a prototype for another custom | 6773 // If we already used the object as a prototype for another custom |
6816 // element. | 6774 // element. |
6817 if (scope.nativePrototypeTable.get(prototype)) { | 6775 if (scope.nativePrototypeTable.get(prototype)) { |
6818 // TODO(arv): DOMException | 6776 // TODO(arv): DOMException |
6819 throw new Error('NotSupportedError'); | 6777 throw new Error('NotSupportedError'); |
6820 } | 6778 } |
6821 | 6779 |
6822 // Find first object on the prototype chain that already have a native | 6780 // Find first object on the prototype chain that already have a native |
6823 // prototype. Keep track of all the objects before that so we can create | 6781 // prototype. Keep track of all the objects before that so we can create |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6864 // if this element has been wrapped prior to registration, | 6822 // if this element has been wrapped prior to registration, |
6865 // the wrapper is stale; in this case rewrap | 6823 // the wrapper is stale; in this case rewrap |
6866 if (!(wrap(this) instanceof CustomElementConstructor)) { | 6824 if (!(wrap(this) instanceof CustomElementConstructor)) { |
6867 rewrap(this); | 6825 rewrap(this); |
6868 } | 6826 } |
6869 f.apply(wrap(this), arguments); | 6827 f.apply(wrap(this), arguments); |
6870 }; | 6828 }; |
6871 }); | 6829 }); |
6872 | 6830 |
6873 var p = {prototype: newPrototype}; | 6831 var p = {prototype: newPrototype}; |
6874 if (extendsOption) | 6832 if (object.extends) |
6875 p.extends = extendsOption; | 6833 p.extends = object.extends; |
6876 | 6834 |
6877 function CustomElementConstructor(node) { | 6835 function CustomElementConstructor(node) { |
6878 if (!node) { | 6836 if (!node) { |
6879 if (extendsOption) { | 6837 if (object.extends) { |
6880 return document.createElement(extendsOption, tagName); | 6838 return document.createElement(object.extends, tagName); |
6881 } else { | 6839 } else { |
6882 return document.createElement(tagName); | 6840 return document.createElement(tagName); |
6883 } | 6841 } |
6884 } | 6842 } |
6885 this.impl = node; | 6843 this.impl = node; |
6886 } | 6844 } |
6887 CustomElementConstructor.prototype = prototype; | 6845 CustomElementConstructor.prototype = prototype; |
6888 CustomElementConstructor.prototype.constructor = CustomElementConstructor; | 6846 CustomElementConstructor.prototype.constructor = CustomElementConstructor; |
6889 | 6847 |
6890 scope.constructorTable.set(newPrototype, CustomElementConstructor); | 6848 scope.constructorTable.set(newPrototype, CustomElementConstructor); |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7072 return new Selection(originalGetSelection.call(unwrap(this))); | 7030 return new Selection(originalGetSelection.call(unwrap(this))); |
7073 }, | 7031 }, |
7074 }); | 7032 }); |
7075 | 7033 |
7076 registerWrapper(OriginalWindow, Window); | 7034 registerWrapper(OriginalWindow, Window); |
7077 | 7035 |
7078 scope.wrappers.Window = Window; | 7036 scope.wrappers.Window = Window; |
7079 | 7037 |
7080 })(window.ShadowDOMPolyfill); | 7038 })(window.ShadowDOMPolyfill); |
7081 | 7039 |
7082 /** | |
7083 * Copyright 2014 The Polymer Authors. All rights reserved. | |
7084 * Use of this source code is goverened by a BSD-style | |
7085 * license that can be found in the LICENSE file. | |
7086 */ | |
7087 | |
7088 (function(scope) { | |
7089 'use strict'; | |
7090 | |
7091 var unwrap = scope.unwrap; | |
7092 | |
7093 // DataTransfer (Clipboard in old Blink/WebKit) has a single method that | |
7094 // requires wrapping. Since it is only a method we do not need a real wrapper, | |
7095 // we can just override the method. | |
7096 | |
7097 var OriginalDataTransfer = window.DataTransfer || window.Clipboard; | |
7098 var OriginalDataTransferSetDragImage = | |
7099 OriginalDataTransfer.prototype.setDragImage; | |
7100 | |
7101 OriginalDataTransfer.prototype.setDragImage = function(image, x, y) { | |
7102 OriginalDataTransferSetDragImage.call(this, unwrap(image), x, y); | |
7103 }; | |
7104 | |
7105 })(window.ShadowDOMPolyfill); | |
7106 | |
7107 // Copyright 2013 The Polymer Authors. All rights reserved. | 7040 // Copyright 2013 The Polymer Authors. All rights reserved. |
7108 // Use of this source code is goverened by a BSD-style | 7041 // Use of this source code is goverened by a BSD-style |
7109 // license that can be found in the LICENSE file. | 7042 // license that can be found in the LICENSE file. |
7110 | 7043 |
7111 (function(scope) { | 7044 (function(scope) { |
7112 'use strict'; | 7045 'use strict'; |
7113 | 7046 |
7114 var isWrapperFor = scope.isWrapperFor; | 7047 var isWrapperFor = scope.isWrapperFor; |
7115 | 7048 |
7116 // This is a list of the elements we currently override the global constructor | 7049 // This is a list of the elements we currently override the global constructor |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7267 relatively simply implemented. The goal is to allow users to avoid the | 7200 relatively simply implemented. The goal is to allow users to avoid the |
7268 most obvious pitfalls and do so without compromising performance significantly
. | 7201 most obvious pitfalls and do so without compromising performance significantly
. |
7269 For ShadowDOM styling that's not covered here, a set of best practices | 7202 For ShadowDOM styling that's not covered here, a set of best practices |
7270 can be provided that should allow users to accomplish more complex styling. | 7203 can be provided that should allow users to accomplish more complex styling. |
7271 | 7204 |
7272 The following is a list of specific ShadowDOM styling features and a brief | 7205 The following is a list of specific ShadowDOM styling features and a brief |
7273 discussion of the approach used to shim. | 7206 discussion of the approach used to shim. |
7274 | 7207 |
7275 Shimmed features: | 7208 Shimmed features: |
7276 | 7209 |
7277 * :host, :host-context: ShadowDOM allows styling of the shadowRoot's host | 7210 * :host, :ancestor: ShadowDOM allows styling of the shadowRoot's host |
7278 element using the :host rule. To shim this feature, the :host styles are | 7211 element using the :host rule. To shim this feature, the :host styles are |
7279 reformatted and prefixed with a given scope name and promoted to a | 7212 reformatted and prefixed with a given scope name and promoted to a |
7280 document level stylesheet. | 7213 document level stylesheet. |
7281 For example, given a scope name of .foo, a rule like this: | 7214 For example, given a scope name of .foo, a rule like this: |
7282 | 7215 |
7283 :host { | 7216 :host { |
7284 background: red; | 7217 background: red; |
7285 } | 7218 } |
7286 } | 7219 } |
7287 | 7220 |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7441 registerRoot: function(root, name, extendsName) { | 7374 registerRoot: function(root, name, extendsName) { |
7442 var def = this.registry[name] = { | 7375 var def = this.registry[name] = { |
7443 root: root, | 7376 root: root, |
7444 name: name, | 7377 name: name, |
7445 extendsName: extendsName | 7378 extendsName: extendsName |
7446 } | 7379 } |
7447 var styles = this.findStyles(root); | 7380 var styles = this.findStyles(root); |
7448 def.rootStyles = styles; | 7381 def.rootStyles = styles; |
7449 def.scopeStyles = def.rootStyles; | 7382 def.scopeStyles = def.rootStyles; |
7450 var extendee = this.registry[def.extendsName]; | 7383 var extendee = this.registry[def.extendsName]; |
7451 if (extendee) { | 7384 if (extendee && (!root || root.querySelector('shadow'))) { |
7452 def.scopeStyles = extendee.scopeStyles.concat(def.scopeStyles); | 7385 def.scopeStyles = extendee.scopeStyles.concat(def.scopeStyles); |
7453 } | 7386 } |
7454 return def; | 7387 return def; |
7455 }, | 7388 }, |
7456 findStyles: function(root) { | 7389 findStyles: function(root) { |
7457 if (!root) { | 7390 if (!root) { |
7458 return []; | 7391 return []; |
7459 } | 7392 } |
7460 var styles = root.querySelectorAll('style'); | 7393 var styles = root.querySelectorAll('style'); |
7461 return Array.prototype.filter.call(styles, function(s) { | 7394 return Array.prototype.filter.call(styles, function(s) { |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7536 * .foo {... } | 7469 * .foo {... } |
7537 * | 7470 * |
7538 * and converts this to | 7471 * and converts this to |
7539 * | 7472 * |
7540 * scopeName .foo { ... } | 7473 * scopeName .foo { ... } |
7541 */ | 7474 */ |
7542 scopeCssText: function(cssText, scopeSelector) { | 7475 scopeCssText: function(cssText, scopeSelector) { |
7543 var unscoped = this.extractUnscopedRulesFromCssText(cssText); | 7476 var unscoped = this.extractUnscopedRulesFromCssText(cssText); |
7544 cssText = this.insertPolyfillHostInCssText(cssText); | 7477 cssText = this.insertPolyfillHostInCssText(cssText); |
7545 cssText = this.convertColonHost(cssText); | 7478 cssText = this.convertColonHost(cssText); |
7546 cssText = this.convertColonHostContext(cssText); | 7479 cssText = this.convertColonAncestor(cssText); |
7547 cssText = this.convertCombinators(cssText); | 7480 cssText = this.convertCombinators(cssText); |
7548 if (scopeSelector) { | 7481 if (scopeSelector) { |
7549 var self = this, cssText; | 7482 var self = this, cssText; |
7550 withCssRules(cssText, function(rules) { | 7483 withCssRules(cssText, function(rules) { |
7551 cssText = self.scopeRules(rules, scopeSelector); | 7484 cssText = self.scopeRules(rules, scopeSelector); |
7552 }); | 7485 }); |
7553 | 7486 |
7554 } | 7487 } |
7555 cssText = cssText + '\n' + unscoped; | 7488 cssText = cssText + '\n' + unscoped; |
7556 return cssText.trim(); | 7489 return cssText.trim(); |
(...skipping 28 matching lines...) Expand all Loading... |
7585 * | 7518 * |
7586 * to | 7519 * to |
7587 * | 7520 * |
7588 * scopeName.foo > .bar | 7521 * scopeName.foo > .bar |
7589 */ | 7522 */ |
7590 convertColonHost: function(cssText) { | 7523 convertColonHost: function(cssText) { |
7591 return this.convertColonRule(cssText, cssColonHostRe, | 7524 return this.convertColonRule(cssText, cssColonHostRe, |
7592 this.colonHostPartReplacer); | 7525 this.colonHostPartReplacer); |
7593 }, | 7526 }, |
7594 /* | 7527 /* |
7595 * convert a rule like :host-context(.foo) > .bar { } | 7528 * convert a rule like :ancestor(.foo) > .bar { } |
7596 * | 7529 * |
7597 * to | 7530 * to |
7598 * | 7531 * |
7599 * scopeName.foo > .bar, .foo scopeName > .bar { } | 7532 * scopeName.foo > .bar, .foo scopeName > .bar { } |
7600 * | 7533 * |
7601 * and | 7534 * and |
7602 * | 7535 * |
7603 * :host-context(.foo:host) .bar { ... } | 7536 * :ancestor(.foo:host) .bar { ... } |
7604 * | 7537 * |
7605 * to | 7538 * to |
7606 * | 7539 * |
7607 * scopeName.foo .bar { ... } | 7540 * scopeName.foo .bar { ... } |
7608 */ | 7541 */ |
7609 convertColonHostContext: function(cssText) { | 7542 convertColonAncestor: function(cssText) { |
7610 return this.convertColonRule(cssText, cssColonHostContextRe, | 7543 return this.convertColonRule(cssText, cssColonAncestorRe, |
7611 this.colonHostContextPartReplacer); | 7544 this.colonAncestorPartReplacer); |
7612 }, | 7545 }, |
7613 convertColonRule: function(cssText, regExp, partReplacer) { | 7546 convertColonRule: function(cssText, regExp, partReplacer) { |
7614 // p1 = :host, p2 = contents of (), p3 rest of rule | 7547 // p1 = :host, p2 = contents of (), p3 rest of rule |
7615 return cssText.replace(regExp, function(m, p1, p2, p3) { | 7548 return cssText.replace(regExp, function(m, p1, p2, p3) { |
7616 p1 = polyfillHostNoCombinator; | 7549 p1 = polyfillHostNoCombinator; |
7617 if (p2) { | 7550 if (p2) { |
7618 var parts = p2.split(','), r = []; | 7551 var parts = p2.split(','), r = []; |
7619 for (var i=0, l=parts.length, p; (i<l) && (p=parts[i]); i++) { | 7552 for (var i=0, l=parts.length, p; (i<l) && (p=parts[i]); i++) { |
7620 p = p.trim(); | 7553 p = p.trim(); |
7621 r.push(partReplacer(p1, p, p3)); | 7554 r.push(partReplacer(p1, p, p3)); |
7622 } | 7555 } |
7623 return r.join(','); | 7556 return r.join(','); |
7624 } else { | 7557 } else { |
7625 return p1 + p3; | 7558 return p1 + p3; |
7626 } | 7559 } |
7627 }); | 7560 }); |
7628 }, | 7561 }, |
7629 colonHostContextPartReplacer: function(host, part, suffix) { | 7562 colonAncestorPartReplacer: function(host, part, suffix) { |
7630 if (part.match(polyfillHost)) { | 7563 if (part.match(polyfillHost)) { |
7631 return this.colonHostPartReplacer(host, part, suffix); | 7564 return this.colonHostPartReplacer(host, part, suffix); |
7632 } else { | 7565 } else { |
7633 return host + part + suffix + ', ' + part + ' ' + host + suffix; | 7566 return host + part + suffix + ', ' + part + ' ' + host + suffix; |
7634 } | 7567 } |
7635 }, | 7568 }, |
7636 colonHostPartReplacer: function(host, part, suffix) { | 7569 colonHostPartReplacer: function(host, part, suffix) { |
7637 return host + part.replace(polyfillHost, '') + suffix; | 7570 return host + part.replace(polyfillHost, '') + suffix; |
7638 }, | 7571 }, |
7639 /* | 7572 /* |
7640 * Convert ^ and ^^ combinators by replacing with space. | 7573 * Convert ^ and ^^ combinators by replacing with space. |
7641 */ | 7574 */ |
7642 convertCombinators: function(cssText) { | 7575 convertCombinators: function(cssText) { |
7643 for (var i=0; i < combinatorsRe.length; i++) { | 7576 return cssText.replace(/\^\^/g, ' ').replace(/\^/g, ' '); |
7644 cssText = cssText.replace(combinatorsRe[i], ' '); | |
7645 } | |
7646 return cssText; | |
7647 }, | 7577 }, |
7648 // change a selector like 'div' to 'name div' | 7578 // change a selector like 'div' to 'name div' |
7649 scopeRules: function(cssRules, scopeSelector) { | 7579 scopeRules: function(cssRules, scopeSelector) { |
7650 var cssText = ''; | 7580 var cssText = ''; |
7651 if (cssRules) { | 7581 if (cssRules) { |
7652 Array.prototype.forEach.call(cssRules, function(rule) { | 7582 Array.prototype.forEach.call(cssRules, function(rule) { |
7653 if (rule.selectorText && (rule.style && rule.style.cssText)) { | 7583 if (rule.selectorText && (rule.style && rule.style.cssText)) { |
7654 cssText += this.scopeSelector(rule.selectorText, scopeSelector, | 7584 cssText += this.scopeSelector(rule.selectorText, scopeSelector, |
7655 this.strictStyling) + ' {\n\t'; | 7585 this.strictStyling) + ' {\n\t'; |
7656 cssText += this.propertiesFromRule(rule) + '\n}\n\n'; | 7586 cssText += this.propertiesFromRule(rule) + '\n}\n\n'; |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7709 var t = p.trim().replace(polyfillHostRe, ''); | 7639 var t = p.trim().replace(polyfillHostRe, ''); |
7710 if (t && (splits.indexOf(t) < 0) && (t.indexOf(attrName) < 0)) { | 7640 if (t && (splits.indexOf(t) < 0) && (t.indexOf(attrName) < 0)) { |
7711 p = t.replace(/([^:]*)(:*)(.*)/, '$1' + attrName + '$2$3') | 7641 p = t.replace(/([^:]*)(:*)(.*)/, '$1' + attrName + '$2$3') |
7712 } | 7642 } |
7713 return p; | 7643 return p; |
7714 }).join(sep); | 7644 }).join(sep); |
7715 }); | 7645 }); |
7716 return scoped; | 7646 return scoped; |
7717 }, | 7647 }, |
7718 insertPolyfillHostInCssText: function(selector) { | 7648 insertPolyfillHostInCssText: function(selector) { |
7719 return selector.replace(colonHostContextRe, polyfillHostContext).replace( | 7649 return selector.replace(hostRe, polyfillHost).replace(colonHostRe, |
7720 colonHostRe, polyfillHost); | 7650 polyfillHost).replace(colonAncestorRe, polyfillAncestor); |
7721 }, | 7651 }, |
7722 propertiesFromRule: function(rule) { | 7652 propertiesFromRule: function(rule) { |
7723 var cssText = rule.style.cssText; | |
7724 // TODO(sorvell): Safari cssom incorrectly removes quotes from the content | 7653 // TODO(sorvell): Safari cssom incorrectly removes quotes from the content |
7725 // property. (https://bugs.webkit.org/show_bug.cgi?id=118045) | 7654 // property. (https://bugs.webkit.org/show_bug.cgi?id=118045) |
7726 // don't replace attr rules | 7655 if (rule.style.content && !rule.style.content.match(/['"]+/)) { |
7727 if (rule.style.content && !rule.style.content.match(/['"]+|attr/)) { | 7656 return rule.style.cssText.replace(/content:[^;]*;/g, 'content: \'' + |
7728 cssText = cssText.replace(/content:[^;]*;/g, 'content: \'' + | |
7729 rule.style.content + '\';'); | 7657 rule.style.content + '\';'); |
7730 } | 7658 } |
7731 // TODO(sorvell): we can workaround this issue here, but we need a list | 7659 return rule.style.cssText; |
7732 // of troublesome properties to fix https://github.com/Polymer/platform/issu
es/53 | |
7733 // | |
7734 // inherit rules can be omitted from cssText | |
7735 // TODO(sorvell): remove when Blink bug is fixed: | |
7736 // https://code.google.com/p/chromium/issues/detail?id=358273 | |
7737 var style = rule.style; | |
7738 for (var i in style) { | |
7739 if (style[i] === 'initial') { | |
7740 cssText += i + ': initial; '; | |
7741 } | |
7742 } | |
7743 return cssText; | |
7744 }, | 7660 }, |
7745 replaceTextInStyles: function(styles, action) { | 7661 replaceTextInStyles: function(styles, action) { |
7746 if (styles && action) { | 7662 if (styles && action) { |
7747 if (!(styles instanceof Array)) { | 7663 if (!(styles instanceof Array)) { |
7748 styles = [styles]; | 7664 styles = [styles]; |
7749 } | 7665 } |
7750 Array.prototype.forEach.call(styles, function(s) { | 7666 Array.prototype.forEach.call(styles, function(s) { |
7751 s.textContent = action.call(this, s.textContent); | 7667 s.textContent = action.call(this, s.textContent); |
7752 }, this); | 7668 }, this); |
7753 } | 7669 } |
(...skipping 15 matching lines...) Expand all Loading... |
7769 // TODO(sorvell): remove either content or comment | 7685 // TODO(sorvell): remove either content or comment |
7770 cssCommentRuleRe = /\/\*\s@polyfill-rule([^*]*\*+([^/*][^*]*\*+)*)\//gim, | 7686 cssCommentRuleRe = /\/\*\s@polyfill-rule([^*]*\*+([^/*][^*]*\*+)*)\//gim, |
7771 cssContentRuleRe = /(polyfill-rule)[^}]*(content\:[\s]*'([^']*)'[^;]*;)[^}]*
}/gim, | 7687 cssContentRuleRe = /(polyfill-rule)[^}]*(content\:[\s]*'([^']*)'[^;]*;)[^}]*
}/gim, |
7772 // TODO(sorvell): remove either content or comment | 7688 // TODO(sorvell): remove either content or comment |
7773 cssCommentUnscopedRuleRe = /\/\*\s@polyfill-unscoped-rule([^*]*\*+([^/*][^*]
*\*+)*)\//gim, | 7689 cssCommentUnscopedRuleRe = /\/\*\s@polyfill-unscoped-rule([^*]*\*+([^/*][^*]
*\*+)*)\//gim, |
7774 cssContentUnscopedRuleRe = /(polyfill-unscoped-rule)[^}]*(content\:[\s]*'([^
']*)'[^;]*;)[^}]*}/gim, | 7690 cssContentUnscopedRuleRe = /(polyfill-unscoped-rule)[^}]*(content\:[\s]*'([^
']*)'[^;]*;)[^}]*}/gim, |
7775 cssPseudoRe = /::(x-[^\s{,(]*)/gim, | 7691 cssPseudoRe = /::(x-[^\s{,(]*)/gim, |
7776 cssPartRe = /::part\(([^)]*)\)/gim, | 7692 cssPartRe = /::part\(([^)]*)\)/gim, |
7777 // note: :host pre-processed to -shadowcsshost. | 7693 // note: :host pre-processed to -shadowcsshost. |
7778 polyfillHost = '-shadowcsshost', | 7694 polyfillHost = '-shadowcsshost', |
7779 // note: :host-context pre-processed to -shadowcsshostcontext. | 7695 // note: :ancestor pre-processed to -shadowcssancestor. |
7780 polyfillHostContext = '-shadowcsscontext', | 7696 polyfillAncestor = '-shadowcssancestor', |
7781 parenSuffix = ')(?:\\((' + | 7697 parenSuffix = ')(?:\\((' + |
7782 '(?:\\([^)(]*\\)|[^)(]*)+?' + | 7698 '(?:\\([^)(]*\\)|[^)(]*)+?' + |
7783 ')\\))?([^,{]*)'; | 7699 ')\\))?([^,{]*)'; |
7784 cssColonHostRe = new RegExp('(' + polyfillHost + parenSuffix, 'gim'), | 7700 cssColonHostRe = new RegExp('(' + polyfillHost + parenSuffix, 'gim'), |
7785 cssColonHostContextRe = new RegExp('(' + polyfillHostContext + parenSuffix,
'gim'), | 7701 cssColonAncestorRe = new RegExp('(' + polyfillAncestor + parenSuffix, 'gim')
, |
7786 selectorReSuffix = '([>\\s~+\[.,{:][\\s\\S]*)?$', | 7702 selectorReSuffix = '([>\\s~+\[.,{:][\\s\\S]*)?$', |
| 7703 hostRe = /@host/gim, |
7787 colonHostRe = /\:host/gim, | 7704 colonHostRe = /\:host/gim, |
7788 colonHostContextRe = /\:host-context/gim, | 7705 colonAncestorRe = /\:ancestor/gim, |
7789 /* host name without combinator */ | 7706 /* host name without combinator */ |
7790 polyfillHostNoCombinator = polyfillHost + '-no-combinator', | 7707 polyfillHostNoCombinator = polyfillHost + '-no-combinator', |
7791 polyfillHostRe = new RegExp(polyfillHost, 'gim'), | 7708 polyfillHostRe = new RegExp(polyfillHost, 'gim'), |
7792 polyfillHostContextRe = new RegExp(polyfillHostContext, 'gim'), | 7709 polyfillAncestorRe = new RegExp(polyfillAncestor, 'gim'); |
7793 combinatorsRe = [ | |
7794 /\^\^/g, | |
7795 /\^/g, | |
7796 /\/shadow\//g, | |
7797 /\/shadow-deep\//g, | |
7798 /::shadow/g, | |
7799 /\/deep\//g | |
7800 ]; | |
7801 | 7710 |
7802 function stylesToCssText(styles, preserveComments) { | 7711 function stylesToCssText(styles, preserveComments) { |
7803 var cssText = ''; | 7712 var cssText = ''; |
7804 Array.prototype.forEach.call(styles, function(s) { | 7713 Array.prototype.forEach.call(styles, function(s) { |
7805 cssText += s.textContent + '\n\n'; | 7714 cssText += s.textContent + '\n\n'; |
7806 }); | 7715 }); |
7807 // strip comments for easier processing | 7716 // strip comments for easier processing |
7808 if (!preserveComments) { | 7717 if (!preserveComments) { |
7809 cssText = cssText.replace(cssCommentRe, ''); | 7718 cssText = cssText.replace(cssCommentRe, ''); |
7810 } | 7719 } |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8002 // poor man's adapter for template.content on various platform scenarios | 7911 // poor man's adapter for template.content on various platform scenarios |
8003 window.templateContent = window.templateContent || function(inTemplate) { | 7912 window.templateContent = window.templateContent || function(inTemplate) { |
8004 return inTemplate.content; | 7913 return inTemplate.content; |
8005 }; | 7914 }; |
8006 | 7915 |
8007 // so we can call wrap/unwrap without testing for ShadowDOMPolyfill | 7916 // so we can call wrap/unwrap without testing for ShadowDOMPolyfill |
8008 | 7917 |
8009 window.wrap = window.unwrap = function(n){ | 7918 window.wrap = window.unwrap = function(n){ |
8010 return n; | 7919 return n; |
8011 } | 7920 } |
8012 | 7921 |
8013 addEventListener('DOMContentLoaded', function() { | 7922 var originalCreateShadowRoot = Element.prototype.webkitCreateShadowRoot; |
8014 if (CustomElements.useNative === false) { | 7923 Element.prototype.webkitCreateShadowRoot = function() { |
8015 var originalCreateShadowRoot = Element.prototype.createShadowRoot; | 7924 var elderRoot = this.webkitShadowRoot; |
8016 Element.prototype.createShadowRoot = function() { | 7925 var root = originalCreateShadowRoot.call(this); |
8017 var root = originalCreateShadowRoot.call(this); | 7926 root.olderShadowRoot = elderRoot; |
8018 CustomElements.watchShadow(this); | 7927 root.host = this; |
8019 return root; | 7928 CustomElements.watchShadow(this); |
8020 }; | 7929 return root; |
| 7930 } |
| 7931 |
| 7932 Object.defineProperties(Element.prototype, { |
| 7933 shadowRoot: { |
| 7934 get: function() { |
| 7935 return this.webkitShadowRoot; |
| 7936 } |
| 7937 }, |
| 7938 createShadowRoot: { |
| 7939 value: function() { |
| 7940 return this.webkitCreateShadowRoot(); |
| 7941 } |
8021 } | 7942 } |
8022 }); | 7943 }); |
8023 | 7944 |
8024 window.templateContent = function(inTemplate) { | 7945 window.templateContent = function(inTemplate) { |
8025 // if MDV exists, it may need to boostrap this template to reveal content | 7946 // if MDV exists, it may need to boostrap this template to reveal content |
8026 if (window.HTMLTemplateElement && HTMLTemplateElement.bootstrap) { | 7947 if (window.HTMLTemplateElement && HTMLTemplateElement.bootstrap) { |
8027 HTMLTemplateElement.bootstrap(inTemplate); | 7948 HTMLTemplateElement.bootstrap(inTemplate); |
8028 } | 7949 } |
8029 // fallback when there is no Shadow DOM polyfill, no MDV polyfill, and no | 7950 // fallback when there is no Shadow DOM polyfill, no MDV polyfill, and no |
8030 // native template support | 7951 // native template support |
8031 if (!inTemplate.content && !inTemplate._content) { | 7952 if (!inTemplate.content && !inTemplate._content) { |
8032 var frag = document.createDocumentFragment(); | 7953 var frag = document.createDocumentFragment(); |
8033 while (inTemplate.firstChild) { | 7954 while (inTemplate.firstChild) { |
(...skipping 1827 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9861 // don't need fetch | 9782 // don't need fetch |
9862 return true; | 9783 return true; |
9863 } | 9784 } |
9864 // first node waiting for inUrl | 9785 // first node waiting for inUrl |
9865 this.pending[url] = [elt]; | 9786 this.pending[url] = [elt]; |
9866 // need fetch (not a dupe) | 9787 // need fetch (not a dupe) |
9867 return false; | 9788 return false; |
9868 }, | 9789 }, |
9869 fetch: function(url, elt) { | 9790 fetch: function(url, elt) { |
9870 flags.load && console.log('fetch', url, elt); | 9791 flags.load && console.log('fetch', url, elt); |
9871 if (url.match(/^data:/)) { | 9792 var receiveXhr = function(err, resource) { |
9872 // Handle Data URI Scheme | 9793 this.receive(url, elt, err, resource); |
9873 var pieces = url.split(','); | 9794 }.bind(this); |
9874 var header = pieces[0]; | 9795 xhr.load(url, receiveXhr); |
9875 var body = pieces[1]; | 9796 // TODO(sorvell): blocked on |
9876 if(header.indexOf(';base64') > -1) { | 9797 // https://code.google.com/p/chromium/issues/detail?id=257221 |
9877 body = atob(body); | 9798 // xhr'ing for a document makes scripts in imports runnable; otherwise |
9878 } else { | 9799 // they are not; however, it requires that we have doctype=html in |
9879 body = decodeURIComponent(body); | 9800 // the import which is unacceptable. This is only needed on Chrome |
9880 } | 9801 // to avoid the bug above. |
9881 setTimeout(function() { | 9802 /* |
9882 this.receive(url, elt, null, body); | 9803 if (isDocumentLink(elt)) { |
9883 }.bind(this), 0); | 9804 xhr.loadDocument(url, receiveXhr); |
9884 } else { | 9805 } else { |
9885 var receiveXhr = function(err, resource) { | |
9886 this.receive(url, elt, err, resource); | |
9887 }.bind(this); | |
9888 xhr.load(url, receiveXhr); | 9806 xhr.load(url, receiveXhr); |
9889 // TODO(sorvell): blocked on) | |
9890 // https://code.google.com/p/chromium/issues/detail?id=257221 | |
9891 // xhr'ing for a document makes scripts in imports runnable; otherwise | |
9892 // they are not; however, it requires that we have doctype=html in | |
9893 // the import which is unacceptable. This is only needed on Chrome | |
9894 // to avoid the bug above. | |
9895 /* | |
9896 if (isDocumentLink(elt)) { | |
9897 xhr.loadDocument(url, receiveXhr); | |
9898 } else { | |
9899 xhr.load(url, receiveXhr); | |
9900 } | |
9901 */ | |
9902 } | 9807 } |
| 9808 */ |
9903 }, | 9809 }, |
9904 receive: function(url, elt, err, resource) { | 9810 receive: function(url, elt, err, resource) { |
9905 this.cache[url] = resource; | 9811 this.cache[url] = resource; |
9906 var $p = this.pending[url]; | 9812 var $p = this.pending[url]; |
9907 for (var i=0, l=$p.length, p; (i<l) && (p=$p[i]); i++) { | 9813 for (var i=0, l=$p.length, p; (i<l) && (p=$p[i]); i++) { |
9908 //if (!err) { | 9814 //if (!err) { |
9909 this.onload(url, p, resource); | 9815 this.onload(url, p, resource); |
9910 //} | 9816 //} |
9911 this.tail(); | 9817 this.tail(); |
9912 } | 9818 } |
(...skipping 1104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11017 scope.upgradeElement = nop; | 10923 scope.upgradeElement = nop; |
11018 | 10924 |
11019 scope.watchShadow = nop; | 10925 scope.watchShadow = nop; |
11020 scope.upgrade = nop; | 10926 scope.upgrade = nop; |
11021 scope.upgradeAll = nop; | 10927 scope.upgradeAll = nop; |
11022 scope.upgradeSubtree = nop; | 10928 scope.upgradeSubtree = nop; |
11023 scope.observeDocument = nop; | 10929 scope.observeDocument = nop; |
11024 scope.upgradeDocument = nop; | 10930 scope.upgradeDocument = nop; |
11025 scope.upgradeDocumentTree = nop; | 10931 scope.upgradeDocumentTree = nop; |
11026 scope.takeRecords = nop; | 10932 scope.takeRecords = nop; |
11027 scope.reservedTagList = []; | |
11028 | 10933 |
11029 } else { | 10934 } else { |
11030 | 10935 |
11031 /** | 10936 /** |
11032 * Registers a custom tag name with the document. | 10937 * Registers a custom tag name with the document. |
11033 * | 10938 * |
11034 * When a registered element is created, a `readyCallback` method is called | 10939 * When a registered element is created, a `readyCallback` method is called |
11035 * in the scope of the element. The `readyCallback` method can be specified on | 10940 * in the scope of the element. The `readyCallback` method can be specified on |
11036 * either `options.prototype` or `options.lifecycle` with the latter taking | 10941 * either `options.prototype` or `options.lifecycle` with the latter taking |
11037 * precedence. | 10942 * precedence. |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11074 if (!name) { | 10979 if (!name) { |
11075 // TODO(sjmiles): replace with more appropriate error (EricB can probably | 10980 // TODO(sjmiles): replace with more appropriate error (EricB can probably |
11076 // offer guidance) | 10981 // offer guidance) |
11077 throw new Error('document.registerElement: first argument `name` must not
be empty'); | 10982 throw new Error('document.registerElement: first argument `name` must not
be empty'); |
11078 } | 10983 } |
11079 if (name.indexOf('-') < 0) { | 10984 if (name.indexOf('-') < 0) { |
11080 // TODO(sjmiles): replace with more appropriate error (EricB can probably | 10985 // TODO(sjmiles): replace with more appropriate error (EricB can probably |
11081 // offer guidance) | 10986 // offer guidance) |
11082 throw new Error('document.registerElement: first argument (\'name\') must
contain a dash (\'-\'). Argument provided was \'' + String(name) + '\'.'); | 10987 throw new Error('document.registerElement: first argument (\'name\') must
contain a dash (\'-\'). Argument provided was \'' + String(name) + '\'.'); |
11083 } | 10988 } |
11084 // prevent registering reserved names | |
11085 if (isReservedTag(name)) { | |
11086 throw new Error('Failed to execute \'registerElement\' on \'Document\': Re
gistration failed for type \'' + String(name) + '\'. The type name is invalid.')
; | |
11087 } | |
11088 // elements may only be registered once | 10989 // elements may only be registered once |
11089 if (getRegisteredDefinition(name)) { | 10990 if (getRegisteredDefinition(name)) { |
11090 throw new Error('DuplicateDefinitionError: a type with name \'' + String(n
ame) + '\' is already registered'); | 10991 throw new Error('DuplicateDefinitionError: a type with name \'' + String(n
ame) + '\' is already registered'); |
11091 } | 10992 } |
11092 // must have a prototype, default to an extension of HTMLElement | 10993 // must have a prototype, default to an extension of HTMLElement |
11093 // TODO(sjmiles): probably should throw if no prototype, check spec | 10994 // TODO(sjmiles): probably should throw if no prototype, check spec |
11094 if (!definition.prototype) { | 10995 if (!definition.prototype) { |
11095 // TODO(sjmiles): replace with more appropriate error (EricB can probably | 10996 // TODO(sjmiles): replace with more appropriate error (EricB can probably |
11096 // offer guidance) | 10997 // offer guidance) |
11097 throw new Error('Options missing required prototype property'); | 10998 throw new Error('Options missing required prototype property'); |
(...skipping 23 matching lines...) Expand all Loading... |
11121 // force our .constructor to be our actual constructor | 11022 // force our .constructor to be our actual constructor |
11122 definition.prototype.constructor = definition.ctor; | 11023 definition.prototype.constructor = definition.ctor; |
11123 // if initial parsing is complete | 11024 // if initial parsing is complete |
11124 if (scope.ready) { | 11025 if (scope.ready) { |
11125 // upgrade any pre-existing nodes of this type | 11026 // upgrade any pre-existing nodes of this type |
11126 scope.upgradeDocumentTree(document); | 11027 scope.upgradeDocumentTree(document); |
11127 } | 11028 } |
11128 return definition.ctor; | 11029 return definition.ctor; |
11129 } | 11030 } |
11130 | 11031 |
11131 function isReservedTag(name) { | |
11132 for (var i = 0; i < reservedTagList.length; i++) { | |
11133 if (name === reservedTagList[i]) { | |
11134 return true; | |
11135 } | |
11136 } | |
11137 } | |
11138 | |
11139 var reservedTagList = [ | |
11140 'annotation-xml', 'color-profile', 'font-face', 'font-face-src', | |
11141 'font-face-uri', 'font-face-format', 'font-face-name', 'missing-glyph' | |
11142 ]; | |
11143 | |
11144 function ancestry(extnds) { | 11032 function ancestry(extnds) { |
11145 var extendee = getRegisteredDefinition(extnds); | 11033 var extendee = getRegisteredDefinition(extnds); |
11146 if (extendee) { | 11034 if (extendee) { |
11147 return ancestry(extendee.extends).concat([extendee]); | 11035 return ancestry(extendee.extends).concat([extendee]); |
11148 } | 11036 } |
11149 return []; | 11037 return []; |
11150 } | 11038 } |
11151 | 11039 |
11152 function resolveTagName(definition) { | 11040 function resolveTagName(definition) { |
11153 // if we are explicitly extending something, that thing is our | 11041 // if we are explicitly extending something, that thing is our |
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11430 return false; | 11318 return false; |
11431 } | 11319 } |
11432 } else { | 11320 } else { |
11433 isInstance = function(obj, base) { | 11321 isInstance = function(obj, base) { |
11434 return obj instanceof base; | 11322 return obj instanceof base; |
11435 } | 11323 } |
11436 } | 11324 } |
11437 | 11325 |
11438 // exports | 11326 // exports |
11439 scope.instanceof = isInstance; | 11327 scope.instanceof = isInstance; |
11440 scope.reservedTagList = reservedTagList; | |
11441 | 11328 |
11442 // bc | 11329 // bc |
11443 document.register = document.registerElement; | 11330 document.register = document.registerElement; |
11444 | 11331 |
11445 scope.hasNative = hasNative; | 11332 scope.hasNative = hasNative; |
11446 scope.useNative = useNative; | 11333 scope.useNative = useNative; |
11447 | 11334 |
11448 })(window.CustomElements); | 11335 })(window.CustomElements); |
11449 | 11336 |
11450 /* | 11337 /* |
(...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11864 window.PointerEventsPolyfill = scope; | 11751 window.PointerEventsPolyfill = scope; |
11865 })(window.PointerEventsPolyfill); | 11752 })(window.PointerEventsPolyfill); |
11866 | 11753 |
11867 /* | 11754 /* |
11868 * Copyright 2013 The Polymer Authors. All rights reserved. | 11755 * Copyright 2013 The Polymer Authors. All rights reserved. |
11869 * Use of this source code is governed by a BSD-style | 11756 * Use of this source code is governed by a BSD-style |
11870 * license that can be found in the LICENSE file. | 11757 * license that can be found in the LICENSE file. |
11871 */ | 11758 */ |
11872 (function() { | 11759 (function() { |
11873 function shadowSelector(v) { | 11760 function shadowSelector(v) { |
11874 return 'body /shadow-deep/ ' + selector(v); | 11761 return 'body ^^ ' + selector(v); |
11875 } | 11762 } |
11876 function selector(v) { | 11763 function selector(v) { |
11877 return '[touch-action="' + v + '"]'; | 11764 return '[touch-action="' + v + '"]'; |
11878 } | 11765 } |
11879 function rule(v) { | 11766 function rule(v) { |
11880 return '{ -ms-touch-action: ' + v + '; touch-action: ' + v + '; touch-action
-delay: none; }'; | 11767 return '{ -ms-touch-action: ' + v + '; touch-action: ' + v + '; touch-action
-delay: none; }'; |
11881 } | 11768 } |
11882 var attrib2css = [ | 11769 var attrib2css = [ |
11883 'none', | 11770 'none', |
11884 'auto', | 11771 'auto', |
11885 'pan-x', | 11772 'pan-x', |
11886 'pan-y', | 11773 'pan-y', |
11887 { | 11774 { |
11888 rule: 'pan-x pan-y', | 11775 rule: 'pan-x pan-y', |
11889 selectors: [ | 11776 selectors: [ |
11890 'pan-x pan-y', | 11777 'pan-x pan-y', |
11891 'pan-y pan-x' | 11778 'pan-y pan-x' |
11892 ] | 11779 ] |
11893 } | 11780 } |
11894 ]; | 11781 ]; |
11895 var styles = ''; | 11782 var styles = ''; |
11896 // only install stylesheet if the browser has touch action support | 11783 attrib2css.forEach(function(r) { |
11897 var head = document.head; | 11784 if (String(r) === r) { |
11898 var hasNativePE = window.PointerEvent || window.MSPointerEvent; | 11785 styles += selector(r) + rule(r) + '\n'; |
11899 // only add shadow selectors if shadowdom is supported | 11786 styles += shadowSelector(r) + rule(r) + '\n'; |
11900 var hasShadowRoot = !window.ShadowDOMPolyfill && document.head.createShadowRoo
t; | 11787 } else { |
11901 | 11788 styles += r.selectors.map(selector) + rule(r.rule) + '\n'; |
11902 if (hasNativePE) { | 11789 styles += r.selectors.map(shadowSelector) + rule(r.rule) + '\n'; |
11903 attrib2css.forEach(function(r) { | 11790 } |
11904 if (String(r) === r) { | 11791 }); |
11905 styles += selector(r) + rule(r) + '\n'; | 11792 var el = document.createElement('style'); |
11906 if (hasShadowRoot) { | 11793 el.textContent = styles; |
11907 styles += shadowSelector(r) + rule(r) + '\n'; | 11794 document.head.appendChild(el); |
11908 } | |
11909 } else { | |
11910 styles += r.selectors.map(selector) + rule(r.rule) + '\n'; | |
11911 if (hasShadowRoot) { | |
11912 styles += r.selectors.map(shadowSelector) + rule(r.rule) + '\n'; | |
11913 } | |
11914 } | |
11915 }); | |
11916 | |
11917 var el = document.createElement('style'); | |
11918 el.textContent = styles; | |
11919 document.head.appendChild(el); | |
11920 } | |
11921 })(); | 11795 })(); |
11922 | 11796 |
11923 /* | 11797 /* |
11924 * Copyright 2013 The Polymer Authors. All rights reserved. | 11798 * Copyright 2013 The Polymer Authors. All rights reserved. |
11925 * Use of this source code is governed by a BSD-style | 11799 * Use of this source code is governed by a BSD-style |
11926 * license that can be found in the LICENSE file. | 11800 * license that can be found in the LICENSE file. |
11927 */ | 11801 */ |
11928 | 11802 |
11929 /** | 11803 /** |
11930 * This is the constructor for new PointerEvents. | 11804 * This is the constructor for new PointerEvents. |
11931 * | 11805 * |
11932 * New Pointer Events must be given a type, and an optional dictionary of | 11806 * New Pointer Events must be given a type, and an optional dictionary of |
11933 * initialization properties. | 11807 * initialization properties. |
11934 * | 11808 * |
11935 * Due to certain platform requirements, events returned from the constructor | 11809 * Due to certain platform requirements, events returned from the constructor |
11936 * identify as MouseEvents. | 11810 * identify as MouseEvents. |
11937 * | 11811 * |
11938 * @constructor | 11812 * @constructor |
11939 * @param {String} inType The type of the event to create. | 11813 * @param {String} inType The type of the event to create. |
11940 * @param {Object} [inDict] An optional dictionary of initial event properties. | 11814 * @param {Object} [inDict] An optional dictionary of initial event properties. |
11941 * @return {Event} A new PointerEvent of type `inType` and initialized with prop
erties from `inDict`. | 11815 * @return {Event} A new PointerEvent of type `inType` and initialized with prop
erties from `inDict`. |
11942 */ | 11816 */ |
11943 (function(scope) { | 11817 (function(scope) { |
| 11818 // test for DOM Level 4 Events |
| 11819 var NEW_MOUSE_EVENT = false; |
| 11820 var HAS_BUTTONS = false; |
| 11821 try { |
| 11822 var ev = new MouseEvent('click', {buttons: 1}); |
| 11823 NEW_MOUSE_EVENT = true; |
| 11824 HAS_BUTTONS = ev.buttons === 1; |
| 11825 ev = null; |
| 11826 } catch(e) { |
| 11827 } |
11944 | 11828 |
11945 var MOUSE_PROPS = [ | 11829 var MOUSE_PROPS = [ |
11946 'bubbles', | 11830 'bubbles', |
11947 'cancelable', | 11831 'cancelable', |
11948 'view', | 11832 'view', |
11949 'detail', | 11833 'detail', |
11950 'screenX', | 11834 'screenX', |
11951 'screenY', | 11835 'screenY', |
11952 'clientX', | 11836 'clientX', |
11953 'clientY', | 11837 'clientY', |
11954 'ctrlKey', | 11838 'ctrlKey', |
11955 'altKey', | 11839 'altKey', |
11956 'shiftKey', | 11840 'shiftKey', |
11957 'metaKey', | 11841 'metaKey', |
11958 'button', | 11842 'button', |
11959 'relatedTarget', | 11843 'relatedTarget', |
11960 'pageX', | |
11961 'pageY' | |
11962 ]; | 11844 ]; |
11963 | 11845 |
11964 var MOUSE_DEFAULTS = [ | 11846 var MOUSE_DEFAULTS = [ |
11965 false, | 11847 false, |
11966 false, | 11848 false, |
11967 null, | 11849 null, |
11968 null, | 11850 null, |
11969 0, | 11851 0, |
11970 0, | 11852 0, |
11971 0, | 11853 0, |
11972 0, | 11854 0, |
11973 false, | 11855 false, |
11974 false, | 11856 false, |
11975 false, | 11857 false, |
11976 false, | 11858 false, |
11977 0, | 11859 0, |
11978 null, | 11860 null |
11979 0, | |
11980 0 | |
11981 ]; | 11861 ]; |
11982 | 11862 |
11983 function PointerEvent(inType, inDict) { | 11863 function PointerEvent(inType, inDict) { |
11984 inDict = inDict || Object.create(null); | 11864 inDict = inDict || {}; |
| 11865 // According to the w3c spec, |
| 11866 // http://www.w3.org/TR/DOM-Level-3-Events/#events-MouseEvent-button |
| 11867 // MouseEvent.button == 0 can mean either no mouse button depressed, or the |
| 11868 // left mouse button depressed. |
| 11869 // |
| 11870 // As of now, the only way to distinguish between the two states of |
| 11871 // MouseEvent.button is by using the deprecated MouseEvent.which property, a
s |
| 11872 // this maps mouse buttons to positive integers > 0, and uses 0 to mean that |
| 11873 // no mouse button is held. |
| 11874 // |
| 11875 // MouseEvent.which is derived from MouseEvent.button at MouseEvent creation
, |
| 11876 // but initMouseEvent does not expose an argument with which to set |
| 11877 // MouseEvent.which. Calling initMouseEvent with a buttonArg of 0 will set |
| 11878 // MouseEvent.button == 0 and MouseEvent.which == 1, breaking the expectatio
ns |
| 11879 // of app developers. |
| 11880 // |
| 11881 // The only way to propagate the correct state of MouseEvent.which and |
| 11882 // MouseEvent.button to a new MouseEvent.button == 0 and MouseEvent.which ==
0 |
| 11883 // is to call initMouseEvent with a buttonArg value of -1. |
| 11884 // |
| 11885 // This is fixed with DOM Level 4's use of buttons |
| 11886 var buttons = inDict.buttons; |
| 11887 // touch has two possible buttons state: 0 and 1, rely on being told the rig
ht one |
| 11888 if (!HAS_BUTTONS && !buttons && inType !== 'touch') { |
| 11889 switch (inDict.which) { |
| 11890 case 1: buttons = 1; break; |
| 11891 case 2: buttons = 4; break; |
| 11892 case 3: buttons = 2; break; |
| 11893 default: buttons = 0; |
| 11894 } |
| 11895 } |
11985 | 11896 |
11986 var e = document.createEvent('Event'); | 11897 var e; |
11987 e.initEvent(inType, inDict.bubbles || false, inDict.cancelable || false); | 11898 if (NEW_MOUSE_EVENT) { |
| 11899 e = new MouseEvent(inType, inDict); |
| 11900 } else { |
| 11901 e = document.createEvent('MouseEvent'); |
11988 | 11902 |
11989 // define inherited MouseEvent properties | 11903 // import values from the given dictionary |
11990 for(var i = 0, p; i < MOUSE_PROPS.length; i++) { | 11904 var props = {}, p; |
11991 p = MOUSE_PROPS[i]; | 11905 for(var i = 0; i < MOUSE_PROPS.length; i++) { |
11992 e[p] = inDict[p] || MOUSE_DEFAULTS[i]; | 11906 p = MOUSE_PROPS[i]; |
| 11907 props[p] = inDict[p] || MOUSE_DEFAULTS[i]; |
| 11908 } |
| 11909 |
| 11910 // define the properties inherited from MouseEvent |
| 11911 e.initMouseEvent( |
| 11912 inType, props.bubbles, props.cancelable, props.view, props.detail, |
| 11913 props.screenX, props.screenY, props.clientX, props.clientY, props.ctrlKe
y, |
| 11914 props.altKey, props.shiftKey, props.metaKey, props.button, props.related
Target |
| 11915 ); |
11993 } | 11916 } |
11994 e.buttons = inDict.buttons || 0; | 11917 |
| 11918 // make the event pass instanceof checks |
| 11919 e.__proto__ = PointerEvent.prototype; |
| 11920 |
| 11921 // define the buttons property according to DOM Level 3 spec |
| 11922 if (!HAS_BUTTONS) { |
| 11923 // IE 10 has buttons on MouseEvent.prototype as a getter w/o any setting |
| 11924 // mechanism |
| 11925 Object.defineProperty(e, 'buttons', {get: function(){ return buttons; }, e
numerable: true}); |
| 11926 } |
11995 | 11927 |
11996 // Spec requires that pointers without pressure specified use 0.5 for down | 11928 // Spec requires that pointers without pressure specified use 0.5 for down |
11997 // state and 0 for up state. | 11929 // state and 0 for up state. |
11998 var pressure = 0; | 11930 var pressure = 0; |
11999 if (inDict.pressure) { | 11931 if (inDict.pressure) { |
12000 pressure = inDict.pressure; | 11932 pressure = inDict.pressure; |
12001 } else { | 11933 } else { |
12002 pressure = e.buttons ? 0.5 : 0; | 11934 pressure = buttons ? 0.5 : 0; |
12003 } | 11935 } |
12004 | 11936 |
12005 // add x/y properties aliased to clientX/Y | |
12006 e.x = e.clientX; | |
12007 e.y = e.clientY; | |
12008 | |
12009 // define the properties of the PointerEvent interface | 11937 // define the properties of the PointerEvent interface |
12010 e.pointerId = inDict.pointerId || 0; | 11938 Object.defineProperties(e, { |
12011 e.width = inDict.width || 0; | 11939 pointerId: { value: inDict.pointerId || 0, enumerable: true }, |
12012 e.height = inDict.height || 0; | 11940 width: { value: inDict.width || 0, enumerable: true }, |
12013 e.pressure = pressure; | 11941 height: { value: inDict.height || 0, enumerable: true }, |
12014 e.tiltX = inDict.tiltX || 0; | 11942 pressure: { value: pressure, enumerable: true }, |
12015 e.tiltY = inDict.tiltY || 0; | 11943 tiltX: { value: inDict.tiltX || 0, enumerable: true }, |
12016 e.pointerType = inDict.pointerType || ''; | 11944 tiltY: { value: inDict.tiltY || 0, enumerable: true }, |
12017 e.hwTimestamp = inDict.hwTimestamp || 0; | 11945 pointerType: { value: inDict.pointerType || '', enumerable: true }, |
12018 e.isPrimary = inDict.isPrimary || false; | 11946 hwTimestamp: { value: inDict.hwTimestamp || 0, enumerable: true }, |
| 11947 isPrimary: { value: inDict.isPrimary || false, enumerable: true } |
| 11948 }); |
12019 return e; | 11949 return e; |
12020 } | 11950 } |
12021 | 11951 |
| 11952 // PointerEvent extends MouseEvent |
| 11953 PointerEvent.prototype = Object.create(MouseEvent.prototype); |
| 11954 |
12022 // attach to window | 11955 // attach to window |
12023 if (!scope.PointerEvent) { | 11956 if (!scope.PointerEvent) { |
12024 scope.PointerEvent = PointerEvent; | 11957 scope.PointerEvent = PointerEvent; |
12025 } | 11958 } |
12026 })(window); | 11959 })(window); |
12027 | 11960 |
12028 /* | 11961 /* |
12029 * Copyright 2013 The Polymer Authors. All rights reserved. | 11962 * Copyright 2013 The Polymer Authors. All rights reserved. |
12030 * Use of this source code is governed by a BSD-style | 11963 * Use of this source code is governed by a BSD-style |
12031 * license that can be found in the LICENSE file. | 11964 * license that can be found in the LICENSE file. |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12122 'pressure', | 12055 'pressure', |
12123 'tiltX', | 12056 'tiltX', |
12124 'tiltY', | 12057 'tiltY', |
12125 'pointerType', | 12058 'pointerType', |
12126 'hwTimestamp', | 12059 'hwTimestamp', |
12127 'isPrimary', | 12060 'isPrimary', |
12128 // event instance | 12061 // event instance |
12129 'type', | 12062 'type', |
12130 'target', | 12063 'target', |
12131 'currentTarget', | 12064 'currentTarget', |
12132 'which', | 12065 'which' |
12133 'pageX', | |
12134 'pageY' | |
12135 ]; | 12066 ]; |
12136 | 12067 |
12137 var CLONE_DEFAULTS = [ | 12068 var CLONE_DEFAULTS = [ |
12138 // MouseEvent | 12069 // MouseEvent |
12139 false, | 12070 false, |
12140 false, | 12071 false, |
12141 null, | 12072 null, |
12142 null, | 12073 null, |
12143 0, | 12074 0, |
12144 0, | 12075 0, |
(...skipping 14 matching lines...) Expand all Loading... |
12159 0, | 12090 0, |
12160 0, | 12091 0, |
12161 0, | 12092 0, |
12162 '', | 12093 '', |
12163 0, | 12094 0, |
12164 false, | 12095 false, |
12165 // event instance | 12096 // event instance |
12166 '', | 12097 '', |
12167 null, | 12098 null, |
12168 null, | 12099 null, |
12169 0, | |
12170 0, | |
12171 0 | 12100 0 |
12172 ]; | 12101 ]; |
12173 | 12102 |
12174 var HAS_SVG_INSTANCE = (typeof SVGElementInstance !== 'undefined'); | 12103 var HAS_SVG_INSTANCE = (typeof SVGElementInstance !== 'undefined'); |
12175 | 12104 |
12176 /** | 12105 /** |
12177 * This module is for normalizing events. Mouse and Touch events will be | 12106 * This module is for normalizing events. Mouse and Touch events will be |
12178 * collected here, and fire PointerEvents that have the same semantics, no | 12107 * collected here, and fire PointerEvents that have the same semantics, no |
12179 * matter the source. | 12108 * matter the source. |
12180 * Events fired: | 12109 * Events fired: |
12181 * - pointerdown: a pointing is added | 12110 * - pointerdown: a pointing is added |
12182 * - pointerup: a pointer is removed | 12111 * - pointerup: a pointer is removed |
12183 * - pointermove: a pointer is moved | 12112 * - pointermove: a pointer is moved |
12184 * - pointerover: a pointer crosses into an element | 12113 * - pointerover: a pointer crosses into an element |
12185 * - pointerout: a pointer leaves an element | 12114 * - pointerout: a pointer leaves an element |
12186 * - pointercancel: a pointer will no longer generate events | 12115 * - pointercancel: a pointer will no longer generate events |
12187 */ | 12116 */ |
12188 var dispatcher = { | 12117 var dispatcher = { |
| 12118 targets: new WeakMap(), |
| 12119 handledEvents: new WeakMap(), |
12189 pointermap: new scope.PointerMap(), | 12120 pointermap: new scope.PointerMap(), |
12190 eventMap: Object.create(null), | 12121 eventMap: {}, |
12191 captureInfo: Object.create(null), | |
12192 // Scope objects for native events. | 12122 // Scope objects for native events. |
12193 // This exists for ease of testing. | 12123 // This exists for ease of testing. |
12194 eventSources: Object.create(null), | 12124 eventSources: {}, |
12195 eventSourceList: [], | 12125 eventSourceList: [], |
12196 /** | 12126 /** |
12197 * Add a new event source that will generate pointer events. | 12127 * Add a new event source that will generate pointer events. |
12198 * | 12128 * |
12199 * `inSource` must contain an array of event names named `events`, and | 12129 * `inSource` must contain an array of event names named `events`, and |
12200 * functions with the names specified in the `events` array. | 12130 * functions with the names specified in the `events` array. |
12201 * @param {string} name A name for the event source | 12131 * @param {string} name A name for the event source |
12202 * @param {Object} source A new source of platform events. | 12132 * @param {Object} source A new source of platform events. |
12203 */ | 12133 */ |
12204 registerSource: function(name, source) { | 12134 registerSource: function(name, source) { |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12274 this.over(event); | 12204 this.over(event); |
12275 if (!this.contains(event.target, event.relatedTarget)) { | 12205 if (!this.contains(event.target, event.relatedTarget)) { |
12276 this.enter(event); | 12206 this.enter(event); |
12277 } | 12207 } |
12278 }, | 12208 }, |
12279 // LISTENER LOGIC | 12209 // LISTENER LOGIC |
12280 eventHandler: function(inEvent) { | 12210 eventHandler: function(inEvent) { |
12281 // This is used to prevent multiple dispatch of pointerevents from | 12211 // This is used to prevent multiple dispatch of pointerevents from |
12282 // platform events. This can happen when two elements in different scopes | 12212 // platform events. This can happen when two elements in different scopes |
12283 // are set up to create pointer events, which is relevant to Shadow DOM. | 12213 // are set up to create pointer events, which is relevant to Shadow DOM. |
12284 if (inEvent._handledByPE) { | 12214 if (this.handledEvents.get(inEvent)) { |
12285 return; | 12215 return; |
12286 } | 12216 } |
12287 var type = inEvent.type; | 12217 var type = inEvent.type; |
12288 var fn = this.eventMap && this.eventMap[type]; | 12218 var fn = this.eventMap && this.eventMap[type]; |
12289 if (fn) { | 12219 if (fn) { |
12290 fn(inEvent); | 12220 fn(inEvent); |
12291 } | 12221 } |
12292 inEvent._handledByPE = true; | 12222 this.handledEvents.set(inEvent, true); |
12293 }, | 12223 }, |
12294 // set up event listeners | 12224 // set up event listeners |
12295 listen: function(target, events) { | 12225 listen: function(target, events) { |
12296 events.forEach(function(e) { | 12226 events.forEach(function(e) { |
12297 this.addEvent(target, e); | 12227 this.addEvent(target, e); |
12298 }, this); | 12228 }, this); |
12299 }, | 12229 }, |
12300 // remove event listeners | 12230 // remove event listeners |
12301 unlisten: function(target, events) { | 12231 unlisten: function(target, events) { |
12302 events.forEach(function(e) { | 12232 events.forEach(function(e) { |
(...skipping 10 matching lines...) Expand all Loading... |
12313 /** | 12243 /** |
12314 * Creates a new Event of type `inType`, based on the information in | 12244 * Creates a new Event of type `inType`, based on the information in |
12315 * `inEvent`. | 12245 * `inEvent`. |
12316 * | 12246 * |
12317 * @param {string} inType A string representing the type of event to create | 12247 * @param {string} inType A string representing the type of event to create |
12318 * @param {Event} inEvent A platform event with a target | 12248 * @param {Event} inEvent A platform event with a target |
12319 * @return {Event} A PointerEvent of type `inType` | 12249 * @return {Event} A PointerEvent of type `inType` |
12320 */ | 12250 */ |
12321 makeEvent: function(inType, inEvent) { | 12251 makeEvent: function(inType, inEvent) { |
12322 // relatedTarget must be null if pointer is captured | 12252 // relatedTarget must be null if pointer is captured |
12323 if (this.captureInfo[inEvent.pointerId]) { | 12253 if (this.captureInfo) { |
12324 inEvent.relatedTarget = null; | 12254 inEvent.relatedTarget = null; |
12325 } | 12255 } |
12326 var e = new PointerEvent(inType, inEvent); | 12256 var e = new PointerEvent(inType, inEvent); |
12327 if (inEvent.preventDefault) { | 12257 if (inEvent.preventDefault) { |
12328 e.preventDefault = inEvent.preventDefault; | 12258 e.preventDefault = inEvent.preventDefault; |
12329 } | 12259 } |
12330 e._target = e._target || inEvent.target; | 12260 this.targets.set(e, this.targets.get(inEvent) || inEvent.target); |
12331 return e; | 12261 return e; |
12332 }, | 12262 }, |
12333 // make and dispatch an event in one call | 12263 // make and dispatch an event in one call |
12334 fireEvent: function(inType, inEvent) { | 12264 fireEvent: function(inType, inEvent) { |
12335 var e = this.makeEvent(inType, inEvent); | 12265 var e = this.makeEvent(inType, inEvent); |
12336 return this.dispatchEvent(e); | 12266 return this.dispatchEvent(e); |
12337 }, | 12267 }, |
12338 /** | 12268 /** |
12339 * Returns a snapshot of inEvent, with writable properties. | 12269 * Returns a snapshot of inEvent, with writable properties. |
12340 * | 12270 * |
12341 * @param {Event} inEvent An event that contains properties to copy. | 12271 * @param {Event} inEvent An event that contains properties to copy. |
12342 * @return {Object} An object containing shallow copies of `inEvent`'s | 12272 * @return {Object} An object containing shallow copies of `inEvent`'s |
12343 * properties. | 12273 * properties. |
12344 */ | 12274 */ |
12345 cloneEvent: function(inEvent) { | 12275 cloneEvent: function(inEvent) { |
12346 var eventCopy = Object.create(null), p; | 12276 var eventCopy = {}, p; |
12347 for (var i = 0; i < CLONE_PROPS.length; i++) { | 12277 for (var i = 0; i < CLONE_PROPS.length; i++) { |
12348 p = CLONE_PROPS[i]; | 12278 p = CLONE_PROPS[i]; |
12349 eventCopy[p] = inEvent[p] || CLONE_DEFAULTS[i]; | 12279 eventCopy[p] = inEvent[p] || CLONE_DEFAULTS[i]; |
12350 // Work around SVGInstanceElement shadow tree | 12280 // Work around SVGInstanceElement shadow tree |
12351 // Return the <use> element that is represented by the instance for Safa
ri, Chrome, IE. | 12281 // Return the <use> element that is represented by the instance for Safa
ri, Chrome, IE. |
12352 // This is the behavior implemented by Firefox. | 12282 // This is the behavior implemented by Firefox. |
12353 if (HAS_SVG_INSTANCE && (p === 'target' || p === 'relatedTarget')) { | 12283 if (HAS_SVG_INSTANCE && (p === 'target' || p === 'relatedTarget')) { |
12354 if (eventCopy[p] instanceof SVGElementInstance) { | 12284 if (eventCopy[p] instanceof SVGElementInstance) { |
12355 eventCopy[p] = eventCopy[p].correspondingUseElement; | 12285 eventCopy[p] = eventCopy[p].correspondingUseElement; |
12356 } | 12286 } |
12357 } | 12287 } |
12358 } | 12288 } |
12359 // keep the semantics of preventDefault | 12289 // keep the semantics of preventDefault |
12360 if (inEvent.preventDefault) { | 12290 if (inEvent.preventDefault) { |
12361 eventCopy.preventDefault = function() { | 12291 eventCopy.preventDefault = function() { |
12362 inEvent.preventDefault(); | 12292 inEvent.preventDefault(); |
12363 }; | 12293 }; |
12364 } | 12294 } |
12365 return eventCopy; | 12295 return eventCopy; |
12366 }, | 12296 }, |
12367 getTarget: function(inEvent) { | 12297 getTarget: function(inEvent) { |
12368 // if pointer capture is set, route all events for the specified pointerId | 12298 // if pointer capture is set, route all events for the specified pointerId |
12369 // to the capture target | 12299 // to the capture target |
12370 return this.captureInfo[inEvent.pointerId] || inEvent._target; | 12300 if (this.captureInfo) { |
| 12301 if (this.captureInfo.id === inEvent.pointerId) { |
| 12302 return this.captureInfo.target; |
| 12303 } |
| 12304 } |
| 12305 return this.targets.get(inEvent); |
12371 }, | 12306 }, |
12372 setCapture: function(inPointerId, inTarget) { | 12307 setCapture: function(inPointerId, inTarget) { |
12373 if (this.captureInfo[inPointerId]) { | 12308 if (this.captureInfo) { |
12374 this.releaseCapture(inPointerId); | 12309 this.releaseCapture(this.captureInfo.id); |
12375 } | 12310 } |
12376 this.captureInfo[inPointerId] = inTarget; | 12311 this.captureInfo = {id: inPointerId, target: inTarget}; |
12377 var e = document.createEvent('Event'); | 12312 var e = new PointerEvent('gotpointercapture', { bubbles: true }); |
12378 e.initEvent('gotpointercapture', true, false); | |
12379 e.pointerId = inPointerId; | |
12380 this.implicitRelease = this.releaseCapture.bind(this, inPointerId); | 12313 this.implicitRelease = this.releaseCapture.bind(this, inPointerId); |
12381 document.addEventListener('pointerup', this.implicitRelease); | 12314 document.addEventListener('pointerup', this.implicitRelease); |
12382 document.addEventListener('pointercancel', this.implicitRelease); | 12315 document.addEventListener('pointercancel', this.implicitRelease); |
12383 e._target = inTarget; | 12316 this.targets.set(e, inTarget); |
12384 this.asyncDispatchEvent(e); | 12317 this.asyncDispatchEvent(e); |
12385 }, | 12318 }, |
12386 releaseCapture: function(inPointerId) { | 12319 releaseCapture: function(inPointerId) { |
12387 var t = this.captureInfo[inPointerId]; | 12320 if (this.captureInfo && this.captureInfo.id === inPointerId) { |
12388 if (t) { | 12321 var e = new PointerEvent('lostpointercapture', { bubbles: true }); |
12389 var e = document.createEvent('Event'); | 12322 var t = this.captureInfo.target; |
12390 e.initEvent('lostpointercapture', true, false); | 12323 this.captureInfo = null; |
12391 e.pointerId = inPointerId; | |
12392 this.captureInfo[inPointerId] = undefined; | |
12393 document.removeEventListener('pointerup', this.implicitRelease); | 12324 document.removeEventListener('pointerup', this.implicitRelease); |
12394 document.removeEventListener('pointercancel', this.implicitRelease); | 12325 document.removeEventListener('pointercancel', this.implicitRelease); |
12395 e._target = t; | 12326 this.targets.set(e, t); |
12396 this.asyncDispatchEvent(e); | 12327 this.asyncDispatchEvent(e); |
12397 } | 12328 } |
12398 }, | 12329 }, |
12399 /** | 12330 /** |
12400 * Dispatches the event to its target. | 12331 * Dispatches the event to its target. |
12401 * | 12332 * |
12402 * @param {Event} inEvent The event to be dispatched. | 12333 * @param {Event} inEvent The event to be dispatched. |
12403 * @return {Boolean} True if an event handler returns true, false otherwise. | 12334 * @return {Boolean} True if an event handler returns true, false otherwise. |
12404 */ | 12335 */ |
12405 dispatchEvent: scope.external.dispatchEvent || function(inEvent) { | 12336 dispatchEvent: scope.external.dispatchEvent || function(inEvent) { |
12406 var t = this.getTarget(inEvent); | 12337 var t = this.getTarget(inEvent); |
12407 if (t) { | 12338 if (t) { |
12408 return t.dispatchEvent(inEvent); | 12339 return t.dispatchEvent(inEvent); |
12409 } | 12340 } |
12410 }, | 12341 }, |
12411 asyncDispatchEvent: function(inEvent) { | 12342 asyncDispatchEvent: function(inEvent) { |
12412 requestAnimationFrame(this.dispatchEvent.bind(this, inEvent)); | 12343 setTimeout(this.dispatchEvent.bind(this, inEvent), 0); |
12413 } | 12344 } |
12414 }; | 12345 }; |
12415 dispatcher.boundHandler = dispatcher.eventHandler.bind(dispatcher); | 12346 dispatcher.boundHandler = dispatcher.eventHandler.bind(dispatcher); |
12416 scope.dispatcher = dispatcher; | 12347 scope.dispatcher = dispatcher; |
12417 scope.register = dispatcher.register.bind(dispatcher); | 12348 scope.register = dispatcher.register.bind(dispatcher); |
12418 scope.unregister = dispatcher.unregister.bind(dispatcher); | 12349 scope.unregister = dispatcher.unregister.bind(dispatcher); |
12419 })(window.PointerEventsPolyfill); | 12350 })(window.PointerEventsPolyfill); |
12420 | 12351 |
12421 /* | 12352 /* |
12422 * Copyright 2013 The Polymer Authors. All rights reserved. | 12353 * Copyright 2013 The Polymer Authors. All rights reserved. |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12545 * Use of this source code is governed by a BSD-style | 12476 * Use of this source code is governed by a BSD-style |
12546 * license that can be found in the LICENSE file. | 12477 * license that can be found in the LICENSE file. |
12547 */ | 12478 */ |
12548 | 12479 |
12549 (function (scope) { | 12480 (function (scope) { |
12550 var dispatcher = scope.dispatcher; | 12481 var dispatcher = scope.dispatcher; |
12551 var pointermap = dispatcher.pointermap; | 12482 var pointermap = dispatcher.pointermap; |
12552 // radius around touchend that swallows mouse events | 12483 // radius around touchend that swallows mouse events |
12553 var DEDUP_DIST = 25; | 12484 var DEDUP_DIST = 25; |
12554 | 12485 |
12555 var WHICH_TO_BUTTONS = [0, 1, 4, 2]; | |
12556 | |
12557 var HAS_BUTTONS = false; | |
12558 try { | |
12559 HAS_BUTTONS = new MouseEvent('test', {buttons: 1}).buttons === 1; | |
12560 } catch (e) {} | |
12561 | |
12562 // handler block for native mouse events | 12486 // handler block for native mouse events |
12563 var mouseEvents = { | 12487 var mouseEvents = { |
12564 POINTER_ID: 1, | 12488 POINTER_ID: 1, |
12565 POINTER_TYPE: 'mouse', | 12489 POINTER_TYPE: 'mouse', |
12566 events: [ | 12490 events: [ |
12567 'mousedown', | 12491 'mousedown', |
12568 'mousemove', | 12492 'mousemove', |
12569 'mouseup', | 12493 'mouseup', |
12570 'mouseover', | 12494 'mouseover', |
12571 'mouseout' | 12495 'mouseout' |
(...skipping 21 matching lines...) Expand all Loading... |
12593 var e = dispatcher.cloneEvent(inEvent); | 12517 var e = dispatcher.cloneEvent(inEvent); |
12594 // forward mouse preventDefault | 12518 // forward mouse preventDefault |
12595 var pd = e.preventDefault; | 12519 var pd = e.preventDefault; |
12596 e.preventDefault = function() { | 12520 e.preventDefault = function() { |
12597 inEvent.preventDefault(); | 12521 inEvent.preventDefault(); |
12598 pd(); | 12522 pd(); |
12599 }; | 12523 }; |
12600 e.pointerId = this.POINTER_ID; | 12524 e.pointerId = this.POINTER_ID; |
12601 e.isPrimary = true; | 12525 e.isPrimary = true; |
12602 e.pointerType = this.POINTER_TYPE; | 12526 e.pointerType = this.POINTER_TYPE; |
12603 if (!HAS_BUTTONS) { | |
12604 e.buttons = WHICH_TO_BUTTONS[e.which] || 0; | |
12605 } | |
12606 return e; | 12527 return e; |
12607 }, | 12528 }, |
12608 mousedown: function(inEvent) { | 12529 mousedown: function(inEvent) { |
12609 if (!this.isEventSimulatedFromTouch(inEvent)) { | 12530 if (!this.isEventSimulatedFromTouch(inEvent)) { |
12610 var p = pointermap.has(this.POINTER_ID); | 12531 var p = pointermap.has(this.POINTER_ID); |
12611 // TODO(dfreedman) workaround for some elements not sending mouseup | 12532 // TODO(dfreedman) workaround for some elements not sending mouseup |
12612 // http://crbug/149091 | 12533 // http://crbug/149091 |
12613 if (p) { | 12534 if (p) { |
12614 this.cancel(inEvent); | 12535 this.cancel(inEvent); |
12615 } | 12536 } |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12660 })(window.PointerEventsPolyfill); | 12581 })(window.PointerEventsPolyfill); |
12661 | 12582 |
12662 /* | 12583 /* |
12663 * Copyright 2013 The Polymer Authors. All rights reserved. | 12584 * Copyright 2013 The Polymer Authors. All rights reserved. |
12664 * Use of this source code is governed by a BSD-style | 12585 * Use of this source code is governed by a BSD-style |
12665 * license that can be found in the LICENSE file. | 12586 * license that can be found in the LICENSE file. |
12666 */ | 12587 */ |
12667 | 12588 |
12668 (function(scope) { | 12589 (function(scope) { |
12669 var dispatcher = scope.dispatcher; | 12590 var dispatcher = scope.dispatcher; |
12670 var captureInfo = dispatcher.captureInfo; | |
12671 var findTarget = scope.findTarget; | 12591 var findTarget = scope.findTarget; |
12672 var allShadows = scope.targetFinding.allShadows.bind(scope.targetFinding); | 12592 var allShadows = scope.targetFinding.allShadows.bind(scope.targetFinding); |
12673 var pointermap = dispatcher.pointermap; | 12593 var pointermap = dispatcher.pointermap; |
12674 var touchMap = Array.prototype.map.call.bind(Array.prototype.map); | 12594 var touchMap = Array.prototype.map.call.bind(Array.prototype.map); |
12675 // This should be long enough to ignore compat mouse events made by touch | 12595 // This should be long enough to ignore compat mouse events made by touch |
12676 var DEDUP_TIMEOUT = 2500; | 12596 var DEDUP_TIMEOUT = 2500; |
12677 var CLICK_COUNT_TIMEOUT = 200; | 12597 var CLICK_COUNT_TIMEOUT = 200; |
12678 var ATTRIB = 'touch-action'; | 12598 var ATTRIB = 'touch-action'; |
12679 var INSTALLER; | 12599 var INSTALLER; |
12680 // The presence of touch event handlers blocks scrolling, and so we must be ca
reful to | 12600 // The presence of touch event handlers blocks scrolling, and so we must be ca
reful to |
12681 // avoid adding handlers unnecessarily. Chrome plans to add a touch-action-de
lay property | 12601 // avoid adding handlers unnecessarily. Chrome plans to add a touch-action-de
lay property |
12682 // (crbug.com/329559) to address this, and once we have that we can opt-in to
a simpler | 12602 // (crbug.com/329559) to address this, and once we have that we can opt-in to
a simpler |
12683 // handler registration mechanism. Rather than try to predict how exactly to
opt-in to | 12603 // handler registration mechanism. Rather than try to predict how exactly to
opt-in to |
12684 // that we'll just leave this disabled until there is a build of Chrome to tes
t. | 12604 // that we'll just leave this disabled until there is a build of Chrome to tes
t. |
12685 var HAS_TOUCH_ACTION_DELAY = false; | 12605 var HAS_TOUCH_ACTION_DELAY = false; |
12686 | 12606 |
12687 // handler block for native touch events | 12607 // handler block for native touch events |
12688 var touchEvents = { | 12608 var touchEvents = { |
| 12609 scrollType: new WeakMap(), |
12689 events: [ | 12610 events: [ |
12690 'touchstart', | 12611 'touchstart', |
12691 'touchmove', | 12612 'touchmove', |
12692 'touchend', | 12613 'touchend', |
12693 'touchcancel' | 12614 'touchcancel' |
12694 ], | 12615 ], |
12695 register: function(target) { | 12616 register: function(target) { |
12696 if (HAS_TOUCH_ACTION_DELAY) { | 12617 if (HAS_TOUCH_ACTION_DELAY) { |
12697 dispatcher.listen(target, this.events); | 12618 dispatcher.listen(target, this.events); |
12698 } else { | 12619 } else { |
12699 INSTALLER.enableOnSubtree(target); | 12620 INSTALLER.enableOnSubtree(target); |
12700 } | 12621 } |
12701 }, | 12622 }, |
12702 unregister: function(target) { | 12623 unregister: function(target) { |
12703 if (HAS_TOUCH_ACTION_DELAY) { | 12624 if (HAS_TOUCH_ACTION_DELAY) { |
12704 dispatcher.unlisten(target, this.events); | 12625 dispatcher.unlisten(target, this.events); |
12705 } else { | 12626 } else { |
12706 // TODO(dfreedman): is it worth it to disconnect the MO? | 12627 // TODO(dfreedman): is it worth it to disconnect the MO? |
12707 } | 12628 } |
12708 }, | 12629 }, |
12709 elementAdded: function(el) { | 12630 elementAdded: function(el) { |
12710 var a = el.getAttribute(ATTRIB); | 12631 var a = el.getAttribute(ATTRIB); |
12711 var st = this.touchActionToScrollType(a); | 12632 var st = this.touchActionToScrollType(a); |
12712 if (st) { | 12633 if (st) { |
12713 el._scrollType = st; | 12634 this.scrollType.set(el, st); |
12714 dispatcher.listen(el, this.events); | 12635 dispatcher.listen(el, this.events); |
12715 // set touch-action on shadows as well | 12636 // set touch-action on shadows as well |
12716 allShadows(el).forEach(function(s) { | 12637 allShadows(el).forEach(function(s) { |
12717 s._scrollType = st; | 12638 this.scrollType.set(s, st); |
12718 dispatcher.listen(s, this.events); | 12639 dispatcher.listen(s, this.events); |
12719 }, this); | 12640 }, this); |
12720 } | 12641 } |
12721 }, | 12642 }, |
12722 elementRemoved: function(el) { | 12643 elementRemoved: function(el) { |
12723 el._scrollType = undefined; | 12644 this.scrollType['delete'](el); |
12724 dispatcher.unlisten(el, this.events); | 12645 dispatcher.unlisten(el, this.events); |
12725 // remove touch-action from shadow | 12646 // remove touch-action from shadow |
12726 allShadows(el).forEach(function(s) { | 12647 allShadows(el).forEach(function(s) { |
12727 s._scrollType = undefined; | 12648 this.scrollType['delete'](s); |
12728 dispatcher.unlisten(s, this.events); | 12649 dispatcher.unlisten(s, this.events); |
12729 }, this); | 12650 }, this); |
12730 }, | 12651 }, |
12731 elementChanged: function(el, oldValue) { | 12652 elementChanged: function(el, oldValue) { |
12732 var a = el.getAttribute(ATTRIB); | 12653 var a = el.getAttribute(ATTRIB); |
12733 var st = this.touchActionToScrollType(a); | 12654 var st = this.touchActionToScrollType(a); |
12734 var oldSt = this.touchActionToScrollType(oldValue); | 12655 var oldSt = this.touchActionToScrollType(oldValue); |
12735 // simply update scrollType if listeners are already established | 12656 // simply update scrollType if listeners are already established |
12736 if (st && oldSt) { | 12657 if (st && oldSt) { |
12737 el._scrollType = st; | 12658 this.scrollType.set(el, st); |
12738 allShadows(el).forEach(function(s) { | 12659 allShadows(el).forEach(function(s) { |
12739 s._scrollType = st; | 12660 this.scrollType.set(s, st); |
12740 }, this); | 12661 }, this); |
12741 } else if (oldSt) { | 12662 } else if (oldSt) { |
12742 this.elementRemoved(el); | 12663 this.elementRemoved(el); |
12743 } else if (st) { | 12664 } else if (st) { |
12744 this.elementAdded(el); | 12665 this.elementAdded(el); |
12745 } | 12666 } |
12746 }, | 12667 }, |
12747 scrollTypes: { | 12668 scrollTypes: { |
12748 EMITTER: 'none', | 12669 EMITTER: 'none', |
12749 XSCROLLER: 'pan-x', | 12670 XSCROLLER: 'pan-x', |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12799 } | 12720 } |
12800 }, | 12721 }, |
12801 typeToButtons: function(type) { | 12722 typeToButtons: function(type) { |
12802 var ret = 0; | 12723 var ret = 0; |
12803 if (type === 'touchstart' || type === 'touchmove') { | 12724 if (type === 'touchstart' || type === 'touchmove') { |
12804 ret = 1; | 12725 ret = 1; |
12805 } | 12726 } |
12806 return ret; | 12727 return ret; |
12807 }, | 12728 }, |
12808 touchToPointer: function(inTouch) { | 12729 touchToPointer: function(inTouch) { |
12809 var cte = this.currentTouchEvent; | |
12810 var e = dispatcher.cloneEvent(inTouch); | 12730 var e = dispatcher.cloneEvent(inTouch); |
12811 // Spec specifies that pointerId 1 is reserved for Mouse. | 12731 // Spec specifies that pointerId 1 is reserved for Mouse. |
12812 // Touch identifiers can start at 0. | 12732 // Touch identifiers can start at 0. |
12813 // Add 2 to the touch identifier for compatibility. | 12733 // Add 2 to the touch identifier for compatibility. |
12814 var id = e.pointerId = inTouch.identifier + 2; | 12734 e.pointerId = inTouch.identifier + 2; |
12815 e.target = captureInfo[id] || findTarget(e); | 12735 e.target = findTarget(e); |
12816 e.bubbles = true; | 12736 e.bubbles = true; |
12817 e.cancelable = true; | 12737 e.cancelable = true; |
12818 e.detail = this.clickCount; | 12738 e.detail = this.clickCount; |
12819 e.button = 0; | 12739 e.button = 0; |
12820 e.buttons = this.typeToButtons(cte.type); | 12740 e.buttons = this.typeToButtons(this.currentTouchEvent); |
12821 e.width = inTouch.webkitRadiusX || inTouch.radiusX || 0; | 12741 e.width = inTouch.webkitRadiusX || inTouch.radiusX || 0; |
12822 e.height = inTouch.webkitRadiusY || inTouch.radiusY || 0; | 12742 e.height = inTouch.webkitRadiusY || inTouch.radiusY || 0; |
12823 e.pressure = inTouch.webkitForce || inTouch.force || 0.5; | 12743 e.pressure = inTouch.webkitForce || inTouch.force || 0.5; |
12824 e.isPrimary = this.isPrimaryTouch(inTouch); | 12744 e.isPrimary = this.isPrimaryTouch(inTouch); |
12825 e.pointerType = this.POINTER_TYPE; | 12745 e.pointerType = this.POINTER_TYPE; |
12826 // forward touch preventDefaults | |
12827 var self = this; | |
12828 e.preventDefault = function() { | |
12829 self.scrolling = false; | |
12830 self.firstXY = null; | |
12831 cte.preventDefault(); | |
12832 }; | |
12833 return e; | 12746 return e; |
12834 }, | 12747 }, |
12835 processTouches: function(inEvent, inFunction) { | 12748 processTouches: function(inEvent, inFunction) { |
12836 var tl = inEvent.changedTouches; | 12749 var tl = inEvent.changedTouches; |
12837 this.currentTouchEvent = inEvent; | 12750 this.currentTouchEvent = inEvent.type; |
12838 for (var i = 0, t; i < tl.length; i++) { | 12751 var pointers = touchMap(tl, this.touchToPointer, this); |
12839 t = tl[i]; | 12752 // forward touch preventDefaults |
12840 inFunction.call(this, this.touchToPointer(t)); | 12753 pointers.forEach(function(p) { |
12841 } | 12754 p.preventDefault = function() { |
| 12755 this.scrolling = false; |
| 12756 this.firstXY = null; |
| 12757 inEvent.preventDefault(); |
| 12758 }; |
| 12759 }, this); |
| 12760 pointers.forEach(inFunction, this); |
12842 }, | 12761 }, |
12843 // For single axis scrollers, determines whether the element should emit | 12762 // For single axis scrollers, determines whether the element should emit |
12844 // pointer events or behave as a scroller | 12763 // pointer events or behave as a scroller |
12845 shouldScroll: function(inEvent) { | 12764 shouldScroll: function(inEvent) { |
12846 if (this.firstXY) { | 12765 if (this.firstXY) { |
12847 var ret; | 12766 var ret; |
12848 var scrollAxis = inEvent.currentTarget._scrollType; | 12767 var scrollAxis = this.scrollType.get(inEvent.currentTarget); |
12849 if (scrollAxis === 'none') { | 12768 if (scrollAxis === 'none') { |
12850 // this element is a touch-action: none, should never scroll | 12769 // this element is a touch-action: none, should never scroll |
12851 ret = false; | 12770 ret = false; |
12852 } else if (scrollAxis === 'XY') { | 12771 } else if (scrollAxis === 'XY') { |
12853 // this element should always scroll | 12772 // this element should always scroll |
12854 ret = true; | 12773 ret = true; |
12855 } else { | 12774 } else { |
12856 var t = inEvent.changedTouches[0]; | 12775 var t = inEvent.changedTouches[0]; |
12857 // check the intended scroll axis, and other axis | 12776 // check the intended scroll axis, and other axis |
12858 var a = scrollAxis; | 12777 var a = scrollAxis; |
(...skipping 26 matching lines...) Expand all Loading... |
12885 // pointermap.pointers() should be < tl.length here, as the touchstart has
not | 12804 // pointermap.pointers() should be < tl.length here, as the touchstart has
not |
12886 // been processed yet. | 12805 // been processed yet. |
12887 if (pointermap.pointers() >= tl.length) { | 12806 if (pointermap.pointers() >= tl.length) { |
12888 var d = []; | 12807 var d = []; |
12889 pointermap.forEach(function(value, key) { | 12808 pointermap.forEach(function(value, key) { |
12890 // Never remove pointerId == 1, which is mouse. | 12809 // Never remove pointerId == 1, which is mouse. |
12891 // Touch identifiers are 2 smaller than their pointerId, which is the | 12810 // Touch identifiers are 2 smaller than their pointerId, which is the |
12892 // index in pointermap. | 12811 // index in pointermap. |
12893 if (key !== 1 && !this.findTouch(tl, key - 2)) { | 12812 if (key !== 1 && !this.findTouch(tl, key - 2)) { |
12894 var p = value.out; | 12813 var p = value.out; |
12895 d.push(p); | 12814 d.push(this.touchToPointer(p)); |
12896 } | 12815 } |
12897 }, this); | 12816 }, this); |
12898 d.forEach(this.cancelOut, this); | 12817 d.forEach(this.cancelOut, this); |
12899 } | 12818 } |
12900 }, | 12819 }, |
12901 touchstart: function(inEvent) { | 12820 touchstart: function(inEvent) { |
12902 this.vacuumTouches(inEvent); | 12821 this.vacuumTouches(inEvent); |
12903 this.setPrimaryTouch(inEvent.changedTouches[0]); | 12822 this.setPrimaryTouch(inEvent.changedTouches[0]); |
12904 this.dedupSynthMouse(inEvent); | 12823 this.dedupSynthMouse(inEvent); |
12905 if (!this.scrolling) { | 12824 if (!this.scrolling) { |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13101 | 13020 |
13102 /** | 13021 /** |
13103 * This module contains the handlers for native platform events. | 13022 * This module contains the handlers for native platform events. |
13104 * From here, the dispatcher is called to create unified pointer events. | 13023 * From here, the dispatcher is called to create unified pointer events. |
13105 * Included are touch events (v1), mouse events, and MSPointerEvents. | 13024 * Included are touch events (v1), mouse events, and MSPointerEvents. |
13106 */ | 13025 */ |
13107 (function(scope) { | 13026 (function(scope) { |
13108 var dispatcher = scope.dispatcher; | 13027 var dispatcher = scope.dispatcher; |
13109 | 13028 |
13110 // only activate if this platform does not have pointer events | 13029 // only activate if this platform does not have pointer events |
13111 if (window.PointerEvent !== scope.PointerEvent) { | 13030 if (window.navigator.pointerEnabled === undefined) { |
| 13031 Object.defineProperty(window.navigator, 'pointerEnabled', {value: true, enum
erable: true}); |
13112 | 13032 |
13113 if (window.navigator.msPointerEnabled) { | 13033 if (window.navigator.msPointerEnabled) { |
13114 var tp = window.navigator.msMaxTouchPoints; | 13034 var tp = window.navigator.msMaxTouchPoints; |
13115 Object.defineProperty(window.navigator, 'maxTouchPoints', { | 13035 Object.defineProperty(window.navigator, 'maxTouchPoints', { |
13116 value: tp, | 13036 value: tp, |
13117 enumerable: true | 13037 enumerable: true |
13118 }); | 13038 }); |
13119 dispatcher.registerSource('ms', scope.msEvents); | 13039 dispatcher.registerSource('ms', scope.msEvents); |
13120 } else { | 13040 } else { |
13121 dispatcher.registerSource('mouse', scope.mouseEvents); | 13041 dispatcher.registerSource('mouse', scope.mouseEvents); |
(...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13481 if (fns) { | 13401 if (fns) { |
13482 this.makeQueue(fns, inEvent); | 13402 this.makeQueue(fns, inEvent); |
13483 } | 13403 } |
13484 this.handledEvents.set(inEvent, true); | 13404 this.handledEvents.set(inEvent, true); |
13485 }, | 13405 }, |
13486 // queue event for async dispatch | 13406 // queue event for async dispatch |
13487 makeQueue: function(inHandlerFns, inEvent) { | 13407 makeQueue: function(inHandlerFns, inEvent) { |
13488 // must clone events to keep the (possibly shadowed) target correct for | 13408 // must clone events to keep the (possibly shadowed) target correct for |
13489 // async dispatching | 13409 // async dispatching |
13490 var e = this.cloneEvent(inEvent); | 13410 var e = this.cloneEvent(inEvent); |
13491 requestAnimationFrame(this.runQueue.bind(this, inHandlerFns, e)); | 13411 setTimeout(this.runQueue.bind(this, inHandlerFns, e), 0); |
13492 }, | 13412 }, |
13493 // Dispatch the queued events | 13413 // Dispatch the queued events |
13494 runQueue: function(inHandlers, inEvent) { | 13414 runQueue: function(inHandlers, inEvent) { |
13495 this.currentPointerId = inEvent.pointerId; | 13415 this.currentPointerId = inEvent.pointerId; |
13496 for (var i = 0, f, l = inHandlers.length; (i < l) && (f = inHandlers[i]);
i++) { | 13416 for (var i = 0, f, l = inHandlers.length; (i < l) && (f = inHandlers[i]);
i++) { |
13497 f(inEvent); | 13417 f(inEvent); |
13498 } | 13418 } |
13499 this.currentPointerId = 0; | 13419 this.currentPointerId = 0; |
13500 }, | 13420 }, |
13501 // set up event listeners | 13421 // set up event listeners |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13542 dispatchEvent: function(inEvent, inTarget) { | 13462 dispatchEvent: function(inEvent, inTarget) { |
13543 var t = inTarget || this.targets.get(inEvent); | 13463 var t = inTarget || this.targets.get(inEvent); |
13544 if (t) { | 13464 if (t) { |
13545 t.dispatchEvent(inEvent); | 13465 t.dispatchEvent(inEvent); |
13546 if (inEvent.tapPrevented) { | 13466 if (inEvent.tapPrevented) { |
13547 this.preventTap(this.currentPointerId); | 13467 this.preventTap(this.currentPointerId); |
13548 } | 13468 } |
13549 } | 13469 } |
13550 }, | 13470 }, |
13551 asyncDispatchEvent: function(inEvent, inTarget) { | 13471 asyncDispatchEvent: function(inEvent, inTarget) { |
13552 requestAnimationFrame(this.dispatchEvent.bind(this, inEvent, inTarget)); | 13472 var fn = function() { |
| 13473 this.dispatchEvent(inEvent, inTarget); |
| 13474 }.bind(this); |
| 13475 setTimeout(fn, 0); |
13553 }, | 13476 }, |
13554 preventTap: function(inPointerId) { | 13477 preventTap: function(inPointerId) { |
13555 var t = this.recognizers.tap; | 13478 var t = this.recognizers.tap; |
13556 if (t){ | 13479 if (t){ |
13557 t.preventTap(inPointerId); | 13480 t.preventTap(inPointerId); |
13558 } | 13481 } |
13559 } | 13482 } |
13560 }; | 13483 }; |
13561 dispatcher.boundHandler = dispatcher.eventHandler.bind(dispatcher); | 13484 dispatcher.boundHandler = dispatcher.eventHandler.bind(dispatcher); |
13562 // recognizers call into the dispatcher and load later | 13485 // recognizers call into the dispatcher and load later |
(...skipping 598 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
14161 if (angle != this.reference.angle) { | 14084 if (angle != this.reference.angle) { |
14162 this.dispatchRotate(angle, points); | 14085 this.dispatchRotate(angle, points); |
14163 } | 14086 } |
14164 }, | 14087 }, |
14165 calcChord: function() { | 14088 calcChord: function() { |
14166 var pointers = []; | 14089 var pointers = []; |
14167 pointermap.forEach(function(p) { | 14090 pointermap.forEach(function(p) { |
14168 pointers.push(p); | 14091 pointers.push(p); |
14169 }); | 14092 }); |
14170 var dist = 0; | 14093 var dist = 0; |
14171 // start with at least two pointers | 14094 var points = {}; |
14172 var points = {a: pointers[0], b: pointers[1]}; | |
14173 var x, y, d; | 14095 var x, y, d; |
14174 for (var i = 0; i < pointers.length; i++) { | 14096 for (var i = 0; i < pointers.length; i++) { |
14175 var a = pointers[i]; | 14097 var a = pointers[i]; |
14176 for (var j = i + 1; j < pointers.length; j++) { | 14098 for (var j = i + 1; j < pointers.length; j++) { |
14177 var b = pointers[j]; | 14099 var b = pointers[j]; |
14178 x = Math.abs(a.clientX - b.clientX); | 14100 x = Math.abs(a.clientX - b.clientX); |
14179 y = Math.abs(a.clientY - b.clientY); | 14101 y = Math.abs(a.clientY - b.clientY); |
14180 d = x + y; | 14102 d = x + y; |
14181 if (d > dist) { | 14103 if (d > dist) { |
14182 dist = d; | 14104 dist = d; |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
14340 // register scopes after a steadystate is reached | 14262 // register scopes after a steadystate is reached |
14341 // less MutationObserver churn | 14263 // less MutationObserver churn |
14342 document.addEventListener('readystatechange', function() { | 14264 document.addEventListener('readystatechange', function() { |
14343 if (document.readyState === 'complete') { | 14265 if (document.readyState === 'complete') { |
14344 registerScopes(); | 14266 registerScopes(); |
14345 } | 14267 } |
14346 }); | 14268 }); |
14347 } | 14269 } |
14348 })(window.PointerGestures); | 14270 })(window.PointerGestures); |
14349 | 14271 |
14350 // Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | 14272 // Copyright 2011 Google Inc. |
14351 // This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt | 14273 // |
14352 // The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt | 14274 // Licensed under the Apache License, Version 2.0 (the "License"); |
14353 // The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt | 14275 // you may not use this file except in compliance with the License. |
14354 // Code distributed by Google as part of the polymer project is also | 14276 // You may obtain a copy of the License at |
14355 // subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt | 14277 // |
| 14278 // http://www.apache.org/licenses/LICENSE-2.0 |
| 14279 // |
| 14280 // Unless required by applicable law or agreed to in writing, software |
| 14281 // distributed under the License is distributed on an "AS IS" BASIS, |
| 14282 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14283 // See the License for the specific language governing permissions and |
| 14284 // limitations under the License. |
14356 | 14285 |
14357 (function(global) { | 14286 (function(global) { |
14358 'use strict'; | 14287 'use strict'; |
14359 | 14288 |
14360 var filter = Array.prototype.filter.call.bind(Array.prototype.filter); | 14289 var filter = Array.prototype.filter.call.bind(Array.prototype.filter); |
14361 | 14290 |
14362 function getTreeScope(node) { | 14291 function getTreeScope(node) { |
14363 while (node.parentNode) { | 14292 while (node.parentNode) { |
14364 node = node.parentNode; | 14293 node = node.parentNode; |
14365 } | 14294 } |
14366 | 14295 |
14367 return typeof node.getElementById === 'function' ? node : null; | 14296 return typeof node.getElementById === 'function' ? node : null; |
14368 } | 14297 } |
14369 | 14298 |
| 14299 |
14370 Node.prototype.bind = function(name, observable) { | 14300 Node.prototype.bind = function(name, observable) { |
14371 console.error('Unhandled binding to Node: ', this, name, observable); | 14301 console.error('Unhandled binding to Node: ', this, name, observable); |
14372 }; | 14302 }; |
14373 | 14303 |
14374 function updateBindings(node, name, binding) { | 14304 function unbind(node, name) { |
14375 var bindings = node.bindings_; | 14305 var bindings = node.bindings; |
14376 if (!bindings) | 14306 if (!bindings) { |
14377 bindings = node.bindings_ = {}; | 14307 node.bindings = {}; |
| 14308 return; |
| 14309 } |
14378 | 14310 |
14379 if (bindings[name]) | 14311 var binding = bindings[name]; |
14380 binding[name].close(); | 14312 if (!binding) |
| 14313 return; |
14381 | 14314 |
14382 return bindings[name] = binding; | 14315 binding.close(); |
| 14316 bindings[name] = undefined; |
14383 } | 14317 } |
14384 | 14318 |
14385 function returnBinding(node, name, binding) { | 14319 Node.prototype.unbind = function(name) { |
14386 return binding; | 14320 unbind(this, name); |
14387 } | 14321 }; |
| 14322 |
| 14323 Node.prototype.unbindAll = function() { |
| 14324 if (!this.bindings) |
| 14325 return; |
| 14326 var names = Object.keys(this.bindings); |
| 14327 for (var i = 0; i < names.length; i++) { |
| 14328 var binding = this.bindings[names[i]]; |
| 14329 if (binding) |
| 14330 binding.close(); |
| 14331 } |
| 14332 |
| 14333 this.bindings = {}; |
| 14334 }; |
14388 | 14335 |
14389 function sanitizeValue(value) { | 14336 function sanitizeValue(value) { |
14390 return value == null ? '' : value; | 14337 return value == null ? '' : value; |
14391 } | 14338 } |
14392 | 14339 |
14393 function updateText(node, value) { | 14340 function updateText(node, value) { |
14394 node.data = sanitizeValue(value); | 14341 node.data = sanitizeValue(value); |
14395 } | 14342 } |
14396 | 14343 |
14397 function textBinding(node) { | 14344 function textBinding(node) { |
14398 return function(value) { | 14345 return function(value) { |
14399 return updateText(node, value); | 14346 return updateText(node, value); |
14400 }; | 14347 }; |
14401 } | 14348 } |
14402 | 14349 |
14403 var maybeUpdateBindings = returnBinding; | |
14404 | |
14405 Object.defineProperty(Platform, 'enableBindingsReflection', { | |
14406 get: function() { | |
14407 return maybeUpdateBindings === updateBindings; | |
14408 }, | |
14409 set: function(enable) { | |
14410 maybeUpdateBindings = enable ? updateBindings : returnBinding; | |
14411 return enable; | |
14412 }, | |
14413 configurable: true | |
14414 }); | |
14415 | |
14416 Text.prototype.bind = function(name, value, oneTime) { | 14350 Text.prototype.bind = function(name, value, oneTime) { |
14417 if (name !== 'textContent') | 14351 if (name !== 'textContent') |
14418 return Node.prototype.bind.call(this, name, value, oneTime); | 14352 return Node.prototype.bind.call(this, name, value, oneTime); |
14419 | 14353 |
14420 if (oneTime) | 14354 if (oneTime) |
14421 return updateText(this, value); | 14355 return updateText(this, value); |
14422 | 14356 |
14423 var observable = value; | 14357 unbind(this, 'textContent'); |
14424 updateText(this, observable.open(textBinding(this))); | 14358 updateText(this, value.open(textBinding(this))); |
14425 return maybeUpdateBindings(this, name, observable); | 14359 return this.bindings.textContent = value; |
14426 } | 14360 } |
14427 | 14361 |
14428 function updateAttribute(el, name, conditional, value) { | 14362 function updateAttribute(el, name, conditional, value) { |
14429 if (conditional) { | 14363 if (conditional) { |
14430 if (value) | 14364 if (value) |
14431 el.setAttribute(name, ''); | 14365 el.setAttribute(name, ''); |
14432 else | 14366 else |
14433 el.removeAttribute(name); | 14367 el.removeAttribute(name); |
14434 return; | 14368 return; |
14435 } | 14369 } |
(...skipping 10 matching lines...) Expand all Loading... |
14446 Element.prototype.bind = function(name, value, oneTime) { | 14380 Element.prototype.bind = function(name, value, oneTime) { |
14447 var conditional = name[name.length - 1] == '?'; | 14381 var conditional = name[name.length - 1] == '?'; |
14448 if (conditional) { | 14382 if (conditional) { |
14449 this.removeAttribute(name); | 14383 this.removeAttribute(name); |
14450 name = name.slice(0, -1); | 14384 name = name.slice(0, -1); |
14451 } | 14385 } |
14452 | 14386 |
14453 if (oneTime) | 14387 if (oneTime) |
14454 return updateAttribute(this, name, conditional, value); | 14388 return updateAttribute(this, name, conditional, value); |
14455 | 14389 |
| 14390 unbind(this, name); |
| 14391 updateAttribute(this, name, conditional, |
| 14392 value.open(attributeBinding(this, name, conditional))); |
14456 | 14393 |
14457 var observable = value; | 14394 return this.bindings[name] = value; |
14458 updateAttribute(this, name, conditional, | |
14459 observable.open(attributeBinding(this, name, conditional))); | |
14460 | |
14461 return maybeUpdateBindings(this, name, observable); | |
14462 }; | 14395 }; |
14463 | 14396 |
14464 var checkboxEventType; | 14397 var checkboxEventType; |
14465 (function() { | 14398 (function() { |
14466 // Attempt to feature-detect which event (change or click) is fired first | 14399 // Attempt to feature-detect which event (change or click) is fired first |
14467 // for checkboxes. | 14400 // for checkboxes. |
14468 var div = document.createElement('div'); | 14401 var div = document.createElement('div'); |
14469 var checkbox = div.appendChild(document.createElement('input')); | 14402 var checkbox = div.appendChild(document.createElement('input')); |
14470 checkbox.setAttribute('type', 'checkbox'); | 14403 checkbox.setAttribute('type', 'checkbox'); |
14471 var first; | 14404 var first; |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
14520 var eventType = getEventForInputType(input); | 14453 var eventType = getEventForInputType(input); |
14521 | 14454 |
14522 function eventHandler() { | 14455 function eventHandler() { |
14523 observable.setValue(input[property]); | 14456 observable.setValue(input[property]); |
14524 observable.discardChanges(); | 14457 observable.discardChanges(); |
14525 (postEventFn || noop)(input); | 14458 (postEventFn || noop)(input); |
14526 Platform.performMicrotaskCheckpoint(); | 14459 Platform.performMicrotaskCheckpoint(); |
14527 } | 14460 } |
14528 input.addEventListener(eventType, eventHandler); | 14461 input.addEventListener(eventType, eventHandler); |
14529 | 14462 |
14530 return { | 14463 var capturedClose = observable.close; |
14531 close: function() { | 14464 observable.close = function() { |
14532 input.removeEventListener(eventType, eventHandler); | 14465 if (!capturedClose) |
14533 observable.close(); | 14466 return; |
14534 }, | 14467 input.removeEventListener(eventType, eventHandler); |
14535 | 14468 |
14536 observable_: observable | 14469 observable.close = capturedClose; |
| 14470 observable.close(); |
| 14471 capturedClose = undefined; |
14537 } | 14472 } |
14538 } | 14473 } |
14539 | 14474 |
14540 function booleanSanitize(value) { | 14475 function booleanSanitize(value) { |
14541 return Boolean(value); | 14476 return Boolean(value); |
14542 } | 14477 } |
14543 | 14478 |
14544 // |element| is assumed to be an HTMLInputElement with |type| == 'radio'. | 14479 // |element| is assumed to be an HTMLInputElement with |type| == 'radio'. |
14545 // Returns an array containing all radio buttons other than |element| that | 14480 // Returns an array containing all radio buttons other than |element| that |
14546 // have the same |name|, either in the form that |element| belongs to or, | 14481 // have the same |name|, either in the form that |element| belongs to or, |
(...skipping 23 matching lines...) Expand all Loading... |
14570 } | 14505 } |
14571 } | 14506 } |
14572 | 14507 |
14573 function checkedPostEvent(input) { | 14508 function checkedPostEvent(input) { |
14574 // Only the radio button that is getting checked gets an event. We | 14509 // Only the radio button that is getting checked gets an event. We |
14575 // therefore find all the associated radio buttons and update their | 14510 // therefore find all the associated radio buttons and update their |
14576 // check binding manually. | 14511 // check binding manually. |
14577 if (input.tagName === 'INPUT' && | 14512 if (input.tagName === 'INPUT' && |
14578 input.type === 'radio') { | 14513 input.type === 'radio') { |
14579 getAssociatedRadioButtons(input).forEach(function(radio) { | 14514 getAssociatedRadioButtons(input).forEach(function(radio) { |
14580 var checkedBinding = radio.bindings_.checked; | 14515 var checkedBinding = radio.bindings.checked; |
14581 if (checkedBinding) { | 14516 if (checkedBinding) { |
14582 // Set the value directly to avoid an infinite call stack. | 14517 // Set the value directly to avoid an infinite call stack. |
14583 checkedBinding.observable_.setValue(false); | 14518 checkedBinding.setValue(false); |
14584 } | 14519 } |
14585 }); | 14520 }); |
14586 } | 14521 } |
14587 } | 14522 } |
14588 | 14523 |
14589 HTMLInputElement.prototype.bind = function(name, value, oneTime) { | 14524 HTMLInputElement.prototype.bind = function(name, value, oneTime) { |
14590 if (name !== 'value' && name !== 'checked') | 14525 if (name !== 'value' && name !== 'checked') |
14591 return HTMLElement.prototype.bind.call(this, name, value, oneTime); | 14526 return HTMLElement.prototype.bind.call(this, name, value, oneTime); |
14592 | 14527 |
| 14528 |
14593 this.removeAttribute(name); | 14529 this.removeAttribute(name); |
14594 var sanitizeFn = name == 'checked' ? booleanSanitize : sanitizeValue; | 14530 var sanitizeFn = name == 'checked' ? booleanSanitize : sanitizeValue; |
14595 var postEventFn = name == 'checked' ? checkedPostEvent : noop; | 14531 var postEventFn = name == 'checked' ? checkedPostEvent : noop; |
14596 | 14532 |
14597 if (oneTime) | 14533 if (oneTime) |
14598 return updateInput(this, name, value, sanitizeFn); | 14534 return updateInput(this, name, value, sanitizeFn); |
14599 | 14535 |
14600 | 14536 unbind(this, name); |
14601 var observable = value; | 14537 bindInputEvent(this, name, value, postEventFn); |
14602 var binding = bindInputEvent(this, name, observable, postEventFn); | |
14603 updateInput(this, name, | 14538 updateInput(this, name, |
14604 observable.open(inputBinding(this, name, sanitizeFn)), | 14539 value.open(inputBinding(this, name, sanitizeFn)), |
14605 sanitizeFn); | 14540 sanitizeFn); |
14606 | 14541 |
14607 // Checkboxes may need to update bindings of other checkboxes. | 14542 return this.bindings[name] = value; |
14608 return updateBindings(this, name, binding); | |
14609 } | 14543 } |
14610 | 14544 |
14611 HTMLTextAreaElement.prototype.bind = function(name, value, oneTime) { | 14545 HTMLTextAreaElement.prototype.bind = function(name, value, oneTime) { |
14612 if (name !== 'value') | 14546 if (name !== 'value') |
14613 return HTMLElement.prototype.bind.call(this, name, value, oneTime); | 14547 return HTMLElement.prototype.bind.call(this, name, value, oneTime); |
14614 | 14548 |
14615 this.removeAttribute('value'); | 14549 this.removeAttribute('value'); |
14616 | 14550 |
14617 if (oneTime) | 14551 if (oneTime) |
14618 return updateInput(this, 'value', value); | 14552 return updateInput(this, 'value', value); |
14619 | 14553 |
14620 var observable = value; | 14554 unbind(this, 'value'); |
14621 var binding = bindInputEvent(this, 'value', observable); | 14555 bindInputEvent(this, 'value', value); |
14622 updateInput(this, 'value', | 14556 updateInput(this, 'value', |
14623 observable.open(inputBinding(this, 'value', sanitizeValue))); | 14557 value.open(inputBinding(this, 'value', sanitizeValue))); |
14624 return maybeUpdateBindings(this, name, binding); | 14558 |
| 14559 return this.bindings.value = value; |
14625 } | 14560 } |
14626 | 14561 |
14627 function updateOption(option, value) { | 14562 function updateOption(option, value) { |
14628 var parentNode = option.parentNode;; | 14563 var parentNode = option.parentNode;; |
14629 var select; | 14564 var select; |
14630 var selectBinding; | 14565 var selectBinding; |
14631 var oldValue; | 14566 var oldValue; |
14632 if (parentNode instanceof HTMLSelectElement && | 14567 if (parentNode instanceof HTMLSelectElement && |
14633 parentNode.bindings_ && | 14568 parentNode.bindings && |
14634 parentNode.bindings_.value) { | 14569 parentNode.bindings.value) { |
14635 select = parentNode; | 14570 select = parentNode; |
14636 selectBinding = select.bindings_.value; | 14571 selectBinding = select.bindings.value; |
14637 oldValue = select.value; | 14572 oldValue = select.value; |
14638 } | 14573 } |
14639 | 14574 |
14640 option.value = sanitizeValue(value); | 14575 option.value = sanitizeValue(value); |
14641 | 14576 |
14642 if (select && select.value != oldValue) { | 14577 if (select && select.value != oldValue) { |
14643 selectBinding.observable_.setValue(select.value); | 14578 selectBinding.setValue(select.value); |
14644 selectBinding.observable_.discardChanges(); | 14579 selectBinding.discardChanges(); |
14645 Platform.performMicrotaskCheckpoint(); | 14580 Platform.performMicrotaskCheckpoint(); |
14646 } | 14581 } |
14647 } | 14582 } |
14648 | 14583 |
14649 function optionBinding(option) { | 14584 function optionBinding(option) { |
14650 return function(value) { | 14585 return function(value) { |
14651 updateOption(option, value); | 14586 updateOption(option, value); |
14652 } | 14587 } |
14653 } | 14588 } |
14654 | 14589 |
14655 HTMLOptionElement.prototype.bind = function(name, value, oneTime) { | 14590 HTMLOptionElement.prototype.bind = function(name, value, oneTime) { |
14656 if (name !== 'value') | 14591 if (name !== 'value') |
14657 return HTMLElement.prototype.bind.call(this, name, value, oneTime); | 14592 return HTMLElement.prototype.bind.call(this, name, value, oneTime); |
14658 | 14593 |
14659 this.removeAttribute('value'); | 14594 this.removeAttribute('value'); |
14660 | 14595 |
14661 if (oneTime) | 14596 if (oneTime) |
14662 return updateOption(this, value); | 14597 return updateOption(this, value); |
14663 | 14598 |
14664 var observable = value; | 14599 unbind(this, 'value'); |
14665 var binding = bindInputEvent(this, 'value', observable); | 14600 bindInputEvent(this, 'value', value); |
14666 updateOption(this, observable.open(optionBinding(this))); | 14601 updateOption(this, value.open(optionBinding(this))); |
14667 return maybeUpdateBindings(this, name, binding); | 14602 return this.bindings.value = value; |
14668 } | 14603 } |
14669 | 14604 |
14670 HTMLSelectElement.prototype.bind = function(name, value, oneTime) { | 14605 HTMLSelectElement.prototype.bind = function(name, value, oneTime) { |
14671 if (name === 'selectedindex') | 14606 if (name === 'selectedindex') |
14672 name = 'selectedIndex'; | 14607 name = 'selectedIndex'; |
14673 | 14608 |
14674 if (name !== 'selectedIndex' && name !== 'value') | 14609 if (name !== 'selectedIndex' && name !== 'value') |
14675 return HTMLElement.prototype.bind.call(this, name, value, oneTime); | 14610 return HTMLElement.prototype.bind.call(this, name, value, oneTime); |
14676 | 14611 |
14677 this.removeAttribute(name); | 14612 this.removeAttribute(name); |
14678 | 14613 |
14679 if (oneTime) | 14614 if (oneTime) |
14680 return updateInput(this, name, value); | 14615 return updateInput(this, name, value); |
14681 | 14616 |
14682 var observable = value; | 14617 unbind(this, name); |
14683 var binding = bindInputEvent(this, name, observable); | 14618 bindInputEvent(this, name, value); |
14684 updateInput(this, name, | 14619 updateInput(this, name, |
14685 observable.open(inputBinding(this, name))); | 14620 value.open(inputBinding(this, name))); |
14686 | 14621 return this.bindings[name] = value; |
14687 // Option update events may need to access select bindings. | |
14688 return updateBindings(this, name, binding); | |
14689 } | 14622 } |
14690 })(this); | 14623 })(this); |
14691 | 14624 |
14692 // Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | 14625 // Copyright 2011 Google Inc. |
14693 // This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt | 14626 // |
14694 // The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt | 14627 // Licensed under the Apache License, Version 2.0 (the "License"); |
14695 // The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt | 14628 // you may not use this file except in compliance with the License. |
14696 // Code distributed by Google as part of the polymer project is also | 14629 // You may obtain a copy of the License at |
14697 // subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt | 14630 // |
| 14631 // http://www.apache.org/licenses/LICENSE-2.0 |
| 14632 // |
| 14633 // Unless required by applicable law or agreed to in writing, software |
| 14634 // distributed under the License is distributed on an "AS IS" BASIS, |
| 14635 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14636 // See the License for the specific language governing permissions and |
| 14637 // limitations under the License. |
14698 | 14638 |
14699 (function(global) { | 14639 (function(global) { |
14700 'use strict'; | 14640 'use strict'; |
14701 | 14641 |
14702 function assert(v) { | 14642 function assert(v) { |
14703 if (!v) | 14643 if (!v) |
14704 throw new Error('Assertion failed'); | 14644 throw new Error('Assertion failed'); |
14705 } | 14645 } |
14706 | 14646 |
14707 var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach); | 14647 var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach); |
(...skipping 444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
15152 var ref = oneTime ? value : value.open(function(ref) { | 15092 var ref = oneTime ? value : value.open(function(ref) { |
15153 self.setAttribute('ref', ref); | 15093 self.setAttribute('ref', ref); |
15154 self.refChanged_(); | 15094 self.refChanged_(); |
15155 }); | 15095 }); |
15156 | 15096 |
15157 this.setAttribute('ref', ref); | 15097 this.setAttribute('ref', ref); |
15158 this.refChanged_(); | 15098 this.refChanged_(); |
15159 if (oneTime) | 15099 if (oneTime) |
15160 return; | 15100 return; |
15161 | 15101 |
15162 if (!this.bindings_) { | 15102 this.unbind('ref'); |
15163 this.bindings_ = { ref: value }; | 15103 return this.bindings.ref = value; |
15164 } else { | |
15165 this.bindings_.ref = value; | |
15166 } | |
15167 | |
15168 return value; | |
15169 }, | 15104 }, |
15170 | 15105 |
15171 processBindingDirectives_: function(directives) { | 15106 processBindingDirectives_: function(directives) { |
15172 if (this.iterator_) | 15107 if (this.iterator_) |
15173 this.iterator_.closeDeps(); | 15108 this.iterator_.closeDeps(); |
15174 | 15109 |
15175 if (!directives.if && !directives.bind && !directives.repeat) { | 15110 if (!directives.if && !directives.bind && !directives.repeat) { |
15176 if (this.iterator_) { | 15111 if (this.iterator_) { |
15177 this.iterator_.close(); | 15112 this.iterator_.close(); |
15178 this.iterator_ = undefined; | 15113 this.iterator_ = undefined; |
| 15114 this.bindings.iterator = undefined; |
15179 } | 15115 } |
15180 | 15116 |
15181 return; | 15117 return; |
15182 } | 15118 } |
15183 | 15119 |
15184 if (!this.iterator_) { | 15120 if (!this.iterator_) { |
15185 this.iterator_ = new TemplateIterator(this); | 15121 this.iterator_ = new TemplateIterator(this); |
| 15122 this.bindings = this.bindings || {}; |
| 15123 this.bindings.iterator = this.iterator_; |
15186 } | 15124 } |
15187 | 15125 |
15188 this.iterator_.updateDependencies(directives, this.model_); | 15126 this.iterator_.updateDependencies(directives, this.model_); |
15189 | 15127 |
15190 if (templateObserver) { | 15128 if (templateObserver) { |
15191 templateObserver.observe(this, { attributes: true, | 15129 templateObserver.observe(this, { attributes: true, |
15192 attributeFilter: ['ref'] }); | 15130 attributeFilter: ['ref'] }); |
15193 } | 15131 } |
15194 | 15132 |
15195 return this.iterator_; | 15133 return this.iterator_; |
15196 }, | 15134 }, |
15197 | 15135 |
15198 createInstance: function(model, bindingDelegate, delegate_) { | 15136 createInstance: function(model, bindingDelegate, delegate_, |
| 15137 instanceBindings_) { |
15199 if (bindingDelegate) | 15138 if (bindingDelegate) |
15200 delegate_ = this.newDelegate_(bindingDelegate); | 15139 delegate_ = this.newDelegate_(bindingDelegate); |
15201 | 15140 |
15202 if (!this.refContent_) | 15141 if (!this.refContent_) |
15203 this.refContent_ = this.ref_.content; | 15142 this.refContent_ = this.ref_.content; |
15204 var content = this.refContent_; | 15143 var content = this.refContent_; |
15205 if (content.firstChild === null) | |
15206 return emptyInstance; | |
15207 | |
15208 var map = this.bindingMap_; | 15144 var map = this.bindingMap_; |
15209 if (!map || map.content !== content) { | 15145 if (!map || map.content !== content) { |
15210 // TODO(rafaelw): Setup a MutationObserver on content to detect | 15146 // TODO(rafaelw): Setup a MutationObserver on content to detect |
15211 // when the instanceMap is invalid. | 15147 // when the instanceMap is invalid. |
15212 map = createInstanceBindingMap(content, | 15148 map = createInstanceBindingMap(content, |
15213 delegate_ && delegate_.prepareBinding) || []; | 15149 delegate_ && delegate_.prepareBinding) || []; |
15214 map.content = content; | 15150 map.content = content; |
15215 this.bindingMap_ = map; | 15151 this.bindingMap_ = map; |
15216 } | 15152 } |
15217 | 15153 |
15218 var stagingDocument = getTemplateStagingDocument(this); | 15154 var stagingDocument = getTemplateStagingDocument(this); |
15219 var instance = stagingDocument.createDocumentFragment(); | 15155 var instance = stagingDocument.createDocumentFragment(); |
15220 instance.templateCreator_ = this; | 15156 instance.templateCreator_ = this; |
15221 instance.protoContent_ = content; | 15157 instance.protoContent_ = content; |
15222 instance.bindings_ = []; | 15158 |
15223 instance.terminator_ = null; | 15159 var instanceRecord = { |
15224 var instanceRecord = instance.templateInstance_ = { | |
15225 firstNode: null, | 15160 firstNode: null, |
15226 lastNode: null, | 15161 lastNode: null, |
15227 model: model | 15162 model: model |
15228 }; | 15163 }; |
15229 | 15164 |
15230 var i = 0; | 15165 var i = 0; |
15231 var collectTerminator = false; | |
15232 for (var child = content.firstChild; child; child = child.nextSibling) { | 15166 for (var child = content.firstChild; child; child = child.nextSibling) { |
15233 // The terminator of the instance is the clone of the last child of the | |
15234 // content. If the last child is an active template, it may produce | |
15235 // instances as a result of production, so simply collecting the last | |
15236 // child of the instance after it has finished producing may be wrong. | |
15237 if (child.nextSibling === null) | |
15238 collectTerminator = true; | |
15239 | |
15240 var clone = cloneAndBindInstance(child, instance, stagingDocument, | 15167 var clone = cloneAndBindInstance(child, instance, stagingDocument, |
15241 map.children[i++], | 15168 map.children[i++], |
15242 model, | 15169 model, |
15243 delegate_, | 15170 delegate_, |
15244 instance.bindings_); | 15171 instanceBindings_); |
15245 clone.templateInstance_ = instanceRecord; | 15172 clone.templateInstance_ = instanceRecord; |
15246 if (collectTerminator) | |
15247 instance.terminator_ = clone; | |
15248 } | 15173 } |
15249 | 15174 |
15250 instanceRecord.firstNode = instance.firstChild; | 15175 instanceRecord.firstNode = instance.firstChild; |
15251 instanceRecord.lastNode = instance.lastChild; | 15176 instanceRecord.lastNode = instance.lastChild; |
15252 instance.templateCreator_ = undefined; | 15177 instance.templateCreator_ = undefined; |
15253 instance.protoContent_ = undefined; | 15178 instance.protoContent_ = undefined; |
15254 return instance; | 15179 return instance; |
15255 }, | 15180 }, |
15256 | 15181 |
15257 get model() { | 15182 get model() { |
(...skipping 14 matching lines...) Expand all Loading... |
15272 return; | 15197 return; |
15273 | 15198 |
15274 this.refContent_ = undefined; | 15199 this.refContent_ = undefined; |
15275 this.iterator_.valueChanged(); | 15200 this.iterator_.valueChanged(); |
15276 this.iterator_.updateIteratedValue(); | 15201 this.iterator_.updateIteratedValue(); |
15277 }, | 15202 }, |
15278 | 15203 |
15279 clear: function() { | 15204 clear: function() { |
15280 this.model_ = undefined; | 15205 this.model_ = undefined; |
15281 this.delegate_ = undefined; | 15206 this.delegate_ = undefined; |
15282 if (this.bindings_ && this.bindings_.ref) | 15207 this.bindings_ = undefined; |
15283 this.bindings_.ref.close() | |
15284 this.refContent_ = undefined; | 15208 this.refContent_ = undefined; |
15285 if (!this.iterator_) | 15209 if (!this.iterator_) |
15286 return; | 15210 return; |
15287 this.iterator_.valueChanged(); | 15211 this.iterator_.valueChanged(); |
15288 this.iterator_.close() | 15212 this.iterator_.close() |
15289 this.iterator_ = undefined; | 15213 this.iterator_ = undefined; |
15290 }, | 15214 }, |
15291 | 15215 |
15292 setDelegate_: function(delegate) { | 15216 setDelegate_: function(delegate) { |
15293 this.delegate_ = delegate; | 15217 this.delegate_ = delegate; |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
15378 | 15302 |
15379 tokens.push(s.slice(lastIndex)); // TEXT | 15303 tokens.push(s.slice(lastIndex)); // TEXT |
15380 break; | 15304 break; |
15381 } | 15305 } |
15382 | 15306 |
15383 tokens = tokens || []; | 15307 tokens = tokens || []; |
15384 tokens.push(s.slice(lastIndex, startIndex)); // TEXT | 15308 tokens.push(s.slice(lastIndex, startIndex)); // TEXT |
15385 var pathString = s.slice(startIndex + 2, endIndex).trim(); | 15309 var pathString = s.slice(startIndex + 2, endIndex).trim(); |
15386 tokens.push(oneTime); // ONE_TIME? | 15310 tokens.push(oneTime); // ONE_TIME? |
15387 onlyOneTime = onlyOneTime && oneTime; | 15311 onlyOneTime = onlyOneTime && oneTime; |
| 15312 tokens.push(Path.get(pathString)); // PATH |
15388 var delegateFn = prepareBindingFn && | 15313 var delegateFn = prepareBindingFn && |
15389 prepareBindingFn(pathString, name, node); | 15314 prepareBindingFn(pathString, name, node); |
15390 // Don't try to parse the expression if there's a prepareBinding function | |
15391 if (delegateFn == null) { | |
15392 tokens.push(Path.get(pathString)); // PATH | |
15393 } else { | |
15394 tokens.push(null); | |
15395 } | |
15396 tokens.push(delegateFn); // DELEGATE_FN | 15315 tokens.push(delegateFn); // DELEGATE_FN |
15397 lastIndex = endIndex + 2; | 15316 lastIndex = endIndex + 2; |
15398 } | 15317 } |
15399 | 15318 |
15400 if (lastIndex === length) | 15319 if (lastIndex === length) |
15401 tokens.push(''); // TEXT | 15320 tokens.push(''); // TEXT |
15402 | 15321 |
15403 tokens.hasOnePath = tokens.length === 5; | 15322 tokens.hasOnePath = tokens.length === 5; |
15404 tokens.isSimplePath = tokens.hasOnePath && | 15323 tokens.isSimplePath = tokens.hasOnePath && |
15405 tokens[0] == '' && | 15324 tokens[0] == '' && |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
15603 } | 15522 } |
15604 | 15523 |
15605 Object.defineProperty(Node.prototype, 'templateInstance', { | 15524 Object.defineProperty(Node.prototype, 'templateInstance', { |
15606 get: function() { | 15525 get: function() { |
15607 var instance = this.templateInstance_; | 15526 var instance = this.templateInstance_; |
15608 return instance ? instance : | 15527 return instance ? instance : |
15609 (this.parentNode ? this.parentNode.templateInstance : undefined); | 15528 (this.parentNode ? this.parentNode.templateInstance : undefined); |
15610 } | 15529 } |
15611 }); | 15530 }); |
15612 | 15531 |
15613 var emptyInstance = document.createDocumentFragment(); | |
15614 emptyInstance.bindings_ = []; | |
15615 emptyInstance.terminator_ = null; | |
15616 | |
15617 function TemplateIterator(templateElement) { | 15532 function TemplateIterator(templateElement) { |
15618 this.closed = false; | 15533 this.closed = false; |
15619 this.templateElement_ = templateElement; | 15534 this.templateElement_ = templateElement; |
15620 this.instances = []; | 15535 |
| 15536 // Flattened array of tuples: |
| 15537 // <instanceTerminatorNode, [bindingsSetupByInstance]> |
| 15538 this.terminators = []; |
| 15539 |
15621 this.deps = undefined; | 15540 this.deps = undefined; |
15622 this.iteratedValue = []; | 15541 this.iteratedValue = []; |
15623 this.presentValue = undefined; | 15542 this.presentValue = undefined; |
15624 this.arrayObserver = undefined; | 15543 this.arrayObserver = undefined; |
15625 } | 15544 } |
15626 | 15545 |
15627 TemplateIterator.prototype = { | 15546 TemplateIterator.prototype = { |
15628 closeDeps: function() { | 15547 closeDeps: function() { |
15629 var deps = this.deps; | 15548 var deps = this.deps; |
15630 if (deps) { | 15549 if (deps) { |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
15705 this.presentValue = value; | 15624 this.presentValue = value; |
15706 if (observeValue) { | 15625 if (observeValue) { |
15707 this.arrayObserver = new ArrayObserver(this.presentValue); | 15626 this.arrayObserver = new ArrayObserver(this.presentValue); |
15708 this.arrayObserver.open(this.handleSplices, this); | 15627 this.arrayObserver.open(this.handleSplices, this); |
15709 } | 15628 } |
15710 | 15629 |
15711 this.handleSplices(ArrayObserver.calculateSplices(this.presentValue, | 15630 this.handleSplices(ArrayObserver.calculateSplices(this.presentValue, |
15712 this.iteratedValue)); | 15631 this.iteratedValue)); |
15713 }, | 15632 }, |
15714 | 15633 |
15715 getLastInstanceNode: function(index) { | 15634 getTerminatorAt: function(index) { |
15716 if (index == -1) | 15635 if (index == -1) |
15717 return this.templateElement_; | 15636 return this.templateElement_; |
15718 var instance = this.instances[index]; | 15637 var terminator = this.terminators[index*2]; |
15719 var terminator = instance.terminator_; | |
15720 if (!terminator) | |
15721 return this.getLastInstanceNode(index - 1); | |
15722 | |
15723 if (terminator.nodeType !== Node.ELEMENT_NODE || | 15638 if (terminator.nodeType !== Node.ELEMENT_NODE || |
15724 this.templateElement_ === terminator) { | 15639 this.templateElement_ === terminator) { |
15725 return terminator; | 15640 return terminator; |
15726 } | 15641 } |
15727 | 15642 |
15728 var subtemplateIterator = terminator.iterator_; | 15643 var subIterator = terminator.iterator_; |
15729 if (!subtemplateIterator) | 15644 if (!subIterator) |
15730 return terminator; | 15645 return terminator; |
15731 | 15646 |
15732 return subtemplateIterator.getLastTemplateNode(); | 15647 return subIterator.getTerminatorAt(subIterator.terminators.length/2 - 1); |
15733 }, | 15648 }, |
15734 | 15649 |
15735 getLastTemplateNode: function() { | 15650 // TODO(rafaelw): If we inserting sequences of instances we can probably |
15736 return this.getLastInstanceNode(this.instances.length - 1); | 15651 // avoid lots of calls to getTerminatorAt(), or cache its result. |
15737 }, | 15652 insertInstanceAt: function(index, fragment, instanceNodes, |
| 15653 instanceBindings) { |
| 15654 var previousTerminator = this.getTerminatorAt(index - 1); |
| 15655 var terminator = previousTerminator; |
| 15656 if (fragment) |
| 15657 terminator = fragment.lastChild || terminator; |
| 15658 else if (instanceNodes) |
| 15659 terminator = instanceNodes[instanceNodes.length - 1] || terminator; |
15738 | 15660 |
15739 insertInstanceAt: function(index, fragment) { | 15661 this.terminators.splice(index*2, 0, terminator, instanceBindings); |
15740 var previousInstanceLast = this.getLastInstanceNode(index - 1); | |
15741 var parent = this.templateElement_.parentNode; | 15662 var parent = this.templateElement_.parentNode; |
15742 this.instances.splice(index, 0, fragment); | 15663 var insertBeforeNode = previousTerminator.nextSibling; |
15743 | 15664 |
15744 parent.insertBefore(fragment, previousInstanceLast.nextSibling); | 15665 if (fragment) { |
| 15666 parent.insertBefore(fragment, insertBeforeNode); |
| 15667 } else if (instanceNodes) { |
| 15668 for (var i = 0; i < instanceNodes.length; i++) |
| 15669 parent.insertBefore(instanceNodes[i], insertBeforeNode); |
| 15670 } |
15745 }, | 15671 }, |
15746 | 15672 |
15747 extractInstanceAt: function(index) { | 15673 extractInstanceAt: function(index) { |
15748 var previousInstanceLast = this.getLastInstanceNode(index - 1); | 15674 var instanceNodes = []; |
15749 var lastNode = this.getLastInstanceNode(index); | 15675 var previousTerminator = this.getTerminatorAt(index - 1); |
| 15676 var terminator = this.getTerminatorAt(index); |
| 15677 instanceNodes.instanceBindings = this.terminators[index*2 + 1]; |
| 15678 this.terminators.splice(index*2, 2); |
| 15679 |
15750 var parent = this.templateElement_.parentNode; | 15680 var parent = this.templateElement_.parentNode; |
15751 var instance = this.instances.splice(index, 1)[0]; | 15681 while (terminator !== previousTerminator) { |
| 15682 var node = previousTerminator.nextSibling; |
| 15683 if (node == terminator) |
| 15684 terminator = previousTerminator; |
15752 | 15685 |
15753 while (lastNode !== previousInstanceLast) { | 15686 parent.removeChild(node); |
15754 var node = previousInstanceLast.nextSibling; | 15687 instanceNodes.push(node); |
15755 if (node == lastNode) | |
15756 lastNode = previousInstanceLast; | |
15757 | |
15758 instance.appendChild(parent.removeChild(node)); | |
15759 } | 15688 } |
15760 | 15689 |
15761 return instance; | 15690 return instanceNodes; |
15762 }, | 15691 }, |
15763 | 15692 |
15764 getDelegateFn: function(fn) { | 15693 getDelegateFn: function(fn) { |
15765 fn = fn && fn(this.templateElement_); | 15694 fn = fn && fn(this.templateElement_); |
15766 return typeof fn === 'function' ? fn : null; | 15695 return typeof fn === 'function' ? fn : null; |
15767 }, | 15696 }, |
15768 | 15697 |
15769 handleSplices: function(splices) { | 15698 handleSplices: function(splices) { |
15770 if (this.closed || !splices.length) | 15699 if (this.closed || !splices.length) |
15771 return; | 15700 return; |
(...skipping 13 matching lines...) Expand all Loading... |
15785 this.instanceModelFn_ = | 15714 this.instanceModelFn_ = |
15786 this.getDelegateFn(delegate && delegate.prepareInstanceModel); | 15715 this.getDelegateFn(delegate && delegate.prepareInstanceModel); |
15787 } | 15716 } |
15788 | 15717 |
15789 if (this.instancePositionChangedFn_ === undefined) { | 15718 if (this.instancePositionChangedFn_ === undefined) { |
15790 this.instancePositionChangedFn_ = | 15719 this.instancePositionChangedFn_ = |
15791 this.getDelegateFn(delegate && | 15720 this.getDelegateFn(delegate && |
15792 delegate.prepareInstancePositionChanged); | 15721 delegate.prepareInstancePositionChanged); |
15793 } | 15722 } |
15794 | 15723 |
15795 // Instance Removals | |
15796 var instanceCache = new Map; | 15724 var instanceCache = new Map; |
15797 var removeDelta = 0; | 15725 var removeDelta = 0; |
15798 for (var i = 0; i < splices.length; i++) { | 15726 splices.forEach(function(splice) { |
15799 var splice = splices[i]; | 15727 splice.removed.forEach(function(model) { |
15800 var removed = splice.removed; | 15728 var instanceNodes = |
15801 for (var j = 0; j < removed.length; j++) { | 15729 this.extractInstanceAt(splice.index + removeDelta); |
15802 var model = removed[j]; | 15730 instanceCache.set(model, instanceNodes); |
15803 var instance = this.extractInstanceAt(splice.index + removeDelta); | 15731 }, this); |
15804 if (instance !== emptyInstance) { | |
15805 instanceCache.set(model, instance); | |
15806 } | |
15807 } | |
15808 | 15732 |
15809 removeDelta -= splice.addedCount; | 15733 removeDelta -= splice.addedCount; |
15810 } | 15734 }, this); |
15811 | 15735 |
15812 // Instance Insertions | 15736 splices.forEach(function(splice) { |
15813 for (var i = 0; i < splices.length; i++) { | |
15814 var splice = splices[i]; | |
15815 var addIndex = splice.index; | 15737 var addIndex = splice.index; |
15816 for (; addIndex < splice.index + splice.addedCount; addIndex++) { | 15738 for (; addIndex < splice.index + splice.addedCount; addIndex++) { |
15817 var model = this.iteratedValue[addIndex]; | 15739 var model = this.iteratedValue[addIndex]; |
15818 var instance = instanceCache.get(model); | 15740 var fragment = undefined; |
15819 if (instance) { | 15741 var instanceNodes = instanceCache.get(model); |
| 15742 var instanceBindings; |
| 15743 if (instanceNodes) { |
15820 instanceCache.delete(model); | 15744 instanceCache.delete(model); |
| 15745 instanceBindings = instanceNodes.instanceBindings; |
15821 } else { | 15746 } else { |
15822 if (this.instanceModelFn_) { | 15747 instanceBindings = []; |
| 15748 if (this.instanceModelFn_) |
15823 model = this.instanceModelFn_(model); | 15749 model = this.instanceModelFn_(model); |
15824 } | |
15825 | 15750 |
15826 if (model === undefined) { | 15751 if (model !== undefined) { |
15827 instance = emptyInstance; | 15752 fragment = template.createInstance(model, undefined, delegate, |
15828 } else { | 15753 instanceBindings); |
15829 instance = template.createInstance(model, undefined, delegate); | |
15830 } | 15754 } |
15831 } | 15755 } |
15832 | 15756 |
15833 this.insertInstanceAt(addIndex, instance); | 15757 this.insertInstanceAt(addIndex, fragment, instanceNodes, |
| 15758 instanceBindings); |
15834 } | 15759 } |
15835 } | 15760 }, this); |
15836 | 15761 |
15837 instanceCache.forEach(function(instance) { | 15762 instanceCache.forEach(function(instanceNodes) { |
15838 this.closeInstanceBindings(instance); | 15763 this.closeInstanceBindings(instanceNodes.instanceBindings); |
15839 }, this); | 15764 }, this); |
15840 | 15765 |
15841 if (this.instancePositionChangedFn_) | 15766 if (this.instancePositionChangedFn_) |
15842 this.reportInstancesMoved(splices); | 15767 this.reportInstancesMoved(splices); |
15843 }, | 15768 }, |
15844 | 15769 |
15845 reportInstanceMoved: function(index) { | 15770 reportInstanceMoved: function(index) { |
15846 var instance = this.instances[index]; | 15771 var previousTerminator = this.getTerminatorAt(index - 1); |
15847 if (instance === emptyInstance) | 15772 var terminator = this.getTerminatorAt(index); |
15848 return; | 15773 if (previousTerminator === terminator) |
| 15774 return; // instance has zero nodes. |
15849 | 15775 |
15850 this.instancePositionChangedFn_(instance.templateInstance_, index); | 15776 // We must use the first node of the instance, because any subsequent |
| 15777 // nodes may have been generated by sub-templates. |
| 15778 // TODO(rafaelw): This is brittle WRT instance mutation -- e.g. if the |
| 15779 // first node was removed by script. |
| 15780 var templateInstance = previousTerminator.nextSibling.templateInstance; |
| 15781 this.instancePositionChangedFn_(templateInstance, index); |
15851 }, | 15782 }, |
15852 | 15783 |
15853 reportInstancesMoved: function(splices) { | 15784 reportInstancesMoved: function(splices) { |
15854 var index = 0; | 15785 var index = 0; |
15855 var offset = 0; | 15786 var offset = 0; |
15856 for (var i = 0; i < splices.length; i++) { | 15787 for (var i = 0; i < splices.length; i++) { |
15857 var splice = splices[i]; | 15788 var splice = splices[i]; |
15858 if (offset != 0) { | 15789 if (offset != 0) { |
15859 while (index < splice.index) { | 15790 while (index < splice.index) { |
15860 this.reportInstanceMoved(index); | 15791 this.reportInstanceMoved(index); |
15861 index++; | 15792 index++; |
15862 } | 15793 } |
15863 } else { | 15794 } else { |
15864 index = splice.index; | 15795 index = splice.index; |
15865 } | 15796 } |
15866 | 15797 |
15867 while (index < splice.index + splice.addedCount) { | 15798 while (index < splice.index + splice.addedCount) { |
15868 this.reportInstanceMoved(index); | 15799 this.reportInstanceMoved(index); |
15869 index++; | 15800 index++; |
15870 } | 15801 } |
15871 | 15802 |
15872 offset += splice.addedCount - splice.removed.length; | 15803 offset += splice.addedCount - splice.removed.length; |
15873 } | 15804 } |
15874 | 15805 |
15875 if (offset == 0) | 15806 if (offset == 0) |
15876 return; | 15807 return; |
15877 | 15808 |
15878 var length = this.instances.length; | 15809 var length = this.terminators.length / 2; |
15879 while (index < length) { | 15810 while (index < length) { |
15880 this.reportInstanceMoved(index); | 15811 this.reportInstanceMoved(index); |
15881 index++; | 15812 index++; |
15882 } | 15813 } |
15883 }, | 15814 }, |
15884 | 15815 |
15885 closeInstanceBindings: function(instance) { | 15816 closeInstanceBindings: function(instanceBindings) { |
15886 var bindings = instance.bindings_; | 15817 for (var i = 0; i < instanceBindings.length; i++) { |
15887 for (var i = 0; i < bindings.length; i++) { | 15818 instanceBindings[i].close(); |
15888 bindings[i].close(); | |
15889 } | 15819 } |
15890 }, | 15820 }, |
15891 | 15821 |
15892 unobserve: function() { | 15822 unobserve: function() { |
15893 if (!this.arrayObserver) | 15823 if (!this.arrayObserver) |
15894 return; | 15824 return; |
15895 | 15825 |
15896 this.arrayObserver.close(); | 15826 this.arrayObserver.close(); |
15897 this.arrayObserver = undefined; | 15827 this.arrayObserver = undefined; |
15898 }, | 15828 }, |
15899 | 15829 |
15900 close: function() { | 15830 close: function() { |
15901 if (this.closed) | 15831 if (this.closed) |
15902 return; | 15832 return; |
15903 this.unobserve(); | 15833 this.unobserve(); |
15904 for (var i = 0; i < this.instances.length; i++) { | 15834 for (var i = 1; i < this.terminators.length; i += 2) { |
15905 this.closeInstanceBindings(this.instances[i]); | 15835 this.closeInstanceBindings(this.terminators[i]); |
15906 } | 15836 } |
15907 | 15837 |
15908 this.instances.length = 0; | 15838 this.terminators.length = 0; |
15909 this.closeDeps(); | 15839 this.closeDeps(); |
15910 this.templateElement_.iterator_ = undefined; | 15840 this.templateElement_.iterator_ = undefined; |
15911 this.closed = true; | 15841 this.closed = true; |
15912 } | 15842 } |
15913 }; | 15843 }; |
15914 | 15844 |
15915 // Polyfill-specific API. | 15845 // Polyfill-specific API. |
15916 HTMLTemplateElement.forAllTemplatesFrom_ = forAllTemplatesFrom; | 15846 HTMLTemplateElement.forAllTemplatesFrom_ = forAllTemplatesFrom; |
15917 })(this); | 15847 })(this); |
15918 | 15848 |
(...skipping 1028 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16947 }; | 16877 }; |
16948 | 16878 |
16949 return parseTopLevel(); | 16879 return parseTopLevel(); |
16950 } | 16880 } |
16951 | 16881 |
16952 global.esprima = { | 16882 global.esprima = { |
16953 parse: parse | 16883 parse: parse |
16954 }; | 16884 }; |
16955 })(this); | 16885 })(this); |
16956 | 16886 |
16957 // Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | 16887 // Copyright 2013 Google Inc. |
16958 // This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt | 16888 // |
16959 // The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt | 16889 // Licensed under the Apache License, Version 2.0 (the "License"); |
16960 // The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt | 16890 // you may not use this file except in compliance with the License. |
16961 // Code distributed by Google as part of the polymer project is also | 16891 // You may obtain a copy of the License at |
16962 // subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt | 16892 // |
| 16893 // http://www.apache.org/licenses/LICENSE-2.0 |
| 16894 // |
| 16895 // Unless required by applicable law or agreed to in writing, software |
| 16896 // distributed under the License is distributed on an "AS IS" BASIS, |
| 16897 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 16898 // See the License for the specific language governing permissions and |
| 16899 // limitations under the License. |
16963 | 16900 |
16964 (function (global) { | 16901 (function (global) { |
16965 'use strict'; | 16902 'use strict'; |
16966 | 16903 |
16967 // JScript does not have __proto__. We wrap all object literals with | 16904 // JScript does not have __proto__. We wrap all object literals with |
16968 // createObject which uses Object.create, Object.defineProperty and | 16905 // createObject which uses Object.create, Object.defineProperty and |
16969 // Object.getOwnPropertyDescriptor to create a new object that does the exact | 16906 // Object.getOwnPropertyDescriptor to create a new object that does the exact |
16970 // same thing. The main downside to this solution is that we have to extract | 16907 // same thing. The main downside to this solution is that we have to extract |
16971 // all those property descriptors for IE. | 16908 // all those property descriptors for IE. |
16972 var createObject = ('__proto__' in {}) ? | 16909 var createObject = ('__proto__' in {}) ? |
(...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
17379 this.filters = delegate.filters; | 17316 this.filters = delegate.filters; |
17380 this.dynamicDeps = delegate.dynamicDeps; | 17317 this.dynamicDeps = delegate.dynamicDeps; |
17381 } | 17318 } |
17382 | 17319 |
17383 Expression.prototype = { | 17320 Expression.prototype = { |
17384 getBinding: function(model, filterRegistry, oneTime) { | 17321 getBinding: function(model, filterRegistry, oneTime) { |
17385 if (oneTime) | 17322 if (oneTime) |
17386 return this.getValue(model, undefined, filterRegistry); | 17323 return this.getValue(model, undefined, filterRegistry); |
17387 | 17324 |
17388 var observer = new CompoundObserver(); | 17325 var observer = new CompoundObserver(); |
17389 // captures deps. | 17326 this.getValue(model, observer, filterRegistry); // captures deps. |
17390 var firstValue = this.getValue(model, observer, filterRegistry); | |
17391 var firstTime = true; | |
17392 var self = this; | 17327 var self = this; |
17393 | 17328 |
17394 function valueFn() { | 17329 function valueFn() { |
17395 // deps cannot have changed on first value retrieval. | |
17396 if (firstTime) { | |
17397 firstTime = false; | |
17398 return firstValue; | |
17399 } | |
17400 | |
17401 if (self.dynamicDeps) | 17330 if (self.dynamicDeps) |
17402 observer.startReset(); | 17331 observer.startReset(); |
17403 | 17332 |
17404 var value = self.getValue(model, | 17333 var value = self.getValue(model, |
17405 self.dynamicDeps ? observer : undefined, | 17334 self.dynamicDeps ? observer : undefined, |
17406 filterRegistry); | 17335 filterRegistry); |
17407 if (self.dynamicDeps) | 17336 if (self.dynamicDeps) |
17408 observer.finishReset(); | 17337 observer.finishReset(); |
17409 | 17338 |
17410 return value; | 17339 return value; |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
17534 return { | 17463 return { |
17535 open: bindingValue, | 17464 open: bindingValue, |
17536 discardChanges: bindingValue, | 17465 discardChanges: bindingValue, |
17537 close: function() { | 17466 close: function() { |
17538 node.removeEventListener(eventType, handler); | 17467 node.removeEventListener(eventType, handler); |
17539 } | 17468 } |
17540 }; | 17469 }; |
17541 } | 17470 } |
17542 } | 17471 } |
17543 | 17472 |
17544 function isLiteralExpression(pathString) { | |
17545 switch (pathString) { | |
17546 case '': | |
17547 return false; | |
17548 | |
17549 case 'false': | |
17550 case 'null': | |
17551 case 'true': | |
17552 return true; | |
17553 } | |
17554 | |
17555 if (!isNaN(Number(pathString))) | |
17556 return true; | |
17557 | |
17558 return false; | |
17559 }; | |
17560 | |
17561 function PolymerExpressions() {} | 17473 function PolymerExpressions() {} |
17562 | 17474 |
17563 PolymerExpressions.prototype = { | 17475 PolymerExpressions.prototype = { |
17564 // "built-in" filters | 17476 // "built-in" filters |
17565 styleObject: function(value) { | 17477 styleObject: function(value) { |
17566 var parts = []; | 17478 var parts = []; |
17567 for (var key in value) { | 17479 for (var key in value) { |
17568 parts.push(convertStylePropertyName(key) + ': ' + value[key]); | 17480 parts.push(convertStylePropertyName(key) + ': ' + value[key]); |
17569 } | 17481 } |
17570 return parts.join('; '); | 17482 return parts.join('; '); |
(...skipping 23 matching lines...) Expand all Loading... |
17594 var path = Path.get(pathString); | 17506 var path = Path.get(pathString); |
17595 if (isEventHandler(name)) { | 17507 if (isEventHandler(name)) { |
17596 if (!path.valid) { | 17508 if (!path.valid) { |
17597 console.error('on-* bindings must be simple path expressions'); | 17509 console.error('on-* bindings must be simple path expressions'); |
17598 return; | 17510 return; |
17599 } | 17511 } |
17600 | 17512 |
17601 return prepareEventBinding(path, name, this); | 17513 return prepareEventBinding(path, name, this); |
17602 } | 17514 } |
17603 | 17515 |
17604 if (!isLiteralExpression(pathString) && path.valid) { | 17516 if (path.valid) { |
17605 if (path.length == 1) { | 17517 if (path.length == 1) { |
17606 return function(model, node, oneTime) { | 17518 return function(model, node, oneTime) { |
17607 if (oneTime) | 17519 if (oneTime) |
17608 return path.getValueFrom(model); | 17520 return path.getValueFrom(model); |
17609 | 17521 |
17610 var scope = findScope(model, path[0]); | 17522 var scope = findScope(model, path[0]); |
17611 return new PathObserver(scope, path); | 17523 return new PathObserver(scope, path); |
17612 }; | 17524 } |
17613 } | 17525 } |
| 17526 |
17614 return; // bail out early if pathString is simple path. | 17527 return; // bail out early if pathString is simple path. |
17615 } | 17528 } |
17616 | 17529 |
17617 return prepareBinding(pathString, name, node, this); | 17530 return prepareBinding(pathString, name, node, this); |
17618 }, | 17531 }, |
17619 | 17532 |
17620 prepareInstanceModel: function(template) { | 17533 prepareInstanceModel: function(template) { |
17621 var scopeName = template.polymerExpressionScopeIdent_; | 17534 var scopeName = template.polymerExpressionScopeIdent_; |
17622 if (!scopeName) | 17535 if (!scopeName) |
17623 return; | 17536 return; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
17666 scope.endOfMicrotask(function() { | 17579 scope.endOfMicrotask(function() { |
17667 flushing = false; | 17580 flushing = false; |
17668 logFlags.data && console.group('Platform.flush()'); | 17581 logFlags.data && console.group('Platform.flush()'); |
17669 scope.performMicrotaskCheckpoint(); | 17582 scope.performMicrotaskCheckpoint(); |
17670 logFlags.data && console.groupEnd(); | 17583 logFlags.data && console.groupEnd(); |
17671 }); | 17584 }); |
17672 } | 17585 } |
17673 }; | 17586 }; |
17674 | 17587 |
17675 // polling dirty checker | 17588 // polling dirty checker |
17676 // flush periodically if platform does not have object observe. | 17589 var FLUSH_POLL_INTERVAL = 125; |
17677 if (!Observer.hasObjectObserve) { | 17590 window.addEventListener('WebComponentsReady', function() { |
17678 var FLUSH_POLL_INTERVAL = 125; | 17591 flush(); |
17679 window.addEventListener('WebComponentsReady', function() { | 17592 // flush periodically if platform does not have object observe. |
17680 flush(); | 17593 if (!Observer.hasObjectObserve) { |
17681 scope.flushPoll = setInterval(flush, FLUSH_POLL_INTERVAL); | 17594 scope.flushPoll = setInterval(flush, FLUSH_POLL_INTERVAL); |
17682 }); | 17595 } |
17683 } else { | 17596 }); |
17684 // make flush a no-op when we have Object.observe | |
17685 flush = function() {}; | |
17686 } | |
17687 | 17597 |
17688 if (window.CustomElements && !CustomElements.useNative) { | 17598 if (window.CustomElements && !CustomElements.useNative) { |
17689 var originalImportNode = Document.prototype.importNode; | 17599 var originalImportNode = Document.prototype.importNode; |
17690 Document.prototype.importNode = function(node, deep) { | 17600 Document.prototype.importNode = function(node, deep) { |
17691 var imported = originalImportNode.call(this, node, deep); | 17601 var imported = originalImportNode.call(this, node, deep); |
17692 CustomElements.upgradeAll(imported); | 17602 CustomElements.upgradeAll(imported); |
17693 return imported; | 17603 return imported; |
17694 } | 17604 } |
17695 } | 17605 } |
17696 | 17606 |
17697 // exports | 17607 // exports |
17698 scope.flush = flush; | 17608 scope.flush = flush; |
17699 | 17609 |
17700 })(window.Platform); | 17610 })(window.Platform); |
17701 | 17611 |
17702 | 17612 |
17703 //# sourceMappingURL=platform.concat.js.map | 17613 //# sourceMappingURL=platform.concat.js.map |
OLD | NEW |