Skip to content

Commit 3c1fe58

Browse files
Gallery Block: Add Media Library button to the upload new image area (#12367)
Fixes: #8309 Supersedes: #9682 This PR adds a media library button in the upload new image are of the gallery block. Trying to follow the design 2 proposed in #9682 (comment) by @kjellr and approved by @karmatosed. A new functionality that allows the gallery to open in library/add frame instead of the edit frame was added to MediaUpload, so when the user pressed the media library button in the add zone the user goes directly to the add to library section when using the edit gallery button on the toolbar the user goes to the edit gallery section. ## Description I added a gallery; I added some images; I selected the gallery; I checked that a new media library button exists in the add to gallery zone. If I click on it I go directly to a frame that allows the addition of images from the library to the gallery. ## How has this been tested? ## Screenshot <img width="997" alt="screenshot 2018-11-27 at 15 35 14" src="https://user-images.githubusercontent.com/11271197/49093136-64176280-f25b-11e8-82de-ff44cee4ab47.png">
1 parent d718a97 commit 3c1fe58

File tree

11 files changed

+320
-188
lines changed

11 files changed

+320
-188
lines changed

packages/block-editor/CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
## 2.0.0 (Unreleased)
22

3+
### New Features
4+
5+
- Added the `addToGallery` property to the `MediaUpload` interface. The property allows users to open the media modal in the `gallery-library`instead of `gallery-edit` state.
6+
- Added the `addToGallery` property to the `MediaPlaceholder` component. The component passes the property to the `MediaUpload` component used inside the placeholder.
7+
- Added the `isAppender` property to the `MediaPlaceholder` component. The property changes the look of the placeholder to be adequate to scenarios where new files are added to an already existing set of files, e.g., adding files to a gallery.
8+
- Added the `dropZoneUIOnly` property to the `MediaPlaceholder` component. The property makes the `MediaPlaceholder` only render a dropzone without any other additional UI.
9+
310
### Breaking Changes
411

512
- `CopyHandler` will now only catch cut/copy events coming from its `props.children`, instead of from anywhere in the `document`.

packages/block-editor/src/components/media-placeholder/index.js

+213-75
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
/**
22
* External dependencies
33
*/
4-
import { every, get, noop, startsWith, defaultTo } from 'lodash';
4+
import {
5+
defaultTo,
6+
every,
7+
get,
8+
isArray,
9+
noop,
10+
startsWith,
11+
} from 'lodash';
512
import classnames from 'classnames';
613

714
/**
@@ -103,8 +110,28 @@ export class MediaPlaceholder extends Component {
103110
}
104111

105112
onFilesUpload( files ) {
106-
const { onSelect, multiple, onError, allowedTypes, mediaUpload } = this.props;
107-
const setMedia = multiple ? onSelect : ( [ media ] ) => onSelect( media );
113+
const {
114+
addToGallery,
115+
allowedTypes,
116+
mediaUpload,
117+
multiple,
118+
onError,
119+
onSelect,
120+
value = [],
121+
} = this.props;
122+
let setMedia;
123+
if ( multiple ) {
124+
if ( addToGallery ) {
125+
const currentValue = value;
126+
setMedia = ( newMedia ) => {
127+
onSelect( currentValue.concat( newMedia ) );
128+
};
129+
} else {
130+
setMedia = onSelect;
131+
}
132+
} else {
133+
setMedia = ( [ media ] ) => onSelect( media );
134+
}
108135
mediaUpload( {
109136
allowedTypes,
110137
filesList: files,
@@ -121,42 +148,32 @@ export class MediaPlaceholder extends Component {
121148
this.setState( { isURLInputVisible: false } );
122149
}
123150

124-
render() {
151+
renderPlaceholder( content, onClick ) {
125152
const {
126-
accept,
127-
icon,
153+
allowedTypes = [],
128154
className,
155+
hasUploadPermissions,
156+
icon,
157+
isAppender,
129158
labels = {},
130-
onSelect,
131-
value = {},
132-
onSelectURL,
133-
onHTMLDrop = noop,
134-
multiple = false,
135159
notices,
136-
allowedTypes = [],
137-
hasUploadPermissions,
138-
mediaUpload,
160+
onSelectURL,
139161
} = this.props;
140162

141-
const {
142-
isURLInputVisible,
143-
src,
144-
} = this.state;
145-
146-
let instructions = labels.instructions || '';
147-
let title = labels.title || '';
163+
let instructions = labels.instructions;
164+
let title = labels.title;
148165

149166
if ( ! hasUploadPermissions && ! onSelectURL ) {
150167
instructions = __( 'To edit this block, you need permission to upload media.' );
151168
}
152169

153-
if ( ! instructions || ! title ) {
170+
if ( instructions === undefined || title === undefined ) {
154171
const isOneType = 1 === allowedTypes.length;
155172
const isAudio = isOneType && 'audio' === allowedTypes[ 0 ];
156173
const isImage = isOneType && 'image' === allowedTypes[ 0 ];
157174
const isVideo = isOneType && 'video' === allowedTypes[ 0 ];
158175

159-
if ( ! instructions ) {
176+
if ( instructions === undefined ) {
160177
if ( hasUploadPermissions ) {
161178
instructions = __( 'Drag a media file, upload a new one or select a file from your library.' );
162179

@@ -180,7 +197,7 @@ export class MediaPlaceholder extends Component {
180197
}
181198
}
182199

183-
if ( ! title ) {
200+
if ( title === undefined ) {
184201
title = __( 'Media' );
185202

186203
if ( isAudio ) {
@@ -193,70 +210,191 @@ export class MediaPlaceholder extends Component {
193210
}
194211
}
195212

213+
const placeholderClassName = classnames(
214+
'block-editor-media-placeholder',
215+
'editor-media-placeholder',
216+
className,
217+
{ 'is-appender': isAppender }
218+
);
219+
196220
return (
197221
<Placeholder
198222
icon={ icon }
199223
label={ title }
200224
instructions={ instructions }
201-
className={ classnames( 'editor-media-placeholder block-editor-media-placeholder', className ) }
225+
className={ placeholderClassName }
202226
notices={ notices }
227+
onClick={ onClick }
203228
>
204-
<MediaUploadCheck>
205-
{ !! mediaUpload && (
206-
<Fragment>
207-
<DropZone
208-
onFilesDrop={ this.onFilesUpload }
209-
onHTMLDrop={ onHTMLDrop }
210-
/>
211-
<FormFileUpload
212-
isLarge
213-
className="editor-media-placeholder__button block-editor-media-placeholder__button"
214-
onChange={ this.onUpload }
215-
accept={ accept }
216-
multiple={ multiple }
217-
>
218-
{ __( 'Upload' ) }
219-
</FormFileUpload>
220-
</Fragment>
221-
) }
222-
<MediaUpload
223-
gallery={ multiple && this.onlyAllowsImages() }
224-
multiple={ multiple }
225-
onSelect={ onSelect }
226-
allowedTypes={ allowedTypes }
227-
value={ value.id }
228-
render={ ( { open } ) => (
229-
<Button
230-
isLarge
231-
className="editor-media-placeholder__button block-editor-media-placeholder__button"
232-
onClick={ open }
233-
>
234-
{ __( 'Media Library' ) }
235-
</Button>
236-
) }
229+
{ content }
230+
</Placeholder>
231+
);
232+
}
233+
234+
renderDropZone() {
235+
const { onHTMLDrop = noop } = this.props;
236+
return (
237+
<DropZone
238+
onFilesDrop={ this.onFilesUpload }
239+
onHTMLDrop={ onHTMLDrop }
240+
/>
241+
);
242+
}
243+
244+
renderUrlSelectionUI() {
245+
const {
246+
onSelectURL,
247+
} = this.props;
248+
if ( ! onSelectURL ) {
249+
return null;
250+
}
251+
const {
252+
isURLInputVisible,
253+
src,
254+
} = this.state;
255+
return (
256+
<div className="editor-media-placeholder__url-input-container block-editor-media-placeholder__url-input-container">
257+
<Button
258+
className="editor-media-placeholder__button block-editor-media-placeholder__button"
259+
onClick={ this.openURLInput }
260+
isToggled={ isURLInputVisible }
261+
isLarge
262+
>
263+
{ __( 'Insert from URL' ) }
264+
</Button>
265+
{ isURLInputVisible && (
266+
<InsertFromURLPopover
267+
src={ src }
268+
onChange={ this.onChangeSrc }
269+
onSubmit={ this.onSubmitSrc }
270+
onClose={ this.closeURLInput }
237271
/>
238-
</MediaUploadCheck>
239-
{ onSelectURL && (
240-
<div className="editor-media-placeholder__url-input-container block-editor-media-placeholder__url-input-container">
272+
) }
273+
</div>
274+
);
275+
}
276+
277+
renderMediaUploadChecked() {
278+
const {
279+
accept,
280+
addToGallery,
281+
allowedTypes = [],
282+
isAppender,
283+
mediaUpload,
284+
multiple = false,
285+
onSelect,
286+
value = {},
287+
} = this.props;
288+
289+
const mediaLibraryButton = (
290+
<MediaUpload
291+
addToGallery={ addToGallery }
292+
gallery={ multiple && this.onlyAllowsImages() }
293+
multiple={ multiple }
294+
onSelect={ onSelect }
295+
allowedTypes={ allowedTypes }
296+
value={
297+
isArray( value ) ?
298+
value.map( ( { id } ) => id ) :
299+
value.id
300+
}
301+
render={ ( { open } ) => {
302+
return (
241303
<Button
242-
className="editor-media-placeholder__button block-editor-media-placeholder__button"
243-
onClick={ this.openURLInput }
244-
isToggled={ isURLInputVisible }
245304
isLarge
305+
className={ classnames(
306+
'editor-media-placeholder__button',
307+
'editor-media-placeholder__media-library-button'
308+
) }
309+
onClick={ ( event ) => {
310+
event.stopPropagation();
311+
open();
312+
} }
246313
>
247-
{ __( 'Insert from URL' ) }
314+
{ __( 'Media Library' ) }
248315
</Button>
249-
{ isURLInputVisible && (
250-
<InsertFromURLPopover
251-
src={ src }
252-
onChange={ this.onChangeSrc }
253-
onSubmit={ this.onSubmitSrc }
254-
onClose={ this.closeURLInput }
255-
/>
316+
);
317+
} }
318+
/>
319+
);
320+
321+
if ( mediaUpload && isAppender ) {
322+
return (
323+
<Fragment>
324+
{ this.renderDropZone() }
325+
<FormFileUpload
326+
onChange={ this.onUpload }
327+
accept={ accept }
328+
multiple={ multiple }
329+
render={ ( { openFileDialog } ) => {
330+
const content = (
331+
<Fragment>
332+
<IconButton
333+
isLarge
334+
className={ classnames(
335+
'block-editor-media-placeholder__button',
336+
'editor-media-placeholder__button',
337+
'block-editor-media-placeholder__upload-button'
338+
) }
339+
icon="upload"
340+
>
341+
{ __( 'Upload' ) }
342+
</IconButton>
343+
{ mediaLibraryButton }
344+
{ this.renderUrlSelectionUI() }
345+
</Fragment>
346+
);
347+
return this.renderPlaceholder( content, openFileDialog );
348+
} }
349+
/>
350+
</Fragment>
351+
);
352+
}
353+
if ( mediaUpload ) {
354+
const content = (
355+
<Fragment>
356+
{ this.renderDropZone() }
357+
<FormFileUpload
358+
isLarge
359+
className={ classnames(
360+
'block-editor-media-placeholder__button',
361+
'editor-media-placeholder__button',
362+
'block-editor-media-placeholder__upload-button'
256363
) }
257-
</div>
258-
) }
259-
</Placeholder>
364+
onChange={ this.onUpload }
365+
accept={ accept }
366+
multiple={ multiple }
367+
>
368+
{ __( 'Upload' ) }
369+
</FormFileUpload>
370+
{ mediaLibraryButton }
371+
{ this.renderUrlSelectionUI() }
372+
</Fragment>
373+
);
374+
return this.renderPlaceholder( content );
375+
}
376+
return this.renderPlaceholder( mediaLibraryButton );
377+
}
378+
379+
render() {
380+
const {
381+
dropZoneUIOnly,
382+
} = this.props;
383+
384+
if ( dropZoneUIOnly ) {
385+
return (
386+
<MediaUploadCheck>
387+
{ this.renderDropZone() }
388+
</MediaUploadCheck>
389+
);
390+
}
391+
392+
return (
393+
<MediaUploadCheck
394+
fallback={ this.renderPlaceholder( this.renderUrlSelectionUI() ) }
395+
>
396+
{ this.renderMediaUploadChecked() }
397+
</MediaUploadCheck>
260398
);
261399
}
262400
}

packages/block-editor/src/components/media-placeholder/style.scss

+27
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,30 @@
4545
.components-form-file-upload .block-editor-media-placeholder__button {
4646
margin-right: $grid-size-small;
4747
}
48+
49+
.block-editor-media-placeholder.is-appender {
50+
min-height: 100px;
51+
outline: $border-width dashed $dark-gray-150;
52+
53+
&:hover {
54+
outline: $border-width dashed $dark-gray-500;
55+
cursor: pointer;
56+
}
57+
58+
.is-dark-theme & {
59+
60+
&:hover {
61+
outline: $border-width dashed $white;
62+
}
63+
}
64+
65+
.block-editor-media-placeholder__upload-button {
66+
margin-right: $grid-size-small;
67+
&.components-button:hover,
68+
&.components-button:focus {
69+
box-shadow: none;
70+
border: $border-width solid $dark-gray-500;
71+
}
72+
}
73+
74+
}

0 commit comments

Comments
 (0)