UNPKG

mutants-appfx

Version:

appfx module

134 lines (119 loc) 4.94 kB
import PropTypes from 'prop-types'; import hoistStatics from "hoist-non-react-statics"; import { Component, createElement } from "react"; import Action from './Action'; function createViewModelInjector(grabViewModelFn, component, viewModelNames) { const injectNames = viewModelNames.join("-"); let wrappedComponentName = (component.displayName || component.name || (component.constructor && component.constructor.name) || "Unknown"); let displayName = "inject-" + wrappedComponentName; if (injectNames) displayName += "-with-" + injectNames class Injector extends Component { static displayName = displayName; static wrappedComponentName = wrappedComponentName; static contextTypes = { viewModel: PropTypes.object, onEvent:PropTypes.func } getChildContext(){ return { controllerEvent:this.controllerEvent } } static childContextTypes = { controllerEvent: PropTypes.func }; controllerEvent = async(methodName,methodArgs)=>{ await this.context.onEvent({'controllerEvent':Action.fromJS(this.context.viewModel,methodName)},'controllerEvent',methodArgs); }; iRef = instance => { this.wrappedInstance = instance } render() { console.log(`wrappedComponentName ========== render ${wrappedComponentName}`); let newProps = {} for (let key in this.props){ if (this.props.hasOwnProperty(key)) { newProps[key] = this.props[key] } } let additionalProps = grabViewModelFn(this.context.viewModel.items || {}, newProps) || {}; for (let key in additionalProps) { let viewModelProp = additionalProps[key]; //增加viewmodel调用controller的事件 if('viewModel'=== key && this.context.onEvent){ if(!viewModelProp.controllerEvent){ viewModelProp.controllerEvent = async(methodName,methodArgs)=>{ await this.context.onEvent({'controllerEvent':Action.fromJS(this.context.viewModel,methodName)},'controllerEvent',methodArgs); }; } } newProps[key] = viewModelProp; } //增加controller的调用事件 if(this.context.onEvent){ newProps.controllerEvent = async(methodName,methodArgs)=>{ await this.context.onEvent({'controllerEvent':Action.fromJS(this.context.viewModel,methodName)},'controllerEvent',methodArgs); }; } if (component.prototype && component.prototype.render) { newProps.ref = this.iRef } return createElement(component, newProps) } } hoistStatics(Injector, component) Injector.viewModelNames = viewModelNames; Injector.wrappedComponent = component return Injector } function grabViewModelsByName(viewModelNames) { return function(viewModels, nextProps) { let viewModelArray = []; viewModelNames.forEach(function(viewModelName) { if ( viewModelName in nextProps){ throw new Error( "viewModelName is same with component's prop [" +viewModelName +"] please rename one" ) } let viewModel = grabViewModel(viewModels,viewModelName); if (!viewModel){ throw new Error( "viewModel injector: ViewModel '" + viewModelName + "' is not available! Make sure it is provided by some Provider" ) } viewModelArray.push(viewModel); }); let viewModelProp = {}; if(viewModelArray.length == 1){ viewModelProp = viewModelArray[0]; }else{ viewModelNames.forEach(function(viewModelName,index){ viewModelProp[viewModelName] = viewModelArray[index]; }); } nextProps['viewModel'] = viewModelProp; return nextProps; } } function grabViewModel(viewModels,viewModelName){ return viewModels.find(it => it.type === viewModelName); } export default function injectViewModel() { const viewModelNames = []; for (let i = 0; i < arguments.length; i++) viewModelNames[i] = arguments[i]; if(viewModelNames.length == 0){ throw new Error( "inject viewModelNames is empty! please fill the args (...viewNames)" ) } let grabViewModelFn = grabViewModelsByName(viewModelNames) return function(componentClass) { return createViewModelInjector(grabViewModelFn, componentClass, viewModelNames) } }