├── .gitignore
├── .npmignore
├── .travis.yml
├── LICENSE
├── README.md
├── cjs
├── index.js
└── package.json
├── esm
└── index.js
├── index.js
├── min.js
├── package.json
└── test
├── es5
├── index.html
└── my-button.js
├── index.html
├── index.js
├── my-button.js
├── nightmare.js
├── package.json
├── shadow.html
└── table.html
/.gitignore:
--------------------------------------------------------------------------------
1 | .nyc_output/
2 | node_modules/
3 | package-lock.json
4 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .nyc_output/
2 | node_modules/
3 | rollup/
4 | test/
5 | package-lock.json
6 | .travis.yml
7 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - stable
4 | git:
5 | depth: 1
6 | branches:
7 | only:
8 | - master
9 | - /^greenkeeper/.*$/
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | ISC License
2 |
3 | Copyright (c) 2018, Andrea Giammarchi, @WebReflection
4 |
5 | Permission to use, copy, modify, and/or distribute this software for any
6 | purpose with or without fee is hereby granted, provided that the above
7 | copyright notice and this permission notice appear in all copies.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 | AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 | OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 | PERFORMANCE OF THIS SOFTWARE.
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Custom Elements with Builtin Extends
2 |
3 | [](https://travis-ci.com/ungap/custom-elements-builtin) [](https://greenkeeper.io/) 
4 |
5 | ## Deprecated
6 |
7 | The current polyfill is [@ungap/custom-elements](https://github.com/ungap/custom-elements#readme) which includes all features detection in it.
8 |
--------------------------------------------------------------------------------
/cjs/index.js:
--------------------------------------------------------------------------------
1 | /*! (c) Andrea Giammarchi - ISC */
2 | (function (document, customElements, Object) {'use strict';
3 | // trick of the year 🎉 https://twitter.com/WebReflection/status/1232269200317652992
4 | if (document.importNode.length != 1 || customElements.get('ungap-li'))
5 | return;
6 | var EXTENDS = 'extends';
7 | try {
8 | // class LI extends HTMLLIElement {}
9 | var desc = {};
10 | desc[EXTENDS] = 'li';
11 | var HtmlLI = HTMLLIElement;
12 | var LI = function () {
13 | return Reflect.construct(HtmlLI, [], LI);
14 | };
15 | LI.prototype = Object.create(HtmlLI.prototype);
16 | customElements.define('ungap-li', LI, desc);
17 | if (!/is="ungap-li"/.test((new LI).outerHTML))
18 | throw desc;
19 | } catch (o_O) {
20 | (function() {
21 | var ATTRIBUTE_CHANGED_CALLBACK = 'attributeChangedCallback';
22 | var CONNECTED_CALLBACK = 'connectedCallback';
23 | var DISCONNECTED_CALLBACK = 'disconnectedCallback';
24 | var ElemProto = Element.prototype;
25 | var assign = Object.assign;
26 | var create = Object.create;
27 | var defineProperties = Object.defineProperties;
28 | var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
29 | var setPrototypeOf = Object.setPrototypeOf;
30 | var define = customElements.define;
31 | var get = customElements.get;
32 | var upgrade = customElements.upgrade;
33 | var whenDefined = customElements.whenDefined;
34 | var registry = create(null);
35 | var lifeCycle = new WeakMap;
36 | var changesOptions = {childList: true, subtree: true};
37 |
38 | // Safari TP decided at some point that it was OK to break the Web
39 | // https://github.com/ungap/custom-elements-builtin/issues/25
40 | Reflect
41 | .ownKeys(self)
42 | .filter(function (k) {
43 | return typeof k == 'string' && /^HTML(?!Element)/.test(k);
44 | })
45 | .forEach(function (k) {
46 | function HTMLBuiltIn() {}
47 | var tmp = self[k];
48 | setPrototypeOf(HTMLBuiltIn, tmp);
49 | (HTMLBuiltIn.prototype = tmp.prototype).constructor = HTMLBuiltIn;
50 | tmp = {};
51 | tmp[k] = {value: HTMLBuiltIn};
52 | defineProperties(self, tmp);
53 | });
54 |
55 | new MutationObserver(DOMChanges).observe(document, changesOptions);
56 | wrapOriginal(Document.prototype, 'importNode');
57 | wrapOriginal(Node.prototype, 'cloneNode');
58 | defineProperties(
59 | customElements,
60 | {
61 | define: {
62 | value: function (name, Class, options) {
63 | name = name.toLowerCase();
64 | if (options && EXTENDS in options) {
65 | // currently options is not used but preserved for the future
66 | registry[name] = assign({}, options, {Class: Class});
67 | var query = options[EXTENDS] + '[is="' + name + '"]';
68 | var changes = document.querySelectorAll(query);
69 | for (var i = 0, length = changes.length; i < length; i++)
70 | setupIfNeeded(changes[i]);
71 | }
72 | else
73 | define.apply(customElements, arguments);
74 | }
75 | },
76 | get: {
77 | value: function (name) {
78 | return name in registry ?
79 | registry[name].Class :
80 | get.call(customElements, name);
81 | }
82 | },
83 | upgrade: {
84 | value: function (node) {
85 | var info = getInfo(node);
86 | if (info && !(node instanceof info.Class))
87 | setup(node, info);
88 | else
89 | upgrade.call(customElements, node);
90 | }
91 | },
92 | whenDefined: {
93 | value: function (name) {
94 | return name in registry ?
95 | Promise.resolve() :
96 | whenDefined.call(customElements, name);
97 | }
98 | }
99 | }
100 | );
101 | var createElement = document.createElement;
102 | defineProperties(
103 | document,
104 | {
105 | createElement: {
106 | value: function (name, options) {
107 | var node = createElement.call(document, name);
108 | if (options && 'is' in options) {
109 | node.setAttribute('is', options.is);
110 | customElements.upgrade(node);
111 | }
112 | return node;
113 | }
114 | }
115 | }
116 | );
117 | var attach = getOwnPropertyDescriptor(ElemProto, 'attachShadow').value;
118 | var innerHTML = getOwnPropertyDescriptor(ElemProto, 'innerHTML');
119 | defineProperties(
120 | ElemProto,
121 | {
122 | attachShadow: {
123 | value: function () {
124 | var root = attach.apply(this, arguments);
125 | new MutationObserver(DOMChanges).observe(root, changesOptions);
126 | return root;
127 | }
128 | },
129 | innerHTML: {
130 | get: innerHTML.get,
131 | set: function (HTML) {
132 | innerHTML.set.call(this, HTML);
133 | if (/\bis=("|')?[a-z0-9_-]+\1/i.test(HTML))
134 | setupSubNodes(this, setupIfNeeded);
135 | }
136 | }
137 | }
138 | );
139 | function DOMChanges(changes) {
140 | for (var i = 0, length = changes.length; i < length; i++) {
141 | var change = changes[i];
142 | var addedNodes = change.addedNodes;
143 | var removedNodes = change.removedNodes;
144 | for (var j = 0, len = addedNodes.length; j < len; j++)
145 | setupIfNeeded(addedNodes[j]);
146 | for (var j = 0, len = removedNodes.length; j < len; j++)
147 | disconnectIfNeeded(removedNodes[j]);
148 | }
149 | }
150 | function attributeChanged(changes) {
151 | for (var i = 0, length = changes.length; i < length; i++) {
152 | var change = changes[i];
153 | var attributeName = change.attributeName;
154 | var oldValue = change.oldValue;
155 | var target = change.target;
156 | var newValue = target.getAttribute(attributeName);
157 | if (
158 | ATTRIBUTE_CHANGED_CALLBACK in target &&
159 | !(oldValue == newValue && newValue == null)
160 | )
161 | target[ATTRIBUTE_CHANGED_CALLBACK](
162 | attributeName,
163 | oldValue,
164 | target.getAttribute(attributeName),
165 | // TODO: add getAttributeNS if the node is XML
166 | null
167 | );
168 | }
169 | }
170 | function disconnectIfNeeded(node) {
171 | if (node.nodeType !== 1)
172 | return;
173 | var info = getInfo(node);
174 | if (
175 | info &&
176 | node instanceof info.Class &&
177 | DISCONNECTED_CALLBACK in node &&
178 | lifeCycle.get(node) !== DISCONNECTED_CALLBACK
179 | ) {
180 | lifeCycle.set(node, DISCONNECTED_CALLBACK);
181 | Promise.resolve(node).then(invokeDisconnectedCallback);
182 | }
183 | setupSubNodes(node, disconnectIfNeeded);
184 | }
185 | function getInfo(node) {
186 | var is = node.getAttribute('is');
187 | if (is) {
188 | is = is.toLowerCase();
189 | if (is in registry)
190 | return registry[is];
191 | }
192 | return null;
193 | }
194 | function invokeConnectedCallback(node) {
195 | node[CONNECTED_CALLBACK]();
196 | }
197 | function invokeDisconnectedCallback(node) {
198 | node[DISCONNECTED_CALLBACK]();
199 | }
200 | function setup(node, info) {
201 | var Class = info.Class;
202 | var oa = Class.observedAttributes || [];
203 | setPrototypeOf(node, Class.prototype);
204 | if (oa.length) {
205 | new MutationObserver(attributeChanged).observe(
206 | node,
207 | {
208 | attributes: true,
209 | attributeFilter: oa,
210 | attributeOldValue: true
211 | }
212 | );
213 | var changes = [];
214 | for (var i = 0, length = oa.length; i < length; i++)
215 | changes.push({attributeName: oa[i], oldValue: null, target: node});
216 | attributeChanged(changes);
217 | }
218 | }
219 | function setupIfNeeded(node) {
220 | if (node.nodeType !== 1)
221 | return;
222 | var info = getInfo(node);
223 | if (info) {
224 | if (!(node instanceof info.Class))
225 | setup(node, info);
226 | if (
227 | CONNECTED_CALLBACK in node &&
228 | node.isConnected &&
229 | lifeCycle.get(node) !== CONNECTED_CALLBACK
230 | ) {
231 | lifeCycle.set(node, CONNECTED_CALLBACK);
232 | Promise.resolve(node).then(invokeConnectedCallback);
233 | }
234 | }
235 | setupSubNodes(node, setupIfNeeded);
236 | }
237 | function setupSubNodes(node, setup) {
238 | for (var
239 | t = node.content,
240 | nodes = (t && t.nodeType == 11 ? t : node).querySelectorAll('[is]'),
241 | i = 0, length = nodes.length; i < length; i++
242 | )
243 | setup(nodes[i]);
244 | }
245 | function wrapOriginal(prototype, name) {
246 | var method = prototype[name];
247 | var desc = {};
248 | desc[name] = {
249 | value: function () {
250 | var result = method.apply(this, arguments);
251 | switch (result.nodeType) {
252 | case 1:
253 | case 11:
254 | setupSubNodes(result, setupIfNeeded);
255 | }
256 | return result;
257 | }
258 | };
259 | defineProperties(prototype, desc);
260 | }
261 | }());
262 | }
263 | }(document, customElements, Object));
264 |
--------------------------------------------------------------------------------
/cjs/package.json:
--------------------------------------------------------------------------------
1 | {"type":"commonjs"}
2 |
--------------------------------------------------------------------------------
/esm/index.js:
--------------------------------------------------------------------------------
1 | /*! (c) Andrea Giammarchi - ISC */
2 | (function (document, customElements, Object) {'use strict';
3 | // trick of the year 🎉 https://twitter.com/WebReflection/status/1232269200317652992
4 | if (document.importNode.length != 1 || customElements.get('ungap-li'))
5 | return;
6 | var EXTENDS = 'extends';
7 | try {
8 | // class LI extends HTMLLIElement {}
9 | var desc = {};
10 | desc[EXTENDS] = 'li';
11 | var HtmlLI = HTMLLIElement;
12 | var LI = function () {
13 | return Reflect.construct(HtmlLI, [], LI);
14 | };
15 | LI.prototype = Object.create(HtmlLI.prototype);
16 | customElements.define('ungap-li', LI, desc);
17 | if (!/is="ungap-li"/.test((new LI).outerHTML))
18 | throw desc;
19 | } catch (o_O) {
20 | (function() {
21 | var ATTRIBUTE_CHANGED_CALLBACK = 'attributeChangedCallback';
22 | var CONNECTED_CALLBACK = 'connectedCallback';
23 | var DISCONNECTED_CALLBACK = 'disconnectedCallback';
24 | var ElemProto = Element.prototype;
25 | var assign = Object.assign;
26 | var create = Object.create;
27 | var defineProperties = Object.defineProperties;
28 | var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
29 | var setPrototypeOf = Object.setPrototypeOf;
30 | var define = customElements.define;
31 | var get = customElements.get;
32 | var upgrade = customElements.upgrade;
33 | var whenDefined = customElements.whenDefined;
34 | var registry = create(null);
35 | var lifeCycle = new WeakMap;
36 | var changesOptions = {childList: true, subtree: true};
37 |
38 | // Safari TP decided at some point that it was OK to break the Web
39 | // https://github.com/ungap/custom-elements-builtin/issues/25
40 | Reflect
41 | .ownKeys(self)
42 | .filter(function (k) {
43 | return typeof k == 'string' && /^HTML(?!Element)/.test(k);
44 | })
45 | .forEach(function (k) {
46 | function HTMLBuiltIn() {}
47 | var tmp = self[k];
48 | setPrototypeOf(HTMLBuiltIn, tmp);
49 | (HTMLBuiltIn.prototype = tmp.prototype).constructor = HTMLBuiltIn;
50 | tmp = {};
51 | tmp[k] = {value: HTMLBuiltIn};
52 | defineProperties(self, tmp);
53 | });
54 |
55 | new MutationObserver(DOMChanges).observe(document, changesOptions);
56 | wrapOriginal(Document.prototype, 'importNode');
57 | wrapOriginal(Node.prototype, 'cloneNode');
58 | defineProperties(
59 | customElements,
60 | {
61 | define: {
62 | value: function (name, Class, options) {
63 | name = name.toLowerCase();
64 | if (options && EXTENDS in options) {
65 | // currently options is not used but preserved for the future
66 | registry[name] = assign({}, options, {Class: Class});
67 | var query = options[EXTENDS] + '[is="' + name + '"]';
68 | var changes = document.querySelectorAll(query);
69 | for (var i = 0, length = changes.length; i < length; i++)
70 | setupIfNeeded(changes[i]);
71 | }
72 | else
73 | define.apply(customElements, arguments);
74 | }
75 | },
76 | get: {
77 | value: function (name) {
78 | return name in registry ?
79 | registry[name].Class :
80 | get.call(customElements, name);
81 | }
82 | },
83 | upgrade: {
84 | value: function (node) {
85 | var info = getInfo(node);
86 | if (info && !(node instanceof info.Class))
87 | setup(node, info);
88 | else
89 | upgrade.call(customElements, node);
90 | }
91 | },
92 | whenDefined: {
93 | value: function (name) {
94 | return name in registry ?
95 | Promise.resolve() :
96 | whenDefined.call(customElements, name);
97 | }
98 | }
99 | }
100 | );
101 | var createElement = document.createElement;
102 | defineProperties(
103 | document,
104 | {
105 | createElement: {
106 | value: function (name, options) {
107 | var node = createElement.call(document, name);
108 | if (options && 'is' in options) {
109 | node.setAttribute('is', options.is);
110 | customElements.upgrade(node);
111 | }
112 | return node;
113 | }
114 | }
115 | }
116 | );
117 | var attach = getOwnPropertyDescriptor(ElemProto, 'attachShadow').value;
118 | var innerHTML = getOwnPropertyDescriptor(ElemProto, 'innerHTML');
119 | defineProperties(
120 | ElemProto,
121 | {
122 | attachShadow: {
123 | value: function () {
124 | var root = attach.apply(this, arguments);
125 | new MutationObserver(DOMChanges).observe(root, changesOptions);
126 | return root;
127 | }
128 | },
129 | innerHTML: {
130 | get: innerHTML.get,
131 | set: function (HTML) {
132 | innerHTML.set.call(this, HTML);
133 | if (/\bis=("|')?[a-z0-9_-]+\1/i.test(HTML))
134 | setupSubNodes(this, setupIfNeeded);
135 | }
136 | }
137 | }
138 | );
139 | function DOMChanges(changes) {
140 | for (var i = 0, length = changes.length; i < length; i++) {
141 | var change = changes[i];
142 | var addedNodes = change.addedNodes;
143 | var removedNodes = change.removedNodes;
144 | for (var j = 0, len = addedNodes.length; j < len; j++)
145 | setupIfNeeded(addedNodes[j]);
146 | for (var j = 0, len = removedNodes.length; j < len; j++)
147 | disconnectIfNeeded(removedNodes[j]);
148 | }
149 | }
150 | function attributeChanged(changes) {
151 | for (var i = 0, length = changes.length; i < length; i++) {
152 | var change = changes[i];
153 | var attributeName = change.attributeName;
154 | var oldValue = change.oldValue;
155 | var target = change.target;
156 | var newValue = target.getAttribute(attributeName);
157 | if (
158 | ATTRIBUTE_CHANGED_CALLBACK in target &&
159 | !(oldValue == newValue && newValue == null)
160 | )
161 | target[ATTRIBUTE_CHANGED_CALLBACK](
162 | attributeName,
163 | oldValue,
164 | target.getAttribute(attributeName),
165 | // TODO: add getAttributeNS if the node is XML
166 | null
167 | );
168 | }
169 | }
170 | function disconnectIfNeeded(node) {
171 | if (node.nodeType !== 1)
172 | return;
173 | var info = getInfo(node);
174 | if (
175 | info &&
176 | node instanceof info.Class &&
177 | DISCONNECTED_CALLBACK in node &&
178 | lifeCycle.get(node) !== DISCONNECTED_CALLBACK
179 | ) {
180 | lifeCycle.set(node, DISCONNECTED_CALLBACK);
181 | Promise.resolve(node).then(invokeDisconnectedCallback);
182 | }
183 | setupSubNodes(node, disconnectIfNeeded);
184 | }
185 | function getInfo(node) {
186 | var is = node.getAttribute('is');
187 | if (is) {
188 | is = is.toLowerCase();
189 | if (is in registry)
190 | return registry[is];
191 | }
192 | return null;
193 | }
194 | function invokeConnectedCallback(node) {
195 | node[CONNECTED_CALLBACK]();
196 | }
197 | function invokeDisconnectedCallback(node) {
198 | node[DISCONNECTED_CALLBACK]();
199 | }
200 | function setup(node, info) {
201 | var Class = info.Class;
202 | var oa = Class.observedAttributes || [];
203 | setPrototypeOf(node, Class.prototype);
204 | if (oa.length) {
205 | new MutationObserver(attributeChanged).observe(
206 | node,
207 | {
208 | attributes: true,
209 | attributeFilter: oa,
210 | attributeOldValue: true
211 | }
212 | );
213 | var changes = [];
214 | for (var i = 0, length = oa.length; i < length; i++)
215 | changes.push({attributeName: oa[i], oldValue: null, target: node});
216 | attributeChanged(changes);
217 | }
218 | }
219 | function setupIfNeeded(node) {
220 | if (node.nodeType !== 1)
221 | return;
222 | var info = getInfo(node);
223 | if (info) {
224 | if (!(node instanceof info.Class))
225 | setup(node, info);
226 | if (
227 | CONNECTED_CALLBACK in node &&
228 | node.isConnected &&
229 | lifeCycle.get(node) !== CONNECTED_CALLBACK
230 | ) {
231 | lifeCycle.set(node, CONNECTED_CALLBACK);
232 | Promise.resolve(node).then(invokeConnectedCallback);
233 | }
234 | }
235 | setupSubNodes(node, setupIfNeeded);
236 | }
237 | function setupSubNodes(node, setup) {
238 | for (var
239 | t = node.content,
240 | nodes = (t && t.nodeType == 11 ? t : node).querySelectorAll('[is]'),
241 | i = 0, length = nodes.length; i < length; i++
242 | )
243 | setup(nodes[i]);
244 | }
245 | function wrapOriginal(prototype, name) {
246 | var method = prototype[name];
247 | var desc = {};
248 | desc[name] = {
249 | value: function () {
250 | var result = method.apply(this, arguments);
251 | switch (result.nodeType) {
252 | case 1:
253 | case 11:
254 | setupSubNodes(result, setupIfNeeded);
255 | }
256 | return result;
257 | }
258 | };
259 | defineProperties(prototype, desc);
260 | }
261 | }());
262 | }
263 | }(document, customElements, Object));
264 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /*! (c) Andrea Giammarchi - ISC */
2 | (function (document, customElements, Object) {'use strict';
3 | // trick of the year 🎉 https://twitter.com/WebReflection/status/1232269200317652992
4 | if (document.importNode.length != 1 || customElements.get('ungap-li'))
5 | return;
6 | var EXTENDS = 'extends';
7 | try {
8 | // class LI extends HTMLLIElement {}
9 | var desc = {};
10 | desc[EXTENDS] = 'li';
11 | var HtmlLI = HTMLLIElement;
12 | var LI = function () {
13 | return Reflect.construct(HtmlLI, [], LI);
14 | };
15 | LI.prototype = Object.create(HtmlLI.prototype);
16 | customElements.define('ungap-li', LI, desc);
17 | if (!/is="ungap-li"/.test((new LI).outerHTML))
18 | throw desc;
19 | } catch (o_O) {
20 | (function() {
21 | var ATTRIBUTE_CHANGED_CALLBACK = 'attributeChangedCallback';
22 | var CONNECTED_CALLBACK = 'connectedCallback';
23 | var DISCONNECTED_CALLBACK = 'disconnectedCallback';
24 | var ElemProto = Element.prototype;
25 | var assign = Object.assign;
26 | var create = Object.create;
27 | var defineProperties = Object.defineProperties;
28 | var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
29 | var setPrototypeOf = Object.setPrototypeOf;
30 | var define = customElements.define;
31 | var get = customElements.get;
32 | var upgrade = customElements.upgrade;
33 | var whenDefined = customElements.whenDefined;
34 | var registry = create(null);
35 | var lifeCycle = new WeakMap;
36 | var changesOptions = {childList: true, subtree: true};
37 |
38 | // Safari TP decided at some point that it was OK to break the Web
39 | // https://github.com/ungap/custom-elements-builtin/issues/25
40 | Reflect
41 | .ownKeys(self)
42 | .filter(function (k) {
43 | return typeof k == 'string' && /^HTML(?!Element)/.test(k);
44 | })
45 | .forEach(function (k) {
46 | function HTMLBuiltIn() {}
47 | var tmp = self[k];
48 | setPrototypeOf(HTMLBuiltIn, tmp);
49 | (HTMLBuiltIn.prototype = tmp.prototype).constructor = HTMLBuiltIn;
50 | tmp = {};
51 | tmp[k] = {value: HTMLBuiltIn};
52 | defineProperties(self, tmp);
53 | });
54 |
55 | new MutationObserver(DOMChanges).observe(document, changesOptions);
56 | wrapOriginal(Document.prototype, 'importNode');
57 | wrapOriginal(Node.prototype, 'cloneNode');
58 | defineProperties(
59 | customElements,
60 | {
61 | define: {
62 | value: function (name, Class, options) {
63 | name = name.toLowerCase();
64 | if (options && EXTENDS in options) {
65 | // currently options is not used but preserved for the future
66 | registry[name] = assign({}, options, {Class: Class});
67 | var query = options[EXTENDS] + '[is="' + name + '"]';
68 | var changes = document.querySelectorAll(query);
69 | for (var i = 0, length = changes.length; i < length; i++)
70 | setupIfNeeded(changes[i]);
71 | }
72 | else
73 | define.apply(customElements, arguments);
74 | }
75 | },
76 | get: {
77 | value: function (name) {
78 | return name in registry ?
79 | registry[name].Class :
80 | get.call(customElements, name);
81 | }
82 | },
83 | upgrade: {
84 | value: function (node) {
85 | var info = getInfo(node);
86 | if (info && !(node instanceof info.Class))
87 | setup(node, info);
88 | else
89 | upgrade.call(customElements, node);
90 | }
91 | },
92 | whenDefined: {
93 | value: function (name) {
94 | return name in registry ?
95 | Promise.resolve() :
96 | whenDefined.call(customElements, name);
97 | }
98 | }
99 | }
100 | );
101 | var createElement = document.createElement;
102 | defineProperties(
103 | document,
104 | {
105 | createElement: {
106 | value: function (name, options) {
107 | var node = createElement.call(document, name);
108 | if (options && 'is' in options) {
109 | node.setAttribute('is', options.is);
110 | customElements.upgrade(node);
111 | }
112 | return node;
113 | }
114 | }
115 | }
116 | );
117 | var attach = getOwnPropertyDescriptor(ElemProto, 'attachShadow').value;
118 | var innerHTML = getOwnPropertyDescriptor(ElemProto, 'innerHTML');
119 | defineProperties(
120 | ElemProto,
121 | {
122 | attachShadow: {
123 | value: function () {
124 | var root = attach.apply(this, arguments);
125 | new MutationObserver(DOMChanges).observe(root, changesOptions);
126 | return root;
127 | }
128 | },
129 | innerHTML: {
130 | get: innerHTML.get,
131 | set: function (HTML) {
132 | innerHTML.set.call(this, HTML);
133 | if (/\bis=("|')?[a-z0-9_-]+\1/i.test(HTML))
134 | setupSubNodes(this, setupIfNeeded);
135 | }
136 | }
137 | }
138 | );
139 | function DOMChanges(changes) {
140 | for (var i = 0, length = changes.length; i < length; i++) {
141 | var change = changes[i];
142 | var addedNodes = change.addedNodes;
143 | var removedNodes = change.removedNodes;
144 | for (var j = 0, len = addedNodes.length; j < len; j++)
145 | setupIfNeeded(addedNodes[j]);
146 | for (var j = 0, len = removedNodes.length; j < len; j++)
147 | disconnectIfNeeded(removedNodes[j]);
148 | }
149 | }
150 | function attributeChanged(changes) {
151 | for (var i = 0, length = changes.length; i < length; i++) {
152 | var change = changes[i];
153 | var attributeName = change.attributeName;
154 | var oldValue = change.oldValue;
155 | var target = change.target;
156 | var newValue = target.getAttribute(attributeName);
157 | if (
158 | ATTRIBUTE_CHANGED_CALLBACK in target &&
159 | !(oldValue == newValue && newValue == null)
160 | )
161 | target[ATTRIBUTE_CHANGED_CALLBACK](
162 | attributeName,
163 | oldValue,
164 | target.getAttribute(attributeName),
165 | // TODO: add getAttributeNS if the node is XML
166 | null
167 | );
168 | }
169 | }
170 | function disconnectIfNeeded(node) {
171 | if (node.nodeType !== 1)
172 | return;
173 | var info = getInfo(node);
174 | if (
175 | info &&
176 | node instanceof info.Class &&
177 | DISCONNECTED_CALLBACK in node &&
178 | lifeCycle.get(node) !== DISCONNECTED_CALLBACK
179 | ) {
180 | lifeCycle.set(node, DISCONNECTED_CALLBACK);
181 | Promise.resolve(node).then(invokeDisconnectedCallback);
182 | }
183 | setupSubNodes(node, disconnectIfNeeded);
184 | }
185 | function getInfo(node) {
186 | var is = node.getAttribute('is');
187 | if (is) {
188 | is = is.toLowerCase();
189 | if (is in registry)
190 | return registry[is];
191 | }
192 | return null;
193 | }
194 | function invokeConnectedCallback(node) {
195 | node[CONNECTED_CALLBACK]();
196 | }
197 | function invokeDisconnectedCallback(node) {
198 | node[DISCONNECTED_CALLBACK]();
199 | }
200 | function setup(node, info) {
201 | var Class = info.Class;
202 | var oa = Class.observedAttributes || [];
203 | setPrototypeOf(node, Class.prototype);
204 | if (oa.length) {
205 | new MutationObserver(attributeChanged).observe(
206 | node,
207 | {
208 | attributes: true,
209 | attributeFilter: oa,
210 | attributeOldValue: true
211 | }
212 | );
213 | var changes = [];
214 | for (var i = 0, length = oa.length; i < length; i++)
215 | changes.push({attributeName: oa[i], oldValue: null, target: node});
216 | attributeChanged(changes);
217 | }
218 | }
219 | function setupIfNeeded(node) {
220 | if (node.nodeType !== 1)
221 | return;
222 | var info = getInfo(node);
223 | if (info) {
224 | if (!(node instanceof info.Class))
225 | setup(node, info);
226 | if (
227 | CONNECTED_CALLBACK in node &&
228 | node.isConnected &&
229 | lifeCycle.get(node) !== CONNECTED_CALLBACK
230 | ) {
231 | lifeCycle.set(node, CONNECTED_CALLBACK);
232 | Promise.resolve(node).then(invokeConnectedCallback);
233 | }
234 | }
235 | setupSubNodes(node, setupIfNeeded);
236 | }
237 | function setupSubNodes(node, setup) {
238 | for (var
239 | t = node.content,
240 | nodes = (t && t.nodeType == 11 ? t : node).querySelectorAll('[is]'),
241 | i = 0, length = nodes.length; i < length; i++
242 | )
243 | setup(nodes[i]);
244 | }
245 | function wrapOriginal(prototype, name) {
246 | var method = prototype[name];
247 | var desc = {};
248 | desc[name] = {
249 | value: function () {
250 | var result = method.apply(this, arguments);
251 | switch (result.nodeType) {
252 | case 1:
253 | case 11:
254 | setupSubNodes(result, setupIfNeeded);
255 | }
256 | return result;
257 | }
258 | };
259 | defineProperties(prototype, desc);
260 | }
261 | }());
262 | }
263 | }(document, customElements, Object));
264 |
--------------------------------------------------------------------------------
/min.js:
--------------------------------------------------------------------------------
1 | !function(P,H,k){"use strict";if(1==P.importNode.length&&!H.get("ungap-li")){var D="extends";try{var e={extends:"li"},t=HTMLLIElement,n=function(){return Reflect.construct(t,[],n)};if(n.prototype=k.create(t.prototype),H.define("ungap-li",n,e),!/is="ungap-li"/.test((new n).outerHTML))throw e}catch(e){!function(){var l="attributeChangedCallback",n="connectedCallback",r="disconnectedCallback",e=Element.prototype,i=k.assign,t=k.create,o=k.defineProperties,a=k.getOwnPropertyDescriptor,s=k.setPrototypeOf,u=H.define,c=H.get,f=H.upgrade,p=H.whenDefined,v=t(null),d=new WeakMap,g={childList:!0,subtree:!0};Reflect.ownKeys(self).filter(function(e){return"string"==typeof e&&/^HTML(?!Element)/.test(e)}).forEach(function(e){function t(){}var n=self[e];s(t,n),(t.prototype=n.prototype).constructor=t,(n={})[e]={value:t},o(self,n)}),new MutationObserver(m).observe(P,g),O(Document.prototype,"importNode"),O(Node.prototype,"cloneNode"),o(H,{define:{value:function(e,t,n){if(e=e.toLowerCase(),n&&D in n){v[e]=i({},n,{Class:t});for(var e=n[D]+'[is="'+e+'"]',r=P.querySelectorAll(e),o=0,a=r.length;o test/es5/my-button.js",
10 | "build": "npm run cjs && npm run esm && npm run min && npm run test && npm run size",
11 | "cjs": "cp index.js cjs/",
12 | "esm": "cp index.js esm/",
13 | "min": "uglifyjs index.js -c -m -o min.js",
14 | "size": "cat index.js | wc -c && cat min.js | wc -c && gzip -c9 min.js | wc -c && cat min.js | brotli | wc -c",
15 | "test": "npm run server & (sleep 1 && npm run nightmare && npm run kill)",
16 | "nightmare": "node test/nightmare.js || (npm run kill && exit 1)",
17 | "server": "node -e 'require(`fs`).writeFileSync(`pid`,require(`child_process`).spawn(`http-server`,[`.`,`-s`]).pid.toString());'",
18 | "kill": "kill -9 $(cat pid) && rm -f pid"
19 | },
20 | "keywords": [
21 | "customElements",
22 | "builtin",
23 | "polyfill",
24 | "ungap"
25 | ],
26 | "author": "Andrea Giammarchi",
27 | "license": "ISC",
28 | "devDependencies": {
29 | "@babel/cli": "^7.13.16",
30 | "@babel/core": "^7.14.0",
31 | "@babel/preset-env": "^7.14.1",
32 | "http-server": "^0.12.3",
33 | "nightmare": "^3.0.2",
34 | "uglify-js": "^3.13.5"
35 | },
36 | "repository": {
37 | "type": "git",
38 | "url": "git+https://github.com/ungap/custom-elements-builtin.git"
39 | },
40 | "bugs": {
41 | "url": "https://github.com/ungap/custom-elements-builtin/issues"
42 | },
43 | "homepage": "https://github.com/ungap/custom-elements-builtin#readme",
44 | "type": "module",
45 | "exports": {
46 | "import": "./esm/index.js",
47 | "default": "./cjs/index.js"
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/test/es5/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
1 |
2 |