diff --git a/build/bin/new.js b/build/bin/new.js index dc0018d98..8c95724d0 100644 --- a/build/bin/new.js +++ b/build/bin/new.js @@ -71,11 +71,11 @@ export default { }, { filename: path.join('../../examples/docs/zh-CN', `${componentname}.md`), - content: `## ${chineseName}` + content: `## ${ComponentName} ${chineseName}` }, { filename: path.join('../../examples/docs/en-US', `${componentname}.md`), - content: `## ${componentname}` + content: `## ${ComponentName}` }, { filename: path.join('../../test/unit/specs', `${componentname}.spec.js`), diff --git a/components.json b/components.json index 43f323a71..4a5ccf80a 100644 --- a/components.json +++ b/components.json @@ -61,5 +61,6 @@ "collapse": "./packages/collapse/index.js", "collapse-item": "./packages/collapse-item/index.js", "cascader": "./packages/cascader/index.js", - "color-picker": "./packages/color-picker/index.js" + "color-picker": "./packages/color-picker/index.js", + "transfer": "./packages/transfer/index.js" } diff --git a/examples/docs/en-US/transfer.md b/examples/docs/en-US/transfer.md new file mode 100644 index 000000000..5bb9fa0ad --- /dev/null +++ b/examples/docs/en-US/transfer.md @@ -0,0 +1,275 @@ + + +## Transfer + +### Basic usage +:::demo Data is passed to Transfer via the `data` attribute. The data needs to be an object array, and each object should have these attributes: `key` being the identification of the data item, `label` being the displayed text, and `disabled` indicating if the data item is disabled. Items inside the target list are in sync with the variable binding to `v-model`, and the value of that variable is an array of target item keys. So, if you don't want the target list be initially empty, you can initialize the `v-model` with an array. +```html + + + +``` +::: + +### Filterable + +You can search and filter data items. + +:::demo Set the `filterable` attribute to `true` to enable filter mode. By default, if the data item `label` contains the search keyword, it will be included in the search result. Also, you can implement you own filter method with the `filter-method` attribute. It takes a method and passes search keyword and each data item to it whenever the keyword changes. For a certain data item, if the method returns true, it will be included in the result list. +```html + + + +``` +::: + +### Customizable + +You can customize list titles, button texts, render function for data items, checking status texts in list footer and list footer contents. + +:::demo Use `titles`, `button-texts`, `render-content` and `footer-format` to respectively customize list titles, button texts, render function for data items, checking status texts in list footer. For list footer contents, two named slots are provided: `left-footer` and `right-footer`. Plus, if you want some items initially checked, you can use `left-default-checked` and `right-default-checked`. Finally, this example demonstrate the `change` event. Note that this demo can't run in jsfiddle because it doesn't support JSX syntax. In a real project, `render-content` will work if relevant dependencies are correctly configured. +```html + + + + + +``` +::: + +### Prop aliases + +By default, Transfer looks for `key`, `label` and `disabled` in a data item. If your data items have different key names, you can use the `props` attribute to define aliases. +:::demo The data items in this example do not have `key`s or `label`s, instead they have `value`s and `desc`s. So you need to set aliases for `key` and `label`. +```html + + + +``` +::: + +### Attributes +| Attribute | Description | Type | Accepted Values | Default | +|---------- |-------- |---------- |------------- |-------- | +| data | data source | array[{ key, label, disabled }] | — | [ ] | +| filterable | whether Transfer is filterable | boolean | — | false | +| filter-placeholder | placeholder for the filter input | string | — | Enter keyword | +| filter-method | custom filter method | function | — | — | +| titles | custom list titles | array | — | ['List 1', 'List 2'] | +| button-texts | custom button texts | array | — | [ ] | +| render-content | custom render function for data items | function(h, option) | — | — | +| footer-format | texts for checking status in list footer | object{noChecked, hasChecked} | — | { noChecked: '${total} items', hasChecked: '${checked}/${total} checked' } | +| props | prop aliases for data source | object{key, label, disabled} | — | — | +| left-default-checked | key array of initially checked data items of the left list | array | — | [ ] | +| right-default-checked | key array of initially checked data items of the right list | array | — | [ ] | + +### Slot +| Name | Description | +|------|--------| +| left-footer | content of left list footer | +| right-footer | content of right list footer | + +### Events +| Event Name | Description | Parameters | +|---------- |-------- |---------- | +| change | triggers when data items change in the right list | key array of current data items in the right list, transfer direction (left or right), moved item keys | diff --git a/examples/docs/zh-CN/transfer.md b/examples/docs/zh-CN/transfer.md new file mode 100644 index 000000000..590b964f8 --- /dev/null +++ b/examples/docs/zh-CN/transfer.md @@ -0,0 +1,281 @@ + + + + +## Transfer 穿梭框 + +### 基础用法 +:::demo Transfer 的数据通过 `data` 属性传入。数据需要是一个对象数组,每个对象有以下属性:`key` 为数据的唯一性标识,`label` 为显示文本,`disabled` 表示该项数据是否禁止转移。目标列表中的数据项会同步到绑定至 `v-model` 的变量,值为数据项的 `key` 所组成的数组。当然,如果希望在初始状态时目标列表不为空,可以像本例一样为 `v-model` 绑定的变量赋予一个初始值。 +```html + + + +``` +::: + +### 可搜索 + +在数据很多的情况下,可以对数据进行搜索和过滤。 + +:::demo 设置 `filterable` 为 `true` 即可开启搜索模式。默认情况下,若数据项的 `label` 属性包含搜索关键字,则会在搜索结果中显示。你也可以使用 `filter-method` 定义自己的搜索逻辑。`filter-method` 接收一个方法,当搜索关键字变化时,会将当前的关键字和每个数据项传给该方法。若方法返回 `true`,则会在搜索结果中显示对应的数据项。 +```html + + + +``` +::: + +### 可自定义 + +可以对列表标题文案、按钮文案、数据项的渲染函数、列表底部的勾选状态文案、列表底部的内容区等进行自定义。 + +:::demo 可以使用 `titles`、`button-texts`、`render-content` 和 `footer-format` 属性分别对列表标题文案、按钮文案、数据项的渲染函数和列表底部的勾选状态文案进行自定义。对于列表底部的内容区,提供了两个具名 slot:`left-footer` 和 `right-footer`。此外,如果希望某些数据项在初始化时就被勾选,可以使用 `left-default-checked` 和 `right-default-checked` 属性。最后,本例还展示了 `change` 事件的用法。注意:由于 jsfiddle 不支持 JSX 语法,所以本例在 jsfiddle 中无法运行。但是在实际的项目中,只要正确地配置了相关依赖,就可以正常运行。 +```html + + + + + +``` +::: + +### 数据项属性别名 + +默认情况下,Transfer 仅能识别数据项中的 `key`、`label` 和 `disabled` 字段。如果你的数据的字段名不同,可以使用 `props` 属性为它们设置别名。 +:::demo 本例中的数据源没有 `key` 和 `label` 字段,在功能上与它们相同的字段名为 `value` 和 `desc`。因此可以使用`props` 属性为 `key` 和 `label` 设置别名。 +```html + + + +``` +::: + +### Attributes +| 参数 | 说明 | 类型 | 可选值 | 默认值 | +|---------- |-------- |---------- |------------- |-------- | +| data | Transfer 的数据源 | array[{ key, label, disabled }] | — | [ ] | +| filterable | 是否可搜索 | boolean | — | false | +| filter-placeholder | 搜索框占位符 | string | — | 请输入搜索内容 | +| filter-method | 自定义搜索方法 | function | — | — | +| titles | 自定义列表标题 | array | — | ['列表 1', '列表 2'] | +| button-texts | 自定义按钮文案 | array | — | [ ] | +| render-content | 自定义数据项渲染函数 | function(h, option) | — | — | +| footer-format | 列表底部勾选状态文案 | object{noChecked, hasChecked} | — | { noChecked: '共 ${total} 项', hasChecked: '已选 ${checked}/${total} 项' } | +| props | 数据源的字段别名 | object{key, label, disabled} | — | — | +| left-default-checked | 初始状态下左侧列表的已勾选项的 key 数组 | array | — | [ ] | +| right-default-checked | 初始状态下右侧列表的已勾选项的 key 数组 | array | — | [ ] | + +### Slot +| name | 说明 | +|------|--------| +| left-footer | 左侧列表底部的内容 | +| right-footer | 右侧列表底部的内容 | + +### Events +| 事件名称 | 说明 | 回调参数 | +|---------- |-------- |---------- | +| change | 右侧列表元素变化时触发 | 当前值、数据移动的方向('left' / 'right')、发生移动的数据 key 数组 | diff --git a/examples/nav.config.json b/examples/nav.config.json index 5d86bbdaa..85642f09d 100644 --- a/examples/nav.config.json +++ b/examples/nav.config.json @@ -116,6 +116,10 @@ "path": "/color-picker", "title": "ColorPicker 颜色选择器" }, + { + "path": "/transfer", + "title": "Transfer 穿梭框" + }, { "path": "/form", "title": "Form 表单" @@ -350,6 +354,10 @@ "path": "/color-picker", "title": "ColorPicker" }, + { + "path": "/transfer", + "title": "Transfer" + }, { "path": "/form", "title": "Form" diff --git a/packages/theme-default/src/common/var.css b/packages/theme-default/src/common/var.css index c82538267..02de8b845 100644 --- a/packages/theme-default/src/common/var.css +++ b/packages/theme-default/src/common/var.css @@ -589,4 +589,17 @@ --collapse-content-fill: var(--color-dark-white); --collapse-content-size: 13px; --collapse-content-color: var(--color-base-black); + + /* Transfer + --------------------------*/ + --transfer-border-color: var(--color-base-gray); + --transfer-box-shadow: var(--box-shadow-base); + --transfer-panel-width: 200px; + --transfer-panel-header-height: 36px; + --transfer-panel-header-background: var(--color-dark-white); + --transfer-panel-footer-height: 36px; + --transfer-panel-body-height: 246px; + --transfer-item-height: 32px; + --transfer-item-hover-background: var(--color-light-gray); + --transfer-filter-height: 22px; } diff --git a/packages/theme-default/src/index.css b/packages/theme-default/src/index.css index aad8da169..d18c11f7a 100644 --- a/packages/theme-default/src/index.css +++ b/packages/theme-default/src/index.css @@ -59,3 +59,4 @@ @import "./collapse-item.css"; @import "./cascader.css"; @import "./color-picker.css"; +@import "./transfer.css"; diff --git a/packages/theme-default/src/transfer.css b/packages/theme-default/src/transfer.css new file mode 100644 index 000000000..13ea6e68e --- /dev/null +++ b/packages/theme-default/src/transfer.css @@ -0,0 +1,168 @@ +@charset "UTF-8"; +@import "./common/var.css"; +@import "./input.css"; +@import "./button.css"; +@import "./checkbox.css"; +@import "./checkbox-group.css"; + +@component-namespace el { + @b transfer { + font-size: var(--font-size-base); + + @e buttons { + display: inline-block; + vertical-align: middle; + padding: 0 10px; + + .el-button { + display: block; + margin: 0 auto; + padding: 8px 12px; + + &:first-child { + margin-bottom: 6px; + } + } + + .el-button [class*="el-icon-"] + span { + margin-left: 0; + } + } + } + + @b transfer-panel { + border: 1px solid var(--transfer-border-color); + background: var(--color-white); + box-shadow: var(--transfer-box-shadow); + display: inline-block; + vertical-align: middle; + width: var(--transfer-panel-width); + box-sizing: border-box; + position: relative; + + @e body { + padding-bottom: var(--transfer-panel-footer-height); + height: var(--transfer-panel-body-height); + } + + @e list { + margin: 0; + padding: 6px 0; + list-style: none; + height: var(--transfer-panel-body-height); + overflow: auto; + box-sizing: border-box; + + @when filterable { + height: calc(var(--transfer-panel-body-height) - var(--transfer-filter-height) - 10px); + } + } + + @e item { + height: var(--transfer-item-height); + line-height: var(--transfer-item-height); + padding-left: 20px; + display: block; + + & + .el-transfer-panel__item { + margin-left: 0; + } + + &.el-checkbox { + color: var(--color-extra-light-black); + } + + &:hover { + background: var(--transfer-item-hover-background); + } + + .el-checkbox__label { + width: 100%; + @utils-ellipsis; + display: block; + box-sizing: border-box; + padding-left: 28px; + } + + .el-checkbox__input { + position: absolute; + top: 9px; + } + } + + @e filter { + margin-top: 10px; + text-align: center; + padding: 0 10px; + width: 100%; + box-sizing: border-box; + + .el-input__inner { + height: var(--transfer-filter-height); + width: 100%; + display: inline-block; + box-sizing: border-box; + } + + .el-input__icon { + right: 10px; + } + + .el-icon-circle-close { + cursor: pointer; + } + } + + .el-transfer-panel__header { + height: var(--transfer-panel-header-height); + line-height: var(--transfer-panel-header-height); + background: var(--transfer-panel-header-background); + margin: 0; + padding-left: 20px; + border-bottom: 1px solid var(--transfer-border-color); + box-sizing: border-box; + color: var(--color-base-black); + } + + .el-transfer-panel__footer { + height: var(--transfer-panel-footer-height); + background: var(--color-white); + margin: 0; + padding: 0; + border-top: 1px solid var(--transfer-border-color); + position: absolute; + bottom: 0; + left: 0; + width: 100%; + z-index: var(--index-normal); + @utils-vertical-center; + + .el-checkbox { + padding-left: 20px; + color: var(--color-base-silver); + } + } + + .el-transfer-panel__empty { + margin: 0; + height: var(--transfer-item-height); + line-height: var(--transfer-item-height); + padding: 6px 20px 0; + color: var(--color-base-silver); + } + + .el-checkbox__label { + padding-left: 14px; + } + + .el-checkbox__inner { + size: 14px; + border-radius: 3px; + &::after { + height: 6px; + width: 3px; + left: 4px; + } + } + } +} diff --git a/packages/transfer/index.js b/packages/transfer/index.js new file mode 100644 index 000000000..0283e8b28 --- /dev/null +++ b/packages/transfer/index.js @@ -0,0 +1,8 @@ +import Transfer from './src/main'; + +/* istanbul ignore next */ +Transfer.install = function(Vue) { + Vue.component(Transfer.name, Transfer); +}; + +export default Transfer; diff --git a/packages/transfer/src/main.vue b/packages/transfer/src/main.vue new file mode 100644 index 000000000..ca25a1939 --- /dev/null +++ b/packages/transfer/src/main.vue @@ -0,0 +1,184 @@ + + + diff --git a/packages/transfer/src/transfer-panel.vue b/packages/transfer/src/transfer-panel.vue new file mode 100644 index 000000000..ebdd892dc --- /dev/null +++ b/packages/transfer/src/transfer-panel.vue @@ -0,0 +1,229 @@ + + + diff --git a/src/index.js b/src/index.js index 5a627a811..7681022c0 100644 --- a/src/index.js +++ b/src/index.js @@ -63,6 +63,7 @@ import Collapse from '../packages/collapse/index.js'; import CollapseItem from '../packages/collapse-item/index.js'; import Cascader from '../packages/cascader/index.js'; import ColorPicker from '../packages/color-picker/index.js'; +import Transfer from '../packages/transfer/index.js'; import locale from 'element-ui/src/locale'; import CollapseTransition from 'element-ui/src/transitions/collapse-transition'; @@ -125,6 +126,7 @@ const components = [ Collapse, CollapseItem, Cascader, + Transfer, ColorPicker, CollapseTransition ]; @@ -223,5 +225,6 @@ module.exports = { Collapse, CollapseItem, Cascader, - ColorPicker + ColorPicker, + Transfer }; diff --git a/src/locale/lang/bg.js b/src/locale/lang/bg.js index 83c8b658c..c937ee648 100644 --- a/src/locale/lang/bg.js +++ b/src/locale/lang/bg.js @@ -90,6 +90,14 @@ export default { }, tree: { emptyText: 'Няма данни' + }, + transfer: { + noMatch: 'Няма намерени', + noData: 'Няма данни', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/ca.js b/src/locale/lang/ca.js index a64c61d85..fcaf06c85 100644 --- a/src/locale/lang/ca.js +++ b/src/locale/lang/ca.js @@ -89,6 +89,14 @@ export default { }, tree: { emptyText: 'Sense Dades' + }, + transfer: { + noMatch: 'No hi ha dades que coincideixin', + noData: 'Sense Dades', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/cz.js b/src/locale/lang/cz.js index 64a54b090..1296e303c 100644 --- a/src/locale/lang/cz.js +++ b/src/locale/lang/cz.js @@ -92,6 +92,14 @@ export default { }, tree: { emptyText: 'Žádná data' + }, + transfer: { + noMatch: 'Žádná shoda', + noData: 'Žádná data', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/da.js b/src/locale/lang/da.js index 0b10c825a..f2ff7cca4 100644 --- a/src/locale/lang/da.js +++ b/src/locale/lang/da.js @@ -89,6 +89,14 @@ export default { }, tree: { emptyText: 'Ingen data' + }, + transfer: { + noMatch: 'Ingen matchende data', + noData: 'Ingen data', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/de.js b/src/locale/lang/de.js index e8d769627..4b7cf747c 100644 --- a/src/locale/lang/de.js +++ b/src/locale/lang/de.js @@ -91,6 +91,14 @@ export default { }, tree: { emptyText: 'Keine Daten' + }, + transfer: { + noMatch: 'Nichts gefunden.', + noData: 'Keine Datei', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/el.js b/src/locale/lang/el.js index db85799a7..81a682a5b 100644 --- a/src/locale/lang/el.js +++ b/src/locale/lang/el.js @@ -60,6 +60,10 @@ export default { noData: 'Χωρίς δεδομένα', placeholder: 'Επιλογή' }, + cascader: { + noMatch: 'Δεν βρέθηκαν αποτελέσματα', + placeholder: 'Επιλογή' + }, pagination: { goto: 'Μετάβαση σε', pagesize: '/σελίδα', @@ -86,6 +90,14 @@ export default { }, tree: { emptyText: 'Χωρίς Δεδομένα' + }, + transfer: { + noMatch: 'Δεν βρέθηκαν αποτελέσματα', + noData: 'Χωρίς δεδομένα', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/en.js b/src/locale/lang/en.js index f474a42f9..b4da84732 100644 --- a/src/locale/lang/en.js +++ b/src/locale/lang/en.js @@ -90,6 +90,14 @@ export default { }, tree: { emptyText: 'No Data' + }, + transfer: { + noMatch: 'No matching data', + noData: 'No data', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/es.js b/src/locale/lang/es.js index 6178c27ea..90e4511c6 100644 --- a/src/locale/lang/es.js +++ b/src/locale/lang/es.js @@ -89,6 +89,14 @@ export default { }, tree: { emptyText: 'Sin Datos' + }, + transfer: { + noMatch: 'No hay datos que coincidan', + noData: 'Sin datos', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/fa.js b/src/locale/lang/fa.js index 79ae20b46..954edeb9c 100644 --- a/src/locale/lang/fa.js +++ b/src/locale/lang/fa.js @@ -90,6 +90,14 @@ export default { }, tree: { emptyText: 'اطلاعاتی وجود ندارد' + }, + transfer: { + noMatch: 'هیچ داده‌ای پیدا نشد', + noData: 'اطلاعاتی وجود ندارد', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/fi.js b/src/locale/lang/fi.js index 370e4111a..1c0291c07 100644 --- a/src/locale/lang/fi.js +++ b/src/locale/lang/fi.js @@ -60,6 +60,10 @@ export default { noData: 'Ei tietoja', placeholder: 'Valitse' }, + cascader: { + noMatch: 'Ei vastaavia tietoja', + placeholder: 'Valitse' + }, pagination: { goto: 'Mene', pagesize: '/sivu', @@ -86,6 +90,14 @@ export default { }, tree: { emptyText: 'Ei tietoja' + }, + transfer: { + noMatch: 'Ei vastaavia tietoja', + noData: 'Ei tietoja', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/fr.js b/src/locale/lang/fr.js index 1231e338b..a8912fe07 100644 --- a/src/locale/lang/fr.js +++ b/src/locale/lang/fr.js @@ -57,7 +57,7 @@ export default { select: { loading: 'Chargement', noMatch: 'Aucune correspondance', - noData: 'Aucun résultat', + noData: 'Aucune donnée', placeholder: 'Choisir' }, cascader: { @@ -89,6 +89,14 @@ export default { }, tree: { emptyText: 'Aucune donnée' + }, + transfer: { + noMatch: 'Aucune correspondance', + noData: 'Aucune donnée', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/id.js b/src/locale/lang/id.js index 9a0dc494d..05f6d36ec 100644 --- a/src/locale/lang/id.js +++ b/src/locale/lang/id.js @@ -90,6 +90,14 @@ export default { }, tree: { emptyText: 'Tidak Ada Data' + }, + transfer: { + noMatch: 'Tidak ada data yang cocok', + noData: 'Tidak ada data', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/it.js b/src/locale/lang/it.js index 05dc6a067..8109aafdc 100644 --- a/src/locale/lang/it.js +++ b/src/locale/lang/it.js @@ -57,7 +57,7 @@ export default { select: { loading: 'Caricamento', noMatch: 'Nessuna corrispondenza', - noData: 'Nessun risultato', + noData: 'Nessun dato', placeholder: 'Seleziona' }, cascader: { @@ -89,6 +89,14 @@ export default { }, tree: { emptyText: 'Nessun dato' + }, + transfer: { + noMatch: 'Nessuna corrispondenza', + noData: 'Nessun dato', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/ja.js b/src/locale/lang/ja.js index ef3b9b94c..f7aa9f4f2 100644 --- a/src/locale/lang/ja.js +++ b/src/locale/lang/ja.js @@ -90,6 +90,14 @@ export default { }, tree: { emptyText: 'データなし' + }, + transfer: { + noMatch: 'データなし', + noData: 'データなし', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/ko.js b/src/locale/lang/ko.js index fa873dd22..7be6d3937 100644 --- a/src/locale/lang/ko.js +++ b/src/locale/lang/ko.js @@ -90,6 +90,14 @@ export default { }, tree: { emptyText: '데이터 없음' + }, + transfer: { + noMatch: '맞는 데이터가 없습니다', + noData: '데이터 없음', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/nb-NO.js b/src/locale/lang/nb-NO.js index 4a942332d..8f1158e32 100644 --- a/src/locale/lang/nb-NO.js +++ b/src/locale/lang/nb-NO.js @@ -89,6 +89,14 @@ export default { }, tree: { emptyText: 'Ingen Data' + }, + transfer: { + noMatch: 'Ingen samsvarende data', + noData: 'Ingen data', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/nl.js b/src/locale/lang/nl.js index ac74b7902..5fd9eb7b2 100644 --- a/src/locale/lang/nl.js +++ b/src/locale/lang/nl.js @@ -90,6 +90,14 @@ export default { }, tree: { emptyText: 'Geen data' + }, + transfer: { + noMatch: 'Geen overeenkomende resultaten', + noData: 'Geen data', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/pl.js b/src/locale/lang/pl.js index a57804358..e3461b879 100644 --- a/src/locale/lang/pl.js +++ b/src/locale/lang/pl.js @@ -90,6 +90,14 @@ export default { }, tree: { emptyText: 'Brak danych' + }, + transfer: { + noMatch: 'Brak dopasowań', + noData: 'Brak danych', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/pt-br.js b/src/locale/lang/pt-br.js index 2560fc1f1..ed0658885 100644 --- a/src/locale/lang/pt-br.js +++ b/src/locale/lang/pt-br.js @@ -90,6 +90,14 @@ export default { }, tree: { emptyText: 'Sem dados' + }, + transfer: { + noMatch: 'Sem resultados', + noData: 'Sem dados', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/pt.js b/src/locale/lang/pt.js index 35a18d3bc..e506f6cd2 100644 --- a/src/locale/lang/pt.js +++ b/src/locale/lang/pt.js @@ -90,6 +90,14 @@ export default { }, tree: { emptyText: 'Sem dados' + }, + transfer: { + noMatch: 'Sem correspondência', + noData: 'Sem dados', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/ru-RU.js b/src/locale/lang/ru-RU.js index 2fb9663ed..59c80700d 100644 --- a/src/locale/lang/ru-RU.js +++ b/src/locale/lang/ru-RU.js @@ -90,6 +90,14 @@ export default { }, tree: { emptyText: 'Нет данных' + }, + transfer: { + noMatch: 'Совпадений не найдено', + noData: 'Нет данных', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/sk.js b/src/locale/lang/sk.js index 0162385c9..31b4f3242 100644 --- a/src/locale/lang/sk.js +++ b/src/locale/lang/sk.js @@ -62,6 +62,10 @@ export default { noData: 'Žiadne dáta', placeholder: 'Vybrať' }, + cascader: { + noMatch: 'Žiadna zhoda', + placeholder: 'Vybrať' + }, pagination: { goto: 'Choď na', pagesize: 'na stranu', @@ -88,6 +92,14 @@ export default { }, tree: { emptyText: 'Žiadne dáta' + }, + transfer: { + noMatch: 'Žiadna zhoda', + noData: 'Žiadne dáta', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/sv-SE.js b/src/locale/lang/sv-SE.js index caef69ef5..36773cf05 100644 --- a/src/locale/lang/sv-SE.js +++ b/src/locale/lang/sv-SE.js @@ -60,6 +60,10 @@ export default { noData: 'Ingen data', placeholder: 'Välj' }, + cascader: { + noMatch: 'Hittade inget', + placeholder: 'Välj' + }, pagination: { goto: 'Gå till', pagesize: '/sida', @@ -86,6 +90,14 @@ export default { }, tree: { emptyText: 'Inga Data' + }, + transfer: { + noMatch: 'Hittade inget', + noData: 'Ingen data', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/th.js b/src/locale/lang/th.js index 656b753ac..7da6f8688 100644 --- a/src/locale/lang/th.js +++ b/src/locale/lang/th.js @@ -90,6 +90,14 @@ export default { }, tree: { emptyText: 'ไม่พบข้อมูล' + }, + transfer: { + noMatch: 'ไม่พบข้อมูลที่ตรงกัน', + noData: 'ไม่พบข้อมูล', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/tk.js b/src/locale/lang/tk.js index fe0b099b2..04344c0cf 100644 --- a/src/locale/lang/tk.js +++ b/src/locale/lang/tk.js @@ -90,6 +90,14 @@ export default { }, tree: { emptyText: 'Maglumat ýok' + }, + transfer: { + noMatch: 'Hiçzat tapylmady', + noData: 'Hiçzat ýok', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/tr-TR.js b/src/locale/lang/tr-TR.js index bb4ed25cb..c8c7fc95b 100644 --- a/src/locale/lang/tr-TR.js +++ b/src/locale/lang/tr-TR.js @@ -90,6 +90,14 @@ export default { }, tree: { emptyText: 'Veri yok' + }, + transfer: { + noMatch: 'Eşleşen veri bulunamadı', + noData: 'Veri yok', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/ua.js b/src/locale/lang/ua.js index 2209ef38a..97f354a5d 100644 --- a/src/locale/lang/ua.js +++ b/src/locale/lang/ua.js @@ -90,6 +90,14 @@ export default { }, tree: { emptyText: 'Нема даних' + }, + transfer: { + noMatch: 'Співпадінь не знайдено', + noData: 'Обрати', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/vi.js b/src/locale/lang/vi.js index 5844029da..4daba4609 100644 --- a/src/locale/lang/vi.js +++ b/src/locale/lang/vi.js @@ -90,6 +90,14 @@ export default { }, tree: { emptyText: 'Không có dữ liệu' + }, + transfer: { + noMatch: 'Dữ liệu không phù hợp', + noData: 'Không tìm thấy dữ liệu', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/src/locale/lang/zh-CN.js b/src/locale/lang/zh-CN.js index 820b76950..e01a438de 100644 --- a/src/locale/lang/zh-CN.js +++ b/src/locale/lang/zh-CN.js @@ -90,6 +90,14 @@ export default { }, tree: { emptyText: '暂无数据' + }, + transfer: { + noMatch: '无匹配数据', + noData: '无数据', + titles: ['列表 1', '列表 2'], + filterPlaceholder: '请输入搜索内容', + noCheckedFormat: '共 {total} 项', + hasCheckedFormat: '已选 {checked}/{total} 项' } } }; diff --git a/src/locale/lang/zh-TW.js b/src/locale/lang/zh-TW.js index d6eae8ede..b567fbd9a 100644 --- a/src/locale/lang/zh-TW.js +++ b/src/locale/lang/zh-TW.js @@ -90,6 +90,14 @@ export default { }, tree: { emptyText: '暫無資料' + }, + transfer: { + noMatch: '無匹配資料', + noData: '無資料', + titles: ['List 1', 'List 2'], // to be translated + filterPlaceholder: 'Enter keyword', // to be translated + noCheckedFormat: '{total} items', // to be translated + hasCheckedFormat: '{checked}/{total} checked' // to be translated } } }; diff --git a/test/unit/specs/transfer.spec.js b/test/unit/specs/transfer.spec.js new file mode 100644 index 000000000..1da5cb792 --- /dev/null +++ b/test/unit/specs/transfer.spec.js @@ -0,0 +1,124 @@ +import { createTest, createVue, destroyVM } from '../util'; +import Transfer from 'packages/transfer'; + +describe('Transfer', () => { + let vm; + const getTestData = () => { + const data = []; + for (let i = 1; i <= 15; i++) { + data.push({ + key: i, + label: `备选项 ${ i }`, + disabled: i % 4 === 0 + }); + } + return data; + }; + const createTransfer = (props, opts) => { + return createVue(Object.assign({ + template: ` + + + `, + + created() { + this.testData = getTestData(); + } + }, opts)); + }; + + afterEach(() => { + destroyVM(vm); + }); + + it('create', () => { + vm = createTest(Transfer, true); + expect(vm.$el).to.exist; + }); + + it('default target list', () => { + vm = createTransfer('v-model="value"', { + data() { + return { + value: [1, 4] + }; + } + }); + expect(vm.$refs.transfer.sourceData.length).to.equal(13); + }); + + it('filterable', done => { + vm = createTransfer('v-model="value" filterable :filter-method="method"', { + data() { + return { + value: [], + method(query, option) { + return option.key === Number(query); + } + }; + } + }); + const transfer = vm.$refs.transfer; + const leftList = transfer.$el.querySelector('.el-transfer-panel').__vue__; + leftList.query = '1'; + setTimeout(_ => { + expect(leftList.filteredData.length).to.equal(1); + done(); + }, 50); + }); + + it('transfer', done => { + vm = createTransfer('v-model="value" :left-default-checked="[2, 3]" :right-default-checked="[1]"', { + data() { + return { + value: [1, 4] + }; + } + }); + const transfer = vm.$refs.transfer; + + setTimeout(_ => { + transfer.addToLeft(); + setTimeout(_ => { + expect(transfer.sourceData.length).to.equal(14); + transfer.addToRight(); + setTimeout(_ => { + expect(transfer.sourceData.length).to.equal(12); + done(); + }, 50); + }, 50); + }, 50); + }); + + it('customize', () => { + vm = createTransfer('v-model="value" :titles="titles" :render-content="renderFunc" :footer-format="format"', { + data() { + return { + value: [2], + titles: ['1', '2'], + format: { noChecked: 'no', hasChecked: 'has' }, + renderFunc(h, option) { + return { option.key } - { option.label }; + } + }; + } + }); + const transfer = vm.$refs.transfer.$el; + expect(transfer.querySelector('.el-transfer-panel__header').innerText).to.equal('1'); + expect(transfer.querySelector('.el-checkbox__label span').innerText).to.equal('1 - 备选项 1'); + expect(transfer.querySelector('.el-transfer-panel__footer .el-checkbox__label').innerText).to.equal('no'); + }); + + it('check', () => { + vm = createTransfer('v-model="value"', { + data() { + return { + value: [] + }; + } + }); + const leftList = vm.$refs.transfer.$el.querySelector('.el-transfer-panel').__vue__; + leftList.handleAllCheckedChange({ target: { checked: true } }); + expect(leftList.checked.length).to.equal(12); + }); +});