import React from 'react'; import Checkbox from '../checkbox'; import Search from './search'; import classNames from 'classnames'; import Animate from 'rc-animate'; import PureRenderMixin from 'rc-util/lib/PureRenderMixin'; import assign from 'object-assign'; import Lazyload from 'react-lazy-load'; import { TransferItem } from './index'; function noop() { } export function isRenderResultPlainObject(result) { return result && !React.isValidElement(result) && Object.prototype.toString.call(result) === '[object Object]'; } export interface TransferListProps { prefixCls: string; dataSource: TransferItem[]; filter?: string; showSearch?: boolean; searchPlaceholder?: string; titleText?: string; style?: React.CSSProperties; handleFilter: (e: any) => void; handleSelect: (selectedItem: any, checked: boolean) => void; handleSelectAll: (dataSource: any[], checkAll: boolean) => void; handleClear: () => void; render?: (item: any) => any; body?: (props: any) => any; footer?: (props: any) => void; checkedKeys: string[]; checkStatus?: boolean; position?: string; notFoundContent?: React.ReactNode | string; filterOption: (filterText: any, item: any) => boolean; lazy?: {}; } export interface TransferListContext { antLocale?: { Transfer?: any, }; } export default class TransferList extends React.Component { static defaultProps = { dataSource: [], titleText: '', showSearch: false, render: noop, }; static contextTypes = { antLocale: React.PropTypes.object, }; context: TransferListContext; timer: number; constructor(props) { super(props); this.state = { mounted: false, }; } componentDidMount() { this.timer = setTimeout(() => { this.setState({ mounted: true, }); }, 0); } componentWillUnmount() { clearTimeout(this.timer); } shouldComponentUpdate(...args) { return PureRenderMixin.shouldComponentUpdate.apply(this, args); } getCheckStatus(filteredDataSource) { const { checkedKeys } = this.props; if (checkedKeys.length === 0) { return 'none'; } else if (filteredDataSource.every(item => checkedKeys.indexOf(item.key) >= 0)) { return 'all'; } return 'part'; } handleSelect = (selectedItem) => { const { checkedKeys } = this.props; const result = checkedKeys.some((key) => key === selectedItem.key); this.props.handleSelect(selectedItem, !result); } handleFilter = (e) => { this.props.handleFilter(e); } handleClear = () => { this.props.handleClear(); } renderCheckbox({ prefixCls, filteredDataSource, checked, checkPart, disabled, checkable }) { const checkAll = (!checkPart) && checked; const checkboxCls = classNames({ [`${prefixCls}-checkbox`]: true, [`${prefixCls}-checkbox-indeterminate`]: checkPart, [`${prefixCls}-checkbox-checked`]: checkAll, [`${prefixCls}-checkbox-disabled`]: disabled, }); return ( this.props.handleSelectAll(filteredDataSource, checkAll)} > {(typeof checkable !== 'boolean') ? checkable : null} ); } matchFilter(filterText, item, text) { const filterOption = this.props.filterOption; if (filterOption) { return filterOption(filterText, item); } return text.indexOf(filterText) >= 0; } render() { const { prefixCls, dataSource, titleText, filter, checkedKeys, lazy, body = noop, footer = noop, showSearch, render = noop, style } = this.props; let { searchPlaceholder, notFoundContent } = this.props; // Custom Layout const footerDom = footer(assign({}, this.props)); const bodyDom = body(assign({}, this.props)); const listCls = classNames({ [prefixCls]: true, [`${prefixCls}-with-footer`]: !!footerDom, }); const filteredDataSource: TransferItem[] = []; const showItems = dataSource.map((item) => { const renderResult = render(item); if (isRenderResultPlainObject(renderResult)) { return { item: item, renderedText: renderResult.value, renderedEl: renderResult.label, }; } return { item: item, renderedText: renderResult, renderedEl: renderResult, }; }).filter(({ item, renderedText }) => { return !(filter && filter.trim() && !this.matchFilter(filter, item, renderedText)); }).map(({ item, renderedText, renderedEl }) => { if (!item.disabled) { filteredDataSource.push(item); } const className = classNames({ [`${prefixCls}-content-item`]: true, [`${prefixCls}-content-item-disabled`]: item.disabled, }); const lazyProps = assign({ height: 32, offset: 500, throttle: 0, debounce: false, }, lazy); return (
  • this.handleSelect(item)} > key === item.key)} disabled={item.disabled} /> {renderedEl}
  • ); }); let unit = '条'; const antLocale = this.context.antLocale; if (antLocale && antLocale.Transfer) { const transferLocale = antLocale.Transfer; unit = dataSource.length > 1 ? transferLocale.itemsUnit : transferLocale.itemUnit; searchPlaceholder = searchPlaceholder || transferLocale.searchPlaceholder; notFoundContent = notFoundContent || transferLocale.notFoundContent; } const checkStatus = this.getCheckStatus(filteredDataSource); const outerPrefixCls = prefixCls.replace('-list', ''); return (
    {this.renderCheckbox({ prefixCls: outerPrefixCls, checked: checkStatus === 'all', checkPart: checkStatus === 'part', checkable: , filteredDataSource, disabled: false, })} {(checkedKeys.length > 0 ? `${checkedKeys.length}/` : '') + dataSource.length} {unit} {titleText}
    {bodyDom ||
    {showSearch ?
    : null} {showItems.length > 0 ? showItems :
    {notFoundContent || '列表为空'}
    }
    } {footerDom ?
    {footerDom}
    : null}
    ); } }