1 |
|
2 |
|
3 |
|
4 | import classnames from 'classnames';
|
5 |
|
6 |
|
7 |
|
8 |
|
9 | import { Component, Fragment } from '@wordpress/element';
|
10 | import { IconButton, Spinner } from '@wordpress/components';
|
11 | import { __ } from '@wordpress/i18n';
|
12 | import { BACKSPACE, DELETE } from '@wordpress/keycodes';
|
13 | import { withSelect } from '@wordpress/data';
|
14 | import { RichText } from '@wordpress/block-editor';
|
15 | import { isBlobURL } from '@wordpress/blob';
|
16 |
|
17 | class GalleryImage extends Component {
|
18 | constructor() {
|
19 | super( ...arguments );
|
20 |
|
21 | this.onSelectImage = this.onSelectImage.bind( this );
|
22 | this.onSelectCaption = this.onSelectCaption.bind( this );
|
23 | this.onRemoveImage = this.onRemoveImage.bind( this );
|
24 | this.bindContainer = this.bindContainer.bind( this );
|
25 |
|
26 | this.state = {
|
27 | captionSelected: false,
|
28 | };
|
29 | }
|
30 |
|
31 | bindContainer( ref ) {
|
32 | this.container = ref;
|
33 | }
|
34 |
|
35 | onSelectCaption() {
|
36 | if ( ! this.state.captionSelected ) {
|
37 | this.setState( {
|
38 | captionSelected: true,
|
39 | } );
|
40 | }
|
41 |
|
42 | if ( ! this.props.isSelected ) {
|
43 | this.props.onSelect();
|
44 | }
|
45 | }
|
46 |
|
47 | onSelectImage() {
|
48 | if ( ! this.props.isSelected ) {
|
49 | this.props.onSelect();
|
50 | }
|
51 |
|
52 | if ( this.state.captionSelected ) {
|
53 | this.setState( {
|
54 | captionSelected: false,
|
55 | } );
|
56 | }
|
57 | }
|
58 |
|
59 | onRemoveImage( event ) {
|
60 | if (
|
61 | this.container === document.activeElement &&
|
62 | this.props.isSelected && [ BACKSPACE, DELETE ].indexOf( event.keyCode ) !== -1
|
63 | ) {
|
64 | event.stopPropagation();
|
65 | event.preventDefault();
|
66 | this.props.onRemove();
|
67 | }
|
68 | }
|
69 |
|
70 | componentDidUpdate( prevProps ) {
|
71 | const { isSelected, image, url } = this.props;
|
72 | if ( image && ! url ) {
|
73 | this.props.setAttributes( {
|
74 | url: image.source_url,
|
75 | alt: image.alt_text,
|
76 | } );
|
77 | }
|
78 |
|
79 |
|
80 |
|
81 | if ( this.state.captionSelected && ! isSelected && prevProps.isSelected ) {
|
82 | this.setState( {
|
83 | captionSelected: false,
|
84 | } );
|
85 | }
|
86 | }
|
87 |
|
88 | render() {
|
89 | const { url, alt, id, linkTo, link, isSelected, caption, onRemove, setAttributes, 'aria-label': ariaLabel } = this.props;
|
90 |
|
91 | let href;
|
92 |
|
93 | switch ( linkTo ) {
|
94 | case 'media':
|
95 | href = url;
|
96 | break;
|
97 | case 'attachment':
|
98 | href = link;
|
99 | break;
|
100 | }
|
101 |
|
102 | const img = (
|
103 |
|
104 |
|
105 |
|
106 | <Fragment>
|
107 | <img
|
108 | src={ url }
|
109 | alt={ alt }
|
110 | data-id={ id }
|
111 | onClick={ this.onSelectImage }
|
112 | onFocus={ this.onSelectImage }
|
113 | onKeyDown={ this.onRemoveImage }
|
114 | tabIndex="0"
|
115 | aria-label={ ariaLabel }
|
116 | ref={ this.bindContainer }
|
117 | />
|
118 | { isBlobURL( url ) && <Spinner /> }
|
119 | </Fragment>
|
120 |
|
121 | );
|
122 |
|
123 | const className = classnames( {
|
124 | 'is-selected': isSelected,
|
125 | 'is-transient': isBlobURL( url ),
|
126 | } );
|
127 |
|
128 | return (
|
129 | <figure className={ className }>
|
130 | { isSelected &&
|
131 | <div className="block-library-gallery-item__inline-menu">
|
132 | <IconButton
|
133 | icon="no-alt"
|
134 | onClick={ onRemove }
|
135 | className="blocks-gallery-item__remove"
|
136 | label={ __( 'Remove Image' ) }
|
137 | />
|
138 | </div>
|
139 | }
|
140 | { href ? <a href={ href }>{ img }</a> : img }
|
141 | { ( ! RichText.isEmpty( caption ) || isSelected ) ? (
|
142 | <RichText
|
143 | tagName="figcaption"
|
144 | placeholder={ __( 'Write caption…' ) }
|
145 | value={ caption }
|
146 | isSelected={ this.state.captionSelected }
|
147 | onChange={ ( newCaption ) => setAttributes( { caption: newCaption } ) }
|
148 | unstableOnFocus={ this.onSelectCaption }
|
149 | inlineToolbar
|
150 | />
|
151 | ) : null }
|
152 | </figure>
|
153 | );
|
154 | }
|
155 | }
|
156 |
|
157 | export default withSelect( ( select, ownProps ) => {
|
158 | const { getMedia } = select( 'core' );
|
159 | const { id } = ownProps;
|
160 |
|
161 | return {
|
162 | image: id ? getMedia( id ) : null,
|
163 | };
|
164 | } )( GalleryImage );
|