ant-design-vue/components/transfer/list.jsx
tangjinzhou ff25efe185
update to antd3.8.3 (#159)
* refactor: align

* feat:  update align to 2.4.3

* feat: update trigger 2.5.4

* feat: update tooltip 3.7.2

* fix: align

* feat: update vc-calendar to 9.6.2

* feat: update vc-checkbox to 2.1.5

* feat: update vc-dialog to 7.1.8

* feat: update vc-from to 2.2.1

* feat: update vc-notification to 3.1.1

* test: update snapshots

* feat: update vc-tree to 1.12.6

* feat: update vc-table to 6.2.8

* feat: update vc-upload to 2.5.1

* feat: update vc-input-number to 4.0.12

* feat: update vc-tabs to 9.2.6

* refactor: vc-menu

* refactor: update vc-menu to 7.0.5

* style: remove unused

* feat: update pagination to 1.16.5

* feat: add vc-progress 2.2.5 tag

* feat: add vc-rate 2.4.0 tag

* feat: update vc-slider to 8.6.1

* fix: tooltip error

* style: delete conosle

* feat: update vc-steps to 3.1.1

* add vc-switch tag 1.6.0

* feat: update upload to 2.5.1

* fix: update vc-menu

* fix: update store

* fix: add ref dir

* fix: trigger mock shouldComponentUpdate

* fix: update vc-select

* revert: trigger lazyrenderbox

* fix: update vc-select

* fix: update vc-select

* fix: update vc-select

* fix: update vc-menu

* fix: update vc-slick ref

* update style to 3.8.2

* test: update snapshots

* update vc-select

* update util & affix

* feat: add drawer

* fix: support title add slot mode

* test: update affix test

* update alert

* update anchor

* update snapshots

* fix: doc and vc-drawer

* update select & auto-complete

* update back-top & grid

* feractor: avatar

* test: add drawer test

* update badge

* update button

* update card

* update divider

* feat: update vc-tabs to 9.3.6 and tabs

* add afterEnter callback

* update form

* fix: update drawer

* test: update snapshots

* update modal & notification

* test: update snapshots

* update message

* update locale-provider

* update dropdown

* update layout popconfirm popover

* update time-picker

* update menu

* update date-picker

* docs: update input docs

* update input

* update snapshots

* update table

* update test snapshots

* feat: update progress

* update checkbox

* feat: update spin

* update radio

* docs: slider steps timeline

* update list

* update transfer

* update collapse

* update cascader

* update upload
2018-09-05 21:28:54 +08:00

300 lines
8.3 KiB
Vue

import classNames from 'classnames'
import PropTypes from '../_util/vue-types'
import { isValidElement, initDefaultProps } from '../_util/props-util'
import BaseMixin from '../_util/BaseMixin'
import getTransitionProps from '../_util/getTransitionProps'
import Checkbox from '../checkbox'
import Search from './search'
import Item from './item'
import triggerEvent from '../_util/triggerEvent'
import addEventListener from '../_util/Dom/addEventListener'
function isIEorEDGE () {
return document.documentMode || /Edge/.test(navigator.userAgent)
}
function noop () {
}
const TransferItem = {
key: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
description: PropTypes.string,
disabled: PropTypes.bool,
}
function isRenderResultPlainObject (result) {
return result && !isValidElement(result) &&
Object.prototype.toString.call(result) === '[object Object]'
}
export const TransferListProps = {
prefixCls: PropTypes.string,
titleText: PropTypes.string,
dataSource: PropTypes.arrayOf(PropTypes.shape(TransferItem).loose),
filter: PropTypes.string,
filterOption: PropTypes.func,
checkedKeys: PropTypes.arrayOf(PropTypes.string),
handleFilter: PropTypes.func,
handleSelect: PropTypes.func,
handleSelectAll: PropTypes.func,
handleClear: PropTypes.func,
renderItem: PropTypes.func,
showSearch: PropTypes.bool,
searchPlaceholder: PropTypes.string,
notFoundContent: PropTypes.any,
itemUnit: PropTypes.string,
itemsUnit: PropTypes.string,
body: PropTypes.any,
footer: PropTypes.any,
lazy: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.object,
]),
}
export default {
name: 'TransferList',
mixins: [BaseMixin],
props: initDefaultProps(TransferListProps, {
dataSource: [],
titleText: '',
showSearch: false,
renderItem: noop,
lazy: {},
}),
data () {
this.timer = null
this.triggerScrollTimer = null
return {
mounted: false,
}
},
mounted () {
this.timer = setTimeout(() => {
this.setState({
mounted: true,
})
}, 0)
this.$nextTick(() => {
if (this.$refs.listContentWrapper) {
const listContentWrapperDom = this.$refs.listContentWrapper.$el
this.scrollEvent = addEventListener(listContentWrapperDom, 'scroll', this.handleScroll)
}
})
},
beforeDestroy () {
clearTimeout(this.timer)
clearTimeout(this.triggerScrollTimer)
clearTimeout(this.fixIERepaintTimer)
if (this.scrollEvent) {
this.scrollEvent.remove()
}
},
updated () {
this.$nextTick(() => {
if (this.scrollEvent) {
this.scrollEvent.remove()
}
if (this.$refs.listContentWrapper) {
const listContentWrapperDom = this.$refs.listContentWrapper.$el
this.scrollEvent = addEventListener(listContentWrapperDom, 'scroll', this.handleScroll)
}
})
},
methods: {
handleScroll (e) {
this.$emit('scroll', e)
},
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.handleSelect(selectedItem, !result)
},
_handleFilter (e) {
this.handleFilter(e)
if (!e.target.value) {
return
}
// Manually trigger scroll event for lazy search bug
// https://github.com/ant-design/ant-design/issues/5631
this.triggerScrollTimer = setTimeout(() => {
const transferNode = this.$el
const listNode = transferNode.querySelectorAll('.ant-transfer-list-content')[0]
if (listNode) {
triggerEvent(listNode, 'scroll')
}
}, 0)
this.fixIERepaint()
},
_handleClear (e) {
this.handleClear(e)
this.fixIERepaint()
},
matchFilter (text, item) {
const { filter, filterOption } = this.$props
if (filterOption) {
return filterOption(filter, item)
}
return text.indexOf(filter) >= 0
},
renderItemHtml (item) {
const { renderItem = noop } = this.$props
const renderResult = renderItem(item)
const isRenderResultPlain = isRenderResultPlainObject(renderResult)
return {
renderedText: isRenderResultPlain ? renderResult.value : renderResult,
renderedEl: isRenderResultPlain ? renderResult.label : renderResult,
}
},
// Fix IE/Edge repaint
// https://github.com/ant-design/ant-design/issues/9697
// https://stackoverflow.com/q/27947912/3040605
fixIERepaint () {
if (!isIEorEDGE()) {
return
}
this.fixIERepaintTimer = window.setTimeout(() => {
if (this.$refs.notFoundNode) {
this.$refs.notFoundNode.className = this.$refs.notFoundNode.className
}
}, 0)
},
filterNull (arr) {
return arr.filter((item) => {
return item !== null
})
},
},
render () {
const {
prefixCls, dataSource, titleText, checkedKeys, lazy,
body = noop, footer = noop, showSearch, filter,
searchPlaceholder, notFoundContent, itemUnit, itemsUnit,
} = this.$props
// Custom Layout
const footerDom = footer({ ...this.$props })
const bodyDom = body({ ...this.$props })
const listCls = classNames(prefixCls, {
[`${prefixCls}-with-footer`]: !!footerDom,
})
const filteredDataSource = []
const totalDataSource = []
const showItems = dataSource.map((item) => {
const { renderedText, renderedEl } = this.renderItemHtml(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}
renderedText={renderedText}
renderedEl={renderedEl}
checked={checked}
prefixCls={prefixCls}
onClick={this._handleSelect}
/>
)
})
const unit = dataSource.length > 1 ? itemsUnit : itemUnit
const search = showSearch ? (
<div class={`${prefixCls}-body-search-wrapper`}>
<Search
prefixCls={`${prefixCls}-search`}
onChange={this._handleFilter}
handleClear={this.handleClear}
placeholder={searchPlaceholder}
value={filter}
/>
</div>
) : null
const transitionName = this.mounted ? `${prefixCls}-content-item-highlight` : ''
const transitionProps = getTransitionProps(transitionName, {
leave: noop,
})
const listBody = bodyDom || (
<div
class={showSearch ? `${prefixCls}-body ${prefixCls}-body-with-search` : `${prefixCls}-body`}
>
{search}
<transition-group
{...transitionProps}
tag='ul'
class={`${prefixCls}-content`}
ref='listContentWrapper'
>
{showItems}
</transition-group>
<div class={`${prefixCls}-body-not-found`} ref='notFoundNode'>
{notFoundContent}
</div>
</div>
)
const listFooter = footerDom ? (
<div class={`${prefixCls}-footer`}>
{footerDom}
</div>
) : null
const checkStatus = this.getCheckStatus(filteredDataSource)
const checkedAll = checkStatus === 'all'
const checkAllCheckbox = (
<Checkbox
ref='checkbox'
checked={checkedAll}
indeterminate={checkStatus === 'part'}
onChange={() => {
this.handleSelectAll(filteredDataSource, checkedAll)
}}
/>
)
return (
<div class={listCls}>
<div class={`${prefixCls}-header`}>
{checkAllCheckbox}
<span class={`${prefixCls}-header-selected`}>
<span>
{(checkedKeys.length > 0 ? `${checkedKeys.length}/` : '') + totalDataSource.length} {unit}
</span>
<span class={`${prefixCls}-header-title`}>
{titleText}
</span>
</span>
</div>
{listBody}
{listFooter}
</div>
)
},
}