Browse Source

vendor custom element builtin

master
Brian Hicks 1 year ago
parent
commit
fa8c37b9e2
  1. 245
      vendor/custom-elements-builtin.js

245
vendor/custom-elements-builtin.js

@ -0,0 +1,245 @@
/*! (c) Andrea Giammarchi - ISC */
(function (document, customElements, Object) {'use strict';
// trick of the year 🎉 https://twitter.com/WebReflection/status/1232269200317652992
if (document.importNode.length != 1 || customElements.get('ungap-li'))
return;
var EXTENDS = 'extends';
try {
// class LI extends HTMLLIElement {}
var desc = {};
desc[EXTENDS] = 'li';
var HtmlLI = HTMLLIElement;
var LI = function () {
return Reflect.construct(HtmlLI, [], LI);
};
LI.prototype = Object.create(HtmlLI.prototype);
customElements.define('ungap-li', LI, desc);
if (!/is="ungap-li"/.test((new LI).outerHTML))
throw desc;
} catch (o_O) {
(function() {
var ATTRIBUTE_CHANGED_CALLBACK = 'attributeChangedCallback';
var CONNECTED_CALLBACK = 'connectedCallback';
var DISCONNECTED_CALLBACK = 'disconnectedCallback';
var ElemProto = Element.prototype;
var assign = Object.assign;
var create = Object.create;
var defineProperties = Object.defineProperties;
var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
var setPrototypeOf = Object.setPrototypeOf;
var define = customElements.define;
var get = customElements.get;
var upgrade = customElements.upgrade;
var whenDefined = customElements.whenDefined;
var registry = create(null);
var lifeCycle = new WeakMap;
var changesOptions = {childList: true, subtree: true};
new MutationObserver(DOMChanges).observe(document, changesOptions);
wrapOriginal(Document.prototype, 'importNode');
wrapOriginal(Node.prototype, 'cloneNode');
defineProperties(
customElements,
{
define: {
value: function (name, Class, options) {
name = name.toLowerCase();
if (options && EXTENDS in options) {
// currently options is not used but preserved for the future
registry[name] = assign({}, options, {Class: Class});
var query = options[EXTENDS] + '[is="' + name + '"]';
var changes = document.querySelectorAll(query);
for (var i = 0, length = changes.length; i < length; i++)
setupIfNeeded(changes[i]);
}
else
define.apply(customElements, arguments);
}
},
get: {
value: function (name) {
return name in registry ?
registry[name].Class :
get.call(customElements, name);
}
},
upgrade: {
value: function (node) {
var info = getInfo(node);
if (info && !(node instanceof info.Class))
setup(node, info);
else
upgrade.call(customElements, node);
}
},
whenDefined: {
value: function (name) {
return name in registry ?
Promise.resolve() :
whenDefined.call(customElements, name);
}
}
}
);
var createElement = document.createElement;
defineProperties(
document,
{
createElement: {
value: function (name, options) {
var node = createElement.call(document, name);
if (options && 'is' in options) {
node.setAttribute('is', options.is);
customElements.upgrade(node);
}
return node;
}
}
}
);
var attach = getOwnPropertyDescriptor(ElemProto, 'attachShadow').value;
var innerHTML = getOwnPropertyDescriptor(ElemProto, 'innerHTML');
defineProperties(
ElemProto,
{
attachShadow: {
value: function () {
var root = attach.apply(this, arguments);
new MutationObserver(DOMChanges).observe(root, changesOptions);
return root;
}
},
innerHTML: {
get: innerHTML.get,
set: function (HTML) {
innerHTML.set.call(this, HTML);
if (/\bis=("|')?[a-z0-9_-]+\1/i.test(HTML))
setupSubNodes(this, setupIfNeeded);
}
}
}
);
function DOMChanges(changes) {
for (var i = 0, length = changes.length; i < length; i++) {
var change = changes[i];
var addedNodes = change.addedNodes;
var removedNodes = change.removedNodes;
for (var j = 0, len = addedNodes.length; j < len; j++)
setupIfNeeded(addedNodes[j]);
for (var j = 0, len = removedNodes.length; j < len; j++)
disconnectIfNeeded(removedNodes[j]);
}
}
function attributeChanged(changes) {
for (var i = 0, length = changes.length; i < length; i++) {
var change = changes[i];
var attributeName = change.attributeName;
var oldValue = change.oldValue;
var target = change.target;
var newValue = target.getAttribute(attributeName);
if (
ATTRIBUTE_CHANGED_CALLBACK in target &&
!(oldValue == newValue && newValue == null)
)
target[ATTRIBUTE_CHANGED_CALLBACK](
attributeName,
oldValue,
target.getAttribute(attributeName),
// TODO: add getAttributeNS if the node is XML
null
);
}
}
function disconnectIfNeeded(node) {
if (node.nodeType !== 1)
return;
var info = getInfo(node);
if (
info &&
node instanceof info.Class &&
DISCONNECTED_CALLBACK in node &&
lifeCycle.get(node) !== DISCONNECTED_CALLBACK
) {
lifeCycle.set(node, DISCONNECTED_CALLBACK);
Promise.resolve(node).then(invokeDisconnectedCallback);
}
setupSubNodes(node, disconnectIfNeeded);
}
function getInfo(node) {
var is = node.getAttribute('is');
if (is) {
is = is.toLowerCase();
if (is in registry)
return registry[is];
}
return null;
}
function invokeConnectedCallback(node) {
node[CONNECTED_CALLBACK]();
}
function invokeDisconnectedCallback(node) {
node[DISCONNECTED_CALLBACK]();
}
function setup(node, info) {
var Class = info.Class;
var oa = Class.observedAttributes || [];
setPrototypeOf(node, Class.prototype);
if (oa.length) {
new MutationObserver(attributeChanged).observe(
node,
{
attributes: true,
attributeFilter: oa,
attributeOldValue: true
}
);
var changes = [];
for (var i = 0, length = oa.length; i < length; i++)
changes.push({attributeName: oa[i], oldValue: null, target: node});
attributeChanged(changes);
}
}
function setupIfNeeded(node) {
if (node.nodeType !== 1)
return;
var info = getInfo(node);
if (info) {
if (!(node instanceof info.Class))
setup(node, info);
if (
CONNECTED_CALLBACK in node &&
node.isConnected &&
lifeCycle.get(node) !== CONNECTED_CALLBACK
) {
lifeCycle.set(node, CONNECTED_CALLBACK);
Promise.resolve(node).then(invokeConnectedCallback);
}
}
setupSubNodes(node, setupIfNeeded);
}
function setupSubNodes(node, setup) {
for (var
t = node.content,
nodes = (t && t.nodeType == 11 ? t : node).querySelectorAll('[is]'),
i = 0, length = nodes.length; i < length; i++
)
setup(nodes[i]);
}
function wrapOriginal(prototype, name) {
var method = prototype[name];
var desc = {};
desc[name] = {
value: function () {
var result = method.apply(this, arguments);
switch (result.nodeType) {
case 1:
case 11:
setupSubNodes(result, setupIfNeeded);
}
return result;
}
};
defineProperties(prototype, desc);
}
}());
}
}(document, customElements, Object));
Loading…
Cancel
Save