fix(transfer): checkall should response to filter result; fix #4654 (#4665)

This commit is contained in:
paranoidjk 2017-01-27 17:08:12 +08:00 committed by 偏右
parent 85086f14b6
commit f2e19c16be
3 changed files with 149 additions and 33 deletions

View File

@ -1,3 +1,4 @@
/* eslint no-use-before-define: "off" */
import React from 'react';
import { render, mount } from 'enzyme';
import { renderToJson } from 'enzyme-to-json';
@ -26,6 +27,50 @@ const listCommonProps = {
lazy: false,
};
const searchTransferProps = {
dataSource: [
{
key: '0',
title: 'content1',
description: 'description of content1',
chosen: false,
},
{
key: '1',
title: 'content2',
description: 'description of content2',
chosen: false,
},
{
key: '2',
title: 'content3',
description: 'description of content3',
chosen: false,
},
{
key: '3',
title: 'content4',
description: 'description of content4',
chosen: false,
},
{
key: '4',
title: 'content5',
description: 'description of content5',
chosen: false,
},
{
key: '5',
title: 'content6',
description: 'description of content6',
chosen: false,
},
],
selectedKeys: [],
targetKeys: ['3', '4'],
lazy: false,
};
describe('Transfer', () => {
it('should render correctly', () => {
const wrapper = render(<Transfer {...listCommonProps} />);
@ -82,4 +127,69 @@ describe('Transfer', () => {
wrapper.find(TransferSearch).at(0).find('input').simulate('change', { target: { value: 'a' } });
expect(wrapper.find(TransferList).at(0).find(TransferItem).find(Checkbox)).toHaveLength(1);
});
it('should display the correct count of items when filter by input', () => {
const filterOption = (inputValue, option) => option.description.indexOf(inputValue) > -1;
const renderFunc = item => item.title;
const wrapper = mount(
<Transfer
{...searchTransferProps}
showSearch
filterOption={filterOption}
render={renderFunc}
/>
);
wrapper.find(TransferSearch).at(0).find('input').simulate('change', { target: { value: 'content2' } });
expect(wrapper.find(TransferList).at(0).find('.ant-transfer-list-header-selected > span').at(0)
.first()
.text()
.trim()).toEqual('1');
});
it('should just check the filtered item when click on check all after search by input', () => {
const filterOption = (inputValue, option) => option.description.indexOf(inputValue) > -1;
const renderFunc = item => item.title;
const handleSelectChange = jest.fn();
const wrapper = mount(
<Transfer
{...searchTransferProps}
showSearch
filterOption={filterOption}
render={renderFunc}
onSelectChange={handleSelectChange}
/>
);
wrapper.find(TransferSearch).at(0).find('input')
.simulate('change', { target: { value: 'content2' } });
wrapper.find(TransferList).at(0).find('.ant-transfer-list-header input[type="checkbox"]').filterWhere(n => !n.prop('checked'))
.simulate('change');
expect(handleSelectChange).toHaveBeenCalledWith(['1'], []);
});
it('should transfer just the filtered item after search by input', () => {
const filterOption = (inputValue, option) => option.description.indexOf(inputValue) > -1;
const renderFunc = item => item.title;
const handleChange = jest.fn();
const handleSelectChange = (sourceSelectedKeys, targetSelectedKeys) => {
wrapper.setProps({
selectedKeys: [...sourceSelectedKeys, ...targetSelectedKeys],
});
};
const wrapper = mount(
<Transfer
{...searchTransferProps}
showSearch
filterOption={filterOption}
render={renderFunc}
onSelectChange={handleSelectChange}
onChange={handleChange}
/>
);
wrapper.find(TransferSearch).at(0).find('input')
.simulate('change', { target: { value: 'content2' } });
wrapper.find(TransferList).at(0).find('.ant-transfer-list-header input[type="checkbox"]').filterWhere(n => !n.prop('checked'))
.simulate('change');
wrapper.find(TransferOperation).find(Button).at(1).simulate('click');
expect(handleChange).toHaveBeenCalledWith(['1', '3', '4'], 'right', ['1']);
});
});

View File

@ -5,38 +5,12 @@ import assign from 'object-assign';
import Lazyload from 'react-lazy-load';
import Checkbox from '../checkbox';
function isRenderResultPlainObject(result) {
return result && !React.isValidElement(result) &&
Object.prototype.toString.call(result) === '[object Object]';
}
export default class Item extends React.Component<any, any> {
shouldComponentUpdate(...args) {
return PureRenderMixin.shouldComponentUpdate.apply(this, args);
}
matchFilter = (text) => {
const { filter, filterOption, item } = this.props;
if (filterOption) {
return filterOption(filter, item);
}
return text.indexOf(filter) >= 0;
}
render() {
const { render, filter, item, lazy, checked, prefixCls, onClick } = this.props;
const renderResult = render(item);
let renderedText;
let renderedEl;
if (isRenderResultPlainObject(renderResult)) {
renderedText = renderResult.value;
renderedEl = renderResult.label;
} else {
renderedText = renderResult;
renderedEl = renderResult;
}
if (filter && filter.trim() && !this.matchFilter(renderedText)) {
return null;
}
const { renderedText, renderedEl, item, lazy, checked, prefixCls, onClick } = this.props;
const className = classNames({
[`${prefixCls}-content-item`]: true,

View File

@ -11,6 +11,11 @@ import Checkbox from '../checkbox';
function noop() {
}
function isRenderResultPlainObject(result) {
return result && !React.isValidElement(result) &&
Object.prototype.toString.call(result) === '[object Object]';
}
export interface TransferListProps {
prefixCls: string;
dataSource: TransferItem[];
@ -103,9 +108,27 @@ export default class TransferList extends React.Component<TransferListProps, any
this.props.handleClear();
}
matchFilter = (text, item) => {
const { filter, filterOption } = this.props;
if (filterOption) {
return filterOption(filter, item);
}
return text.indexOf(filter) >= 0;
}
renderItem = (item) => {
const { render = noop } = this.props;
const renderResult = render(item);
const isRenderResultPlain = isRenderResultPlainObject(renderResult);
return {
renderedText: isRenderResultPlain ? renderResult.value : renderResult,
renderedEl: isRenderResultPlain ? renderResult.label : renderResult,
};
}
render() {
const { prefixCls, dataSource, titleText, filter, checkedKeys, lazy, filterOption,
body = noop, footer = noop, showSearch, render = noop, style } = this.props;
const { prefixCls, dataSource, titleText, checkedKeys, lazy,
body = noop, footer = noop, showSearch, style, filter } = this.props;
let { searchPlaceholder, notFoundContent } = this.props;
@ -118,20 +141,29 @@ export default class TransferList extends React.Component<TransferListProps, any
});
const filteredDataSource: TransferItem[] = [];
const totalDataSource: TransferItem[] = [];
const showItems = dataSource.map((item) => {
const { renderedText, renderedEl } = this.renderItem(item);
if (filter && filter.trim() && !this.matchFilter(renderedText, item)) {
return null;
}
// all show items
totalDataSource.push(item);
if (!item.disabled) {
// response to checkAll items
filteredDataSource.push(item);
}
const checked = checkedKeys.indexOf(item.key) >= 0;
return (
<Item
key={item.key}
item={item}
lazy={lazy}
render={render}
filter={filter}
filterOption={filterOption}
renderedText={renderedText}
renderedEl={renderedEl}
checked={checked}
prefixCls={prefixCls}
onClick={this.handleSelect}
@ -200,7 +232,7 @@ export default class TransferList extends React.Component<TransferListProps, any
{checkAllCheckbox}
<span className={`${prefixCls}-header-selected`}>
<span>
{(checkedKeys.length > 0 ? `${checkedKeys.length}/` : '') + dataSource.length} {unit}
{(checkedKeys.length > 0 ? `${checkedKeys.length}/` : '') + totalDataSource.length} {unit}
</span>
<span className={`${prefixCls}-header-title`}>
{titleText}