UNPKG

framework-entersol-web

Version:

Framework based on bootstrap 5

205 lines (187 loc) 6.46 kB
import urlJoin from "url-join"; import React from "react"; import PropTypes from "prop-types"; import { HashRouter, BrowserRouter, withRouter, Router, Route, Redirect, Switch } from "react-router-dom"; import { hash } from "../functions"; import controllers from "../controllers"; import { addComponents } from "../components"; const routePropTypes = { path: PropTypes.oneOfType([ PropTypes.string, PropTypes.arrayOf(PropTypes.string) ]).isRequired, content: PropTypes.any.isRequired, name: PropTypes.string, component: PropTypes.string, exact: PropTypes.bool, strict: PropTypes.bool, location: PropTypes.object, sensitive: PropTypes.bool, redirect: PropTypes.string, routes: PropTypes.oneOfType([ PropTypes.arrayOf(PropTypes.shape(this)), PropTypes.shape(this) ]) }; const schemaPropTypes = { test: PropTypes.bool, theme: PropTypes.string, routes: routePropTypes.routes, redirect: PropTypes.func, defaultController: PropTypes.func, } const schemaDefaultProps = { routes: [], defaultController: controllers.Controller } export default class SchemaController extends React.Component { static jsClass = 'SchemaController'; static propTypes = schemaPropTypes; static defaultProps = schemaDefaultProps; state = { routeNodes: [] } constructor(props) { super(props); } buildRoutes() { // crear un clone de lo que se recibe const schemaStr = JSON.stringify(this.props.routes); const routesSchema = JSON.parse(schemaStr); // se crean las rutas de forma única. let routes; if (Array.isArray(routesSchema)) routes = routesSchema.map(this.views); else if (typeof routesSchema === 'object' && routesSchema.name) routes = this.views(routesSchema); else if (typeof routesSchema === 'object') routes = Object.keys(routesSchema) .map((name, i) => this.views({ name, ...routesSchema[name] }, i)) this.setState({ routeNodes: routes }); } componentDidMount() { this.buildRoutes(); } componentDidUpdate(prevProps, prevState) { // comprobar si ha cambiado el schema let newHash = hash(JSON.stringify(this.props.routes)); if (this.routesHash !== newHash) { this.buildRoutes(); this.routesHash = newHash; } } /** views * Método recursivo que procesa el schema de rutas * usar en el mapeo de un arreglo ej. routes.map(this.views) * permite que el schema tenga un arreglo de paths **/ views = (route, i) => { const Controller = controllers[route.component] || this.props.defaultController || controllers.Controller; let subroutes = false; if (Array.isArray(route.routes)) subroutes = []; else if (typeof route.routes === 'object') { subroutes = []; route.routes = Object.keys(route.routes) .map(name => ({ name, ...route.routes[name] })); } if (subroutes) { const mapRoutes = (subRoute, i) => { // crear un clone para no tocar el original subRoute = JSON.parse(JSON.stringify(subRoute)); // si las rutas son un arreglo if (Array.isArray(route.path) && Array.isArray(subRoute.path)) { subRoute.path = subRoute.path.reduce((paths, path) => { paths.push(route.path.map(parentPath => urlJoin(parentPath, path))); return paths; }, []); } else if (Array.isArray(subRoute.path)) { subRoute.path = subRoute.path.map(path => urlJoin(route.path, path)); } else if (Array.isArray(route.path)) { subRoute.path = route.path.map(path => urlJoin(path, subRoute.path)); } else { subRoute.path = urlJoin(route.path, subRoute.path || ''); } return this.views(subRoute, i); } subroutes = route.routes.map(mapRoutes); } // si exacto no está definido entonces true let exact = (typeof route.exact === 'undefined' || route.exact); // si hay subroutas entonces false exact = exact && !route.routes; const routeProps = { path: route.path, exact, strict: route.strict, location: route.location, sensitive: route.sensitive }; const RedirViewManager = (props) => { let redirTo = typeof this.props.redirect === 'function' && this.props.redirect(props.location); if (redirTo) return <Redirect to={{ pathname: redirTo, state: { from: props.location } }} /> const viewClassName = Array.from(document.body.classList) .find(cl => cl.endsWith('-view')); document.body.classList.remove(viewClassName); document.body.classList.add(route.name + '-view'); document.body.classList.forEach(cls => { if (cls.startsWith('location-')) document.body.classList.remove(cls); }); document.body.classList.add('location' + props.location.pathname.replace(/\//g, '-')); const useSwitch = (typeof route.useSwitch === 'undefined' || route.useSwitch); return (<Controller {...route} {...props} test={this.props.test}> {useSwitch ? <Switch>{subroutes}</Switch> : subroutes } </Controller>); } const key = i || typeof i === 'number' ? (i + '-' + route.name) : route.name; return (<Route key={key} {...routeProps} render={RedirViewManager} />); } render() { let { history, theme } = this.props; let { routeNodes } = this.state; return (<Router history={history}> {theme && <link rel="stylesheet" type="text/css" href={theme} />} <Switch> {routeNodes} </Switch> </Router>); } } export const RouterSchema = (props) => { let RController = withRouter(SchemaController); return (<RController {...props} />); } RouterSchema.propTypes = schemaPropTypes; RouterSchema.defaultProps = schemaDefaultProps; export const BrowserRouterSchema = (props) => { let RController = withRouter(SchemaController); return (<BrowserRouter><RController {...props} /></BrowserRouter>); } BrowserRouterSchema.propTypes = schemaPropTypes; BrowserRouterSchema.defaultProps = schemaDefaultProps; export const HashRouterSchema = (props) => { let RController = withRouter(SchemaController); return (<HashRouter><RController {...props} /></HashRouter>); } HashRouterSchema.propTypes = schemaPropTypes; HashRouterSchema.defaultProps = schemaDefaultProps; addComponents({ RoutesContainer: SchemaController });