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

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

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

Powered by Google App Engine
This is Rietveld 408576698