export const component = ({
elementFactory,
inputs,
outputs,
selector,
providers,
props
}) => {
let composeArgs = [];
let selectorInstance,
selectorServices;
if (selector) {
selectorServices = rcInject.getServiceInjectName(selector);
selector.displayName = selector.displayName || cuid();
selectorInstance = rcInject.getService(selector);
selectorInstance.name = selector.displayName;
inputs = selectorInstance.inputs;
outputs = selectorInstance.outputs;
if (inputs.toString() === BaseSelector.prototype.inputs.toString() && selector.dataBindings) {
inputs = () => {
return (state, ownProps) => {
let iState = {};
switch (true) {
case typeof selector.dataBindings === 'function':
iState = selector
.dataBindings
.call(selectorInstance, state, ownProps);
break;
case Array.isArray(selector.dataBindings):
if(selector.noFlattern){
selector
.dataBindings
.forEach(name => {
const model = BaseSelector.appStore.models[name];
iState[name] = model.state;
});
}else{
selector
.dataBindings
.forEach(name => {
const model = BaseSelector.appStore.models[name];
Object.assign(iState, model.state);
});
}
break;
default:
for (let key in selector.dataBindings) {
if (typeof selector.dataBindings[key] === 'function') {
iState[key] = selector
.dataBindings[key]
.call(selectorInstance, state, ownProps);
} else {
iState[key] = selector.dataBindings[key];
}
}
break;
}
return iState;
}
}
}
if (outputs.toString() === BaseSelector.prototype.outputs.toString() && selector.eventBindings) {
outputs = () => {
return (dispatch, ownProps) => {
let iActions = {};
switch (true) {
case typeof(selector.eventBindings) === 'function':
iActions = selector
.eventBindings
.call(selectorInstance, dispatch, ownProps);
break;
case Array.isArray(selector.eventBindings):
selector
.dataBindings
.forEach(name => {
const model = BaseSelector.appStore.models[name];
const names = Object.getOwnPropertyNames(model.__proto__);
names.shift();
if (selector.noFlattern) {
const mAction = {};
names.forEach(method => {
if (typeof model[method] === 'function') {
mAction[method] = model[method].bind(model);
}
});
iActions[name] = mAction;
iActions.__deep__ = true;
} else {
names.forEach(method => {
if (typeof model[method] === 'function') {
iActions[method] = model[method].bind(model);
}
});
}
});
break;
default:
for (let key in selector.eventBindings) {
iActions[key] = selector
.eventBindings[key]
.bind(selectorInstance);
}
break;
}
return iActions;
}
}
}
}
composeArgs.push(BaseComponent => {
const contextTypes = {};
const services = {};
const parentContextTypes = [];
for (let key in BaseComponent.contextTypes) {
contextTypes[key] = BaseComponent.contextTypes[key];
parentContextTypes.push(key);
services[key] = rcInject.getService(key)
}
delete services.selector;
if (selectorInstance) {
contextTypes.selector = PropTypes.object.isRequired;
}
eachProvider(providers, (Provider, key) => {
let name = key || Provider.displayName;
if (name) {
contextTypes[name] = PropTypes.any.isRequired;
} else {
throw new Error('服务${Provider.name}:displayName静态属性不能为空!');
}
});
if (contextTypes) {
BaseComponent.contextTypes = Object.assign(BaseComponent.contextTypes || {}, contextTypes);
}
const Component = connect(inputs, outputs, (stateProps, dispatchProps, parentProps) => {
if(dispatchProps.__deep__){
return deepMerge(stateProps, dispatchProps, parentProps);
}else{
return Object.assign({}, stateProps, dispatchProps, parentProps);
}
})(BaseComponent);
Component.__view__ = true;
const handleChange = Component.prototype.handleChange;
Component.prototype.handleChange = function () {
var storeState = this
.store
.getState();
for (let name in this.store.models) {
this.store.models[name].state = storeState[name];
}
handleChange.call(this);
}
Component.childContextTypes = contextTypes;
Component.prototype.getChildContext = function () {
if (this.$services_) {
return this.$services_;
}
this.$services_ = services;
parentContextTypes.forEach(name => {
if (!services[name]) {
services[name] = getParantService.call(this, name);
}
});
eachProvider(providers, (Provider, key) => {
let name = key || Provider.displayName;
services[name] = getService.call(this, name) || rcInject.instantiate(Provider, name, getService.bind(this));
});
if (services.selector) {
services
.selector
.emit('afterInitialize');
}
return services;
}
const _clearCache = Component.prototype.clearCache;
const _unmount = Component.prototype.componentWillUnmount;
Component.prototype.clearCache = function () {
if (!services.selector && selectorInstance) {
services.selector = selectorInstance;
services
.selector
.emit('beforeInitialize');
}
return _clearCache.call(this);
}
Component.prototype.componentWillMount = function () {
if (services.selector) {
if (services.selector.parentSelector === undefined) {
services.selector.parentSelector = getParantService.call(this, 'selector') || this.props.parentSelector || null;
}
services.selector.getService = (name) => {
return getService.call(this, name) || rcInject.getService(name);
};
if (selectorServices) {
selectorServices.forEach(name => {
services.selector.context[name] = getService.call(this, name) || rcInject.getService(name) || (services[name] = rcInject.instantiate(findProvider(providers, name), name, (name) => {
return services[name] || getService.call(this, name);
}));
});
}
try {
services
.selector
.initialize(this.props);
} catch (e) {
console.error(e);
}
}
}
Component.prototype.componentWillUnmount = function () {
const services = this.$services_;
eachProvider(providers, (Provider, key) => {
if (services[key]) {
if (services[key].destroy) {
services[key].destroy();
}
if (services[key].dispose) {
services[key].dispose();
}
delete services[key];
}
});
_unmount.call(this);
}
return Component;
});
if (props) {
composeArgs.push(_withState(props));
}
if (elementFactory) {
return compose(...composeArgs)(elementFactory);
} else {
return compose(...composeArgs)
}
}
function eachProvider(providers, callback) {
if (Array.isArray(providers)) {
providers.forEach(Provider => callback(Provider));
} else {
for (let key in providers) {
callback(providers[key], key);
}
}
}
function findProvider(providers, name) {
if (Array.isArray(providers)) {
return providers.find(Provider => Provider.displayName === name);
} else {
return providers[name];
}
}