| OLD | NEW |
| 1 // Copyright (c) 2012 The Polymer Authors. All rights reserved. | 1 // Copyright (c) 2012 The Polymer Authors. All rights reserved. |
| 2 // | 2 // |
| 3 // Redistribution and use in source and binary forms, with or without | 3 // Redistribution and use in source and binary forms, with or without |
| 4 // modification, are permitted provided that the following conditions are | 4 // modification, are permitted provided that the following conditions are |
| 5 // met: | 5 // met: |
| 6 // | 6 // |
| 7 // * Redistributions of source code must retain the above copyright | 7 // * Redistributions of source code must retain the above copyright |
| 8 // notice, this list of conditions and the following disclaimer. | 8 // notice, this list of conditions and the following disclaimer. |
| 9 // * Redistributions in binary form must reproduce the above | 9 // * Redistributions in binary form must reproduce the above |
| 10 // copyright notice, this list of conditions and the following disclaimer | 10 // copyright notice, this list of conditions and the following disclaimer |
| 11 // in the documentation and/or other materials provided with the | 11 // in the documentation and/or other materials provided with the |
| 12 // distribution. | 12 // distribution. |
| 13 // * Neither the name of Google Inc. nor the names of its | 13 // * Neither the name of Google Inc. nor the names of its |
| 14 // contributors may be used to endorse or promote products derived from | 14 // contributors may be used to endorse or promote products derived from |
| 15 // this software without specific prior written permission. | 15 // this software without specific prior written permission. |
| 16 // | 16 // |
| 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 28 window.CustomElements = {flags:{}}; | 28 if (typeof WeakMap === 'undefined') { |
| 29 // SideTable is a weak map where possible. If WeakMap is not available the | |
| 30 // association is stored as an expando property. | |
| 31 var SideTable; | |
| 32 // TODO(arv): WeakMap does not allow for Node etc to be keys in Firefox | |
| 33 if (typeof WeakMap !== 'undefined' && navigator.userAgent.indexOf('Firefox/') <
0) { | |
| 34 SideTable = WeakMap; | |
| 35 } else { | |
| 36 (function() { | 29 (function() { |
| 37 var defineProperty = Object.defineProperty; | 30 var defineProperty = Object.defineProperty; |
| 38 var counter = Date.now() % 1e9; | 31 var counter = Date.now() % 1e9; |
| 39 | 32 |
| 40 SideTable = function() { | 33 var WeakMap = function() { |
| 41 this.name = '__st' + (Math.random() * 1e9 >>> 0) + (counter++ + '__'); | 34 this.name = '__st' + (Math.random() * 1e9 >>> 0) + (counter++ + '__'); |
| 42 }; | 35 }; |
| 43 | 36 |
| 44 SideTable.prototype = { | 37 WeakMap.prototype = { |
| 45 set: function(key, value) { | 38 set: function(key, value) { |
| 46 var entry = key[this.name]; | 39 var entry = key[this.name]; |
| 47 if (entry && entry[0] === key) | 40 if (entry && entry[0] === key) |
| 48 entry[1] = value; | 41 entry[1] = value; |
| 49 else | 42 else |
| 50 defineProperty(key, this.name, {value: [key, value], writable: true}); | 43 defineProperty(key, this.name, {value: [key, value], writable: true}); |
| 51 }, | 44 }, |
| 52 get: function(key) { | 45 get: function(key) { |
| 53 var entry; | 46 var entry; |
| 54 return (entry = key[this.name]) && entry[0] === key ? | 47 return (entry = key[this.name]) && entry[0] === key ? |
| 55 entry[1] : undefined; | 48 entry[1] : undefined; |
| 56 }, | 49 }, |
| 57 delete: function(key) { | 50 delete: function(key) { |
| 58 this.set(key, undefined); | 51 this.set(key, undefined); |
| 59 } | 52 } |
| 60 } | 53 }; |
| 54 |
| 55 window.WeakMap = WeakMap; |
| 61 })(); | 56 })(); |
| 62 } | 57 } |
| 63 | 58 |
| 64 (function(global) { | 59 (function(global) { |
| 65 | 60 |
| 66 var registrationsTable = new SideTable(); | 61 var registrationsTable = new WeakMap(); |
| 67 | 62 |
| 68 // We use setImmediate or postMessage for our future callback. | 63 // We use setImmediate or postMessage for our future callback. |
| 69 var setImmediate = window.msSetImmediate; | 64 var setImmediate = window.msSetImmediate; |
| 70 | 65 |
| 71 // Use post message to emulate setImmediate. | 66 // Use post message to emulate setImmediate. |
| 72 if (!setImmediate) { | 67 if (!setImmediate) { |
| 73 var setImmediateQueue = []; | 68 var setImmediateQueue = []; |
| 74 var sentinel = String(Math.random()); | 69 var sentinel = String(Math.random()); |
| 75 window.addEventListener('message', function(e) { | 70 window.addEventListener('message', function(e) { |
| 76 if (e.data === sentinel) { | 71 if (e.data === sentinel) { |
| (...skipping 512 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 589 }); | 584 }); |
| 590 | 585 |
| 591 } | 586 } |
| 592 | 587 |
| 593 clearRecords(); | 588 clearRecords(); |
| 594 } | 589 } |
| 595 }; | 590 }; |
| 596 | 591 |
| 597 global.JsMutationObserver = JsMutationObserver; | 592 global.JsMutationObserver = JsMutationObserver; |
| 598 | 593 |
| 594 // Provide unprefixed MutationObserver with native or JS implementation |
| 595 if (!global.MutationObserver && global.WebKitMutationObserver) |
| 596 global.MutationObserver = global.WebKitMutationObserver; |
| 597 |
| 598 if (!global.MutationObserver) |
| 599 global.MutationObserver = JsMutationObserver; |
| 600 |
| 601 |
| 599 })(this); | 602 })(this); |
| 600 | 603 |
| 601 if (!window.MutationObserver) { | 604 window.CustomElements = window.CustomElements || {flags:{}}; |
| 602 window.MutationObserver = | |
| 603 window.WebKitMutationObserver || | |
| 604 window.JsMutationObserver; | |
| 605 if (!MutationObserver) { | |
| 606 throw new Error("no mutation observer support"); | |
| 607 } | |
| 608 } | |
| 609 | |
| 610 (function(scope){ | 605 (function(scope){ |
| 611 | 606 |
| 612 var logFlags = window.logFlags || {}; | 607 var logFlags = window.logFlags || {}; |
| 613 | 608 |
| 614 // walk the subtree rooted at node, applying 'find(element, data)' function | 609 // walk the subtree rooted at node, applying 'find(element, data)' function |
| 615 // to each element | 610 // to each element |
| 616 // if 'find' returns true for 'element', do not search element's subtree | 611 // if 'find' returns true for 'element', do not search element's subtree |
| 617 function findAll(node, find, data) { | 612 function findAll(node, find, data) { |
| 618 var e = node.firstElementChild; | 613 var e = node.firstElementChild; |
| 619 if (!e) { | 614 if (!e) { |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 775 } | 770 } |
| 776 } | 771 } |
| 777 | 772 |
| 778 function removedNode(node) { | 773 function removedNode(node) { |
| 779 removed(node); | 774 removed(node); |
| 780 forSubtree(node, function(e) { | 775 forSubtree(node, function(e) { |
| 781 removed(e); | 776 removed(e); |
| 782 }); | 777 }); |
| 783 } | 778 } |
| 784 | 779 |
| 785 | |
| 786 function removed(element) { | 780 function removed(element) { |
| 787 if (hasPolyfillMutations) { | 781 if (hasPolyfillMutations) { |
| 788 deferMutation(function() { | 782 deferMutation(function() { |
| 789 _removed(element); | 783 _removed(element); |
| 790 }); | 784 }); |
| 791 } else { | 785 } else { |
| 792 _removed(element); | 786 _removed(element); |
| 793 } | 787 } |
| 794 } | 788 } |
| 795 | 789 |
| 796 function removed(element) { | 790 function _removed(element) { |
| 797 // TODO(sjmiles): temporary: do work on all custom elements so we can track | 791 // TODO(sjmiles): temporary: do work on all custom elements so we can track |
| 798 // behavior even when callbacks not defined | 792 // behavior even when callbacks not defined |
| 799 if (element.leftViewCallback || (element.__upgraded__ && logFlags.dom)) { | 793 if (element.leftViewCallback || (element.__upgraded__ && logFlags.dom)) { |
| 800 logFlags.dom && console.log('removed:', element.localName); | 794 logFlags.dom && console.log('removed:', element.localName); |
| 801 if (!inDocument(element)) { | 795 if (!inDocument(element)) { |
| 802 element.__inserted = (element.__inserted || 0) - 1; | 796 element.__inserted = (element.__inserted || 0) - 1; |
| 803 // if we are in a 'inserted' state, bluntly adjust to an 'removed' state | 797 // if we are in a 'inserted' state, bluntly adjust to an 'removed' state |
| 804 if (element.__inserted > 0) { | 798 if (element.__inserted > 0) { |
| 805 element.__inserted = 0; | 799 element.__inserted = 0; |
| 806 } | 800 } |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 839 } | 833 } |
| 840 } | 834 } |
| 841 | 835 |
| 842 function watchRoot(root) { | 836 function watchRoot(root) { |
| 843 if (!root.__watched) { | 837 if (!root.__watched) { |
| 844 observe(root); | 838 observe(root); |
| 845 root.__watched = true; | 839 root.__watched = true; |
| 846 } | 840 } |
| 847 } | 841 } |
| 848 | 842 |
| 849 function filter(inNode) { | |
| 850 switch (inNode.localName) { | |
| 851 case 'style': | |
| 852 case 'script': | |
| 853 case 'template': | |
| 854 case undefined: | |
| 855 return true; | |
| 856 } | |
| 857 } | |
| 858 | |
| 859 function handler(mutations) { | 843 function handler(mutations) { |
| 860 // | 844 // |
| 861 if (logFlags.dom) { | 845 if (logFlags.dom) { |
| 862 var mx = mutations[0]; | 846 var mx = mutations[0]; |
| 863 if (mx && mx.type === 'childList' && mx.addedNodes) { | 847 if (mx && mx.type === 'childList' && mx.addedNodes) { |
| 864 if (mx.addedNodes) { | 848 if (mx.addedNodes) { |
| 865 var d = mx.addedNodes[0]; | 849 var d = mx.addedNodes[0]; |
| 866 while (d && d !== document && !d.host) { | 850 while (d && d !== document && !d.host) { |
| 867 d = d.parentNode; | 851 d = d.parentNode; |
| 868 } | 852 } |
| 869 var u = d && (d.URL || d._URL || (d.host && d.host.localName)) || ''; | 853 var u = d && (d.URL || d._URL || (d.host && d.host.localName)) || ''; |
| 870 u = u.split('/?').shift().split('/').pop(); | 854 u = u.split('/?').shift().split('/').pop(); |
| 871 } | 855 } |
| 872 } | 856 } |
| 873 console.group('mutations (%d) [%s]', mutations.length, u || ''); | 857 console.group('mutations (%d) [%s]', mutations.length, u || ''); |
| 874 } | 858 } |
| 875 // | 859 // |
| 876 mutations.forEach(function(mx) { | 860 mutations.forEach(function(mx) { |
| 877 //logFlags.dom && console.group('mutation'); | 861 //logFlags.dom && console.group('mutation'); |
| 878 if (mx.type === 'childList') { | 862 if (mx.type === 'childList') { |
| 879 forEach(mx.addedNodes, function(n) { | 863 forEach(mx.addedNodes, function(n) { |
| 880 //logFlags.dom && console.log(n.localName); | 864 //logFlags.dom && console.log(n.localName); |
| 881 if (filter(n)) { | 865 if (!n.localName) { |
| 882 return; | 866 return; |
| 883 } | 867 } |
| 884 // nodes added may need lifecycle management | 868 // nodes added may need lifecycle management |
| 885 addedNode(n); | 869 addedNode(n); |
| 886 }); | 870 }); |
| 887 // removed nodes may need lifecycle management | 871 // removed nodes may need lifecycle management |
| 888 forEach(mx.removedNodes, function(n) { | 872 forEach(mx.removedNodes, function(n) { |
| 889 //logFlags.dom && console.log(n.localName); | 873 //logFlags.dom && console.log(n.localName); |
| 890 if (filter(n)) { | 874 if (!n.localName) { |
| 891 return; | 875 return; |
| 892 } | 876 } |
| 893 removedNode(n); | 877 removedNode(n); |
| 894 }); | 878 }); |
| 895 } | 879 } |
| 896 //logFlags.dom && console.groupEnd(); | 880 //logFlags.dom && console.groupEnd(); |
| 897 }); | 881 }); |
| 898 logFlags.dom && console.groupEnd(); | 882 logFlags.dom && console.groupEnd(); |
| 899 }; | 883 }; |
| 900 | 884 |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1024 if (!name) { | 1008 if (!name) { |
| 1025 // TODO(sjmiles): replace with more appropriate error (EricB can probably | 1009 // TODO(sjmiles): replace with more appropriate error (EricB can probably |
| 1026 // offer guidance) | 1010 // offer guidance) |
| 1027 throw new Error('document.register: first argument `name` must not be empt
y'); | 1011 throw new Error('document.register: first argument `name` must not be empt
y'); |
| 1028 } | 1012 } |
| 1029 if (name.indexOf('-') < 0) { | 1013 if (name.indexOf('-') < 0) { |
| 1030 // TODO(sjmiles): replace with more appropriate error (EricB can probably | 1014 // TODO(sjmiles): replace with more appropriate error (EricB can probably |
| 1031 // offer guidance) | 1015 // offer guidance) |
| 1032 throw new Error('document.register: first argument (\'name\') must contain
a dash (\'-\'). Argument provided was \'' + String(name) + '\'.'); | 1016 throw new Error('document.register: first argument (\'name\') must contain
a dash (\'-\'). Argument provided was \'' + String(name) + '\'.'); |
| 1033 } | 1017 } |
| 1034 // record name | 1018 // elements may only be registered once |
| 1035 definition.name = name; | 1019 if (getRegisteredDefinition(name)) { |
| 1020 throw new Error('DuplicateDefinitionError: a type with name \'' + String(n
ame) + '\' is already registered'); |
| 1021 } |
| 1036 // must have a prototype, default to an extension of HTMLElement | 1022 // must have a prototype, default to an extension of HTMLElement |
| 1037 // TODO(sjmiles): probably should throw if no prototype, check spec | 1023 // TODO(sjmiles): probably should throw if no prototype, check spec |
| 1038 if (!definition.prototype) { | 1024 if (!definition.prototype) { |
| 1039 // TODO(sjmiles): replace with more appropriate error (EricB can probably | 1025 // TODO(sjmiles): replace with more appropriate error (EricB can probably |
| 1040 // offer guidance) | 1026 // offer guidance) |
| 1041 throw new Error('Options missing required prototype property'); | 1027 throw new Error('Options missing required prototype property'); |
| 1042 } | 1028 } |
| 1029 // record name |
| 1030 definition.name = name.toLowerCase(); |
| 1043 // ensure a lifecycle object so we don't have to null test it | 1031 // ensure a lifecycle object so we don't have to null test it |
| 1044 definition.lifecycle = definition.lifecycle || {}; | 1032 definition.lifecycle = definition.lifecycle || {}; |
| 1045 // build a list of ancestral custom elements (for native base detection) | 1033 // build a list of ancestral custom elements (for native base detection) |
| 1046 // TODO(sjmiles): we used to need to store this, but current code only | 1034 // TODO(sjmiles): we used to need to store this, but current code only |
| 1047 // uses it in 'resolveTagName': it should probably be inlined | 1035 // uses it in 'resolveTagName': it should probably be inlined |
| 1048 definition.ancestry = ancestry(definition.extends); | 1036 definition.ancestry = ancestry(definition.extends); |
| 1049 // extensions of native specializations of HTMLElement require localName | 1037 // extensions of native specializations of HTMLElement require localName |
| 1050 // to remain native, and use secondary 'is' specifier for extension type | 1038 // to remain native, and use secondary 'is' specifier for extension type |
| 1051 resolveTagName(definition); | 1039 resolveTagName(definition); |
| 1052 // some platforms require modifications to the user-supplied prototype | 1040 // some platforms require modifications to the user-supplied prototype |
| 1053 // chain | 1041 // chain |
| 1054 resolvePrototypeChain(definition); | 1042 resolvePrototypeChain(definition); |
| 1055 // overrides to implement attributeChanged callback | 1043 // overrides to implement attributeChanged callback |
| 1056 overrideAttributeApi(definition.prototype); | 1044 overrideAttributeApi(definition.prototype); |
| 1057 // 7.1.5: Register the DEFINITION with DOCUMENT | 1045 // 7.1.5: Register the DEFINITION with DOCUMENT |
| 1058 registerDefinition(name, definition); | 1046 registerDefinition(definition.name, definition); |
| 1059 // 7.1.7. Run custom element constructor generation algorithm with PROTOTYPE | 1047 // 7.1.7. Run custom element constructor generation algorithm with PROTOTYPE |
| 1060 // 7.1.8. Return the output of the previous step. | 1048 // 7.1.8. Return the output of the previous step. |
| 1061 definition.ctor = generateConstructor(definition); | 1049 definition.ctor = generateConstructor(definition); |
| 1062 definition.ctor.prototype = definition.prototype; | 1050 definition.ctor.prototype = definition.prototype; |
| 1063 // force our .constructor to be our actual constructor | 1051 // force our .constructor to be our actual constructor |
| 1064 definition.prototype.constructor = definition.ctor; | 1052 definition.prototype.constructor = definition.ctor; |
| 1065 // if initial parsing is complete | 1053 // if initial parsing is complete |
| 1066 if (scope.ready || scope.performedInitialDocumentUpgrade) { | 1054 if (scope.ready || scope.performedInitialDocumentUpgrade) { |
| 1067 // upgrade any pre-existing nodes of this type | 1055 // upgrade any pre-existing nodes of this type |
| 1068 scope.upgradeAll(document); | 1056 scope.upgradeAll(document); |
| 1069 } | 1057 } |
| 1070 return definition.ctor; | 1058 return definition.ctor; |
| 1071 } | 1059 } |
| 1072 | 1060 |
| 1073 function ancestry(extnds) { | 1061 function ancestry(extnds) { |
| 1074 var extendee = registry[extnds]; | 1062 var extendee = getRegisteredDefinition(extnds); |
| 1075 if (extendee) { | 1063 if (extendee) { |
| 1076 return ancestry(extendee.extends).concat([extendee]); | 1064 return ancestry(extendee.extends).concat([extendee]); |
| 1077 } | 1065 } |
| 1078 return []; | 1066 return []; |
| 1079 } | 1067 } |
| 1080 | 1068 |
| 1081 function resolveTagName(definition) { | 1069 function resolveTagName(definition) { |
| 1082 // if we are explicitly extending something, that thing is our | 1070 // if we are explicitly extending something, that thing is our |
| 1083 // baseTag, unless it represents a custom component | 1071 // baseTag, unless it represents a custom component |
| 1084 var baseTag = definition.extends; | 1072 var baseTag = definition.extends; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1132 // output is a valid DOM element with the proper wrapper in place. | 1120 // output is a valid DOM element with the proper wrapper in place. |
| 1133 // | 1121 // |
| 1134 return upgrade(domCreateElement(definition.tag), definition); | 1122 return upgrade(domCreateElement(definition.tag), definition); |
| 1135 } | 1123 } |
| 1136 | 1124 |
| 1137 function upgrade(element, definition) { | 1125 function upgrade(element, definition) { |
| 1138 // some definitions specify an 'is' attribute | 1126 // some definitions specify an 'is' attribute |
| 1139 if (definition.is) { | 1127 if (definition.is) { |
| 1140 element.setAttribute('is', definition.is); | 1128 element.setAttribute('is', definition.is); |
| 1141 } | 1129 } |
| 1130 // remove 'unresolved' attr, which is a standin for :unresolved. |
| 1131 element.removeAttribute('unresolved'); |
| 1142 // make 'element' implement definition.prototype | 1132 // make 'element' implement definition.prototype |
| 1143 implement(element, definition); | 1133 implement(element, definition); |
| 1144 // flag as upgraded | 1134 // flag as upgraded |
| 1145 element.__upgraded__ = true; | 1135 element.__upgraded__ = true; |
| 1146 // there should never be a shadow root on element at this point | 1136 // there should never be a shadow root on element at this point |
| 1147 // we require child nodes be upgraded before `created` | 1137 // we require child nodes be upgraded before `created` |
| 1148 scope.upgradeSubtree(element); | 1138 scope.upgradeSubtree(element); |
| 1149 // lifecycle management | 1139 // lifecycle management |
| 1150 created(element); | 1140 created(element); |
| 1151 // OUTPUT | 1141 // OUTPUT |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1169 // TODO(sjmiles): 'used' allows us to only copy the 'youngest' version of | 1159 // TODO(sjmiles): 'used' allows us to only copy the 'youngest' version of |
| 1170 // any property. This set should be precalculated. We also need to | 1160 // any property. This set should be precalculated. We also need to |
| 1171 // consider this for supporting 'super'. | 1161 // consider this for supporting 'super'. |
| 1172 var used = {}; | 1162 var used = {}; |
| 1173 // start with inSrc | 1163 // start with inSrc |
| 1174 var p = inSrc; | 1164 var p = inSrc; |
| 1175 // sometimes the default is HTMLUnknownElement.prototype instead of | 1165 // sometimes the default is HTMLUnknownElement.prototype instead of |
| 1176 // HTMLElement.prototype, so we add a test | 1166 // HTMLElement.prototype, so we add a test |
| 1177 // the idea is to avoid mixing in native prototypes, so adding | 1167 // the idea is to avoid mixing in native prototypes, so adding |
| 1178 // the second test is WLOG | 1168 // the second test is WLOG |
| 1179 while (p && p !== inNative && p !== HTMLUnknownElement.prototype) { | 1169 while (p !== inNative && p !== HTMLUnknownElement.prototype) { |
| 1180 var keys = Object.getOwnPropertyNames(p); | 1170 var keys = Object.getOwnPropertyNames(p); |
| 1181 for (var i=0, k; k=keys[i]; i++) { | 1171 for (var i=0, k; k=keys[i]; i++) { |
| 1182 if (!used[k]) { | 1172 if (!used[k]) { |
| 1183 Object.defineProperty(inTarget, k, | 1173 Object.defineProperty(inTarget, k, |
| 1184 Object.getOwnPropertyDescriptor(p, k)); | 1174 Object.getOwnPropertyDescriptor(p, k)); |
| 1185 used[k] = 1; | 1175 used[k] = 1; |
| 1186 } | 1176 } |
| 1187 } | 1177 } |
| 1188 p = Object.getPrototypeOf(p); | 1178 p = Object.getPrototypeOf(p); |
| 1189 } | 1179 } |
| 1190 } | 1180 } |
| 1191 | 1181 |
| 1192 function created(element) { | 1182 function created(element) { |
| 1193 // invoke createdCallback | 1183 // invoke createdCallback |
| 1194 if (element.createdCallback) { | 1184 if (element.createdCallback) { |
| 1195 element.createdCallback(); | 1185 element.createdCallback(); |
| 1196 } | 1186 } |
| 1197 } | 1187 } |
| 1198 | 1188 |
| 1199 // attribute watching | 1189 // attribute watching |
| 1200 | 1190 |
| 1201 function overrideAttributeApi(prototype) { | 1191 function overrideAttributeApi(prototype) { |
| 1202 // overrides to implement callbacks | 1192 // overrides to implement callbacks |
| 1203 // TODO(sjmiles): should support access via .attributes NamedNodeMap | 1193 // TODO(sjmiles): should support access via .attributes NamedNodeMap |
| 1204 // TODO(sjmiles): preserves user defined overrides, if any | 1194 // TODO(sjmiles): preserves user defined overrides, if any |
| 1195 if (prototype.setAttribute._polyfilled) { |
| 1196 return; |
| 1197 } |
| 1205 var setAttribute = prototype.setAttribute; | 1198 var setAttribute = prototype.setAttribute; |
| 1206 prototype.setAttribute = function(name, value) { | 1199 prototype.setAttribute = function(name, value) { |
| 1207 changeAttribute.call(this, name, value, setAttribute); | 1200 changeAttribute.call(this, name, value, setAttribute); |
| 1208 } | 1201 } |
| 1209 var removeAttribute = prototype.removeAttribute; | 1202 var removeAttribute = prototype.removeAttribute; |
| 1210 prototype.removeAttribute = function(name) { | 1203 prototype.removeAttribute = function(name) { |
| 1211 changeAttribute.call(this, name, null, removeAttribute); | 1204 changeAttribute.call(this, name, null, removeAttribute); |
| 1212 } | 1205 } |
| 1206 prototype.setAttribute._polyfilled = true; |
| 1213 } | 1207 } |
| 1214 | 1208 |
| 1209 // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/ |
| 1210 // index.html#dfn-attribute-changed-callback |
| 1215 function changeAttribute(name, value, operation) { | 1211 function changeAttribute(name, value, operation) { |
| 1216 var oldValue = this.getAttribute(name); | 1212 var oldValue = this.getAttribute(name); |
| 1217 operation.apply(this, arguments); | 1213 operation.apply(this, arguments); |
| 1214 var newValue = this.getAttribute(name); |
| 1218 if (this.attributeChangedCallback | 1215 if (this.attributeChangedCallback |
| 1219 && (this.getAttribute(name) !== oldValue)) { | 1216 && (newValue !== oldValue)) { |
| 1220 this.attributeChangedCallback(name, oldValue, value); | 1217 this.attributeChangedCallback(name, oldValue, newValue); |
| 1221 } | 1218 } |
| 1222 } | 1219 } |
| 1223 | 1220 |
| 1224 // element registry (maps tag names to definitions) | 1221 // element registry (maps tag names to definitions) |
| 1225 | 1222 |
| 1226 var registry = {}; | 1223 var registry = {}; |
| 1227 | 1224 |
| 1225 function getRegisteredDefinition(name) { |
| 1226 if (name) { |
| 1227 return registry[name.toLowerCase()]; |
| 1228 } |
| 1229 } |
| 1230 |
| 1228 function registerDefinition(name, definition) { | 1231 function registerDefinition(name, definition) { |
| 1229 if (registry[name]) { | 1232 if (registry[name]) { |
| 1230 throw new Error('Cannot register a tag more than once'); | 1233 throw new Error('a type with that name is already registered.'); |
| 1231 } | 1234 } |
| 1232 registry[name] = definition; | 1235 registry[name] = definition; |
| 1233 } | 1236 } |
| 1234 | 1237 |
| 1235 function generateConstructor(definition) { | 1238 function generateConstructor(definition) { |
| 1236 return function() { | 1239 return function() { |
| 1237 return instantiate(definition); | 1240 return instantiate(definition); |
| 1238 }; | 1241 }; |
| 1239 } | 1242 } |
| 1240 | 1243 |
| 1241 function createElement(tag, typeExtension) { | 1244 function createElement(tag, typeExtension) { |
| 1242 var definition = registry[typeExtension || tag]; | 1245 // TODO(sjmiles): ignore 'tag' when using 'typeExtension', we could |
| 1246 // error check it, or perhaps there should only ever be one argument |
| 1247 var definition = getRegisteredDefinition(typeExtension || tag); |
| 1243 if (definition) { | 1248 if (definition) { |
| 1244 if (tag == definition.tag && typeExtension == definition.is) { | 1249 if (tag == definition.tag && typeExtension == definition.is) { |
| 1245 return new definition.ctor(); | 1250 return new definition.ctor(); |
| 1246 } | 1251 } |
| 1247 // Handle empty string for type extension. | 1252 // Handle empty string for type extension. |
| 1248 if (!typeExtension && !definition.is) { | 1253 if (!typeExtension && !definition.is) { |
| 1249 return new definition.ctor(); | 1254 return new definition.ctor(); |
| 1250 } | 1255 } |
| 1251 } | 1256 } |
| 1252 | 1257 |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1370 && inElt.getAttribute('rel') === IMPORT_LINK_TYPE); | 1375 && inElt.getAttribute('rel') === IMPORT_LINK_TYPE); |
| 1371 } | 1376 } |
| 1372 | 1377 |
| 1373 var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach); | 1378 var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach); |
| 1374 | 1379 |
| 1375 // exports | 1380 // exports |
| 1376 | 1381 |
| 1377 CustomElements.parser = parser; | 1382 CustomElements.parser = parser; |
| 1378 | 1383 |
| 1379 })(); | 1384 })(); |
| 1380 (function(){ | 1385 (function(scope){ |
| 1381 | 1386 |
| 1382 // bootstrap parsing | 1387 // bootstrap parsing |
| 1383 function bootstrap() { | 1388 function bootstrap() { |
| 1384 // parse document | 1389 // parse document |
| 1385 CustomElements.parser.parse(document); | 1390 CustomElements.parser.parse(document); |
| 1386 // one more pass before register is 'live' | 1391 // one more pass before register is 'live' |
| 1387 CustomElements.upgradeDocument(document); | 1392 CustomElements.upgradeDocument(document); |
| 1388 CustomElements.performedInitialDocumentUpgrade = true; | 1393 CustomElements.performedInitialDocumentUpgrade = true; |
| 1389 // choose async | 1394 // choose async |
| 1390 var async = window.Platform && Platform.endOfMicrotask ? | 1395 var async = window.Platform && Platform.endOfMicrotask ? |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1402 // notify the system that we are bootstrapped | 1407 // notify the system that we are bootstrapped |
| 1403 document.body.dispatchEvent( | 1408 document.body.dispatchEvent( |
| 1404 new CustomEvent('WebComponentsReady', {bubbles: true}) | 1409 new CustomEvent('WebComponentsReady', {bubbles: true}) |
| 1405 ); | 1410 ); |
| 1406 }); | 1411 }); |
| 1407 } | 1412 } |
| 1408 | 1413 |
| 1409 // CustomEvent shim for IE | 1414 // CustomEvent shim for IE |
| 1410 if (typeof window.CustomEvent !== 'function') { | 1415 if (typeof window.CustomEvent !== 'function') { |
| 1411 window.CustomEvent = function(inType) { | 1416 window.CustomEvent = function(inType) { |
| 1412 var e = document.createEvent('HTMLEvents'); | 1417 var e = document.createEvent('HTMLEvents'); |
| 1413 e.initEvent(inType, true, true); | 1418 e.initEvent(inType, true, true); |
| 1414 return e; | 1419 return e; |
| 1415 }; | 1420 }; |
| 1416 } | 1421 } |
| 1417 | 1422 |
| 1418 if (document.readyState === 'complete') { | 1423 // When loading at readyState complete time (or via flag), boot custom elements |
| 1424 // immediately. |
| 1425 // If relevant, HTMLImports must already be loaded. |
| 1426 if (document.readyState === 'complete' || scope.flags.eager) { |
| 1419 bootstrap(); | 1427 bootstrap(); |
| 1428 // When loading at readyState interactive time, bootstrap only if HTMLImports |
| 1429 // are not pending. Also avoid IE as the semantics of this state are unreliable. |
| 1430 } else if (document.readyState === 'interactive' && !window.attachEvent && |
| 1431 (!window.HTMLImports || window.HTMLImports.ready)) { |
| 1432 bootstrap(); |
| 1433 // When loading at other readyStates, wait for the appropriate DOM event to |
| 1434 // bootstrap. |
| 1420 } else { | 1435 } else { |
| 1421 var loadEvent = window.HTMLImports ? 'HTMLImportsLoaded' : | 1436 var loadEvent = window.HTMLImports ? 'HTMLImportsLoaded' : |
| 1422 document.readyState == 'loading' ? 'DOMContentLoaded' : 'load'; | 1437 document.readyState == 'loading' ? 'DOMContentLoaded' : 'load'; |
| 1423 window.addEventListener(loadEvent, bootstrap); | 1438 window.addEventListener(loadEvent, bootstrap); |
| 1424 } | 1439 } |
| 1425 | 1440 |
| 1426 })(); | 1441 })(window.CustomElements); |
| 1427 | 1442 |
| 1428 (function() { | 1443 (function() { |
| 1429 // Patch to allow custom element and shadow dom to work together, from: | 1444 // Patch to allow custom element and shadow dom to work together, from: |
| 1430 // https://github.com/Polymer/platform/blob/master/src/patches-shadowdom-polyfil
l.js | 1445 // https://github.com/Polymer/platform/blob/master/src/patches-shadowdom-polyfil
l.js |
| 1431 // include .host reference | 1446 // include .host reference |
| 1432 if (HTMLElement.prototype.createShadowRoot) { | 1447 if (HTMLElement.prototype.createShadowRoot) { |
| 1433 var originalCreateShadowRoot = HTMLElement.prototype.createShadowRoot; | 1448 var originalCreateShadowRoot = HTMLElement.prototype.createShadowRoot; |
| 1434 HTMLElement.prototype.createShadowRoot = function() { | 1449 HTMLElement.prototype.createShadowRoot = function() { |
| 1435 var root = originalCreateShadowRoot.call(this); | 1450 var root = originalCreateShadowRoot.call(this); |
| 1436 root.host = this; | 1451 root.host = this; |
| 1437 return root; | 1452 return root; |
| 1438 } | 1453 } |
| 1439 } | 1454 } |
| 1440 | 1455 |
| 1441 | 1456 |
| 1442 // Patch to allow custom elements and shadow dom to work together, from: | 1457 // Patch to allow custom elements and shadow dom to work together, from: |
| 1443 // https://github.com/Polymer/platform/blob/master/src/patches-custom-elements.j
s | 1458 // https://github.com/Polymer/platform-dev/blob/2bb9c56d90f9ac19c2e65cdad368668a
ff514f14/src/patches-custom-elements.js |
| 1444 if (window.ShadowDOMPolyfill) { | 1459 if (window.ShadowDOMPolyfill) { |
| 1445 function nop() {}; | |
| 1446 | |
| 1447 // disable shadow dom watching | |
| 1448 CustomElements.watchShadow = nop; | |
| 1449 CustomElements.watchAllShadows = nop; | |
| 1450 | 1460 |
| 1451 // ensure wrapped inputs for these functions | 1461 // ensure wrapped inputs for these functions |
| 1452 var fns = ['upgradeAll', 'upgradeSubtree', 'observeDocument', | 1462 var fns = ['upgradeAll', 'upgradeSubtree', 'observeDocument', |
| 1453 'upgradeDocument']; | 1463 'upgradeDocument']; |
| 1454 | 1464 |
| 1455 // cache originals | 1465 // cache originals |
| 1456 var original = {}; | 1466 var original = {}; |
| 1457 fns.forEach(function(fn) { | 1467 fns.forEach(function(fn) { |
| 1458 original[fn] = CustomElements[fn]; | 1468 original[fn] = CustomElements[fn]; |
| 1459 }); | 1469 }); |
| 1460 | 1470 |
| 1461 // override | 1471 // override |
| 1462 fns.forEach(function(fn) { | 1472 fns.forEach(function(fn) { |
| 1463 CustomElements[fn] = function(inNode) { | 1473 CustomElements[fn] = function(inNode) { |
| 1464 return original[fn](ShadowDOMPolyfill.wrapIfNeeded(inNode)); | 1474 return original[fn](window.ShadowDOMPolyfill.wrapIfNeeded(inNode)); |
| 1465 }; | 1475 }; |
| 1466 }); | 1476 }); |
| 1477 |
| 1478 } |
| 1479 |
| 1480 // Patch to make importNode work. |
| 1481 // https://github.com/Polymer/platform-dev/blob/64a92f273462f04a84abbe2f054294f2
b62dbcd6/src/patches-mdv.js |
| 1482 if (window.CustomElements && !CustomElements.useNative) { |
| 1483 var originalImportNode = Document.prototype.importNode; |
| 1484 Document.prototype.importNode = function(node, deep) { |
| 1485 var imported = originalImportNode.call(this, node, deep); |
| 1486 CustomElements.upgradeAll(imported); |
| 1487 return imported; |
| 1488 } |
| 1467 } | 1489 } |
| 1468 | 1490 |
| 1469 })(); | 1491 })(); |
| OLD | NEW |