mutants-appfx
Version:
appfx module
134 lines (119 loc) • 4.94 kB
JavaScript
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)
}
}