[MM-47086] Migrate "components/size_aware_image.jsx" and tests to Typescript (#25230)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
fb1038548e
Коммит
ef0c5e2125
@@ -41,10 +41,10 @@ exports[`components/SizeAwareImage should load download and copy link buttons wh
|
|||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
onLoad={[Function]}
|
onLoad={[Function]}
|
||||||
src="https://example.com/image.png"
|
src="https://example.com/image.png"
|
||||||
tabIndex="0"
|
tabIndex={0}
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
className="image-preview-utility-buttons-container"
|
className="image-preview-utility-buttons-container image-preview-utility-buttons-container--small-image"
|
||||||
>
|
>
|
||||||
<OverlayTrigger
|
<OverlayTrigger
|
||||||
className="hidden-xs"
|
className="hidden-xs"
|
||||||
@@ -167,10 +167,10 @@ exports[`components/SizeAwareImage should match snapshot when handleSmallImageCo
|
|||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
onLoad={[Function]}
|
onLoad={[Function]}
|
||||||
src="https://example.com/image.png"
|
src="https://example.com/image.png"
|
||||||
tabIndex="0"
|
tabIndex={0}
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
className="image-preview-utility-buttons-container"
|
className="image-preview-utility-buttons-container image-preview-utility-buttons-container--small-image"
|
||||||
>
|
>
|
||||||
<OverlayTrigger
|
<OverlayTrigger
|
||||||
className="hidden-xs"
|
className="hidden-xs"
|
||||||
@@ -306,10 +306,10 @@ exports[`components/SizeAwareImage should render a placeholder and has loader wh
|
|||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
onLoad={[Function]}
|
onLoad={[Function]}
|
||||||
src="https://example.com/image.png"
|
src="https://example.com/image.png"
|
||||||
tabIndex="0"
|
tabIndex={0}
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
className="image-preview-utility-buttons-container"
|
className="image-preview-utility-buttons-container image-preview-utility-buttons-container--small-image"
|
||||||
>
|
>
|
||||||
<OverlayTrigger
|
<OverlayTrigger
|
||||||
className="hidden-xs"
|
className="hidden-xs"
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React, {PureComponent} from 'react';
|
import React, {PureComponent} from 'react';
|
||||||
import type {MouseEvent} from 'react';
|
import type {KeyboardEvent, MouseEvent} from 'react';
|
||||||
|
|
||||||
import type {Post, PostImage} from '@mattermost/types/posts';
|
import type {Post, PostImage} from '@mattermost/types/posts';
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ export default class MarkdownImage extends PureComponent<Props, State> {
|
|||||||
return index > 0 ? url.substring(index + 1) : null;
|
return index > 0 ? url.substring(index + 1) : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
showModal = (e: MouseEvent<HTMLImageElement>, link: string) => {
|
showModal = (e: KeyboardEvent<HTMLImageElement> | MouseEvent<HTMLElement>, link = '') => {
|
||||||
const extension = this.getFileExtensionFromUrl(link);
|
const extension = this.getFileExtensionFromUrl(link);
|
||||||
|
|
||||||
if (!this.props.imageIsLink && extension) {
|
if (!this.props.imageIsLink && extension) {
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ describe('components/post_view/MessageAttachment', () => {
|
|||||||
<MessageAttachment {...props}/>,
|
<MessageAttachment {...props}/>,
|
||||||
);
|
);
|
||||||
|
|
||||||
wrapper.instance().showModal({preventDefault: () => {}}, 'https://example.com/image.png');
|
wrapper.instance().showModal({preventDefault: () => {}} as unknown as React.KeyboardEvent<HTMLImageElement> | React.MouseEvent<HTMLElement, MouseEvent>, 'https://example.com/image.png');
|
||||||
expect(props.actions.openModal).toHaveBeenCalledTimes(1);
|
expect(props.actions.openModal).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import truncate from 'lodash/truncate';
|
import truncate from 'lodash/truncate';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import type {CSSProperties} from 'react';
|
import type {KeyboardEvent, MouseEvent, CSSProperties} from 'react';
|
||||||
|
|
||||||
import type {PostAction, PostActionOption} from '@mattermost/types/integration_actions';
|
import type {PostAction, PostActionOption} from '@mattermost/types/integration_actions';
|
||||||
import type {
|
import type {
|
||||||
@@ -312,14 +312,14 @@ export default class MessageAttachment extends React.PureComponent<Props, State>
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
handleFormattedTextClick = (e: React.MouseEvent) => Utils.handleFormattedTextClick(e, this.props.currentRelativeTeamUrl);
|
handleFormattedTextClick = (e: MouseEvent) => Utils.handleFormattedTextClick(e, this.props.currentRelativeTeamUrl);
|
||||||
|
|
||||||
getFileExtensionFromUrl = (url: string) => {
|
getFileExtensionFromUrl = (url: string) => {
|
||||||
const index = url.lastIndexOf('.');
|
const index = url.lastIndexOf('.');
|
||||||
return index > 0 ? url.substring(index + 1) : null;
|
return index > 0 ? url.substring(index + 1) : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
showModal = (e: {preventDefault: () => void}, link: string) => {
|
showModal = (e: (KeyboardEvent<HTMLImageElement> | MouseEvent<HTMLElement>), link = '') => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const extension = this.getFileExtensionFromUrl(link);
|
const extension = this.getFileExtensionFromUrl(link);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import type {KeyboardEvent, MouseEvent} from 'react';
|
||||||
|
|
||||||
import type {Post, PostImage as PostImageMetadata} from '@mattermost/types/posts';
|
import type {Post, PostImage as PostImageMetadata} from '@mattermost/types/posts';
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class PostImage extends React.PureComponent<Props> {
|
export default class PostImage extends React.PureComponent<Props> {
|
||||||
showModal = (e: React.MouseEvent, link: string) => {
|
showModal = (e: (KeyboardEvent<HTMLImageElement> | MouseEvent<HTMLElement>), link = '') => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
this.props.actions.openModal({
|
this.props.actions.openModal({
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ describe('components/SingleImageView', () => {
|
|||||||
<SingleImageView {...baseProps}/>,
|
<SingleImageView {...baseProps}/>,
|
||||||
);
|
);
|
||||||
expect(wrapper.state('loaded')).toEqual(false);
|
expect(wrapper.state('loaded')).toEqual(false);
|
||||||
wrapper.find(SizeAwareImage).prop('onImageLoaded')();
|
wrapper.find(SizeAwareImage).prop('onImageLoaded')?.({height: 0, width: 0});
|
||||||
expect(wrapper.state('loaded')).toEqual(true);
|
expect(wrapper.state('loaded')).toEqual(true);
|
||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import type {KeyboardEvent, MouseEvent} from 'react';
|
||||||
|
|
||||||
import type {FileInfo} from '@mattermost/types/files';
|
import type {FileInfo} from '@mattermost/types/files';
|
||||||
|
|
||||||
@@ -82,7 +83,7 @@ export default class SingleImageView extends React.PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
handleImageClick = (e: React.MouseEvent<HTMLDivElement>) => {
|
handleImageClick = (e: (KeyboardEvent<HTMLImageElement> | MouseEvent<HTMLDivElement | HTMLImageElement>)) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
this.props.actions.openModal({
|
this.props.actions.openModal({
|
||||||
|
|||||||
@@ -7,11 +7,13 @@ import {Provider} from 'react-redux';
|
|||||||
|
|
||||||
import LoadingImagePreview from 'components/loading_image_preview';
|
import LoadingImagePreview from 'components/loading_image_preview';
|
||||||
import SizeAwareImage from 'components/size_aware_image';
|
import SizeAwareImage from 'components/size_aware_image';
|
||||||
|
import type {Props} from 'components/size_aware_image';
|
||||||
|
|
||||||
import mockStore from 'tests/test_store';
|
import mockStore from 'tests/test_store';
|
||||||
|
import {TestHelper} from 'utils/test_helper';
|
||||||
|
|
||||||
describe('components/SizeAwareImage', () => {
|
describe('components/SizeAwareImage', () => {
|
||||||
const baseProps = {
|
const baseProps: Props = {
|
||||||
dimensions: {
|
dimensions: {
|
||||||
height: 200,
|
height: 200,
|
||||||
width: 300,
|
width: 300,
|
||||||
@@ -21,9 +23,9 @@ describe('components/SizeAwareImage', () => {
|
|||||||
getFilePublicLink: jest.fn().mockReturnValue(Promise.resolve({data: {link: 'https://example.com/image.png'}})),
|
getFilePublicLink: jest.fn().mockReturnValue(Promise.resolve({data: {link: 'https://example.com/image.png'}})),
|
||||||
src: 'https://example.com/image.png',
|
src: 'https://example.com/image.png',
|
||||||
className: 'class',
|
className: 'class',
|
||||||
fileInfo: {
|
fileInfo: TestHelper.getFileInfoMock({
|
||||||
name: 'photo-1533709752211-118fcaf03312',
|
name: 'photo-1533709752211-118fcaf03312',
|
||||||
},
|
}),
|
||||||
enablePublicLink: true,
|
enablePublicLink: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -69,11 +71,11 @@ describe('components/SizeAwareImage', () => {
|
|||||||
test('should render a mini preview when showLoader is true and preview is set', () => {
|
test('should render a mini preview when showLoader is true and preview is set', () => {
|
||||||
const props = {
|
const props = {
|
||||||
...baseProps,
|
...baseProps,
|
||||||
fileInfo: {
|
fileInfo: TestHelper.getFileInfoMock({
|
||||||
...baseProps.fileInfo,
|
...baseProps.fileInfo,
|
||||||
mime_type: 'mime_type',
|
mime_type: 'mime_type',
|
||||||
mini_preview: 'mini_preview',
|
mini_preview: 'mini_preview',
|
||||||
},
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
const wrapper = mount(<Provider store={store}><SizeAwareImage {...props}/></Provider>);
|
const wrapper = mount(<Provider store={store}><SizeAwareImage {...props}/></Provider>);
|
||||||
@@ -108,17 +110,22 @@ describe('components/SizeAwareImage', () => {
|
|||||||
const height = 123;
|
const height = 123;
|
||||||
const width = 1234;
|
const width = 1234;
|
||||||
|
|
||||||
const wrapper = shallow(<SizeAwareImage {...baseProps}/>);
|
const wrapper = shallow<SizeAwareImage>(<SizeAwareImage {...baseProps}/>);
|
||||||
|
|
||||||
wrapper.find('img').prop('onLoad')({target: {naturalHeight: height, naturalWidth: width}});
|
wrapper.find('img')?.prop('onLoad')?.({target: {naturalHeight: height, naturalWidth: width}} as unknown as React.SyntheticEvent<HTMLImageElement>);
|
||||||
expect(wrapper.state('loaded')).toBe(true);
|
expect(wrapper.state('loaded')).toBe(true);
|
||||||
expect(baseProps.onImageLoaded).toHaveBeenCalledWith({height, width});
|
expect(baseProps.onImageLoaded).toHaveBeenCalledWith({height, width});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should call onImageLoadFail when image load fails and should have svg', () => {
|
test('should call onImageLoadFail when image load fails and should have svg', () => {
|
||||||
const wrapper = mount(<Provider store={store}><SizeAwareImage {...baseProps}/></Provider>);
|
const wrapper = mount(<Provider store={store}><SizeAwareImage {...baseProps}/></Provider>);
|
||||||
|
const errorEvent = {
|
||||||
wrapper.find(SizeAwareImage).find('img').prop('onError')();
|
target: {},
|
||||||
|
currentTarget: {},
|
||||||
|
preventDefault: () => {},
|
||||||
|
stopPropagation: () => {},
|
||||||
|
} as React.SyntheticEvent<HTMLImageElement>;
|
||||||
|
wrapper.find(SizeAwareImage).find('img').prop('onError')?.(errorEvent);
|
||||||
|
|
||||||
expect(wrapper.find(SizeAwareImage).state('error')).toBe(true);
|
expect(wrapper.find(SizeAwareImage).state('error')).toBe(true);
|
||||||
expect(wrapper.find(SizeAwareImage).find('svg').exists()).toEqual(true);
|
expect(wrapper.find(SizeAwareImage).find('svg').exists()).toEqual(true);
|
||||||
@@ -147,7 +154,7 @@ describe('components/SizeAwareImage', () => {
|
|||||||
|
|
||||||
expect(wrapper.find('div.small-image__container').exists()).toEqual(true);
|
expect(wrapper.find('div.small-image__container').exists()).toEqual(true);
|
||||||
expect(wrapper.find('div.small-image__container').prop('className')).
|
expect(wrapper.find('div.small-image__container').prop('className')).
|
||||||
toEqual('small-image__container cursor--pointer a11y--active');
|
toEqual('small-image__container cursor--pointer a11y--active small-image__container--min-width');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should properly set container div width', () => {
|
test('should properly set container div width', () => {
|
||||||
@@ -4,12 +4,15 @@
|
|||||||
/* eslint-disable @mattermost/use-external-link */
|
/* eslint-disable @mattermost/use-external-link */
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import type {KeyboardEvent, MouseEvent, SyntheticEvent} from 'react';
|
||||||
import {FormattedMessage} from 'react-intl';
|
import {FormattedMessage} from 'react-intl';
|
||||||
|
|
||||||
import {DownloadOutlineIcon, LinkVariantIcon, CheckIcon} from '@mattermost/compass-icons/components';
|
import {DownloadOutlineIcon, LinkVariantIcon, CheckIcon} from '@mattermost/compass-icons/components';
|
||||||
|
import type {FileInfo} from '@mattermost/types/files';
|
||||||
|
import type {PostImage} from '@mattermost/types/posts';
|
||||||
|
|
||||||
|
import type {ActionFunc} from 'mattermost-redux/types/actions';
|
||||||
import {getFileMiniPreviewUrl} from 'mattermost-redux/utils/file_utils';
|
import {getFileMiniPreviewUrl} from 'mattermost-redux/utils/file_utils';
|
||||||
|
|
||||||
import LoadingImagePreview from 'components/loading_image_preview';
|
import LoadingImagePreview from 'components/loading_image_preview';
|
||||||
@@ -23,83 +26,103 @@ const MIN_IMAGE_SIZE = 48;
|
|||||||
const MIN_IMAGE_SIZE_FOR_INTERNAL_BUTTONS = 100;
|
const MIN_IMAGE_SIZE_FOR_INTERNAL_BUTTONS = 100;
|
||||||
const MAX_IMAGE_HEIGHT = 350;
|
const MAX_IMAGE_HEIGHT = 350;
|
||||||
|
|
||||||
|
export type Props = {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The source URL of the image
|
||||||
|
*/
|
||||||
|
src: string;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dimensions object to create empty space required to prevent scroll pop
|
||||||
|
*/
|
||||||
|
dimensions?: Partial<PostImage>;
|
||||||
|
fileInfo?: FileInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fileURL of the original image
|
||||||
|
*/
|
||||||
|
fileURL?: string;
|
||||||
|
|
||||||
|
alt?: string;
|
||||||
|
height?: string;
|
||||||
|
width?: string;
|
||||||
|
title?: string;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Boolean value to pass for showing a loader when image is being loaded
|
||||||
|
*/
|
||||||
|
showLoader?: boolean;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A callback that is called as soon as the image component has a height value
|
||||||
|
*/
|
||||||
|
onImageLoaded?: ({height, width}: {height: number; width: number}) => void;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A callback that is called when image load fails
|
||||||
|
*/
|
||||||
|
onImageLoadFail?: () => void;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fetch the onClick function
|
||||||
|
*/
|
||||||
|
onClick?: (e: (KeyboardEvent<HTMLImageElement> | MouseEvent<HTMLImageElement | HTMLDivElement>), link?: string) => void;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* css classes that can added to the img as well as parent div on svg for placeholder
|
||||||
|
*/
|
||||||
|
className?: string;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enables the logic of surrounding small images with a bigger container div for better click/tap targeting
|
||||||
|
*/
|
||||||
|
handleSmallImageContainer?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables copy URL functionality through a button on image hover.
|
||||||
|
*/
|
||||||
|
enablePublicLink?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action to fetch public link of an image from server.
|
||||||
|
*/
|
||||||
|
getFilePublicLink?: () => ActionFunc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prevents display of utility buttons when image in a location that makes them inappropriate
|
||||||
|
*/
|
||||||
|
hideUtilities?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
loaded: boolean;
|
||||||
|
isSmallImage: boolean;
|
||||||
|
linkCopiedRecently: boolean;
|
||||||
|
linkCopyInProgress: boolean;
|
||||||
|
error: boolean;
|
||||||
|
imageWidth: number;
|
||||||
|
}
|
||||||
|
|
||||||
// SizeAwareImage is a component used for rendering images where the dimensions of the image are important for
|
// SizeAwareImage is a component used for rendering images where the dimensions of the image are important for
|
||||||
// ensuring that the page is laid out correctly.
|
// ensuring that the page is laid out correctly.
|
||||||
export default class SizeAwareImage extends React.PureComponent {
|
export default class SizeAwareImage extends React.PureComponent<Props, State> {
|
||||||
static propTypes = {
|
public heightTimeout = 0;
|
||||||
|
public mounted = false;
|
||||||
|
public timeout: NodeJS.Timeout|null = null;
|
||||||
|
|
||||||
/*
|
constructor(props: Props) {
|
||||||
* The source URL of the image
|
|
||||||
*/
|
|
||||||
src: PropTypes.string.isRequired,
|
|
||||||
|
|
||||||
/*
|
|
||||||
* dimensions object to create empty space required to prevent scroll pop
|
|
||||||
*/
|
|
||||||
dimensions: PropTypes.object,
|
|
||||||
fileInfo: PropTypes.object,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fileURL of the original image
|
|
||||||
*/
|
|
||||||
fileURL: PropTypes.string,
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Boolean value to pass for showing a loader when image is being loaded
|
|
||||||
*/
|
|
||||||
showLoader: PropTypes.bool,
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A callback that is called as soon as the image component has a height value
|
|
||||||
*/
|
|
||||||
onImageLoaded: PropTypes.func,
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A callback that is called when image load fails
|
|
||||||
*/
|
|
||||||
onImageLoadFail: PropTypes.func,
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Fetch the onClick function
|
|
||||||
*/
|
|
||||||
onClick: PropTypes.func,
|
|
||||||
|
|
||||||
/*
|
|
||||||
* css classes that can added to the img as well as parent div on svg for placeholder
|
|
||||||
*/
|
|
||||||
className: PropTypes.string,
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Enables the logic of surrounding small images with a bigger container div for better click/tap targeting
|
|
||||||
*/
|
|
||||||
handleSmallImageContainer: PropTypes.bool,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enables copy URL functionality through a button on image hover.
|
|
||||||
*/
|
|
||||||
enablePublicLink: PropTypes.bool,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action to fetch public link of an image from server.
|
|
||||||
*/
|
|
||||||
getFilePublicLink: PropTypes.func,
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Prevents display of utility buttons when image in a location that makes them inappropriate
|
|
||||||
*/
|
|
||||||
hideUtilities: PropTypes.bool,
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
super(props);
|
||||||
const {dimensions} = props;
|
const {dimensions} = props;
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
loaded: false,
|
loaded: false,
|
||||||
isSmallImage: this.dimensionsAvailable(dimensions) ? this.isSmallImage(
|
isSmallImage: this.dimensionsAvailable(dimensions) ? this.isSmallImage(
|
||||||
dimensions.width, dimensions.height) : false,
|
dimensions?.width ?? 0, dimensions?.height ?? 0) : false,
|
||||||
linkCopiedRecently: false,
|
linkCopiedRecently: false,
|
||||||
linkCopyInProgress: false,
|
linkCopyInProgress: false,
|
||||||
|
error: false,
|
||||||
|
imageWidth: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.heightTimeout = 0;
|
this.heightTimeout = 0;
|
||||||
@@ -113,17 +136,17 @@ export default class SizeAwareImage extends React.PureComponent {
|
|||||||
this.mounted = false;
|
this.mounted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
dimensionsAvailable = (dimensions) => {
|
dimensionsAvailable = (dimensions?: Partial<PostImage>) => {
|
||||||
return dimensions && dimensions.width && dimensions.height;
|
return dimensions && dimensions.width && dimensions.height;
|
||||||
};
|
};
|
||||||
|
|
||||||
isSmallImage = (width, height) => {
|
isSmallImage = (width: number, height: number) => {
|
||||||
return width < MIN_IMAGE_SIZE || height < MIN_IMAGE_SIZE;
|
return width < MIN_IMAGE_SIZE || height < MIN_IMAGE_SIZE;
|
||||||
};
|
};
|
||||||
|
|
||||||
handleLoad = (event) => {
|
handleLoad = (event: SyntheticEvent<HTMLImageElement, Event>) => {
|
||||||
if (this.mounted) {
|
if (this.mounted) {
|
||||||
const image = event.target;
|
const image = event.target as HTMLImageElement;
|
||||||
const isSmallImage = this.isSmallImage(image.naturalWidth, image.naturalHeight);
|
const isSmallImage = this.isSmallImage(image.naturalWidth, image.naturalHeight);
|
||||||
this.setState({
|
this.setState({
|
||||||
loaded: true,
|
loaded: true,
|
||||||
@@ -147,13 +170,13 @@ export default class SizeAwareImage extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
handleImageClick = (e) => {
|
handleImageClick = (e: MouseEvent<HTMLImageElement>) => {
|
||||||
this.props.onClick?.(e, this.props.src);
|
this.props.onClick?.(e, this.props.src);
|
||||||
};
|
};
|
||||||
|
|
||||||
onEnterKeyDown = (e) => {
|
onEnterKeyDown = (e: KeyboardEvent<HTMLImageElement>) => {
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
this.handleImageClick(e);
|
this.props.onClick?.(e, this.props.src);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -197,7 +220,7 @@ export default class SizeAwareImage extends React.PureComponent {
|
|||||||
<img
|
<img
|
||||||
{...props}
|
{...props}
|
||||||
aria-label={ariaLabelImage}
|
aria-label={ariaLabelImage}
|
||||||
tabIndex='0'
|
tabIndex={0}
|
||||||
onClick={this.handleImageClick}
|
onClick={this.handleImageClick}
|
||||||
onKeyDown={this.onEnterKeyDown}
|
onKeyDown={this.onEnterKeyDown}
|
||||||
className={
|
className={
|
||||||
@@ -387,9 +410,9 @@ export default class SizeAwareImage extends React.PureComponent {
|
|||||||
let fallback;
|
let fallback;
|
||||||
|
|
||||||
if (this.dimensionsAvailable(dimensions) && !this.state.loaded) {
|
if (this.dimensionsAvailable(dimensions) && !this.state.loaded) {
|
||||||
const ratio = dimensions.height > MAX_IMAGE_HEIGHT ? MAX_IMAGE_HEIGHT / dimensions.height : 1;
|
const ratio = (dimensions?.height ?? 0) > MAX_IMAGE_HEIGHT ? MAX_IMAGE_HEIGHT / (dimensions?.height ?? 1) : 1;
|
||||||
const height = dimensions.height * ratio;
|
const height = (dimensions?.height ?? 0) * ratio;
|
||||||
const width = dimensions.width * ratio;
|
const width = (dimensions?.width ?? 0) * ratio;
|
||||||
|
|
||||||
const miniPreview = getFileMiniPreviewUrl(fileInfo);
|
const miniPreview = getFileMiniPreviewUrl(fileInfo);
|
||||||
|
|
||||||
@@ -397,13 +420,13 @@ export default class SizeAwareImage extends React.PureComponent {
|
|||||||
fallback = (
|
fallback = (
|
||||||
<div
|
<div
|
||||||
className={`image-loading__container ${this.props.className}`}
|
className={`image-loading__container ${this.props.className}`}
|
||||||
style={{maxWidth: dimensions.width}}
|
style={{maxWidth: dimensions?.width}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
aria-label={ariaLabelImage}
|
aria-label={ariaLabelImage}
|
||||||
className={this.props.className}
|
className={this.props.className}
|
||||||
src={miniPreview}
|
src={miniPreview}
|
||||||
tabIndex='0'
|
tabIndex={0}
|
||||||
height={height}
|
height={height}
|
||||||
width={width}
|
width={width}
|
||||||
/>
|
/>
|
||||||
@@ -454,7 +477,7 @@ export default class SizeAwareImage extends React.PureComponent {
|
|||||||
}, 1500);
|
}, 1500);
|
||||||
};
|
};
|
||||||
|
|
||||||
copyLinkToAsset = () => {
|
copyLinkToAsset = async () => {
|
||||||
// if linkCopyInProgress is true return
|
// if linkCopyInProgress is true return
|
||||||
if (this.state.linkCopyInProgress !== true) {
|
if (this.state.linkCopyInProgress !== true) {
|
||||||
// set linkCopyInProgress to true to prevent multiple api calls
|
// set linkCopyInProgress to true to prevent multiple api calls
|
||||||
@@ -468,11 +491,12 @@ export default class SizeAwareImage extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// copying public link to clipboard
|
// copying public link to clipboard
|
||||||
this.props.getFilePublicLink().then((data) => {
|
if (this.props.getFilePublicLink) {
|
||||||
const fileURL = data.data.link;
|
const data: any = await this.props.getFilePublicLink();
|
||||||
|
const fileURL = data.data?.link;
|
||||||
copyToClipboard(fileURL ?? '');
|
copyToClipboard(fileURL ?? '');
|
||||||
this.startCopyTimer();
|
this.startCopyTimer();
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ссылка в новой задаче
Block a user