@syncfusion/ej2-vue-base
Version:
A common package of Essential JS 2 base Vue libraries, methods and class definitions
362 lines (352 loc) • 16.9 kB
text/typescript
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types */
import { setTemplateEngine, getTemplateEngine, getUniqueID, createElement, detach, extend, getValue } from '@syncfusion/ej2-base';
import { aVue as Vue, isExecute } from './component-base';
const stringCompiler: (template: string, helper?: object) => (data: Object | JSON) => string = getTemplateEngine();
/**
* Compiler function that convert the template property to DOM element.
*
* @param {any} templateElement - represents value of the template property from the component.
* @param {Object} helper - represents helper object to utilize on template compilation.
* @returns {NodeList} template element that append to the component.
*/
export function compile(
templateElement: any,
helper?: Object
): (data: Object | JSON, component?: any, propName?: any, element?: any, root?: any) => Object {
return (data: any, context: any, propName: any, element: any, root: any): any => {
let returnEle: any;
if (context) {
let plugins: any = context.vueInstance && context.vueInstance.plugins ? { plugins: context.vueInstance.plugins } : {};
const vueInstance: any = context.vueInstance ? context.vueInstance :
((root && root.vueInstance) ? root.vueInstance : null);
const pid: string = getUniqueID('templateParentDiv');
const id: string = getUniqueID('templateDiv');
const ele: HTMLElement = createElement('div', {
id: pid,
innerHTML: '<div id="' + id + '"></div>'
});
document.body.appendChild(ele);
if (!isExecute && (typeof templateElement === 'string' || (templateElement.prototype && templateElement.prototype.CSPTemplate && typeof templateElement === 'function'))) {
const vueSlot: any = getCurrentVueSlot(context.vueInstance, templateElement, root);
if (vueSlot) {
// Compilation for Vue 3 slot template
const app: any = Vue.createVNode({
render(): any {
return vueSlot[`${templateElement}`]({ data: data });
}
}, plugins);
ele.innerHTML = '';
// Get values for Vue 3 slot template
getValues(app, context.vueInstance, root);
Vue.render(app, ele);
returnEle = ele.childNodes;
if (vueInstance) {
let templateInstance: any = vueInstance.templateCollection;
if (!templateInstance) {
vueInstance.templateCollection = {};
templateInstance = vueInstance.templateCollection;
}
if (propName) {
if (!templateInstance[`${propName}`]) {
templateInstance[`${propName}`] = [];
}
templateInstance[`${propName}`].push(ele);
}
}
detach(ele);
} else {
// Compilation for Vue 3 string template
detach(ele);
return stringCompiler(templateElement, helper)(data);
}
} else if (!isExecute) {
// Compilation for Vue 3 functional template
const tempObj: any = templateElement.call(this, {});
const object: any = tempObj;
const propsData: any = getValue('template.propsData', tempObj);
const dataObj: any = {
data: { data: extend(tempObj.data || {}, data) },
parent: context.vueInstance
};
if (!object.template) {
object.template = object[Object.keys(object)[0]];
}
let templateCompRef: any;
if (object.template.extends) {
templateCompRef = object.template.extends._context.components.template;
} else {
templateCompRef = object.template._context.components[templateElement.name];
if (!templateCompRef) {
const key: any = Object.keys(object.template._context.components)[0];
templateCompRef = object.template._context.components[`${key}`];
}
}
let tempRef: any;
if (propsData) {
if (templateCompRef.setup) {
tempRef = (<any>Object).assign({}, propsData);
} else {
tempRef = (<any>Object).assign(templateCompRef.data(), propsData);
}
}
else {
if (templateCompRef.setup) {
tempRef = (<any>Object).assign({}, dataObj.data);
} else {
tempRef = (<any>Object).assign(templateCompRef.data(), dataObj.data);
}
if (templateCompRef.components) {
const objkeys: any = Object.keys(templateCompRef.components) || [];
for (const objstring of objkeys) {
const intComponent: any = templateCompRef.components[`${objstring}`];
if (intComponent && intComponent.data) {
if (!intComponent.__data) { intComponent.__data = intComponent.data; }
intComponent.data = function (proxy: any): Object {
return (Object as any).assign(intComponent.__data.call(proxy), dataObj.data);
};
}
}
}
}
if (templateCompRef.setup) {
plugins = (<any>Object).assign(plugins, data);
}
templateCompRef.data = function (): any { return tempRef; };
const app: any = Vue.createVNode(templateCompRef, plugins);
ele.innerHTML = '';
// Get values for Vue 3 functional template
getValues(app, context.vueInstance, root);
Vue.render(app, ele);
returnEle = ele.childNodes;
dataObj.parent = null;
if (vueInstance) {
let templateInstance: any = vueInstance.templateCollection;
if (!templateInstance) {
vueInstance.templateCollection = {};
templateInstance = vueInstance.templateCollection;
}
if (propName) {
if (!templateInstance[`${propName}`]) {
templateInstance[`${propName}`] = [];
}
templateInstance[`${propName}`].push(ele);
}
}
detach(ele);
} else if (typeof templateElement === 'string' || (templateElement.prototype && templateElement.prototype.CSPTemplate && typeof templateElement === 'function')) {
const vueSlot: any = getVueSlot(context.vueInstance, templateElement, root);
if (vueSlot) {
// Get provide values for Vue 2 slot template
let provided: any = {};
const getProvideValues: any = (vueinstance: any) => {
if (vueinstance['$parent']) { getProvideValues(vueinstance.$parent); }
if (vueinstance['_provided'] && Object.keys(vueinstance['_provided']).length > 0) {
provided = { ...provided, ...vueinstance._provided };
}
};
const vueInstance: any = context.vueInstance ? context.vueInstance :
((root && root.vueInstance) ? root.vueInstance : null);
if (vueInstance) {
getProvideValues(vueInstance);
}
// Compilation for Vue 2 slot template
const vueTemplate: any = new Vue({
provide: { ...provided },
render(): any {
return vueSlot[`${templateElement}`]({ data: data });
}
});
vueTemplate.$mount('#' + id);
returnEle = ele.childNodes;
if (vueInstance) {
let templateInstance: any = vueInstance.templateCollection;
if (!templateInstance) {
vueInstance.templateCollection = {};
templateInstance = vueInstance.templateCollection;
}
if (propName) {
if (!templateInstance[`${propName}`]) {
templateInstance[`${propName}`] = [];
}
templateInstance[`${propName}`].push(returnEle[0]);
}
}
detach(ele);
} else {
// Compilation for Vue 2 string template
detach(ele);
return stringCompiler(templateElement, helper)(data);
}
} else {
// Compilation for Vue 2 functional template
const tempObj: any = templateElement.call(this, {});
let templateFunction: any = tempObj.template;
const propsData: any = getValue('template.propsData', tempObj);
const dataObj: any = {
data: { data: extend(tempObj.data || {}, data) },
parent: context.vueInstance
};
if (propsData) {
templateFunction = tempObj.template.extends;
dataObj.propsData = propsData;
}
if (typeof templateFunction !== 'function') {
templateFunction = Vue.extend(templateFunction);
}
if (templateFunction.options.setup) {
dataObj.propsData = (<any>Object).assign(dataObj.propsData || {}, data);
}
const templateVue: any = new templateFunction(dataObj);
// let templateVue = new Vue(tempObj.template);
// templateVue.$data.data = extend(tempObj.data, data);
templateVue.$mount('#' + id);
returnEle = ele.childNodes;
dataObj.parent = null;
if (vueInstance) {
let templateInstance: any = vueInstance.templateCollection;
if (!templateInstance) {
vueInstance.templateCollection = {};
templateInstance = vueInstance.templateCollection;
}
if (propName) {
if (!templateInstance[`${propName}`]) {
templateInstance[`${propName}`] = [];
}
templateInstance[`${propName}`].push(returnEle[0]);
}
}
detach(ele);
}
}
return returnEle || [];
};
}
setTemplateEngine({ compile: compile as any });
/**
* Collect values from the app instance.
*
* @param {any} app - represents global application instance
* @param {any} cInstance - represents Vue component instance
* @param {any} root - represents parent component instance
* @returns {void}
*/
function getValues(app: any, cInstance: any, root: any): void {
const vueInstance: any = cInstance ? cInstance : ((root && root.vueInstance) ? root.vueInstance : null);
if (!vueInstance) {
return;
}
// Get globally defined variables.
app['appContext'] = vueInstance['$']['appContext'];
// Get provide value from child component.
let provided: any = {};
const getProvideValue: any = (vueinstance: any) => {
if (vueinstance['$'] && vueinstance['$']['parent']) { getProvideValue(vueinstance.$.parent); }
if (vueinstance['provides'] && Object.keys(vueinstance['provides']).length > 0) {
provided = { ...provided, ...vueinstance.provides };
}
};
getProvideValue(vueInstance);
if (app['appContext']['provides']) {
app.appContext.provides = { ...app.appContext.provides, ...provided };
}
}
/**
* Get the Vue2 slot template from the root or current Vue component.
*
* @param {any} vueInstance - represents parent Vue instance.
* @param {any} templateElement - represents component property value
* @param {any} root - represents root Vue instance
* @returns {any} template Vue instance
*/
function getVueSlot(vueInstance: any, templateElement: any, root: any): any {
if (!vueInstance && !(root && root.vueInstance)) {
return undefined;
}
const instance: any = (root && root.vueInstance) ? root.vueInstance : vueInstance;
return getVueChildSlot(instance, templateElement);
}
/**
* Get the Vue2 nested slot template from the root or current Vue component.
*
* @param {any} vueInstance - represents parent Vue instance.
* @param {any} templateElement - represents component property value
* @returns {any} nested template Vue instance
*/
function getVueChildSlot(vueInstance: any, templateElement: any): any {
if (!vueInstance) {
return undefined;
}
const slots: any = vueInstance.$slots;
const scopedSlots: any = vueInstance.$scopedSlots;
const vSlots: any = vueInstance.scopedSlots;
const children: any = vueInstance.children;
if (scopedSlots && scopedSlots[`${templateElement}`]) {
return scopedSlots;
} else if (slots && slots.default) {
const childSlots: any = slots.default;
for (let i: number = 0; i < childSlots.length; i++) {
const slot: any = getVueChildSlot(getSlot(childSlots[parseInt(i.toString(), 10)]), templateElement);
if (slot) {
return slot;
}
}
} else if (vSlots && vSlots[`${templateElement}`]) {
return vSlots;
} else if (children) {
for (let i: number = 0; i < children.length; i++) {
const slot: any = getVueChildSlot(getSlot(children[parseInt(i.toString(), 10)]), templateElement);
if (slot) {
return slot;
}
}
}
return undefined;
}
/**
* Collect the component slot directive instance.
*
* @param {any} vnode - represents Vue components slot instance.
* @returns {any} the slot instance of the directive.
*/
function getSlot(vnode: any): any {
const slot: any = (vnode.componentOptions && vnode.componentOptions.children) ? vnode.componentOptions :
(!vnode.data && (vnode.tag === 'e-markersettings' || vnode.tag === 'e-markersetting')) ? vnode : vnode.data;
return vnode.componentInstance ? vnode.componentInstance : slot;
}
/**
* Get the Vue3 slot template from the root or current Vue component.
*
* @param {any} vueInstance - represents parent Vue instance.
* @param {any} templateElement - represents component property value
* @param {any} root - represents root Vue instance
* @returns {any} slot template instance
*/
function getCurrentVueSlot(vueInstance: any, templateElement: any, root: any): any {
if (!vueInstance && !(root && root.vueInstance)) {
return undefined;
}
const slots: any = (root && root.vueInstance) ? root.vueInstance.$slots : vueInstance.$slots;
return getChildVueSlot(slots, templateElement);
}
/**
* Get the Vue3 nested slot template from the root or current Vue component.
*
* @param {any} slots - represents slot instance.
* @param {any} templateElement - represents component property value
* @returns {any} nested template Vue instance
*/
function getChildVueSlot(slots: any, templateElement: any): any {
if (slots && slots[`${templateElement}`]) {
return slots;
} else if (slots && slots.default) {
let childSlots: any = slots.default();
childSlots = childSlots.flatMap((item: any) => Array.isArray(item.children) ? item.children : item);
for (let i: number = 0; i < childSlots.length; i++) {
const slot: any = getChildVueSlot(childSlots[parseInt(i.toString(), 10)].children, templateElement);
if (slot) {
return slot;
}
}
}
return undefined;
}