ant-design-vue/components/upload/UploadList.jsx
tangjinzhou 73bef787cd
Feat 1.5.0 (#1853)
* feat: add Result component

* fix: update md template tag html>tpl
- fix `result` typo
- update jest `result` snapshots

* refactor: svg file to functional component icon
- update jest snapshot

* feat: add result

* Feat descriptions (#1251)

* feat: add descriptions

* fix: add descriptions types and fix docs

* fix: lint change code

* fix: demo warning

* fix: update demo, snapshot and remove classnames

* test: add descriptions test

* fix: descriptions demo (#1498)

* feat: add page header (#1250)

* feat: add page-header component

* update site: page-header

* ts definition update: page-header

* get page-header props with getComponentFromProp func

* optimize page-header

* doc: add page-header actions.md responsive.md

* breadcrumb itemRender add pure function support

* style: format code

* feat: update style to 3.23.6 from 2.13.6

* feat: update style to 3.26.8 from 3.23.6

* chore: update util

* chore: update util

* feat: update affix

* feat: update alert

* feat: update anchor

* feat: update auto-complete

* feat: update avatar

* feat: update back-top

* feat: update badge

* feat: update button

* feat: update breadcrumb

* feat: update ts

* docs: update doc

* feat: update calendat

* feat: update card

* feat: update carousel

* feat: update carousel

* feat: update checkbox

* feat: update comment

* feat: update config-provider

* docs: update doc

* feat: update collapse

* feat: update locale

* feat: update date-picker

* feat: update divider

* feat: update drawer

* feat: update dropdown

* feat: update rc-trigger

* feat: update dropdown

* feat: update empty

* test: add empty test

* feat: update form

* feat: update form

* feat: update spin

* feat: update grid

* docs: update grid doc

* feat: update icon

* feat: update slider

* feat: update textarea

* feat: update input-number

* feat: update layout

* feat: update list

* feat: update menu

* feat: meaage add key for update content

* feat: modal add closeIcon support

* feat: update notification

* feat: add pagination disabled support

* feat: popconfirm add disabled support

* test: update popover

* feat: progress support custom line-gradiend

* feat: update radio

* test: update radio test

* docs: update rate demo

* feat: skeleton add avatar support number type

* test: add switch test

* test: update statistic test

* fix: input clear icon event

* feat: steps add type、 v-model、subTitle

* feat: delete typography component

* feat: delete Typography style

* perf: update select

* feat: add download transformFile previewFile actio

* docs: update upload

* feat: update  tree-select

* docs: update tree-select

* feat: tree add blockNode selectable

* docs: add tree demo

* test: update snap

* docs: updatedoc

* feat: update tag

* docs: update ad doc

* feat: update tooltip

* feat: update timeline

* feat: time-picker add clearIcon

* docs: update tabs

* feat: transfer support custom children

* test: update transfer test

* feat: update table

* test: update table test

* test: update test

* feat: calendar update locale

* test: update test snap

* feat: add mentions (#1790)

* feat: mentions style

* feat: theme default

* feat: add mentions component

* feat: mentions API

* feat: add unit test for mentions

* feat: update mentions demo

* perf: model and inheritAttrs for mentions

* perf: use getComponentFromProp instead of this.$props

* perf: mentions rm defaultProps

* feat: rm rows in mentionsProps

* fix: mentions keyDown didn't work

* docs: update mentions api

* perf: mentions code

* feat: update mentions

* bump 1.5.0-alpha.1

* feat: pageheader add ghost prop

* docs: update descriptions demo

* chore: page-header add ghost type

* fix: color error

* feat: update to 3.26.12

* fix: some prop default value

* fix(typo): form, carousel, upload. duplicate identifier (#1848)

* Add Mentions Type (#1845)

* feat: add mentions type

* feat: add mentions in ant-design-vue.d.ts

* docs: update doc

* docs: add changelog

* fix: mentions getPopupCotainer value (#1850)

* docs: update doc

* docs: uptate demo

* docs: update demo

* docs: delete demo

* docs: delete doc

* test: update snapshots

* style: format code

* chore: update travis

* docs: update demo

Co-authored-by: Sendya <18x@loacg.com>
Co-authored-by: zkwolf <chenhao5866@gmail.com>
Co-authored-by: drafish <xwlyy1991@163.com>
Co-authored-by: Amour1688 <31695475+Amour1688@users.noreply.github.com>
2020-03-07 19:45:13 +08:00

273 lines
8.5 KiB
Vue

import BaseMixin from '../_util/BaseMixin';
import { getOptionProps, initDefaultProps, getListeners } from '../_util/props-util';
import getTransitionProps from '../_util/getTransitionProps';
import { ConfigConsumerProps } from '../config-provider';
import { previewImage, isImageUrl } from './utils';
import Icon from '../icon';
import Tooltip from '../tooltip';
import Progress from '../progress';
import classNames from 'classnames';
import { UploadListProps } from './interface';
export default {
name: 'AUploadList',
mixins: [BaseMixin],
props: initDefaultProps(UploadListProps, {
listType: 'text', // or picture
progressAttr: {
strokeWidth: 2,
showInfo: false,
},
showRemoveIcon: true,
showDownloadIcon: false,
showPreviewIcon: true,
previewFile: previewImage,
}),
inject: {
configProvider: { default: () => ConfigConsumerProps },
},
updated() {
this.$nextTick(() => {
const { listType, items, previewFile } = this.$props;
if (listType !== 'picture' && listType !== 'picture-card') {
return;
}
(items || []).forEach(file => {
if (
typeof document === 'undefined' ||
typeof window === 'undefined' ||
!window.FileReader ||
!window.File ||
!(file.originFileObj instanceof File || file.originFileObj instanceof Blob) ||
file.thumbUrl !== undefined
) {
return;
}
/*eslint-disable */
file.thumbUrl = '';
if (previewFile) {
previewFile(file.originFileObj).then(previewDataUrl => {
// Need append '' to avoid dead loop
file.thumbUrl = previewDataUrl || '';
this.$forceUpdate();
});
}
});
});
},
methods: {
handlePreview(file, e) {
const { preview } = getListeners(this);
if (!preview) {
return;
}
e.preventDefault();
return this.$emit('preview', file);
},
handleDownload(file) {
const { download } = getListeners(this);
if (typeof download === 'function') {
download(file);
} else if (file.url) {
window.open(file.url);
}
},
handleClose(file) {
this.$emit('remove', file);
},
},
render() {
const {
prefixCls: customizePrefixCls,
items = [],
listType,
showPreviewIcon,
showRemoveIcon,
showDownloadIcon,
locale,
progressAttr,
} = getOptionProps(this);
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('upload', customizePrefixCls);
const list = items.map(file => {
let progress;
let icon = <Icon type={file.status === 'uploading' ? 'loading' : 'paper-clip'} />;
if (listType === 'picture' || listType === 'picture-card') {
if (listType === 'picture-card' && file.status === 'uploading') {
icon = <div class={`${prefixCls}-list-item-uploading-text`}>{locale.uploading}</div>;
} else if (!file.thumbUrl && !file.url) {
icon = <Icon class={`${prefixCls}-list-item-thumbnail`} type="picture" theme="twoTone" />;
} else {
const thumbnail = isImageUrl(file) ? (
<img
src={file.thumbUrl || file.url}
alt={file.name}
class={`${prefixCls}-list-item-image`}
/>
) : (
<Icon type="file" class={`${prefixCls}-list-item-icon`} theme="twoTone" />
);
icon = (
<a
class={`${prefixCls}-list-item-thumbnail`}
onClick={e => this.handlePreview(file, e)}
href={file.url || file.thumbUrl}
target="_blank"
rel="noopener noreferrer"
>
{thumbnail}
</a>
);
}
}
if (file.status === 'uploading') {
const progressProps = {
props: {
...progressAttr,
type: 'line',
percent: file.percent,
},
};
// show loading icon if upload progress listener is disabled
const loadingProgress = 'percent' in file ? <Progress {...progressProps} /> : null;
progress = (
<div class={`${prefixCls}-list-item-progress`} key="progress">
{loadingProgress}
</div>
);
}
const infoUploadingClass = classNames({
[`${prefixCls}-list-item`]: true,
[`${prefixCls}-list-item-${file.status}`]: true,
[`${prefixCls}-list-item-list-type-${listType}`]: true,
});
const linkProps =
typeof file.linkProps === 'string' ? JSON.parse(file.linkProps) : file.linkProps;
const removeIcon = showRemoveIcon ? (
<Icon type="delete" title={locale.removeFile} onClick={() => this.handleClose(file)} />
) : null;
const downloadIcon =
showDownloadIcon && file.status === 'done' ? (
<Icon
type="download"
title={locale.downloadFile}
onClick={() => this.handleDownload(file)}
/>
) : null;
const downloadOrDelete = listType !== 'picture-card' && (
<span
key="download-delete"
class={`${prefixCls}-list-item-card-actions ${listType === 'picture' ? 'picture' : ''}`}
>
{downloadIcon && <a title={locale.downloadFile}>{downloadIcon}</a>}
{removeIcon && <a title={locale.removeFile}>{removeIcon}</a>}
</span>
);
const listItemNameClass = classNames({
[`${prefixCls}-list-item-name`]: true,
[`${prefixCls}-list-item-name-icon-count-${
[downloadIcon, removeIcon].filter(x => x).length
}`]: true,
});
const preview = file.url
? [
<a
target="_blank"
rel="noopener noreferrer"
class={listItemNameClass}
title={file.name}
{...linkProps}
href={file.url}
onClick={e => this.handlePreview(file, e)}
>
{file.name}
</a>,
downloadOrDelete,
]
: [
<span
key="view"
class={`${prefixCls}-list-item-name`}
onClick={e => this.handlePreview(file, e)}
title={file.name}
>
{file.name}
</span>,
downloadOrDelete,
];
const style =
file.url || file.thumbUrl
? undefined
: {
pointerEvents: 'none',
opacity: 0.5,
};
const previewIcon = showPreviewIcon ? (
<a
href={file.url || file.thumbUrl}
target="_blank"
rel="noopener noreferrer"
style={style}
onClick={e => this.handlePreview(file, e)}
title={locale.previewFile}
>
<Icon type="eye-o" />
</a>
) : null;
const actions = listType === 'picture-card' && file.status !== 'uploading' && (
<span class={`${prefixCls}-list-item-actions`}>
{previewIcon}
{file.status === 'done' && downloadIcon}
{removeIcon}
</span>
);
let message;
if (file.response && typeof file.response === 'string') {
message = file.response;
} else {
message = (file.error && file.error.statusText) || locale.uploadError;
}
const iconAndPreview = (
<span>
{icon}
{preview}
</span>
);
const transitionProps = getTransitionProps('fade');
const dom = (
<div class={infoUploadingClass} key={file.uid}>
<div class={`${prefixCls}-list-item-info`}>{iconAndPreview}</div>
{actions}
<transition {...transitionProps}>{progress}</transition>
</div>
);
const listContainerNameClass = classNames({
[`${prefixCls}-list-picture-card-container`]: listType === 'picture-card',
});
return (
<div key={file.uid} class={listContainerNameClass}>
{file.status === 'error' ? <Tooltip title={message}>{dom}</Tooltip> : <span>{dom}</span>}
</div>
);
});
const listClassNames = classNames({
[`${prefixCls}-list`]: true,
[`${prefixCls}-list-${listType}`]: true,
});
const animationDirection = listType === 'picture-card' ? 'animate-inline' : 'animate';
const transitionGroupProps = getTransitionProps(`${prefixCls}-${animationDirection}`);
return (
<transition-group {...transitionGroupProps} tag="div" class={listClassNames}>
{list}
</transition-group>
);
},
};