<commit_before>import React from 'react';
import { PropTypes } from 'react';
import List from './list';
import Operation from './operation';
import Search from './search';
import classNames from 'classnames';

function noop() {
}

export interface TransferItem {
  key: number | string;
  title: string;
  description?: string;
  disabled?: boolean;
}

// Transfer
export interface TransferProps {
  dataSource: TransferItem[];
  targetKeys: string[];
  render?: (record: TransferItem) => any;
  onChange?: (targetKeys: TransferItem[], direction: string, moveKeys: any) => void;
  onSelectChange?: (sourceSelectedKeys: string[], targetSelectedKeys: string[]) => void;
  listStyle?: React.CSSProperties;
  className?: string;
  prefixCls?: string;
  titles?: string[];
  operations?: string[];
  showSearch?: boolean;
  searchPlaceholder?: string;
  notFoundContent?: React.ReactNode;
  footer?: (props: any) => any;
  style?: React.CSSProperties;
  filterOption: (inputValue: any, item: any) => boolean;
  body?: (props: any) => any;
  rowKey?: (record: any) => string;
}

export default class Transfer extends React.Component<TransferProps, any> {
  static List = List;
  static Operation = Operation;
  static Search = Search;

  static defaultProps = {
    prefixCls: 'ant-transfer',
    dataSource: [],
    render: noop,
    targetKeys: [],
    onChange: noop,
    onSelectChange: noop,
    titles: ['源列表', '目的列表'],
    operations: [],
    showSearch: false,
    body: noop,
    footer: noop,
  };

  static propTypes = {
    prefixCls: PropTypes.string,
    dataSource: PropTypes.array,
    render: PropTypes.func,
    targetKeys: PropTypes.array,
    onChange: PropTypes.func,
    height: PropTypes.number,
    listStyle: PropTypes.object,
    className: PropTypes.string,
    titles: PropTypes.array,
    operations: PropTypes.array,
    showSearch: PropTypes.bool,
    filterOption: PropTypes.func,
    searchPlaceholder: PropTypes.string,
    notFoundContent: PropTypes.node,
    body: PropTypes.func,
    footer: PropTypes.func,
    rowKey: PropTypes.func,
  };

  splitedDataSource: any;

  constructor(props) {
    super(props);
    this.state = {
      leftFilter: '',
      rightFilter: '',
      leftCheckedKeys: [],
      rightCheckedKeys: [],
    };
  }

  componentWillReceiveProps(nextProps) {
    const { leftCheckedKeys, rightCheckedKeys } = this.state;
    if (nextProps.targetKeys !== this.props.targetKeys ||
        nextProps.dataSource !== this.props.dataSource) {
      // clear cached splited dataSource
      this.splitedDataSource = null;

      const { dataSource, targetKeys } = nextProps;
      // clear key nolonger existed
      // clear checkedKeys according to targetKeys
      this.setState({
        leftCheckedKeys: leftCheckedKeys
          .filter(data => dataSource.filter(item => item.key === data).length)
          .filter(data => targetKeys.filter(key => key === data).length === 0),
        rightCheckedKeys: rightCheckedKeys
          .filter(data => dataSource.filter(item => item.key === data).length)
          .filter(data => targetKeys.filter(key => key === data).length > 0),
      });
    }
  }
  splitDataSource(props) {
    if (this.splitedDataSource) {
      return this.splitedDataSource;
    }

    const { dataSource, targetKeys } = props;
    if (props.rowKey) {
      dataSource.forEach(record => {
        record.key = props.rowKey(record);
      });
    }

    const leftDataSource = dataSource.filter(({ key }) => targetKeys.indexOf(key) === -1);
    const rightDataSource = dataSource.filter(({ key }) => targetKeys.indexOf(key) >= 0);

    this.splitedDataSource = {
      leftDataSource,
      rightDataSource,<commit_msg>fix: should follow the targetKeys' order, close: #3152<commit_after>import React from 'react';
import { PropTypes } from 'react';
import List from './list';
import Operation from './operation';
import Search from './search';
import classNames from 'classnames';

function noop() {
}

export interface TransferItem {
  key: number | string;
  title: string;
  description?: string;
  disabled?: boolean;
}

// Transfer
export interface TransferProps {
  dataSource: TransferItem[];
  targetKeys: string[];
  render?: (record: TransferItem) => any;
  onChange?: (targetKeys: TransferItem[], direction: string, moveKeys: any) => void;
  onSelectChange?: (sourceSelectedKeys: string[], targetSelectedKeys: string[]) => void;
  listStyle?: React.CSSProperties;
  className?: string;
  prefixCls?: string;
  titles?: string[];
  operations?: string[];
  showSearch?: boolean;
  searchPlaceholder?: string;
  notFoundContent?: React.ReactNode;
  footer?: (props: any) => any;
  style?: React.CSSProperties;
  filterOption: (inputValue: any, item: any) => boolean;
  body?: (props: any) => any;
  rowKey?: (record: any) => string;
}

export default class Transfer extends React.Component<TransferProps, any> {
  static List = List;
  static Operation = Operation;
  static Search = Search;

  static defaultProps = {
    prefixCls: 'ant-transfer',
    dataSource: [],
    render: noop,
    targetKeys: [],
    onChange: noop,
    onSelectChange: noop,
    titles: ['源列表', '目的列表'],
    operations: [],
    showSearch: false,
    body: noop,
    footer: noop,
  };

  static propTypes = {
    prefixCls: PropTypes.string,
    dataSource: PropTypes.array,
    render: PropTypes.func,
    targetKeys: PropTypes.array,
    onChange: PropTypes.func,
    height: PropTypes.number,
    listStyle: PropTypes.object,
    className: PropTypes.string,
    titles: PropTypes.array,
    operations: PropTypes.array,
    showSearch: PropTypes.bool,
    filterOption: PropTypes.func,
    searchPlaceholder: PropTypes.string,
    notFoundContent: PropTypes.node,
    body: PropTypes.func,
    footer: PropTypes.func,
    rowKey: PropTypes.func,
  };

  splitedDataSource: any;

  constructor(props) {
    super(props);
    this.state = {
      leftFilter: '',
      rightFilter: '',
      leftCheckedKeys: [],
      rightCheckedKeys: [],
    };
  }

  componentWillReceiveProps(nextProps) {
    const { leftCheckedKeys, rightCheckedKeys } = this.state;
    if (nextProps.targetKeys !== this.props.targetKeys ||
        nextProps.dataSource !== this.props.dataSource) {
      // clear cached splited dataSource
      this.splitedDataSource = null;

      const { dataSource, targetKeys } = nextProps;
      // clear key nolonger existed
      // clear checkedKeys according to targetKeys
      this.setState({
        leftCheckedKeys: leftCheckedKeys
          .filter(data => dataSource.filter(item => item.key === data).length)
          .filter(data => targetKeys.filter(key => key === data).length === 0),
        rightCheckedKeys: rightCheckedKeys
          .filter(data => dataSource.filter(item => item.key === data).length)
          .filter(data => targetKeys.filter(key => key === data).length > 0),
      });
    }
  }
  splitDataSource(props) {
    if (this.splitedDataSource) {
      return this.splitedDataSource;
    }

    const { dataSource, targetKeys } = props;
    if (props.rowKey) {
      dataSource.forEach(record => {
        record.key = props.rowKey(record);
      });
    }

    const leftDataSource = dataSource.filter(({ key }) => targetKeys.indexOf(key) === -1);
    const rightDataSource = [];
    targetKeys.forEach((targetKey) => {
      const targetItem = dataSource.filter(record => record.key === targetKey)[0];
      if (targetItem) {
        rightDataSource.push(targetItem);
      }
    });

    this.splitedDataSource = {
      leftDataSource,
      rightDataSource,
{'fraction_non_alphanumeric': 0.13153724247226625, 'fraction_numerical': 0.001584786053882726, 'mean_word_length': 3.3299028016009147, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1182432', 'n_tokens_mistral': 2186, 'n_tokens_neox': 2218, 'n_words': 539}