nowrapper
Version:
nowrapper
204 lines (180 loc) • 6.87 kB
JSX
import React from 'react';
import PropTypes from 'prop-types';
import LocaleMap from '../locale/dialog';
import Context from 'noform/lib/context/dialogForm';
import DialogContent from './DialogContent';
import { If } from 'noform';
const noop = () => {};
const isPromise = content => Promise.resolve(content) === content;
class DialogForm {
constructor(options, getDialogInstance) {
this.options = options;
this.dialogCore = null;
this.getDialogInstance = getDialogInstance;
}
hide = () => {
const dialogInstance = this.getDialogInstance();
dialogInstance.hide();
}
handleCancel = () => {
const { onCancel } = this.options;
if (onCancel && typeof onCancel === 'function') {
onCancel();
}
this.hide();
}
handleOk = () => {
const { onOk = this.hide, enableValidate } = this.options;
let values = {};
if (this.dialogCore) values = this.dialogCore.getValues();
const params = [values, this.hide, this.dialogCore];
if (enableValidate && this.dialogCore) {
return this.dialogCore.validate((err) => {
if (!err) return onOk(...params);
return null;
});
}
return onOk(...params);
}
renderFooter = (Button, opts) => {
const { layout, loading = false } = opts || {};
const { label } = layout || {};
const { locale = 'en', footer, btnLoadingPropsName, footerAlign } = this.options;
const textMap = LocaleMap[locale];
const { hasCancel = true } = this.options;
const okText = this.options.okText || textMap.ok;
const cancelText = this.options.cancelText || textMap.cancel;
let footerElement = null;
if (footer) {
const footerOpts = Object.assign(opts || {});
footerOpts.ok = this.handleOk;
footerOpts.cancel = this.handleCancel;
if (this.dialogCore) footerOpts.ctx = this.dialogCore;
footerElement = footer(this.hide, footerOpts);
} else {
let styleProps = {};
const alignCls = ['left', 'center', 'right'].indexOf(footerAlign) !== -1 ? `align-${footerAlign}` : '';
if (footerAlign === 'label' && label) {
styleProps.style = { marginLeft: `${Number(label / 24).toFixed(2) * 100}%`, float: 'none' };
}
footerElement = <If when={(values, ctx) => {
return ctx.globalStatus !== 'preview';
}}>
<div key="footer" className={`noform-dialog-custom-btns ${alignCls}`} {...styleProps}>
<ActionButton disabled={loading} key="align-footer-ok" btnLoadingPropsName={btnLoadingPropsName} btnOrigin={Button} type="primary" onClick={this.handleOk}>{okText}</ActionButton>
{ hasCancel ? <span key="align-footer-sep" style={{ marginRight: '12px' }} /> : null }
{ hasCancel ? <ActionButton disabled={loading} key="align-footer-cancel" btnLoadingPropsName={btnLoadingPropsName} btnOrigin={Button} onClick={this.handleCancel}>{cancelText}</ActionButton> : null }
</div>
</If>
}
return footerElement;
}
renderContent = (Button) => {
const { content, task } = this.options;
const onDialogMount = (core) => {
this.dialogCore = core;
};
const footer = this.renderFooter.bind(this, Button);
return <DialogContent content={content} task={task} footer={footer} onMount={onDialogMount} />
}
}
class DialogFormFactory {
constructor({ Dialog, Button, compatiMap }) {
this.Dialog = Dialog;
this.Button = Button;
this.compatiMap = compatiMap;
const { show, ...others } = Dialog;
Object.keys(others).forEach((key) => {
this[key] = others[key];
});
}
show = (options) => {
const { Dialog, Button, compatiMap } = this;
if (!Dialog || !Button) {
throw Error('DialogForm initialize failed, make sure you have passed antd components');
}
const {
closablePolifill, title, className, width, ...others
} = options;
let dialogInstance = null;
// 按钮loading属性
const btnLoadingPropsName = compatiMap.btnLoadingProps || 'loading';
const dialogForm = new DialogForm({
...options,
compatiMap,
btnLoadingPropsName,
}, () => dialogInstance);
const content = dialogForm.renderContent(Button);
// 入口属性
const entryProps = compatiMap.show({
...options,
title,
content,
});
if (entryProps.closablePolifill) {
entryProps.title = <div>
{title}
{entryProps.closablePolifill(() => dialogInstance)}
</div>
}
dialogInstance = Dialog.show({
...others,
...entryProps,
});
dialogInstance = compatiMap.dialogInstance(dialogInstance);
return dialogInstance;
}
}
class ActionButton extends React.Component {
static propTypes = {
onLoading: PropTypes.func,
offLoading: PropTypes.func,
onClick: PropTypes.func,
btnLoadingPropsName: PropTypes.string,
btnOrigin: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
}
constructor(props, context) {
super(props, context);
this.state = {
isLoading: false,
};
}
enableLoading = () => {
const { onLoading } = this.props;
if (onLoading) {
onLoading();
}
this.setState({ isLoading: true });
}
disableLoading = () => {
const { offLoading } = this.props;
if (offLoading) {
offLoading();
}
this.setState({ isLoading: false });
}
handleAction = () => {
const { onClick } = this.props;
if (typeof onClick === 'function') {
this.enableLoading();
const actionResult = onClick();
if (isPromise(actionResult)) {
actionResult
.then(this.disableLoading, this.disableLoading)
.catch(this.disableLoading);
} else {
this.disableLoading();
}
}
}
render() {
const {
onClick, btnLoadingPropsName = 'loading', btnOrigin, ...others
} = this.props;
const Button = btnOrigin;
const { isLoading } = this.state;
const btnLoadingProps = { [btnLoadingPropsName]: isLoading };
return <Button onClick={this.handleAction} {...others} {...btnLoadingProps} />;
}
}
export default DialogFormFactory;