diff --git a/blocks/library/gallery/block.js b/blocks/library/gallery/block.js new file mode 100644 index 00000000000000..19712352623a9b --- /dev/null +++ b/blocks/library/gallery/block.js @@ -0,0 +1,205 @@ +/** + * External Dependencies + */ +import { filter } from 'lodash'; + +/** + * WordPress dependencies + */ +import { Component } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; +import { mediaUpload } from '@wordpress/utils'; +import { Dashicon, Toolbar, Placeholder, FormFileUpload } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import MediaUploadButton from '../../media-upload-button'; +import InspectorControls from '../../inspector-controls'; +import RangeControl from '../../inspector-controls/range-control'; +import ToggleControl from '../../inspector-controls/toggle-control'; +import SelectControl from '../../inspector-controls/select-control'; +import BlockControls from '../../block-controls'; +import BlockAlignmentToolbar from '../../block-alignment-toolbar'; +import GalleryImage from './gallery-image'; +import BlockDescription from '../../block-description'; + +const isGallery = true; +const MAX_COLUMNS = 8; +const linkOptions = [ + { value: 'attachment', label: __( 'Attachment Page' ) }, + { value: 'media', label: __( 'Media File' ) }, + { value: 'none', label: __( 'None' ) }, +]; + +export function defaultColumnsNumber( attributes ) { + return Math.min( 3, attributes.images.length ); +} + +class GalleryBlock extends Component { + constructor() { + super( ...arguments ); + + this.onSelectImage = this.onSelectImage.bind( this ); + this.onSelectImages = this.onSelectImages.bind( this ); + this.setLinkTo = this.setLinkTo.bind( this ); + this.setColumnsNumber = this.setColumnsNumber.bind( this ); + this.updateAlignment = this.updateAlignment.bind( this ); + this.toggleImageCrop = this.toggleImageCrop.bind( this ); + this.uploadFromFiles = this.uploadFromFiles.bind( this ); + this.onRemoveImage = this.onRemoveImage.bind( this ); + + this.state = { + selectedImage: null, + }; + } + + onSelectImage( index ) { + return () => { + this.setState( ( state ) => ( { + selectedImage: index === state.selectedImage ? null : index, + } ) ); + }; + } + + onRemoveImage( index ) { + return () => { + this.props.setAttributes( { + images: filter( this.props.attributes.images, ( img, i ) => index !== i ), + } ); + }; + } + + onSelectImages( imgs ) { + this.props.setAttributes( { images: imgs } ); + } + + setLinkTo( value ) { + this.props.setAttributes( { linkTo: value } ); + } + + setColumnsNumber( value ) { + this.props.setAttributes( { columns: value } ); + } + + updateAlignment( nextAlign ) { + this.props.setAttributes( { align: nextAlign } ); + } + + toggleImageCrop() { + this.props.setAttributes( { imageCrop: ! this.props.attributes.imageCrop } ); + } + + uploadFromFiles( event ) { + mediaUpload( event.target.files, this.props.setAttributes, isGallery ); + } + + render() { + const { attributes, focus, className } = this.props; + const { images, columns = defaultColumnsNumber( attributes ), align, imageCrop, linkTo } = attributes; + + const controls = ( + focus && ( + + + { !! images.length && ( + +
  • + img.id ) } + > + + +
  • +
    + ) } +
    + ) + ); + + if ( images.length === 0 ) { + const uploadButtonProps = { isLarge: true }; + + return [ + controls, + + + { __( 'Upload' ) } + + + { __( 'Insert from Media Library' ) } + + , + ]; + } + + return [ + controls, + focus && images.length > 1 && ( + + +

    { __( 'Image galleries are a great way to share groups of pictures on your site.' ) }

    +
    +

    { __( 'Gallery Settings' ) }

    + + + +
    + ), +
    + { images.map( ( img, index ) => ( + + ) ) } +
    , + ]; + } +} + +export default GalleryBlock; diff --git a/blocks/library/gallery/editor.scss b/blocks/library/gallery/editor.scss index 550a81048e536b..11e0077c8e19ed 100644 --- a/blocks/library/gallery/editor.scss +++ b/blocks/library/gallery/editor.scss @@ -6,3 +6,26 @@ .editor-visual-editor__block[data-type="core/gallery"] .editor-visual-editor__block-edit { overflow: hidden; } + +.blocks-gallery-image { + position: relative; + + &.is-selected { + outline: 4px solid $blue-medium-500; + outline-offset: -4px; + } +} + +.blocks-gallery-image__inline-menu { + position: absolute; + top: 8px; + right: 8px; + border: 1px solid $light-gray-500; + background-color: $white; + display: inline-flex; + z-index: z-index( '.blocks-gallery-image__inline-menu' ); +} + +.blocks-gallery-image__remove { + padding: 0; +} diff --git a/blocks/library/gallery/gallery-image.js b/blocks/library/gallery/gallery-image.js index 7f113901f0807f..9369e622bd6c27 100644 --- a/blocks/library/gallery/gallery-image.js +++ b/blocks/library/gallery/gallery-image.js @@ -1,3 +1,13 @@ +/** + * External Depenedencies + */ +import classnames from 'classnames'; + +/** + * WordPress Dependencies + */ +import { IconButton } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; export default function GalleryImage( props ) { let href = null; @@ -11,10 +21,26 @@ export default function GalleryImage( props ) { } const image = {; + const className = classnames( 'blocks-gallery-image', { + 'is-selected': props.isSelected, + } ); + // Disable reason: Each block can be selected by clicking on it and we should keep the same saved markup + /* eslint-disable jsx-a11y/no-static-element-interactions, jsx-a11y/onclick-has-role, jsx-a11y/click-events-have-key-events */ return ( -
    +
    + { props.isSelected && +
    + +
    + } { href ? { image } : image }
    ); + /* eslint-enable jsx-a11y/no-static-element-interactions, jsx-a11y/onclick-has-role, jsx-a11y/click-events-have-key-events */ } diff --git a/blocks/library/gallery/index.js b/blocks/library/gallery/index.js index 49ca753fbee6bf..b736e591c8160f 100644 --- a/blocks/library/gallery/index.js +++ b/blocks/library/gallery/index.js @@ -2,8 +2,6 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { mediaUpload } from '@wordpress/utils'; -import { Dashicon, Toolbar, Placeholder, FormFileUpload } from '@wordpress/components'; /** * Internal dependencies @@ -11,28 +9,10 @@ import { Dashicon, Toolbar, Placeholder, FormFileUpload } from '@wordpress/compo import './editor.scss'; import './style.scss'; import { registerBlockType, source } from '../../api'; -import MediaUploadButton from '../../media-upload-button'; -import InspectorControls from '../../inspector-controls'; -import RangeControl from '../../inspector-controls/range-control'; -import ToggleControl from '../../inspector-controls/toggle-control'; -import SelectControl from '../../inspector-controls/select-control'; -import BlockControls from '../../block-controls'; -import BlockAlignmentToolbar from '../../block-alignment-toolbar'; import GalleryImage from './gallery-image'; -import BlockDescription from '../../block-description'; +import { default as GalleryBlock, defaultColumnsNumber } from './block'; const { query, attr } = source; -const isGallery = true; -const MAX_COLUMNS = 8; -const linkOptions = [ - { value: 'attachment', label: __( 'Attachment Page' ) }, - { value: 'media', label: __( 'Media File' ) }, - { value: 'none', label: __( 'None' ) }, -]; - -function defaultColumnsNumber( attributes ) { - return Math.min( 3, attributes.images.length ); -} registerBlockType( 'core/gallery', { title: __( 'Gallery' ), @@ -74,117 +54,7 @@ registerBlockType( 'core/gallery', { } }, - edit( { attributes, setAttributes, focus, className } ) { - const { images, columns = defaultColumnsNumber( attributes ), align, imageCrop, linkTo } = attributes; - const setLinkTo = ( value ) => setAttributes( { linkTo: value } ); - const setColumnsNumber = ( value ) => setAttributes( { columns: value } ); - const updateAlignment = ( nextAlign ) => setAttributes( { align: nextAlign } ); - const toggleImageCrop = () => setAttributes( { imageCrop: ! imageCrop } ); - - const onSelectImages = ( imgs ) => setAttributes( { images: imgs } ); - - const uploadFromFiles = ( event ) => { - mediaUpload( event.target.files, setAttributes, isGallery ); - }; - - const controls = ( - focus && ( - - - { !! images.length && ( - -
  • - img.id ) } - > - - -
  • -
    - ) } -
    - ) - ); - - if ( images.length === 0 ) { - const uploadButtonProps = { isLarge: true }; - - return [ - controls, - - - { __( 'Upload' ) } - - - { __( 'Insert from Media Library' ) } - - , - ]; - } - - return [ - controls, - focus && images.length > 1 && ( - - -

    { __( 'Image galleries are a great way to share groups of pictures on your site.' ) }

    -
    -

    { __( 'Gallery Settings' ) }

    - - - -
    - ), -
    - { images.map( ( img ) => ( - - ) ) } -
    , - ]; - }, + edit: GalleryBlock, save( { attributes } ) { const { images, columns = defaultColumnsNumber( attributes ), align, imageCrop, linkTo } = attributes; diff --git a/editor/assets/stylesheets/_z-index.scss b/editor/assets/stylesheets/_z-index.scss index 39a20663791bff..34f7c702e42d30 100644 --- a/editor/assets/stylesheets/_z-index.scss +++ b/editor/assets/stylesheets/_z-index.scss @@ -36,6 +36,7 @@ $z-layers: ( // Show popovers above wp-admin menus and submenus and sidebar: // #adminmenuwrap { z-index: 9990 } '.components-popover': 1000000, + '.blocks-gallery-image__inline-menu': 1000000, '.blocks-url-input__suggestions': 9999, );