2016-11-18 11:46:55 +08:00
|
|
|
<script>
|
|
|
|
import List from './list.vue';
|
|
|
|
import Operation from './operation.vue';
|
2017-03-30 16:05:20 +08:00
|
|
|
import Locale from '../../mixins/locale';
|
2017-03-09 11:14:40 +08:00
|
|
|
import Emitter from '../../mixins/emitter';
|
2016-11-18 11:46:55 +08:00
|
|
|
|
|
|
|
const prefixCls = 'ivu-transfer';
|
|
|
|
|
|
|
|
export default {
|
2017-06-08 10:20:11 +08:00
|
|
|
name: 'Transfer',
|
2017-03-30 16:05:20 +08:00
|
|
|
mixins: [ Emitter, Locale ],
|
2017-07-12 11:37:06 +08:00
|
|
|
render (h) {
|
2017-03-08 17:04:07 +08:00
|
|
|
|
|
|
|
function cloneVNode (vnode) {
|
2017-03-08 17:08:10 +08:00
|
|
|
const clonedChildren = vnode.children && vnode.children.map(vnode => cloneVNode(vnode));
|
2017-07-12 11:37:06 +08:00
|
|
|
const cloned = h(vnode.tag, vnode.data, clonedChildren);
|
2017-03-08 17:04:07 +08:00
|
|
|
cloned.text = vnode.text;
|
|
|
|
cloned.isComment = vnode.isComment;
|
|
|
|
cloned.componentOptions = vnode.componentOptions;
|
|
|
|
cloned.elm = vnode.elm;
|
|
|
|
cloned.context = vnode.context;
|
|
|
|
cloned.ns = vnode.ns;
|
|
|
|
cloned.isStatic = vnode.isStatic;
|
|
|
|
cloned.key = vnode.key;
|
|
|
|
|
|
|
|
return cloned;
|
|
|
|
}
|
|
|
|
|
2017-03-15 18:56:37 +08:00
|
|
|
const vNodes = this.$slots.default === undefined ? [] : this.$slots.default;
|
|
|
|
const clonedVNodes = this.$slots.default === undefined ? [] : vNodes.map(vnode => cloneVNode(vnode));
|
2017-03-08 17:04:07 +08:00
|
|
|
|
2017-07-12 11:37:06 +08:00
|
|
|
return h('div', {
|
2017-03-08 17:04:07 +08:00
|
|
|
'class': this.classes
|
|
|
|
}, [
|
2017-07-12 11:37:06 +08:00
|
|
|
h(List, {
|
2017-03-08 17:04:07 +08:00
|
|
|
ref: 'left',
|
|
|
|
props: {
|
|
|
|
prefixCls: this.prefixCls + '-list',
|
|
|
|
data: this.leftData,
|
|
|
|
renderFormat: this.renderFormat,
|
|
|
|
checkedKeys: this.leftCheckedKeys,
|
|
|
|
validKeysCount: this.leftValidKeysCount,
|
2017-05-15 16:37:12 +08:00
|
|
|
listStyle: this.listStyle,
|
2017-03-30 16:05:20 +08:00
|
|
|
title: this.localeTitles[0],
|
2017-03-08 17:04:07 +08:00
|
|
|
filterable: this.filterable,
|
2017-03-30 16:05:20 +08:00
|
|
|
filterPlaceholder: this.localeFilterPlaceholder,
|
2017-03-08 17:04:07 +08:00
|
|
|
filterMethod: this.filterMethod,
|
2017-03-30 16:05:20 +08:00
|
|
|
notFoundText: this.localeNotFoundText
|
2017-03-08 17:04:07 +08:00
|
|
|
},
|
|
|
|
on: {
|
|
|
|
'on-checked-keys-change': this.handleLeftCheckedKeysChange
|
|
|
|
}
|
|
|
|
}, vNodes),
|
|
|
|
|
2017-07-12 11:37:06 +08:00
|
|
|
h(Operation, {
|
2017-03-08 17:04:07 +08:00
|
|
|
props: {
|
|
|
|
prefixCls: this.prefixCls,
|
|
|
|
operations: this.operations,
|
|
|
|
leftActive: this.leftValidKeysCount > 0,
|
|
|
|
rightActive: this.rightValidKeysCount > 0
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
|
2017-07-12 11:37:06 +08:00
|
|
|
h(List, {
|
2017-03-08 17:04:07 +08:00
|
|
|
ref: 'right',
|
|
|
|
props: {
|
|
|
|
prefixCls: this.prefixCls + '-list',
|
|
|
|
data: this.rightData,
|
|
|
|
renderFormat: this.renderFormat,
|
|
|
|
checkedKeys: this.rightCheckedKeys,
|
|
|
|
validKeysCount: this.rightValidKeysCount,
|
2017-05-15 16:37:12 +08:00
|
|
|
listStyle: this.listStyle,
|
2017-03-30 16:05:20 +08:00
|
|
|
title: this.localeTitles[1],
|
2017-03-08 17:04:07 +08:00
|
|
|
filterable: this.filterable,
|
2017-03-30 16:05:20 +08:00
|
|
|
filterPlaceholder: this.localeFilterPlaceholder,
|
2017-03-08 17:04:07 +08:00
|
|
|
filterMethod: this.filterMethod,
|
2017-03-30 16:05:20 +08:00
|
|
|
notFoundText: this.localeNotFoundText
|
2017-03-08 17:04:07 +08:00
|
|
|
},
|
|
|
|
on: {
|
|
|
|
'on-checked-keys-change': this.handleRightCheckedKeysChange
|
|
|
|
}
|
2017-03-15 19:59:46 +08:00
|
|
|
}, clonedVNodes)
|
2017-03-08 17:04:07 +08:00
|
|
|
]);
|
|
|
|
},
|
2016-11-18 11:46:55 +08:00
|
|
|
props: {
|
|
|
|
data: {
|
|
|
|
type: Array,
|
|
|
|
default () {
|
2016-12-25 22:49:42 +08:00
|
|
|
return [];
|
2016-11-18 11:46:55 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
renderFormat: {
|
|
|
|
type: Function,
|
|
|
|
default (item) {
|
|
|
|
return item.label || item.key;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
targetKeys: {
|
|
|
|
type: Array,
|
|
|
|
default () {
|
2016-12-25 22:49:42 +08:00
|
|
|
return [];
|
2016-11-18 11:46:55 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
selectedKeys: {
|
|
|
|
type: Array,
|
|
|
|
default () {
|
2016-12-25 22:49:42 +08:00
|
|
|
return [];
|
2016-11-18 11:46:55 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
listStyle: {
|
|
|
|
type: Object,
|
|
|
|
default () {
|
2016-12-25 22:49:42 +08:00
|
|
|
return {};
|
2016-11-18 11:46:55 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
titles: {
|
2017-03-30 16:05:20 +08:00
|
|
|
type: Array
|
2016-11-18 11:46:55 +08:00
|
|
|
},
|
|
|
|
operations: {
|
|
|
|
type: Array,
|
|
|
|
default () {
|
2016-12-25 22:49:42 +08:00
|
|
|
return [];
|
2016-11-18 11:46:55 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
filterable: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false
|
|
|
|
},
|
|
|
|
filterPlaceholder: {
|
2017-03-30 16:05:20 +08:00
|
|
|
type: String
|
2016-11-18 11:46:55 +08:00
|
|
|
},
|
|
|
|
filterMethod: {
|
|
|
|
type: Function,
|
|
|
|
default (data, query) {
|
|
|
|
const type = ('label' in data) ? 'label' : 'key';
|
|
|
|
return data[type].indexOf(query) > -1;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
notFoundText: {
|
2017-03-30 16:05:20 +08:00
|
|
|
type: String
|
2016-11-18 11:46:55 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
data () {
|
|
|
|
return {
|
|
|
|
prefixCls: prefixCls,
|
|
|
|
leftData: [],
|
|
|
|
rightData: [],
|
|
|
|
leftCheckedKeys: [],
|
|
|
|
rightCheckedKeys: []
|
2016-12-25 22:49:42 +08:00
|
|
|
};
|
2016-11-18 11:46:55 +08:00
|
|
|
},
|
|
|
|
computed: {
|
|
|
|
classes () {
|
|
|
|
return [
|
|
|
|
`${prefixCls}`
|
2016-12-25 22:49:42 +08:00
|
|
|
];
|
2016-11-18 11:46:55 +08:00
|
|
|
},
|
|
|
|
leftValidKeysCount () {
|
|
|
|
return this.getValidKeys('left').length;
|
|
|
|
},
|
|
|
|
rightValidKeysCount () {
|
|
|
|
return this.getValidKeys('right').length;
|
2017-03-30 16:05:20 +08:00
|
|
|
},
|
|
|
|
localeFilterPlaceholder () {
|
|
|
|
if (this.filterPlaceholder === undefined) {
|
|
|
|
return this.t('i.transfer.filterPlaceholder');
|
|
|
|
} else {
|
|
|
|
return this.filterPlaceholder;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
localeNotFoundText () {
|
|
|
|
if (this.notFoundText === undefined) {
|
|
|
|
return this.t('i.transfer.notFoundText');
|
|
|
|
} else {
|
|
|
|
return this.notFoundText;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
localeTitles () {
|
|
|
|
if (this.titles === undefined) {
|
|
|
|
return [this.t('i.transfer.titles.source'), this.t('i.transfer.titles.target')];
|
|
|
|
} else {
|
|
|
|
return this.titles;
|
|
|
|
}
|
2016-11-18 11:46:55 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
getValidKeys (direction) {
|
|
|
|
return this[`${direction}Data`].filter(data => !data.disabled && this[`${direction}CheckedKeys`].indexOf(data.key) > -1).map(data => data.key);
|
|
|
|
},
|
|
|
|
splitData (init = false) {
|
|
|
|
this.leftData = [...this.data];
|
|
|
|
this.rightData = [];
|
|
|
|
if (this.targetKeys.length > 0) {
|
|
|
|
this.targetKeys.forEach((targetKey) => {
|
2017-06-14 17:40:29 +08:00
|
|
|
const filteredData = this.leftData.filter((data, index) => {
|
|
|
|
if (data.key === targetKey) {
|
|
|
|
this.leftData.splice(index, 1);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2017-06-14 17:48:25 +08:00
|
|
|
});
|
|
|
|
if (filteredData && filteredData.length > 0) this.rightData.push(filteredData[0]);
|
2016-11-18 11:46:55 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
if (init) {
|
|
|
|
this.splitSelectedKey();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
splitSelectedKey () {
|
|
|
|
const selectedKeys = this.selectedKeys;
|
|
|
|
if (selectedKeys.length > 0) {
|
|
|
|
this.leftCheckedKeys = this.leftData
|
|
|
|
.filter(data => selectedKeys.indexOf(data.key) > -1)
|
|
|
|
.map(data => data.key);
|
|
|
|
this.rightCheckedKeys = this.rightData
|
|
|
|
.filter(data => selectedKeys.indexOf(data.key) > -1)
|
|
|
|
.map(data => data.key);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
moveTo (direction) {
|
|
|
|
const targetKeys = this.targetKeys;
|
|
|
|
const opposite = direction === 'left' ? 'right' : 'left';
|
|
|
|
const moveKeys = this.getValidKeys(opposite);
|
|
|
|
const newTargetKeys = direction === 'right' ?
|
|
|
|
moveKeys.concat(targetKeys) :
|
|
|
|
targetKeys.filter(targetKey => !moveKeys.some(checkedKey => targetKey === checkedKey));
|
|
|
|
|
|
|
|
this.$refs[opposite].toggleSelectAll(false);
|
|
|
|
this.$emit('on-change', newTargetKeys, direction, moveKeys);
|
2017-03-09 11:14:40 +08:00
|
|
|
this.dispatch('FormItem', 'on-form-change', {
|
|
|
|
tarketKeys: newTargetKeys,
|
|
|
|
direction: direction,
|
|
|
|
moveKeys: moveKeys
|
|
|
|
});
|
2017-03-07 15:06:38 +08:00
|
|
|
},
|
|
|
|
handleLeftCheckedKeysChange (keys) {
|
|
|
|
this.leftCheckedKeys = keys;
|
|
|
|
},
|
|
|
|
handleRightCheckedKeysChange (keys) {
|
|
|
|
this.rightCheckedKeys = keys;
|
2017-11-07 17:54:36 +08:00
|
|
|
},
|
|
|
|
handleCheckedKeys () {
|
|
|
|
const sourceSelectedKeys = this.getValidKeys('left');
|
|
|
|
const targetSelectedKeys = this.getValidKeys('right');
|
|
|
|
this.$emit('on-selected-change', sourceSelectedKeys, targetSelectedKeys);
|
2016-11-18 11:46:55 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
watch: {
|
|
|
|
targetKeys () {
|
|
|
|
this.splitData(false);
|
2017-04-01 11:21:35 +08:00
|
|
|
},
|
|
|
|
data () {
|
|
|
|
this.splitData(false);
|
2016-11-18 11:46:55 +08:00
|
|
|
}
|
|
|
|
},
|
2017-07-12 16:22:00 +08:00
|
|
|
mounted () {
|
2016-11-18 11:46:55 +08:00
|
|
|
this.splitData(true);
|
|
|
|
}
|
2016-12-25 22:49:42 +08:00
|
|
|
};
|
|
|
|
</script>
|