periodicjs.ext.reactapp
Version:
380 lines (366 loc) • 17.6 kB
JavaScript
import React, { createElement, } from 'react';
import * as rebulma from 're-bulma';
import * as recharts from 'recharts';
import * as victory from 'victory';
import MaskedInput from 'react-text-mask';
import { Link, } from 'react-router';
import Slider, { Range, } from 'rc-slider';
import { default as Slick } from 'react-slick';
import { default as RCTable } from 'rc-table';
import { default as RCSwitch } from 'rc-switch';
import { default as RCTree, TreeNode as RCTreeNode } from 'rc-tree';
import Steps, { Step as RCStep, } from 'rc-steps';
import { Carousel, } from 'react-responsive-carousel';
import GoogleMap from 'google-map-react';
import { getAdvancedBinding, } from './advancedBinding';
import ResponsiveForm from '../ResponsiveForm';
import DynamicForm from '../DynamicForm';
import DynamicLayout from '../DynamicLayout';
import RawOutput from '../RawOutput';
import RawStateOutput from '../RawOutput/RawStateOutput';
import MenuAppLink from '../AppSidebar/MenuAppLink';
import SubMenuLinks from '../AppSidebar/SubMenuLinks';
import CodeMirror from '../RACodeMirror';
import PreviewEditor from '../PreviewEditor';
import ResponsiveDatalist from '../ResponsiveDatalist';
// import Editor from '../RAEditor';
import ResponsiveTable from '../ResponsiveTable';
import ResponsiveCard from '../ResponsiveCard';
import DynamicChart from '../DynamicChart';
// import DynamicResponsiveChart from '../DynamicChart/responsive';
import DynamicComponent from '../DynamicComponent';
import ResponsiveTabs from '../ResponsiveTabs';
import ResponsiveBar from '../ResponsiveBar';
import ResponsiveLink from '../ResponsiveLink';
import ResponsiveLogs from '../AppSectionLoading/log';
import ResponsiveIFrame from '../ResponsiveIFrame';
import ResponsiveButton from '../ResponsiveButton';
import ResponsiveSteps from '../ResponsiveSteps';
import FormItem from '../FormItem';
import utilities from '../../util';
let advancedBinding = getAdvancedBinding();
let renderIndex = 0;
//https://stackoverflow.com/questions/1007981/how-to-get-function-parameter-names-values-dynamically
export const STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
export const ARGUMENT_NAMES = /([^\s,]+)/g;
export function getParamNames(func) {
var fnStr = func.toString().replace(STRIP_COMMENTS, '');
var result = fnStr.slice(fnStr.indexOf('(')+1, fnStr.indexOf(')')).match(ARGUMENT_NAMES);
if(result === null){
result = [];
}
return result;
}
export function getEvalProps(options = {}) {
const { rjx, } = options;
// console.warn({rjx})
// eslint-disable-next-line
const scopedEval = eval; //https://github.com/rollup/rollup/wiki/Troubleshooting#avoiding-eval
const evProps = Object.keys(rjx.__dangerouslyEvalProps || {}).reduce((eprops, epropName) => {
let evVal;
try {
// eslint-disable-next-line
evVal = scopedEval(rjx.__dangerouslyEvalProps[ epropName ]);
} catch (e) {
if (this.debug || rjx.debug) evVal = e;
}
eprops[ epropName ] = (typeof evVal === 'function')
? evVal.call(this, { rjx })
: evVal;
// console.warn('eprops',eprops)
return eprops;
}, {});
const evBindProps = Object.keys(rjx.__dangerouslyBindEvalProps || {}).reduce((eprops, epropName) => {
let evVal;
try {
let args;
// InlineFunction = Function.prototype.constructor.apply({}, args);
const functionDefinition = scopedEval(rjx.__dangerouslyBindEvalProps[ epropName ]);
if (rjx.__functionargs && rjx.__functionargs[ epropName ]) {
args = [this,].concat(rjx.__functionargs[ epropName ].map(arg => rjx.props[ arg ]));
} else if (rjx.__functionparams) {
const functionDefArgs = getParamNames(functionDefinition);
args = [this,].concat(functionDefArgs);
} else {
args = [this,];
}
// eslint-disable-next-line
evVal = functionDefinition.bind(...args);
} catch (e) {
if (this.debug || rjx.debug) evVal = e;
}
// eslint-disable-next-line
eprops[ epropName ] = evVal;
return eprops;
}, {});
return Object.assign({}, evProps, evBindProps);
}
export function getFunctionFromProps(options) {
const { propFunc, propBody, } = options;
if (typeof propFunc === 'function') {
return propFunc.bind(this);
} else if (typeof propFunc === 'string' && propFunc.includes('func:inline')) {
let InlineFunction;
// eslint-disable-next-line
InlineFunction = Function('param1','param2','"use strict";' + propBody);
const [ propFuncName, funcName, ] = propFunc.split('.');
// console.info({ propFunc, propBody, propFuncName, funcName, });
Object.defineProperty(
InlineFunction,
'name',
{
value: funcName ||propFuncName,
}
);
return InlineFunction.bind(this);
} else if (typeof propFunc === 'string' && propFunc.indexOf('func:this.props.reduxRouter') !== -1) {
return this.props.reduxRouter[ propFunc.replace('func:this.props.reduxRouter.', '') ];
} else if (typeof propFunc === 'string' && propFunc.indexOf('func:this.props') !== -1) {
return this.props[ propFunc.replace('func:this.props.', '') ].bind(this);
} else if (typeof propFunc === 'string' && propFunc.indexOf('func:window') !== -1 && typeof window[propFunc.replace('func:window.', '')] ==='function') {
return window[ propFunc.replace('func:window.', '') ].bind(this);
} else if(typeof this.props[propFunc] ==='function') {
return propFunc.bind(this);
} else {
return function () { }
}
}
export let AppLayoutMap = Object.assign({}, { victory,
recharts, ResponsiveForm, DynamicLayout, DynamicComponent, DynamicForm, RawOutput, RawStateOutput, FormItem, MenuAppLink, SubMenuLinks, ResponsiveTable, ResponsiveCard, DynamicChart, /* DynamicResponsiveChart,*/ ResponsiveBar, ResponsiveTabs, ResponsiveDatalist, CodeMirror, Range, Slider, GoogleMap, Carousel, PreviewEditor, ResponsiveSteps, /* Editor,*/
ResponsiveLink,
ResponsiveLogs,
ResponsiveButton,
ResponsiveIFrame,
MaskedInput,
RCTable,
RCTree,
RCTreeNode,
RCSwitch,
Slick,
RCSteps: Steps,
RCStep
}, React.DOM, rebulma, window.__ra_custom_elements, { Link, });
export function getComponentFromMap(options = {}) {
const { componentObject, AppLayoutMap } = options;
// let reactComponent = null;
try {
if (typeof componentObject.component !== 'string') {
return componentObject.component;
} else if (React.DOM[ componentObject.component ]) {
return componentObject.component;
} else if (recharts[ componentObject.component.replace('recharts.', '') ]) {
return recharts[ componentObject.component.replace('recharts.', '') ];
} else if (victory[ componentObject.component.replace('victory.', '') ]) {
return victory[ componentObject.component.replace('victory.', '') ];
} else {
return AppLayoutMap[ componentObject.component ];
}
} catch (e) {
console.error(e, (e.stack) ? e.stack:'no stack');
// throw e;
return null;
}
}
export function getRenderedComponent(componentObject, resources, debug) {
if (debug) {
console.debug({resources,componentObject})
}
try {
if (advancedBinding) {
AppLayoutMap.ResponsiveLink = ResponsiveLink.bind(this);
AppLayoutMap.ResponsiveButton = ResponsiveButton.bind(this);
}
} catch (e) {
console.warn('deeply nested props are unsupported on this device', e);
}
// console.log('this.props', this);
renderIndex++;
// if(resources) console.info({ resources });
if (componentObject && componentObject.$$typeof) {
return componentObject;
} else if (componentObject && componentObject.component.$$typeof) {
return componentObject.component;
} else if (!componentObject) {
return createElement('span', {}, debug ? 'Error: Missing Component Object' : '');
}
try {
const getFunction = getFunctionFromProps.bind(this);
let asyncprops = (componentObject.asyncprops && typeof componentObject.asyncprops === 'object')
? utilities.traverse(componentObject.asyncprops, resources)
: {};
let windowprops = (componentObject.windowprops && typeof componentObject.windowprops === 'object')
? utilities.traverse(componentObject.windowprops, window)
: {};
let thisprops = (componentObject.thisprops && typeof componentObject.thisprops === 'object')
? utilities.traverse(componentObject.thisprops, Object.assign({
__reactapp_manifest: {
_component: componentObject,
_resources: resources,
},
}, this.props, componentObject.props, this.props.getState()))
: {};
let thisDotProps = (!React.DOM[ componentObject.component ] && !rebulma[ componentObject.component ] && !componentObject.ignoreReduxProps)
? this.props
: null;
//allowing javascript injections
let evalProps = (componentObject.__dangerouslyEvalProps||componentObject.__dangerouslyBindEvalProps)
? getEvalProps.call(this, { rjx:componentObject, })
: {};
let insertedComponents = (componentObject.__dangerouslyInsertComponents)
? Object.keys(componentObject.__dangerouslyInsertComponents).reduce((cprops, cpropName) => {
// eslint-disable-next-line
cprops[ cpropName ] = getRenderedComponent.call(this, componentObject.__dangerouslyInsertComponents[ cpropName ], resources, debug);
return cprops;
}, {})
: {};
// if (componentObject.__dangerouslyInsertComponents){ console.log({ insertedComponents });}
let renderedCompProps = Object.assign({
key: renderIndex,
__inline:{},
}, thisDotProps,
thisprops,
componentObject.props, asyncprops, windowprops, evalProps, insertedComponents);
if (renderedCompProps.ref) {
// console.warn('typeof renderedCompProps.ref', typeof renderedCompProps.ref);
renderedCompProps.ref = (typeof renderedCompProps.ref)
? renderedCompProps.ref
: getFunction({
propFunc: renderedCompProps.ref,
propBody: componentObject.__inline[ renderedCompProps.ref ],
});
}
//Allowing for window functions
if(componentObject.hasWindowFunc || componentObject.hasPropFunc){
Object.keys(renderedCompProps).forEach(key => {
// if (typeof renderedCompProps[key] ==='string' && renderedCompProps[key].indexOf('func:window') !== -1 && typeof window[ renderedCompProps[key].replace('func:window.', '') ] ==='function'){
// renderedCompProps[key]= window[ renderedCompProps[key].replace('func:window.', '') ].bind(this);
// }
if (typeof renderedCompProps[key] ==='string' && renderedCompProps[key].indexOf('func:') !== -1 ){
renderedCompProps[ key ] = getFunction({ propFunc: renderedCompProps[ key ] });
}
});
}
if (componentObject.hasWindowComponent && window.__ra_custom_elements) {
Object.keys(renderedCompProps).forEach(key => {
if (typeof renderedCompProps[key] ==='string' && renderedCompProps[key].indexOf('func:window.__ra_custom_elements') !== -1 && typeof window.__ra_custom_elements[ renderedCompProps[key].replace('func:window.__ra_custom_elements.', '') ] ==='function'){
renderedCompProps[ key ] = React.createElement(window.__ra_custom_elements[ renderedCompProps[ key ].replace('func:window.__ra_custom_elements.', '') ], (renderedCompProps[ 'windowCompProps' ]) ? renderedCompProps[ 'windowCompProps' ]
: this.props, null);
}
});
}
if (componentObject.__dangerouslyCalcProps && Object.keys(componentObject.__dangerouslyCalcProps).length) {
Object.keys(componentObject.__dangerouslyCalcProps).forEach(epropName => {
const functionBodyString = componentObject.__dangerouslyCalcProps[ epropName ];
// eslint-disable-next-line
const stringFunction = Function('renderedCompProps', '"use strict";' + functionBodyString);
Object.defineProperty(
stringFunction,
'name',
{
value: `${epropName}Function`,
}
);
renderedCompProps[ epropName ] = stringFunction(renderedCompProps);
});
}
if (renderedCompProps._children /* && !componentObject.children */) {
if (Array.isArray(renderedCompProps._children)) {
componentObject.children = [].concat(renderedCompProps._children);
} else {
componentObject.children = renderedCompProps._children;
}
delete renderedCompProps._children;
}
let comparisons = {};
// if (thisprops) {
// console.debug({ thisprops, renderedCompProps });
// }
// console.debug('componentObject.component', componentObject.component, { thisDotProps, });
if (componentObject.comparisonprops) {
comparisons = componentObject.comparisonprops.map(comp => {
let compares = {};
if (Array.isArray(comp.left)) {
compares.left = comp.left;
}
if (Array.isArray(comp.right)) {
compares.right = comp.right;
}
let propcompares = utilities.traverse(compares, renderedCompProps);
let opscompares = Object.assign({}, comp, propcompares);
// console.debug({ opscompares, compares, renderedCompProps });
if (opscompares.operation === 'eq') {
// return opscompares.left == opscompares.right;
return opscompares.left === opscompares.right;
} else if (opscompares.operation === 'dneq') {
// return opscompares.left != opscompares.right;
return opscompares.left !== opscompares.right;
} else if (opscompares.operation === 'dnseq') {
return opscompares.left !== opscompares.right;
} else if (opscompares.operation === 'seq') {
return opscompares.left === opscompares.right;
} else if (opscompares.operation === 'lt') {
return opscompares.left < opscompares.right;
} else if (opscompares.operation === 'lte') {
return opscompares.left <= opscompares.right;
} else if (opscompares.operation === 'gt') {
return opscompares.left > opscompares.right;
} else if (opscompares.operation === 'gte') {
return opscompares.left >= opscompares.right;
} else if (opscompares.operation === 'dne') {
return opscompares.left === undefined || opscompares.left === null;
} else { //'exists'
return opscompares.left !== undefined || opscompares.left !== null;
}
});
// console.debug({ comparisons });
// console.debug(comparisons.filter(comp => comp === true).length);
}
if (componentObject.comparisonprops && comparisons.filter(comp => comp === true).length!==comparisons.length && (!componentObject.comparisonorprops || (componentObject.comparisonorprops && comparisons.filter(comp => comp === true).length===0))) {
return null;
} else if (typeof componentObject.conditionalprops !== 'undefined'
&& !Object.keys(utilities.traverse(componentObject.conditionalprops, renderedCompProps)).filter(key => utilities.traverse(componentObject.conditionalprops, renderedCompProps)[ key ]).length && (!componentObject.comparisonorprops || (componentObject.comparisonorprops && comparisons.filter(comp => comp === true).length===0))) {
return null;
} else {
return createElement(
//element component
getComponentFromMap({ componentObject, AppLayoutMap }),
// (typeof componentObject.component === 'string')
// ? (React.DOM[ componentObject.component ])
// ? componentObject.component
// : (recharts[ componentObject.component.replace('recharts.', '') ])
// ? recharts[ componentObject.component.replace('recharts.', '') ]
// : AppLayoutMap[ componentObject.component ]
// : componentObject.component,
//element props
renderedCompProps,
//props children
(componentObject.children && Array.isArray(componentObject.children) && typeof componentObject.children !== 'string')
? componentObject.children.map(childComponentObject => getRenderedComponent.call(this,
(componentObject.bindprops)
? Object.assign({},
childComponentObject, {
props: Object.assign({},
renderedCompProps,
((childComponentObject.thisprops && childComponentObject.thisprops.style) // this is to make sure when you bind props, if you've defined props in a dynamic property, to not use bind props to remove passing down styles
|| (childComponentObject.asyncprops && childComponentObject.asyncprops.style)
|| (childComponentObject.windowprops && childComponentObject.windowprops.style))
? {}
: {
style: {},
},
childComponentObject.props,
{ key: renderIndex + Math.random(), }),
})
: childComponentObject, resources))
: (typeof componentObject.children === 'undefined')
? (renderedCompProps && renderedCompProps.children && typeof renderedCompProps.children==='string') ? renderedCompProps.children : null
: componentObject.children
);
}
} catch (e) {
console.error({ componentObject, resources, }, 'this', this);
console.error(e, (e.stack) ? e.stack:'no stack');
throw e;
// return createElement('div', {}, e.toString());
}
}