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

Side by Side Diff: pkg/web_components/lib/platform.concat.js

Issue 221653004: "Reverting 34633" (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/web_components/lib/platform.js ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « pkg/web_components/lib/platform.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698