551 lines
19 KiB
JavaScript
551 lines
19 KiB
JavaScript
/**
|
|
* vue-custom-element v3.2.8
|
|
* (c) 2019 Karol Fabjańczuk
|
|
* @license MIT
|
|
*/
|
|
(function (global, factory) {
|
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
typeof define === 'function' && define.amd ? define(factory) :
|
|
(global.VueCustomElement = factory());
|
|
}(this, (function () { 'use strict';
|
|
|
|
/**
|
|
* ES6 Object.getPrototypeOf Polyfill
|
|
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf
|
|
*/
|
|
|
|
Object.setPrototypeOf = Object.setPrototypeOf || setPrototypeOf;
|
|
|
|
function setPrototypeOf(obj, proto) {
|
|
obj.__proto__ = proto;
|
|
return obj;
|
|
}
|
|
|
|
var setPrototypeOf_1 = setPrototypeOf.bind(Object);
|
|
|
|
function isES2015() {
|
|
if (typeof Symbol === 'undefined' || typeof Reflect === 'undefined' || typeof Proxy === 'undefined' || Object.isSealed(Proxy)) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
var isES2015$1 = isES2015();
|
|
|
|
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
|
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
|
|
|
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
|
|
|
function _CustomElement() {
|
|
return Reflect.construct(HTMLElement, [], this.__proto__.constructor);
|
|
}
|
|
|
|
|
|
Object.setPrototypeOf(_CustomElement.prototype, HTMLElement.prototype);
|
|
Object.setPrototypeOf(_CustomElement, HTMLElement);
|
|
function registerCustomElement(tag) {
|
|
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
|
|
if (typeof customElements === 'undefined') {
|
|
return;
|
|
}
|
|
|
|
function constructorCallback() {
|
|
if (options.shadow === true && HTMLElement.prototype.attachShadow) {
|
|
this.attachShadow({ mode: 'open' });
|
|
}
|
|
typeof options.constructorCallback === 'function' && options.constructorCallback.call(this);
|
|
}
|
|
function connectedCallback() {
|
|
typeof options.connectedCallback === 'function' && options.connectedCallback.call(this);
|
|
}
|
|
|
|
function disconnectedCallback() {
|
|
typeof options.disconnectedCallback === 'function' && options.disconnectedCallback.call(this);
|
|
}
|
|
|
|
function attributeChangedCallback(name, oldValue, value) {
|
|
typeof options.attributeChangedCallback === 'function' && options.attributeChangedCallback.call(this, name, oldValue, value);
|
|
}
|
|
|
|
function define(tagName, CustomElement) {
|
|
var existingCustomElement = customElements.get(tagName);
|
|
return typeof existingCustomElement !== 'undefined' ? existingCustomElement : customElements.define(tagName, CustomElement);
|
|
}
|
|
|
|
if (isES2015$1) {
|
|
var CustomElement = function (_CustomElement2) {
|
|
_inherits(CustomElement, _CustomElement2);
|
|
|
|
function CustomElement(self) {
|
|
var _ret;
|
|
|
|
_classCallCheck(this, CustomElement);
|
|
|
|
var _this = _possibleConstructorReturn(this, (CustomElement.__proto__ || Object.getPrototypeOf(CustomElement)).call(this));
|
|
|
|
var me = self ? HTMLElement.call(self) : _this;
|
|
|
|
constructorCallback.call(me);
|
|
return _ret = me, _possibleConstructorReturn(_this, _ret);
|
|
}
|
|
|
|
_createClass(CustomElement, null, [{
|
|
key: 'observedAttributes',
|
|
get: function get() {
|
|
return options.observedAttributes || [];
|
|
}
|
|
}]);
|
|
|
|
return CustomElement;
|
|
}(_CustomElement);
|
|
|
|
CustomElement.prototype.connectedCallback = connectedCallback;
|
|
CustomElement.prototype.disconnectedCallback = disconnectedCallback;
|
|
CustomElement.prototype.attributeChangedCallback = attributeChangedCallback;
|
|
|
|
define(tag, CustomElement);
|
|
return CustomElement;
|
|
} else {
|
|
var _CustomElement3 = function _CustomElement3(self) {
|
|
var me = self ? HTMLElement.call(self) : this;
|
|
|
|
constructorCallback.call(me);
|
|
return me;
|
|
};
|
|
|
|
_CustomElement3.observedAttributes = options.observedAttributes || [];
|
|
|
|
_CustomElement3.prototype = Object.create(HTMLElement.prototype, {
|
|
constructor: {
|
|
configurable: true,
|
|
writable: true,
|
|
value: _CustomElement3
|
|
}
|
|
});
|
|
|
|
_CustomElement3.prototype.connectedCallback = connectedCallback;
|
|
_CustomElement3.prototype.disconnectedCallback = disconnectedCallback;
|
|
_CustomElement3.prototype.attributeChangedCallback = attributeChangedCallback;
|
|
|
|
define(tag, _CustomElement3);
|
|
return _CustomElement3;
|
|
}
|
|
}
|
|
|
|
var camelizeRE = /-(\w)/g;
|
|
var camelize = function camelize(str) {
|
|
return str.replace(camelizeRE, function (_, c) {
|
|
return c ? c.toUpperCase() : '';
|
|
});
|
|
};
|
|
var hyphenateRE = /([^-])([A-Z])/g;
|
|
var hyphenate = function hyphenate(str) {
|
|
return str.replace(hyphenateRE, '$1-$2').replace(hyphenateRE, '$1-$2').toLowerCase();
|
|
};
|
|
|
|
function toArray(list) {
|
|
var start = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
|
|
var i = list.length - start;
|
|
var ret = new Array(i);
|
|
while (i--) {
|
|
ret[i] = list[i + start];
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
|
|
|
|
function convertAttributeValue(value, overrideType) {
|
|
if (value === null || value === undefined) {
|
|
return overrideType === Boolean ? false : undefined;
|
|
}
|
|
var propsValue = value;
|
|
var isBoolean = ['true', 'false'].indexOf(value) > -1;
|
|
var valueParsed = parseFloat(propsValue, 10);
|
|
var isNumber = !isNaN(valueParsed) && isFinite(propsValue) && typeof propsValue === 'string' && !propsValue.match(/^0+[^.]\d*$/g);
|
|
|
|
if (overrideType && overrideType !== Boolean && (typeof propsValue === 'undefined' ? 'undefined' : _typeof(propsValue)) !== overrideType) {
|
|
propsValue = overrideType(value);
|
|
} else if (isBoolean || overrideType === Boolean) {
|
|
propsValue = propsValue === '' ? true : propsValue === 'true';
|
|
} else if (isNumber) {
|
|
propsValue = valueParsed;
|
|
}
|
|
|
|
return propsValue;
|
|
}
|
|
|
|
function extractProps(collection, props) {
|
|
if (collection && collection.length) {
|
|
collection.forEach(function (prop) {
|
|
var camelCaseProp = camelize(prop);
|
|
props.camelCase.indexOf(camelCaseProp) === -1 && props.camelCase.push(camelCaseProp);
|
|
});
|
|
} else if (collection && (typeof collection === 'undefined' ? 'undefined' : _typeof(collection)) === 'object') {
|
|
for (var prop in collection) {
|
|
var camelCaseProp = camelize(prop);
|
|
props.camelCase.indexOf(camelCaseProp) === -1 && props.camelCase.push(camelCaseProp);
|
|
|
|
if (collection[camelCaseProp] && collection[camelCaseProp].type) {
|
|
props.types[prop] = [].concat(collection[camelCaseProp].type)[0];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function getProps() {
|
|
var componentDefinition = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
|
|
var props = {
|
|
camelCase: [],
|
|
hyphenate: [],
|
|
types: {}
|
|
};
|
|
|
|
if (componentDefinition.mixins) {
|
|
componentDefinition.mixins.forEach(function (mixin) {
|
|
extractProps(mixin.props, props);
|
|
});
|
|
}
|
|
|
|
if (componentDefinition.extends && componentDefinition.extends.props) {
|
|
var parentProps = componentDefinition.extends.props;
|
|
|
|
|
|
extractProps(parentProps, props);
|
|
}
|
|
|
|
extractProps(componentDefinition.props, props);
|
|
|
|
props.camelCase.forEach(function (prop) {
|
|
props.hyphenate.push(hyphenate(prop));
|
|
});
|
|
|
|
return props;
|
|
}
|
|
|
|
function reactiveProps(element, props) {
|
|
props.camelCase.forEach(function (name, index) {
|
|
Object.defineProperty(element, name, {
|
|
get: function get() {
|
|
return this.__vue_custom_element__[name];
|
|
},
|
|
set: function set(value) {
|
|
if (((typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object' || typeof value === 'function') && this.__vue_custom_element__) {
|
|
var propName = props.camelCase[index];
|
|
this.__vue_custom_element__[propName] = value;
|
|
} else {
|
|
var type = props.types[props.camelCase[index]];
|
|
this.setAttribute(props.hyphenate[index], convertAttributeValue(value, type));
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
function getPropsData(element, componentDefinition, props) {
|
|
var propsData = componentDefinition.propsData || {};
|
|
|
|
props.hyphenate.forEach(function (name, index) {
|
|
var propCamelCase = props.camelCase[index];
|
|
var propValue = element.attributes[name] || element[propCamelCase];
|
|
|
|
var type = null;
|
|
if (props.types[propCamelCase]) {
|
|
type = props.types[propCamelCase];
|
|
}
|
|
|
|
if (propValue instanceof Attr) {
|
|
propsData[propCamelCase] = convertAttributeValue(propValue.value, type);
|
|
} else if (typeof propValue !== 'undefined') {
|
|
propsData[propCamelCase] = propValue;
|
|
}
|
|
});
|
|
|
|
return propsData;
|
|
}
|
|
|
|
function getAttributes(children) {
|
|
var attributes = {};
|
|
|
|
toArray(children.attributes).forEach(function (attribute) {
|
|
attributes[attribute.nodeName === 'vue-slot' ? 'slot' : attribute.nodeName] = attribute.nodeValue;
|
|
});
|
|
|
|
return attributes;
|
|
}
|
|
|
|
function getChildNodes(element) {
|
|
if (element.childNodes.length) return element.childNodes;
|
|
if (element.content && element.content.childNodes && element.content.childNodes.length) {
|
|
return element.content.childNodes;
|
|
}
|
|
|
|
var placeholder = document.createElement('div');
|
|
|
|
placeholder.innerHTML = element.innerHTML;
|
|
|
|
return placeholder.childNodes;
|
|
}
|
|
|
|
function templateElement(createElement, element, elementOptions) {
|
|
var templateChildren = getChildNodes(element);
|
|
|
|
var vueTemplateChildren = toArray(templateChildren).map(function (child) {
|
|
if (child.nodeName === '#text') return child.nodeValue;
|
|
|
|
return createElement(child.tagName, {
|
|
attrs: getAttributes(child),
|
|
domProps: {
|
|
innerHTML: child.innerHTML
|
|
}
|
|
});
|
|
});
|
|
|
|
elementOptions.slot = element.id;
|
|
|
|
return createElement('template', elementOptions, vueTemplateChildren);
|
|
}
|
|
|
|
function getSlots() {
|
|
var children = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
var createElement = arguments[1];
|
|
|
|
var slots = [];
|
|
toArray(children).forEach(function (child) {
|
|
if (child.nodeName === '#text') {
|
|
if (child.nodeValue.trim()) {
|
|
slots.push(createElement('span', child.nodeValue));
|
|
}
|
|
} else if (child.nodeName !== '#comment') {
|
|
var attributes = getAttributes(child);
|
|
var elementOptions = {
|
|
attrs: attributes,
|
|
domProps: {
|
|
innerHTML: child.innerHTML === '' ? child.innerText : child.innerHTML
|
|
}
|
|
};
|
|
|
|
if (attributes.slot) {
|
|
elementOptions.slot = attributes.slot;
|
|
attributes.slot = undefined;
|
|
}
|
|
|
|
var slotVueElement = child.tagName === 'TEMPLATE' ? templateElement(createElement, child, elementOptions) : createElement(child.tagName, elementOptions);
|
|
|
|
slots.push(slotVueElement);
|
|
}
|
|
});
|
|
|
|
return slots;
|
|
}
|
|
|
|
function customEvent(eventName, detail) {
|
|
var params = { bubbles: false, cancelable: false, detail: detail };
|
|
var event = void 0;
|
|
if (typeof window.CustomEvent === 'function') {
|
|
event = new CustomEvent(eventName, params);
|
|
} else {
|
|
event = document.createEvent('CustomEvent');
|
|
event.initCustomEvent(eventName, params.bubbles, params.cancelable, params.detail);
|
|
}
|
|
return event;
|
|
}
|
|
|
|
function customEmit(element, eventName) {
|
|
for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
|
|
args[_key - 2] = arguments[_key];
|
|
}
|
|
|
|
var event = customEvent(eventName, [].concat(args));
|
|
element.dispatchEvent(event);
|
|
}
|
|
|
|
function createVueInstance(element, Vue, componentDefinition, props, options) {
|
|
if (!element.__vue_custom_element__) {
|
|
var beforeCreate = function beforeCreate() {
|
|
this.$emit = function emit() {
|
|
var _proto__$$emit;
|
|
|
|
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
|
|
args[_key] = arguments[_key];
|
|
}
|
|
|
|
customEmit.apply(undefined, [element].concat(args));
|
|
this.__proto__ && (_proto__$$emit = this.__proto__.$emit).call.apply(_proto__$$emit, [this].concat(args));
|
|
};
|
|
};
|
|
|
|
var ComponentDefinition = Vue.util.extend({}, componentDefinition);
|
|
var propsData = getPropsData(element, ComponentDefinition, props);
|
|
var vueVersion = Vue.version && parseInt(Vue.version.split('.')[0], 10) || 0;
|
|
|
|
ComponentDefinition.beforeCreate = [].concat(ComponentDefinition.beforeCreate || [], beforeCreate);
|
|
|
|
if (ComponentDefinition._compiled) {
|
|
var ctorOptions = {};
|
|
if (ComponentDefinition._Ctor) {
|
|
ctorOptions = Object.values(ComponentDefinition._Ctor)[0].options;
|
|
}
|
|
ctorOptions.beforeCreate = ComponentDefinition.beforeCreate;
|
|
}
|
|
|
|
var rootElement = void 0;
|
|
|
|
if (vueVersion >= 2) {
|
|
var elementOriginalChildren = element.cloneNode(true).childNodes;
|
|
rootElement = {
|
|
propsData: propsData,
|
|
props: props.camelCase,
|
|
computed: {
|
|
reactiveProps: function reactiveProps$$1() {
|
|
var _this = this;
|
|
|
|
var reactivePropsList = {};
|
|
props.camelCase.forEach(function (prop) {
|
|
typeof _this[prop] !== 'undefined' && (reactivePropsList[prop] = _this[prop]);
|
|
});
|
|
|
|
return reactivePropsList;
|
|
}
|
|
},
|
|
render: function render(createElement) {
|
|
var data = {
|
|
props: this.reactiveProps
|
|
};
|
|
|
|
return createElement(ComponentDefinition, data, getSlots(elementOriginalChildren, createElement));
|
|
}
|
|
};
|
|
} else if (vueVersion === 1) {
|
|
rootElement = ComponentDefinition;
|
|
rootElement.propsData = propsData;
|
|
} else {
|
|
rootElement = ComponentDefinition;
|
|
var propsWithDefault = {};
|
|
Object.keys(propsData).forEach(function (prop) {
|
|
propsWithDefault[prop] = { default: propsData[prop] };
|
|
});
|
|
rootElement.props = propsWithDefault;
|
|
}
|
|
|
|
var elementInnerHtml = vueVersion >= 2 ? '<div></div>' : ('<div>' + element.innerHTML + '</div>').replace(/vue-slot=/g, 'slot=');
|
|
if (options.shadow && element.shadowRoot) {
|
|
element.shadowRoot.innerHTML = elementInnerHtml;
|
|
rootElement.el = element.shadowRoot.children[0];
|
|
} else {
|
|
element.innerHTML = elementInnerHtml;
|
|
rootElement.el = element.children[0];
|
|
}
|
|
|
|
reactiveProps(element, props);
|
|
|
|
if (typeof options.beforeCreateVueInstance === 'function') {
|
|
rootElement = options.beforeCreateVueInstance(rootElement) || rootElement;
|
|
}
|
|
|
|
element.__vue_custom_element__ = new Vue(rootElement);
|
|
element.__vue_custom_element_props__ = props;
|
|
element.getVueInstance = function () {
|
|
return element.__vue_custom_element__.$children[0];
|
|
};
|
|
|
|
if (options.shadow && options.shadowCss && element.shadowRoot) {
|
|
var style = document.createElement('style');
|
|
style.type = 'text/css';
|
|
style.appendChild(document.createTextNode(options.shadowCss));
|
|
|
|
element.shadowRoot.appendChild(style);
|
|
}
|
|
element.removeAttribute('vce-cloak');
|
|
element.setAttribute('vce-ready', '');
|
|
customEmit(element, 'vce-ready');
|
|
}
|
|
}
|
|
|
|
function install(Vue) {
|
|
Vue.customElement = function vueCustomElement(tag, componentDefinition) {
|
|
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
|
|
var isAsyncComponent = typeof componentDefinition === 'function';
|
|
var optionsProps = isAsyncComponent && { props: options.props || [] };
|
|
var props = getProps(isAsyncComponent ? optionsProps : componentDefinition);
|
|
|
|
var CustomElement = registerCustomElement(tag, {
|
|
constructorCallback: function constructorCallback() {
|
|
typeof options.constructorCallback === 'function' && options.constructorCallback.call(this);
|
|
},
|
|
connectedCallback: function connectedCallback() {
|
|
var _this = this;
|
|
|
|
var asyncComponentPromise = isAsyncComponent && componentDefinition();
|
|
var isAsyncComponentPromise = asyncComponentPromise && asyncComponentPromise.then && typeof asyncComponentPromise.then === 'function';
|
|
|
|
typeof options.connectedCallback === 'function' && options.connectedCallback.call(this);
|
|
|
|
if (isAsyncComponent && !isAsyncComponentPromise) {
|
|
throw new Error('Async component ' + tag + ' do not returns Promise');
|
|
}
|
|
if (!this.__detached__) {
|
|
if (isAsyncComponentPromise) {
|
|
asyncComponentPromise.then(function (lazyLoadedComponent) {
|
|
var lazyLoadedComponentProps = getProps(lazyLoadedComponent);
|
|
createVueInstance(_this, Vue, lazyLoadedComponent, lazyLoadedComponentProps, options);
|
|
typeof options.vueInstanceCreatedCallback === 'function' && options.vueInstanceCreatedCallback.call(_this);
|
|
});
|
|
} else {
|
|
createVueInstance(this, Vue, componentDefinition, props, options);
|
|
typeof options.vueInstanceCreatedCallback === 'function' && options.vueInstanceCreatedCallback.call(this);
|
|
}
|
|
}
|
|
|
|
this.__detached__ = false;
|
|
},
|
|
disconnectedCallback: function disconnectedCallback() {
|
|
var _this2 = this;
|
|
|
|
this.__detached__ = true;
|
|
typeof options.disconnectedCallback === 'function' && options.disconnectedCallback.call(this);
|
|
|
|
options.destroyTimeout !== null && setTimeout(function () {
|
|
if (_this2.__detached__ && _this2.__vue_custom_element__) {
|
|
_this2.__vue_custom_element__.$destroy(true);
|
|
delete _this2.__vue_custom_element__;
|
|
delete _this2.__vue_custom_element_props__;
|
|
}
|
|
}, options.destroyTimeout || 3000);
|
|
},
|
|
attributeChangedCallback: function attributeChangedCallback(name, oldValue, value) {
|
|
if (this.__vue_custom_element__ && typeof value !== 'undefined') {
|
|
var nameCamelCase = camelize(name);
|
|
typeof options.attributeChangedCallback === 'function' && options.attributeChangedCallback.call(this, name, oldValue, value);
|
|
var type = this.__vue_custom_element_props__.types[nameCamelCase];
|
|
this.__vue_custom_element__[nameCamelCase] = convertAttributeValue(value, type);
|
|
}
|
|
},
|
|
|
|
|
|
observedAttributes: props.hyphenate,
|
|
|
|
shadow: !!options.shadow && !!HTMLElement.prototype.attachShadow
|
|
});
|
|
|
|
return CustomElement;
|
|
};
|
|
}
|
|
|
|
if (typeof window !== 'undefined' && window.Vue) {
|
|
window.Vue.use(install);
|
|
if (install.installed) {
|
|
install.installed = false;
|
|
}
|
|
}
|
|
|
|
return install;
|
|
|
|
})));
|