Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gallery: Move "Add new" action to Toolbar #25321

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions packages/block-library/src/gallery/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ import {
withNotices,
RangeControl,
} from '@wordpress/components';
import { MediaPlaceholder, InspectorControls } from '@wordpress/block-editor';
import {
BlockControls,
MediaPlaceholder,
InspectorControls,
} from '@wordpress/block-editor';
import { Component, Platform } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { getBlobByURL, isBlobURL, revokeBlobURL } from '@wordpress/blob';
Expand All @@ -38,6 +42,7 @@ import { withViewportMatch } from '@wordpress/viewport';
import { sharedIcon } from './shared-icon';
import { defaultColumnsNumber, pickRelevantMediaFiles } from './shared';
import Gallery from './gallery';
import MediaAddButton from './media-add';
import {
LINK_DESTINATION_ATTACHMENT,
LINK_DESTINATION_MEDIA,
Expand Down Expand Up @@ -356,6 +361,7 @@ class GalleryEdit extends Component {
} = this.props;
const {
columns = defaultColumnsNumber( attributes ),
ids,
imageCrop,
images,
linkTo,
Expand All @@ -367,7 +373,6 @@ class GalleryEdit extends Component {
const mediaPlaceholder = (
<MediaPlaceholder
addToGallery={ hasImages }
isAppender={ hasImages }
className={ className }
disableMediaButtons={ hasImages && ! isSelected }
icon={ ! hasImages && sharedIcon }
Expand Down Expand Up @@ -396,6 +401,17 @@ class GalleryEdit extends Component {

return (
<>
<BlockControls>
{ hasImages && (
<MediaAddButton
allowedTypes={ ALLOWED_MEDIA_TYPES }
images={ images }
onError={ this.onUploadError }
onSelect={ this.onSelectImages }
value={ ids }
/>
) }
</BlockControls>
<InspectorControls>
<PanelBody title={ __( 'Gallery settings' ) }>
{ images.length > 1 && (
Expand Down Expand Up @@ -436,7 +452,6 @@ class GalleryEdit extends Component {
<Gallery
{ ...this.props }
selectedImage={ this.state.selectedImage }
mediaPlaceholder={ mediaPlaceholder }
onMoveBackward={ this.onMoveBackward }
onMoveForward={ this.onMoveForward }
onRemoveImage={ this.onRemoveImage }
Expand Down
151 changes: 151 additions & 0 deletions packages/block-library/src/gallery/media-add.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/**
* WordPress dependencies
*/
import { MediaUpload, MediaUploadCheck } from '@wordpress/block-editor';
import {
Dropdown,
FormFileUpload,
MenuItem,
NavigableMenu,
ToolbarButton,
ToolbarGroup,
} from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { createRef } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { media as mediaIcon, upload } from '@wordpress/icons';
import { DOWN } from '@wordpress/keycodes';

export default function MediaAddButton( {
allowedTypes,
images,
onError,
onSelect,
value,
} ) {
const mediaUpload = useSelect(
( select ) => select( 'core/block-editor' ).getSettings().mediaUpload,
[]
);

const onKeyDown = ( event ) => {
if ( event.keyCode === DOWN ) {
event.preventDefault();
event.stopPropagation();
event.target.click();
}
};

const mediaLibraryButton = ( { open } ) => (
<MenuItem icon={ mediaIcon } onClick={ open }>
{ __( 'Open Media Library' ) }
</MenuItem>
);

const mediaUploadButton = ( { openFileDialog } ) => (
<MenuItem icon={ upload } onClick={ openFileDialog }>
{ __( 'Upload' ) }
</MenuItem>
);

const onFileUpload = ( event, onClose ) => {
// Since the setMedia function runs multiple times per upload group
// and is passed newMedia containing every item in its group each time, we must
// filter out whatever this upload group had previously returned to the
// gallery before adding and returning the image array with replacement newMedia
// values.

// Define an array to store urls from newMedia between subsequent function calls.
let lastMediaPassed = [];
const setMedia = ( newMedia ) => {
// Remove any images this upload group is responsible for (lastMediaPassed).
// Their replacements are contained in newMedia.
const filteredMedia = ( images ?? [] ).filter( ( item ) => {
// If Item has id, only remove it if lastMediaPassed has an item with that id.
if ( item.id ) {
return ! lastMediaPassed.some(
// Be sure to convert to number for comparison.
( { id } ) => Number( id ) === Number( item.id )
);
}

// Compare transient images via .includes since gallery may append extra info onto the url.
return ! lastMediaPassed.some( ( { urlSlug } ) =>
item.url.includes( urlSlug )
);
} );

// Return the filtered media array along with newMedia.
onSelect( filteredMedia.concat( newMedia ) );

// Reset lastMediaPassed and set it with ids and urls from newMedia.
lastMediaPassed = newMedia.map( ( media ) => {
// Add everything up to '.fileType' to compare via .includes.
const cutOffIndex = media.url.lastIndexOf( '.' );
const urlSlug = media.url.slice( 0, cutOffIndex );

return {
id: media.id,
urlSlug,
};
} );
};

mediaUpload( {
allowedTypes,
filesList: event.target.files,
onFileChange: setMedia,
onError,
} );

onClose();
};

const dropdownToggle = ( { isOpen, onToggle } ) => (
<ToolbarGroup className="media-add">
<ToolbarButton
ref={ createRef() }
aria-expanded={ isOpen }
aria-haspopup="true"
onClick={ onToggle }
onKeyDown={ onKeyDown }
>
{ __( 'Add image' ) }
</ToolbarButton>
</ToolbarGroup>
);

const dropdownContent = ( { onClose } ) => (
<NavigableMenu className="block-editor-media-add__media-upload-menu">
<MediaUpload
multiple
gallery
addToGallery
title={ __( 'Add image' ) }
onSelect={ onSelect }
onError={ onError }
allowedTypes={ allowedTypes }
value={ value }
render={ mediaLibraryButton }
/>
<MediaUploadCheck>
<FormFileUpload
onChange={ ( event ) => onFileUpload( event, onClose ) }
accept={ allowedTypes }
render={ mediaUploadButton }
/>
</MediaUploadCheck>
</NavigableMenu>
);

return (
<Dropdown
popoverProps={ {
isAlternate: true,
} }
contentClassName="block-editor-media-add__options"
renderToggle={ dropdownToggle }
renderContent={ dropdownContent }
/>
);
}