@wordpress/block-library
Version:
Block library for the WordPress editor.
280 lines (251 loc) • 7.53 kB
JavaScript
import { createElement, Fragment } from "@wordpress/element";
/**
* External dependencies
*/
import classnames from 'classnames';
import { get } from 'lodash';
/**
* WordPress dependencies
*/
import { Component } from '@wordpress/element';
import { Button, Spinner, ButtonGroup } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { BACKSPACE, DELETE } from '@wordpress/keycodes';
import { withSelect, withDispatch } from '@wordpress/data';
import { RichText, MediaPlaceholder, store as blockEditorStore, __experimentalGetElementClassName } from '@wordpress/block-editor';
import { isBlobURL } from '@wordpress/blob';
import { compose } from '@wordpress/compose';
import { closeSmall, chevronLeft, chevronRight, edit, image as imageIcon } from '@wordpress/icons';
import { store as coreStore } from '@wordpress/core-data';
/**
* Internal dependencies
*/
import { pickRelevantMediaFiles } from './shared';
import { LINK_DESTINATION_ATTACHMENT, LINK_DESTINATION_MEDIA } from './constants';
const isTemporaryImage = (id, url) => !id && isBlobURL(url);
class GalleryImage extends Component {
constructor() {
super(...arguments);
this.onSelectImage = this.onSelectImage.bind(this);
this.onRemoveImage = this.onRemoveImage.bind(this);
this.bindContainer = this.bindContainer.bind(this);
this.onEdit = this.onEdit.bind(this);
this.onSelectImageFromLibrary = this.onSelectImageFromLibrary.bind(this);
this.onSelectCustomURL = this.onSelectCustomURL.bind(this);
this.state = {
isEditing: false
};
}
bindContainer(ref) {
this.container = ref;
}
onSelectImage() {
if (!this.props.isSelected) {
this.props.onSelect();
}
}
onRemoveImage(event) {
if (this.container === this.container.ownerDocument.activeElement && this.props.isSelected && [BACKSPACE, DELETE].indexOf(event.keyCode) !== -1) {
event.preventDefault();
this.props.onRemove();
}
}
onEdit() {
this.setState({
isEditing: true
});
}
componentDidUpdate() {
const {
image,
url,
__unstableMarkNextChangeAsNotPersistent
} = this.props;
if (image && !url) {
__unstableMarkNextChangeAsNotPersistent();
this.props.setAttributes({
url: image.source_url,
alt: image.alt_text
});
}
}
deselectOnBlur() {
this.props.onDeselect();
}
onSelectImageFromLibrary(media) {
const {
setAttributes,
id,
url,
alt,
caption,
sizeSlug
} = this.props;
if (!media || !media.url) {
return;
}
let mediaAttributes = pickRelevantMediaFiles(media, sizeSlug); // If the current image is temporary but an alt text was meanwhile
// written by the user, make sure the text is not overwritten.
if (isTemporaryImage(id, url)) {
if (alt) {
const {
alt: omittedAlt,
...restMediaAttributes
} = mediaAttributes;
mediaAttributes = restMediaAttributes;
}
} // If a caption text was meanwhile written by the user,
// make sure the text is not overwritten by empty captions.
if (caption && !get(mediaAttributes, ['caption'])) {
const {
caption: omittedCaption,
...restMediaAttributes
} = mediaAttributes;
mediaAttributes = restMediaAttributes;
}
setAttributes(mediaAttributes);
this.setState({
isEditing: false
});
}
onSelectCustomURL(newURL) {
const {
setAttributes,
url
} = this.props;
if (newURL !== url) {
setAttributes({
url: newURL,
id: undefined
});
this.setState({
isEditing: false
});
}
}
render() {
const {
url,
alt,
id,
linkTo,
link,
isFirstItem,
isLastItem,
isSelected,
caption,
onRemove,
onMoveForward,
onMoveBackward,
setAttributes,
'aria-label': ariaLabel
} = this.props;
const {
isEditing
} = this.state;
let href;
switch (linkTo) {
case LINK_DESTINATION_MEDIA:
href = url;
break;
case LINK_DESTINATION_ATTACHMENT:
href = link;
break;
}
const img = // Disable reason: Image itself is not meant to be interactive, but should
// direct image selection and unfocus caption fields.
/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
createElement(Fragment, null, createElement("img", {
src: url,
alt: alt,
"data-id": id,
onKeyDown: this.onRemoveImage,
tabIndex: "0",
"aria-label": ariaLabel,
ref: this.bindContainer
}), isBlobURL(url) && createElement(Spinner, null))
/* eslint-enable jsx-a11y/no-noninteractive-element-interactions */
;
const className = classnames({
'is-selected': isSelected,
'is-transient': isBlobURL(url)
});
return (// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions
createElement("figure", {
className: className,
onClick: this.onSelectImage,
onFocus: this.onSelectImage
}, !isEditing && (href ? createElement("a", {
href: href
}, img) : img), isEditing && createElement(MediaPlaceholder, {
labels: {
title: __('Edit gallery image')
},
icon: imageIcon,
onSelect: this.onSelectImageFromLibrary,
onSelectURL: this.onSelectCustomURL,
accept: "image/*",
allowedTypes: ['image'],
value: {
id,
src: url
}
}), createElement(ButtonGroup, {
className: "block-library-gallery-item__inline-menu is-left"
}, createElement(Button, {
icon: chevronLeft,
onClick: isFirstItem ? undefined : onMoveBackward,
label: __('Move image backward'),
"aria-disabled": isFirstItem,
disabled: !isSelected
}), createElement(Button, {
icon: chevronRight,
onClick: isLastItem ? undefined : onMoveForward,
label: __('Move image forward'),
"aria-disabled": isLastItem,
disabled: !isSelected
})), createElement(ButtonGroup, {
className: "block-library-gallery-item__inline-menu is-right"
}, createElement(Button, {
icon: edit,
onClick: this.onEdit,
label: __('Replace image'),
disabled: !isSelected
}), createElement(Button, {
icon: closeSmall,
onClick: onRemove,
label: __('Remove image'),
disabled: !isSelected
})), !isEditing && (isSelected || caption) && createElement(RichText, {
tagName: "figcaption",
className: __experimentalGetElementClassName('caption'),
"aria-label": __('Image caption text'),
placeholder: isSelected ? __('Add caption') : null,
value: caption,
onChange: newCaption => setAttributes({
caption: newCaption
}),
inlineToolbar: true
}))
);
}
}
export default compose([withSelect((select, ownProps) => {
const {
getMedia
} = select(coreStore);
const {
id
} = ownProps;
return {
image: id ? getMedia(parseInt(id, 10)) : null
};
}), withDispatch(dispatch => {
const {
__unstableMarkNextChangeAsNotPersistent
} = dispatch(blockEditorStore);
return {
__unstableMarkNextChangeAsNotPersistent
};
})])(GalleryImage);
//# sourceMappingURL=gallery-image.js.map