From b56f61776971f6be82baa02ad218c642bb967579 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Tue, 16 Feb 2021 09:21:46 +1300 Subject: [PATCH 001/103] Refactor gallery to nested image blocks --- packages/block-library/src/gallery/block.json | 65 +- .../block-library/src/gallery/deprecated.js | 1502 +++++++++-------- packages/block-library/src/gallery/edit.js | 379 ++--- .../block-library/src/gallery/editor.scss | 6 + .../src/gallery/gallery-image.js | 318 ---- packages/block-library/src/gallery/gallery.js | 80 +- packages/block-library/src/gallery/save.js | 61 +- packages/block-library/src/gallery/shared.js | 11 +- packages/block-library/src/gallery/style.scss | 157 +- .../block-library/src/gallery/transforms.js | 2 +- .../src/gallery/use-image-sizes.js | 54 + packages/block-library/src/gallery/utils.js | 68 + packages/block-library/src/image/block.json | 5 + packages/block-library/src/image/edit.js | 61 +- packages/block-library/src/image/image.js | 3 +- packages/block-library/src/image/save.js | 12 +- 16 files changed, 1285 insertions(+), 1499 deletions(-) delete mode 100644 packages/block-library/src/gallery/gallery-image.js create mode 100644 packages/block-library/src/gallery/use-image-sizes.js create mode 100644 packages/block-library/src/gallery/utils.js diff --git a/packages/block-library/src/gallery/block.json b/packages/block-library/src/gallery/block.json index 8beac02827f61..44f7d069c8bef 100644 --- a/packages/block-library/src/gallery/block.json +++ b/packages/block-library/src/gallery/block.json @@ -3,56 +3,12 @@ "name": "core/gallery", "category": "media", "attributes": { - "images": { + "imageUploads": { "type": "array", "default": [], - "source": "query", - "selector": ".blocks-gallery-item", - "query": { - "url": { - "type": "string", - "source": "attribute", - "selector": "img", - "attribute": "src" - }, - "fullUrl": { - "type": "string", - "source": "attribute", - "selector": "img", - "attribute": "data-full-url" - }, - "link": { - "type": "string", - "source": "attribute", - "selector": "img", - "attribute": "data-link" - }, - "alt": { - "type": "string", - "source": "attribute", - "selector": "img", - "attribute": "alt", - "default": "" - }, - "id": { - "type": "string", - "source": "attribute", - "selector": "img", - "attribute": "data-id" - }, - "caption": { - "type": "string", - "source": "html", - "selector": ".blocks-gallery-item__caption" - } - } - }, - "ids": { - "type": "array", "items": { - "type": "number" - }, - "default": [] + "type": "object" + } }, "columns": { "type": "number", @@ -68,14 +24,29 @@ "type": "boolean", "default": true }, + "linkTarget": { + "type": "string" + }, "linkTo": { "type": "string" }, "sizeSlug": { "type": "string", "default": "large" + }, + "allowResize": { + "type": "boolean", + "default": false + }, + "isListItem": { + "type": "boolean", + "default": true } }, + "providesContext": { + "allowResize": "allowResize", + "isListItem": "isListItem" + }, "supports": { "anchor": true, "align": true diff --git a/packages/block-library/src/gallery/deprecated.js b/packages/block-library/src/gallery/deprecated.js index 1b82131b89085..84bc9fca5bd97 100644 --- a/packages/block-library/src/gallery/deprecated.js +++ b/packages/block-library/src/gallery/deprecated.js @@ -15,690 +15,824 @@ import { RichText } from '@wordpress/block-editor'; import { defaultColumnsNumber } from './shared'; const deprecated = [ - { - attributes: { - images: { - type: 'array', - default: [], - source: 'query', - selector: '.blocks-gallery-item', - query: { - url: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'src', - }, - fullUrl: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'data-full-url', - }, - link: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'data-link', - }, - alt: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'alt', - default: '', - }, - id: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'data-id', - }, - caption: { - type: 'string', - source: 'html', - selector: '.blocks-gallery-item__caption', - }, - }, - }, - ids: { - type: 'array', - items: { - type: 'number', - }, - default: [], - }, - columns: { - type: 'number', - minimum: 1, - maximum: 8, - }, - caption: { - type: 'string', - source: 'html', - selector: '.blocks-gallery-caption', - }, - imageCrop: { - type: 'boolean', - default: true, - }, - linkTo: { - type: 'string', - default: 'none', - }, - sizeSlug: { - type: 'string', - default: 'large', - }, - }, - supports: { - align: true, - }, - isEligible( { linkTo } ) { - return ! linkTo || linkTo === 'attachment' || linkTo === 'media'; - }, - migrate( attributes ) { - let linkTo = attributes.linkTo; - if ( ! attributes.linkTo ) { - linkTo = 'none'; - } else if ( attributes.linkTo === 'attachment' ) { - linkTo = 'post'; - } else if ( attributes.linkTo === 'media' ) { - linkTo = 'file'; - } - return { - ...attributes, - linkTo, - }; - }, - save( { attributes } ) { - const { - images, - columns = defaultColumnsNumber( attributes ), - imageCrop, - caption, - linkTo, - } = attributes; - - return ( -
- - { ! RichText.isEmpty( caption ) && ( - - ) } -
- ); - }, - }, - { - attributes: { - images: { - type: 'array', - default: [], - source: 'query', - selector: '.blocks-gallery-item', - query: { - url: { - source: 'attribute', - selector: 'img', - attribute: 'src', - }, - fullUrl: { - source: 'attribute', - selector: 'img', - attribute: 'data-full-url', - }, - link: { - source: 'attribute', - selector: 'img', - attribute: 'data-link', - }, - alt: { - source: 'attribute', - selector: 'img', - attribute: 'alt', - default: '', - }, - id: { - source: 'attribute', - selector: 'img', - attribute: 'data-id', - }, - caption: { - type: 'string', - source: 'html', - selector: '.blocks-gallery-item__caption', - }, - }, - }, - ids: { - type: 'array', - default: [], - }, - columns: { - type: 'number', - }, - caption: { - type: 'string', - source: 'html', - selector: '.blocks-gallery-caption', - }, - imageCrop: { - type: 'boolean', - default: true, - }, - linkTo: { - type: 'string', - default: 'none', - }, - }, - supports: { - align: true, - }, - isEligible( { ids } ) { - return ids && ids.some( ( id ) => typeof id === 'string' ); - }, - migrate( attributes ) { - return { - ...attributes, - ids: map( attributes.ids, ( id ) => { - const parsedId = parseInt( id, 10 ); - return Number.isInteger( parsedId ) ? parsedId : null; - } ), - }; - }, - save( { attributes } ) { - const { - images, - columns = defaultColumnsNumber( attributes ), - imageCrop, - caption, - linkTo, - } = attributes; - - return ( -
- - { ! RichText.isEmpty( caption ) && ( - - ) } -
- ); - }, - }, - { - attributes: { - images: { - type: 'array', - default: [], - source: 'query', - selector: 'ul.wp-block-gallery .blocks-gallery-item', - query: { - url: { - source: 'attribute', - selector: 'img', - attribute: 'src', - }, - fullUrl: { - source: 'attribute', - selector: 'img', - attribute: 'data-full-url', - }, - alt: { - source: 'attribute', - selector: 'img', - attribute: 'alt', - default: '', - }, - id: { - source: 'attribute', - selector: 'img', - attribute: 'data-id', - }, - link: { - source: 'attribute', - selector: 'img', - attribute: 'data-link', - }, - caption: { - type: 'array', - source: 'children', - selector: 'figcaption', - }, - }, - }, - ids: { - type: 'array', - default: [], - }, - columns: { - type: 'number', - }, - imageCrop: { - type: 'boolean', - default: true, - }, - linkTo: { - type: 'string', - default: 'none', - }, - }, - supports: { - align: true, - }, - save( { attributes } ) { - const { - images, - columns = defaultColumnsNumber( attributes ), - imageCrop, - linkTo, - } = attributes; - return ( - - ); - }, - }, - { - attributes: { - images: { - type: 'array', - default: [], - source: 'query', - selector: 'ul.wp-block-gallery .blocks-gallery-item', - query: { - url: { - source: 'attribute', - selector: 'img', - attribute: 'src', - }, - alt: { - source: 'attribute', - selector: 'img', - attribute: 'alt', - default: '', - }, - id: { - source: 'attribute', - selector: 'img', - attribute: 'data-id', - }, - link: { - source: 'attribute', - selector: 'img', - attribute: 'data-link', - }, - caption: { - type: 'array', - source: 'children', - selector: 'figcaption', - }, - }, - }, - columns: { - type: 'number', - }, - imageCrop: { - type: 'boolean', - default: true, - }, - linkTo: { - type: 'string', - default: 'none', - }, - }, - isEligible( { images, ids } ) { - return ( - images && - images.length > 0 && - ( ( ! ids && images ) || - ( ids && images && ids.length !== images.length ) || - some( images, ( id, index ) => { - if ( ! id && ids[ index ] !== null ) { - return true; - } - return parseInt( id, 10 ) !== ids[ index ]; - } ) ) - ); - }, - migrate( attributes ) { - return { - ...attributes, - ids: map( attributes.images, ( { id } ) => { - if ( ! id ) { - return null; - } - return parseInt( id, 10 ); - } ), - }; - }, - supports: { - align: true, - }, - save( { attributes } ) { - const { - images, - columns = defaultColumnsNumber( attributes ), - imageCrop, - linkTo, - } = attributes; - return ( - - ); - }, - }, - { - attributes: { - images: { - type: 'array', - default: [], - source: 'query', - selector: - 'div.wp-block-gallery figure.blocks-gallery-image img', - query: { - url: { - source: 'attribute', - attribute: 'src', - }, - alt: { - source: 'attribute', - attribute: 'alt', - default: '', - }, - id: { - source: 'attribute', - attribute: 'data-id', - }, - }, - }, - columns: { - type: 'number', - }, - imageCrop: { - type: 'boolean', - default: true, - }, - linkTo: { - type: 'string', - default: 'none', - }, - align: { - type: 'string', - default: 'none', - }, - }, - supports: { - align: true, - }, - save( { attributes } ) { - const { - images, - columns = defaultColumnsNumber( attributes ), - align, - imageCrop, - linkTo, - } = attributes; - const className = classnames( `columns-${ columns }`, { - alignnone: align === 'none', - 'is-cropped': imageCrop, - } ); - return ( -
- { images.map( ( image ) => { - let href; - - switch ( linkTo ) { - case 'media': - href = image.url; - break; - case 'attachment': - href = image.link; - break; - } - - const img = ( - { - ); - - return ( -
- { href ? { img } : img } -
- ); - } ) } -
- ); - }, - }, + // Just temporarily comment these out until new structure is finalised + // { + // attributes: { + // images: { + // type: 'array', + // default: [], + // source: 'query', + // selector: '.blocks-gallery-item', + // query: { + // url: { + // type: 'string', + // source: 'attribute', + // selector: 'img', + // attribute: 'src', + // }, + // fullUrl: { + // type: 'string', + // source: 'attribute', + // selector: 'img', + // attribute: 'data-full-url', + // }, + // link: { + // type: 'string', + // source: 'attribute', + // selector: 'img', + // attribute: 'data-link', + // }, + // alt: { + // type: 'string', + // source: 'attribute', + // selector: 'img', + // attribute: 'alt', + // default: '', + // }, + // id: { + // type: 'string', + // source: 'attribute', + // selector: 'img', + // attribute: 'data-id', + // }, + // caption: { + // type: 'string', + // source: 'html', + // selector: '.blocks-gallery-item__caption', + // }, + // }, + // }, + // ids: { + // type: 'array', + // items: { + // type: 'number', + // }, + // default: [], + // }, + // columns: { + // type: 'number', + // minimum: 1, + // maximum: 8, + // }, + // caption: { + // type: 'string', + // source: 'html', + // selector: '.blocks-gallery-caption', + // }, + // imageCrop: { + // type: 'boolean', + // default: true, + // }, + // linkTo: { + // type: 'string', + // }, + // sizeSlug: { + // type: 'string', + // default: 'large', + // }, + // }, + // save( { attributes } ) { + // const { + // images, + // columns = defaultColumnsNumber( attributes ), + // imageCrop, + // caption, + // linkTo, + // } = attributes; + // return ( + //
+ // + // { ! RichText.isEmpty( caption ) && ( + // + // ) } + //
+ // ); + // }, + // }, + // { + // attributes: { + // images: { + // type: 'array', + // default: [], + // source: 'query', + // selector: '.blocks-gallery-item', + // query: { + // url: { + // type: 'string', + // source: 'attribute', + // selector: 'img', + // attribute: 'src', + // }, + // fullUrl: { + // type: 'string', + // source: 'attribute', + // selector: 'img', + // attribute: 'data-full-url', + // }, + // link: { + // type: 'string', + // source: 'attribute', + // selector: 'img', + // attribute: 'data-link', + // }, + // alt: { + // type: 'string', + // source: 'attribute', + // selector: 'img', + // attribute: 'alt', + // default: '', + // }, + // id: { + // type: 'string', + // source: 'attribute', + // selector: 'img', + // attribute: 'data-id', + // }, + // caption: { + // type: 'string', + // source: 'html', + // selector: '.blocks-gallery-item__caption', + // }, + // }, + // }, + // ids: { + // type: 'array', + // items: { + // type: 'number', + // }, + // default: [], + // }, + // columns: { + // type: 'number', + // minimum: 1, + // maximum: 8, + // }, + // caption: { + // type: 'string', + // source: 'html', + // selector: '.blocks-gallery-caption', + // }, + // imageCrop: { + // type: 'boolean', + // default: true, + // }, + // linkTo: { + // type: 'string', + // default: 'none', + // }, + // sizeSlug: { + // type: 'string', + // default: 'large', + // }, + // }, + // supports: { + // align: true, + // }, + // isEligible( { linkTo } ) { + // return ! linkTo || linkTo === 'attachment' || linkTo === 'media'; + // }, + // migrate( attributes ) { + // let linkTo = attributes.linkTo; + // if ( ! attributes.linkTo ) { + // linkTo = 'none'; + // } else if ( attributes.linkTo === 'attachment' ) { + // linkTo = 'post'; + // } else if ( attributes.linkTo === 'media' ) { + // linkTo = 'file'; + // } + // return { + // ...attributes, + // linkTo, + // }; + // }, + // save( { attributes } ) { + // const { + // images, + // columns = defaultColumnsNumber( attributes ), + // imageCrop, + // caption, + // linkTo, + // } = attributes; + // return ( + //
+ // + // { ! RichText.isEmpty( caption ) && ( + // + // ) } + //
+ // ); + // }, + // }, + // { + // attributes: { + // images: { + // type: 'array', + // default: [], + // source: 'query', + // selector: '.blocks-gallery-item', + // query: { + // url: { + // source: 'attribute', + // selector: 'img', + // attribute: 'src', + // }, + // fullUrl: { + // source: 'attribute', + // selector: 'img', + // attribute: 'data-full-url', + // }, + // link: { + // source: 'attribute', + // selector: 'img', + // attribute: 'data-link', + // }, + // alt: { + // source: 'attribute', + // selector: 'img', + // attribute: 'alt', + // default: '', + // }, + // id: { + // source: 'attribute', + // selector: 'img', + // attribute: 'data-id', + // }, + // caption: { + // type: 'string', + // source: 'html', + // selector: '.blocks-gallery-item__caption', + // }, + // }, + // }, + // ids: { + // type: 'array', + // default: [], + // }, + // columns: { + // type: 'number', + // }, + // caption: { + // type: 'string', + // source: 'html', + // selector: '.blocks-gallery-caption', + // }, + // imageCrop: { + // type: 'boolean', + // default: true, + // }, + // linkTo: { + // type: 'string', + // default: 'none', + // }, + // }, + // supports: { + // align: true, + // }, + // isEligible( { ids } ) { + // return ids && ids.some( ( id ) => typeof id === 'string' ); + // }, + // migrate( attributes ) { + // return { + // ...attributes, + // ids: map( attributes.ids, ( id ) => { + // const parsedId = parseInt( id, 10 ); + // return Number.isInteger( parsedId ) ? parsedId : null; + // } ), + // }; + // }, + // save( { attributes } ) { + // const { + // images, + // columns = defaultColumnsNumber( attributes ), + // imageCrop, + // caption, + // linkTo, + // } = attributes; + // return ( + //
+ // + // { ! RichText.isEmpty( caption ) && ( + // + // ) } + //
+ // ); + // }, + // }, + // { + // attributes: { + // images: { + // type: 'array', + // default: [], + // source: 'query', + // selector: 'ul.wp-block-gallery .blocks-gallery-item', + // query: { + // url: { + // source: 'attribute', + // selector: 'img', + // attribute: 'src', + // }, + // fullUrl: { + // source: 'attribute', + // selector: 'img', + // attribute: 'data-full-url', + // }, + // alt: { + // source: 'attribute', + // selector: 'img', + // attribute: 'alt', + // default: '', + // }, + // id: { + // source: 'attribute', + // selector: 'img', + // attribute: 'data-id', + // }, + // link: { + // source: 'attribute', + // selector: 'img', + // attribute: 'data-link', + // }, + // caption: { + // type: 'array', + // source: 'children', + // selector: 'figcaption', + // }, + // }, + // }, + // ids: { + // type: 'array', + // default: [], + // }, + // columns: { + // type: 'number', + // }, + // imageCrop: { + // type: 'boolean', + // default: true, + // }, + // linkTo: { + // type: 'string', + // default: 'none', + // }, + // }, + // supports: { + // align: true, + // }, + // save( { attributes } ) { + // const { + // images, + // columns = defaultColumnsNumber( attributes ), + // imageCrop, + // linkTo, + // } = attributes; + // return ( + // + // ); + // }, + // }, + // { + // attributes: { + // images: { + // type: 'array', + // default: [], + // source: 'query', + // selector: 'ul.wp-block-gallery .blocks-gallery-item', + // query: { + // url: { + // source: 'attribute', + // selector: 'img', + // attribute: 'src', + // }, + // alt: { + // source: 'attribute', + // selector: 'img', + // attribute: 'alt', + // default: '', + // }, + // id: { + // source: 'attribute', + // selector: 'img', + // attribute: 'data-id', + // }, + // link: { + // source: 'attribute', + // selector: 'img', + // attribute: 'data-link', + // }, + // caption: { + // type: 'array', + // source: 'children', + // selector: 'figcaption', + // }, + // }, + // }, + // columns: { + // type: 'number', + // }, + // imageCrop: { + // type: 'boolean', + // default: true, + // }, + // linkTo: { + // type: 'string', + // default: 'none', + // }, + // }, + // isEligible( { images, ids } ) { + // return ( + // images && + // images.length > 0 && + // ( ( ! ids && images ) || + // ( ids && images && ids.length !== images.length ) || + // some( images, ( id, index ) => { + // if ( ! id && ids[ index ] !== null ) { + // return true; + // } + // return parseInt( id, 10 ) !== ids[ index ]; + // } ) ) + // ); + // }, + // migrate( attributes ) { + // return { + // ...attributes, + // ids: map( attributes.images, ( { id } ) => { + // if ( ! id ) { + // return null; + // } + // return parseInt( id, 10 ); + // } ), + // }; + // }, + // supports: { + // align: true, + // }, + // save( { attributes } ) { + // const { + // images, + // columns = defaultColumnsNumber( attributes ), + // imageCrop, + // linkTo, + // } = attributes; + // return ( + // + // ); + // }, + // }, + // { + // attributes: { + // images: { + // type: 'array', + // default: [], + // source: 'query', + // selector: + // 'div.wp-block-gallery figure.blocks-gallery-image img', + // query: { + // url: { + // source: 'attribute', + // attribute: 'src', + // }, + // alt: { + // source: 'attribute', + // attribute: 'alt', + // default: '', + // }, + // id: { + // source: 'attribute', + // attribute: 'data-id', + // }, + // }, + // }, + // columns: { + // type: 'number', + // }, + // imageCrop: { + // type: 'boolean', + // default: true, + // }, + // linkTo: { + // type: 'string', + // default: 'none', + // }, + // align: { + // type: 'string', + // default: 'none', + // }, + // }, + // supports: { + // align: true, + // }, + // save( { attributes } ) { + // const { + // images, + // columns = defaultColumnsNumber( attributes ), + // align, + // imageCrop, + // linkTo, + // } = attributes; + // const className = classnames( `columns-${ columns }`, { + // alignnone: align === 'none', + // 'is-cropped': imageCrop, + // } ); + // return ( + //
+ // { images.map( ( image ) => { + // let href; + // switch ( linkTo ) { + // case 'media': + // href = image.url; + // break; + // case 'attachment': + // href = image.link; + // break; + // } + // const img = ( + // { + // ); + // return ( + //
+ // { href ? { img } : img } + //
+ // ); + // } ) } + //
+ // ); + // }, + // }, ]; export default deprecated; diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index 184efb0a6f570..32e28050e18cb 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -1,24 +1,14 @@ /** * External dependencies */ -import { - every, - filter, - find, - forEach, - get, - isEmpty, - map, - reduce, - some, - toString, -} from 'lodash'; +import { toString, isEqual, isEmpty, find } from 'lodash'; /** * WordPress dependencies */ import { compose } from '@wordpress/compose'; import { + Button, PanelBody, SelectControl, ToggleControl, @@ -31,25 +21,27 @@ import { useBlockProps, store as blockEditorStore, } from '@wordpress/block-editor'; -import { Platform, useEffect, useState, useMemo } from '@wordpress/element'; +import { Platform, useEffect, useState } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; -import { getBlobByURL, isBlobURL, revokeBlobURL } from '@wordpress/blob'; -import { useDispatch, withSelect } from '@wordpress/data'; +import { useSelect, useDispatch } from '@wordpress/data'; import { withViewportMatch } from '@wordpress/viewport'; import { View } from '@wordpress/primitives'; -import { store as coreStore } from '@wordpress/core-data'; +import { createBlock } from '@wordpress/blocks'; /** * Internal dependencies */ import { sharedIcon } from './shared-icon'; import { defaultColumnsNumber, pickRelevantMediaFiles } from './shared'; +import { getHrefAndDestination, getImageSizeAttributes } from './utils'; +import { getUpdatedLinkTargetSettings } from '../image/utils'; import Gallery from './gallery'; import { LINK_DESTINATION_ATTACHMENT, LINK_DESTINATION_MEDIA, LINK_DESTINATION_NONE, } from './constants'; +import useImageSizes from './use-image-sizes'; const MAX_COLUMNS = 8; const linkOptions = [ @@ -73,146 +65,104 @@ const MOBILE_CONTROL_PROPS_RANGE_CONTROL = Platform.select( { function GalleryEdit( props ) { const { + setAttributes, attributes, + clientId, + noticeOperations, isSelected, noticeUI, - noticeOperations, - mediaUpload, - imageSizes, - resizedImages, - onFocus, + insertBlocksAfter, } = props; + const { - columns = defaultColumnsNumber( attributes ), - imageCrop, - images, + linkTarget, linkTo, + columns = defaultColumnsNumber( images ), sizeSlug, + imageUploads, + imageCrop, } = attributes; - const [ selectedImage, setSelectedImage ] = useState(); - const [ attachmentCaptions, setAttachmentCaptions ] = useState(); + const { __unstableMarkNextChangeAsNotPersistent } = useDispatch( blockEditorStore ); - function setAttributes( newAttrs ) { - if ( newAttrs.ids ) { - throw new Error( - 'The "ids" attribute should not be changed directly. It is managed automatically when "images" attribute changes' - ); - } - - if ( newAttrs.images ) { - newAttrs = { - ...newAttrs, - // Unlike images[ n ].id which is a string, always ensure the - // ids array contains numbers as per its attribute type. - ids: map( newAttrs.images, ( { id } ) => parseInt( id, 10 ) ), - }; - } + const currentImageOptions = { linkTarget, linkTo, sizeSlug }; - props.setAttributes( newAttrs ); - } + const [ images, setImages ] = useState( [] ); + const [ imageSettings, setImageSettings ] = useState( currentImageOptions ); + const [ dirtyImageOptions, setDirtyImageOptions ] = useState( false ); - function onSelectImage( index ) { - return () => { - setSelectedImage( index ); - }; - } + useEffect( () => { + const currentOptionsState = ! isEqual( + currentImageOptions, + imageSettings + ); + if ( currentOptionsState !== dirtyImageOptions ) { + setDirtyImageOptions( currentOptionsState ); + } + }, [ currentImageOptions, imageSettings ] ); - function onDeselectImage() { - return () => { - setSelectedImage(); + const { getBlock, getMedia, getSettings } = useSelect( ( select ) => { + return { + getBlock: select( 'core/block-editor' ).getBlock, + getSettings: select( 'core/block-editor' ).getSettings, + getMedia: select( 'core' ).getMedia, }; - } + }, [] ); - function onMove( oldIndex, newIndex ) { - const newImages = [ ...images ]; - newImages.splice( newIndex, 1, images[ oldIndex ] ); - newImages.splice( oldIndex, 1, images[ newIndex ] ); - setSelectedImage( newIndex ); - setAttributes( { images: newImages } ); - } + const imageSizeOptions = useImageSizes( images, isSelected, getSettings ); - function onMoveForward( oldIndex ) { - return () => { - if ( oldIndex === images.length - 1 ) { - return; - } - onMove( oldIndex, oldIndex + 1 ); - }; - } + const { replaceInnerBlocks, updateBlockAttributes } = useDispatch( + 'core/block-editor' + ); - function onMoveBackward( oldIndex ) { - return () => { - if ( oldIndex === 0 ) { - return; - } - onMove( oldIndex, oldIndex - 1 ); - }; - } + /** + * Determines the image attributes that should be applied to an image block + * after the gallery updates. + * + * The gallery will receive the full collection of images when a new image + * is added. As a result we need to reapply the image's original settings if + * it already existed in the gallery. If the image is in fact new, we need + * to apply the gallery's current settings to the image. + * + * @param {Object} existingBlock Existing Image block that still exists after gallery update. + * @param {Object} image Media object for the actual image. + * @return {Object} Attributes to set on the new image block. + */ + function buildImageAttributes( existingBlock, image ) { + if ( existingBlock ) { + return existingBlock.attributes; + } - function onRemoveImage( index ) { - return () => { - const newImages = filter( images, ( img, i ) => index !== i ); - setSelectedImage(); - setAttributes( { - images: newImages, - columns: attributes.columns - ? Math.min( newImages.length, attributes.columns ) - : attributes.columns, - } ); + return { + ...pickRelevantMediaFiles( image, sizeSlug ), + ...getHrefAndDestination( image, linkTo ), + ...getUpdatedLinkTargetSettings( linkTarget, attributes ), + sizeSlug, }; } - function selectCaption( newImage ) { - // The image id in both the images and attachmentCaptions arrays is a - // string, so ensure comparison works correctly by converting the - // newImage.id to a string. - const newImageId = toString( newImage.id ); - const currentImage = find( images, { id: newImageId } ); - const currentImageCaption = currentImage - ? currentImage.caption - : newImage.caption; - - if ( ! attachmentCaptions ) { - return currentImageCaption; - } + function onSelectImages( newImages ) { + const newBlocks = newImages.map( ( image ) => { + const existingBlock = find( + images, + ( img ) => img.id === image.id + ); - const attachment = find( attachmentCaptions, { - id: newImageId, + return createBlock( 'core/image', { + ...buildImageAttributes( existingBlock, image ), + id: image.id, + } ); } ); - // if the attachment caption is updated - if ( attachment && attachment.caption !== newImage.caption ) { - return newImage.caption; - } - - return currentImageCaption; - } - - function onSelectImages( newImages ) { - setAttachmentCaptions( + setImages( newImages.map( ( newImage ) => ( { - // Store the attachmentCaption id as a string for consistency - // with the type of the id in the images attribute. id: toString( newImage.id ), - caption: newImage.caption, + url: newImage.url, } ) ) ); - setAttributes( { - images: newImages.map( ( newImage ) => ( { - ...pickRelevantMediaFiles( newImage, sizeSlug ), - caption: selectCaption( newImage, images, attachmentCaptions ), - // The id value is stored in a data attribute, so when the - // block is parsed it's converted to a string. Converting - // to a string here ensures it's type is consistent. - id: toString( newImage.id ), - } ) ), - columns: attributes.columns - ? Math.min( newImages.length, attributes.columns ) - : attributes.columns, - } ); + replaceInnerBlocks( clientId, newBlocks ); } function onUploadError( message ) { @@ -238,81 +188,62 @@ function GalleryEdit( props ) { : __( 'Thumbnails are not cropped.' ); } - function onFocusGalleryCaption() { - setSelectedImage(); + function toggleOpenInNewTab() { + setAttributes( { linkTarget: linkTarget ? undefined : '_blank' } ); } - function setImageAttributes( index, newAttributes ) { - if ( ! images[ index ] ) { - return; - } + function applyImageOptions() { + getBlock( clientId ).innerBlocks.forEach( ( block ) => { + const image = block.attributes.id + ? find( images, { id: block.attributes.id } ) + : null; - setAttributes( { - images: [ - ...images.slice( 0, index ), - { - ...images[ index ], - ...newAttributes, - }, - ...images.slice( index + 1 ), - ], + updateBlockAttributes( block.clientId, { + ...getHrefAndDestination( image.imageData, linkTo ), + ...getUpdatedLinkTargetSettings( linkTarget, block.attributes ), + ...getImageSizeAttributes( image.imageData, sizeSlug ), + } ); } ); + setDirtyImageOptions( false ); + setImageSettings( currentImageOptions ); } - function getImagesSizeOptions() { - return map( - filter( imageSizes, ( { slug } ) => - some( resizedImages, ( sizes ) => sizes[ slug ] ) - ), - ( { name, slug } ) => ( { value: slug, label: name } ) - ); + function cancelImageOptions() { + setAttributes( imageSettings ); } function updateImagesSize( newSizeSlug ) { - const updatedImages = map( images, ( image ) => { - if ( ! image.id ) { - return image; - } - const url = get( resizedImages, [ - parseInt( image.id, 10 ), - newSizeSlug, - ] ); - return { - ...image, - ...( url && { url } ), - }; - } ); - - setAttributes( { images: updatedImages, sizeSlug: newSizeSlug } ); + setAttributes( { sizeSlug: newSizeSlug } ); } useEffect( () => { if ( Platform.OS === 'web' && - images && - images.length > 0 && - every( images, ( { url } ) => isBlobURL( url ) ) + imageUploads && + imageUploads.length > 0 ) { - const filesList = map( images, ( { url } ) => getBlobByURL( url ) ); - forEach( images, ( { url } ) => revokeBlobURL( url ) ); - mediaUpload( { - filesList, - onFileChange: onSelectImages, - allowedTypes: [ 'image' ], - } ); + onSelectImages( imageUploads ); + setAttributes( { imageUploads: undefined } ); } - }, [] ); + }, [ imageUploads ] ); useEffect( () => { - // Deselect images when deselecting the block - if ( ! isSelected ) { - setSelectedImage(); + const newImages = getBlock( clientId ).innerBlocks.map( ( block ) => { + return { + id: block.attributes.id, + url: block.attributes.url, + attributes: block.attributes, + imageData: getMedia( block.attributes.id ), + }; + } ); + + if ( ! isEqual( newImages, images ) ) { + setImages( newImages ); } - }, [ isSelected ] ); + } ); useEffect( () => { - // linkTo attribute must be saved so blocks don't break when changing - // image_default_link_type in options.php + // linkTo attribute must be saved so blocks don't break when changing image_default_link_type in options.php if ( ! linkTo ) { __unstableMarkNextChangeAsNotPersistent(); setAttributes( { @@ -342,7 +273,6 @@ function GalleryEdit( props ) { value={ images } onError={ onUploadError } notices={ hasImages ? undefined : noticeUI } - onFocus={ onFocus } /> ); @@ -352,8 +282,8 @@ function GalleryEdit( props ) { return { mediaPlaceholder }; } - const imageSizeOptions = getImagesSizeOptions(); const shouldShowSizeOptions = hasImages && ! isEmpty( imageSizeOptions ); + const hasLinkTo = linkTo && linkTo !== 'none'; return ( <> @@ -382,6 +312,13 @@ function GalleryEdit( props ) { onChange={ setLinkTo } options={ linkOptions } /> + { hasLinkTo && ( + + ) } { shouldShowSizeOptions && ( ) } + { dirtyImageOptions && ( +
+ + +
+ ) } { noticeUI } ); } - export default compose( [ - withSelect( ( select, { attributes: { ids }, isSelected } ) => { - const { getMedia } = select( coreStore ); - const { getSettings } = select( blockEditorStore ); - const { imageSizes, mediaUpload } = getSettings(); - - const resizedImages = useMemo( () => { - if ( isSelected ) { - return reduce( - ids, - ( currentResizedImages, id ) => { - if ( ! id ) { - return currentResizedImages; - } - const image = getMedia( id ); - const sizes = reduce( - imageSizes, - ( currentSizes, size ) => { - const defaultUrl = get( image, [ - 'sizes', - size.slug, - 'url', - ] ); - const mediaDetailsUrl = get( image, [ - 'media_details', - 'sizes', - size.slug, - 'source_url', - ] ); - return { - ...currentSizes, - [ size.slug ]: - defaultUrl || mediaDetailsUrl, - }; - }, - {} - ); - return { - ...currentResizedImages, - [ parseInt( id, 10 ) ]: sizes, - }; - }, - {} - ); - } - return {}; - }, [ isSelected, ids, imageSizes ] ); - - return { - imageSizes, - mediaUpload, - resizedImages, - }; - } ), withNotices, withViewportMatch( { isNarrow: '< small' } ), ] )( GalleryEdit ); diff --git a/packages/block-library/src/gallery/editor.scss b/packages/block-library/src/gallery/editor.scss index 817f65a62327b..a4ad23f5dad34 100644 --- a/packages/block-library/src/gallery/editor.scss +++ b/packages/block-library/src/gallery/editor.scss @@ -132,3 +132,9 @@ figure.wp-block-gallery { margin-top: -9px; margin-left: -9px; } + +.gallery-settings-buttons { + .components-button:first-child { + margin-right: 8px; + } +} diff --git a/packages/block-library/src/gallery/gallery-image.js b/packages/block-library/src/gallery/gallery-image.js deleted file mode 100644 index e73a7e9cd7d93..0000000000000 --- a/packages/block-library/src/gallery/gallery-image.js +++ /dev/null @@ -1,318 +0,0 @@ -/** - * External dependencies - */ -import classnames from 'classnames'; -import { get, omit } 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, -} 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.onSelectCaption = this.onSelectCaption.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 = { - captionSelected: false, - isEditing: false, - }; - } - - bindContainer( ref ) { - this.container = ref; - } - - onSelectCaption() { - if ( ! this.state.captionSelected ) { - this.setState( { - captionSelected: true, - } ); - } - - if ( ! this.props.isSelected ) { - this.props.onSelect(); - } - } - - onSelectImage() { - if ( ! this.props.isSelected ) { - this.props.onSelect(); - } - - if ( this.state.captionSelected ) { - this.setState( { - captionSelected: false, - } ); - } - } - - onRemoveImage( event ) { - if ( - this.container === this.container.ownerDocument.activeElement && - this.props.isSelected && - [ BACKSPACE, DELETE ].indexOf( event.keyCode ) !== -1 - ) { - event.stopPropagation(); - event.preventDefault(); - this.props.onRemove(); - } - } - - onEdit() { - this.setState( { - isEditing: true, - } ); - } - - componentDidUpdate( prevProps ) { - const { - isSelected, - image, - url, - __unstableMarkNextChangeAsNotPersistent, - } = this.props; - if ( image && ! url ) { - __unstableMarkNextChangeAsNotPersistent(); - this.props.setAttributes( { - url: image.source_url, - alt: image.alt_text, - } ); - } - - // unselect the caption so when the user selects other image and comeback - // the caption is not immediately selected - if ( - this.state.captionSelected && - ! isSelected && - prevProps.isSelected - ) { - this.setState( { - captionSelected: false, - } ); - } - } - - 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 ) { - mediaAttributes = omit( mediaAttributes, [ 'alt' ] ); - } - } - - // 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' ] ) ) { - mediaAttributes = omit( mediaAttributes, [ 'caption' ] ); - } - - 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 */ - <> - { - { isBlobURL( url ) && } - - /* eslint-enable jsx-a11y/no-noninteractive-element-interactions */ - ); - - const className = classnames( { - 'is-selected': isSelected, - 'is-transient': isBlobURL( url ), - } ); - - return ( -
- { ! isEditing && ( href ? { img } : img ) } - { isEditing && ( - - ) } - -
- ); - } -} - -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 ); diff --git a/packages/block-library/src/gallery/gallery.js b/packages/block-library/src/gallery/gallery.js index dc261bbf1e469..d716d319e6df8 100644 --- a/packages/block-library/src/gallery/gallery.js +++ b/packages/block-library/src/gallery/gallery.js @@ -6,15 +6,18 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { RichText } from '@wordpress/block-editor'; +import { + RichText, + __experimentalUseInnerBlocksProps as useInnerBlocksProps, +} from '@wordpress/block-editor'; import { VisuallyHidden } from '@wordpress/components'; -import { __, sprintf } from '@wordpress/i18n'; +import { __ } from '@wordpress/i18n'; import { createBlock } from '@wordpress/blocks'; +import { useRef, useEffect } from '@wordpress/element'; /** * Internal dependencies */ -import GalleryImage from './gallery-image'; import { defaultColumnsNumber } from './shared'; export const Gallery = ( props ) => { @@ -22,29 +25,40 @@ export const Gallery = ( props ) => { attributes, isSelected, setAttributes, - selectedImage, mediaPlaceholder, - onMoveBackward, - onMoveForward, - onRemoveImage, - onSelectImage, - onDeselectImage, - onSetImageAttributes, - onFocusGalleryCaption, insertBlocksAfter, blockProps, + images, } = props; const { align, - columns = defaultColumnsNumber( attributes ), + columns = defaultColumnsNumber( images ), caption, imageCrop, - images, } = attributes; + const galleryRef = useRef(); + const innerBlocksProps = useInnerBlocksProps( + { + className: 'blocks-gallery-grid', + }, + { + allowedBlocks: [ 'core/image' ], + orientation: 'horizontal', + renderAppender: false, + __experimentalLayout: { type: 'default', alignments: [] }, + } + ); + + useEffect( () => { + if ( galleryRef.current && isSelected ) { + galleryRef.current.parentElement.focus(); + } + }, [ isSelected ] ); return (
{ 'is-cropped': imageCrop, } ) } > -
    - { images.map( ( img, index ) => { - const ariaLabel = sprintf( - /* translators: 1: the order number of the image. 2: the total number of images. */ - __( 'image %1$d of %2$d in gallery' ), - index + 1, - images.length - ); +
      - return ( -
    • - - onSetImageAttributes( index, attrs ) - } - caption={ img.caption } - aria-label={ ariaLabel } - sizeSlug={ attributes.sizeSlug } - /> -
    • - ); - } ) } -
    { mediaPlaceholder } { aria-label={ __( 'Gallery caption text' ) } placeholder={ __( 'Write gallery caption…' ) } value={ caption } - unstableOnFocus={ onFocusGalleryCaption } onChange={ ( value ) => setAttributes( { caption: value } ) } inlineToolbar __unstableOnSplitAtEnd={ () => diff --git a/packages/block-library/src/gallery/save.js b/packages/block-library/src/gallery/save.js index 0c51884a5db95..45cd8ac41ab4a 100644 --- a/packages/block-library/src/gallery/save.js +++ b/packages/block-library/src/gallery/save.js @@ -1,73 +1,30 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + /** * WordPress dependencies */ -import { RichText, useBlockProps } from '@wordpress/block-editor'; +import { RichText, useBlockProps, InnerBlocks } from '@wordpress/block-editor'; /** * Internal dependencies */ import { defaultColumnsNumber } from './shared'; -import { - LINK_DESTINATION_ATTACHMENT, - LINK_DESTINATION_MEDIA, -} from './constants'; -export default function save( { attributes } ) { +export default function save( { attributes, innerBlocks } ) { const { - images, - columns = defaultColumnsNumber( attributes ), + columns = defaultColumnsNumber( innerBlocks ), imageCrop, caption, - linkTo, } = attributes; const className = `columns-${ columns } ${ imageCrop ? 'is-cropped' : '' }`; return (
      - { images.map( ( image ) => { - let href; - - switch ( linkTo ) { - case LINK_DESTINATION_MEDIA: - href = image.fullUrl || image.url; - break; - case LINK_DESTINATION_ATTACHMENT: - href = image.link; - break; - } - - const img = ( - { - ); - - return ( -
    • -
      - { href ? { img } : img } - { ! RichText.isEmpty( image.caption ) && ( - - ) } -
      -
    • - ); - } ) } +
    { ! RichText.isEmpty( caption ) && ( { @@ -19,5 +24,7 @@ export const pickRelevantMediaFiles = ( image, sizeSlug = 'large' ) => { if ( fullUrl ) { imageProps.fullUrl = fullUrl; } + imageProps.alt = + imageProps.alt !== '' ? imageProps.alt : __( 'Image gallery image' ); return imageProps; }; diff --git a/packages/block-library/src/gallery/style.scss b/packages/block-library/src/gallery/style.scss index 4a956bf899fa3..c6fa577831cea 100644 --- a/packages/block-library/src/gallery/style.scss +++ b/packages/block-library/src/gallery/style.scss @@ -1,71 +1,68 @@ -.wp-block-gallery, -.blocks-gallery-grid { - display: flex; - flex-wrap: wrap; - list-style-type: none; - padding: 0; - // Some themes give all
      default margin instead of padding. - margin: 0; - - .blocks-gallery-image, - .blocks-gallery-item { - // Add space between thumbnails, and unset right most thumbnails later. - margin: 0 1em 1em 0; +.wp-block-gallery { + ul.blocks-gallery-grid { display: flex; - flex-grow: 1; - flex-direction: column; - justify-content: center; - position: relative; - - // On mobile and responsive viewports, we allow only 1 or 2 columns at the most. - width: calc(50% - 1em); - - &:nth-of-type(even) { - margin-right: 0; - } - - figure { - margin: 0; - height: 100%; - - // IE doesn't support flex so omit that. - @supports (position: sticky) { - display: flex; - align-items: flex-end; - justify-content: flex-start; + flex-wrap: wrap; + list-style-type: none; + padding: 0; + // Some themes give all
        default margin instead of padding. + margin: 0; + + // Need to add the bogus :not(#individual-image) to override long not:() specificity chain + // on default image block on front end. + // Add space between thumbnails, and unset right most thumbnails later. + li.wp-block-image:not(#individual-image) { + margin: 0 $grid-unit-20 $grid-unit-20 0; + &:last-child { + margin-right: 0; } } - img { - display: block; - max-width: 100%; - height: auto; - - // IE doesn't handle cropping, so we need an explicit width here. - width: 100%; + li.wp-block-image { + display: flex; + flex-grow: 1; + flex-direction: column; + justify-content: center; + position: relative; - // IE11 doesn't read rules inside this query. They are applied only to modern browsers. - @supports (position: sticky) { - width: auto; + figure, + figure > div { + margin: 0; + height: 100%; } - } - - figcaption { - position: absolute; - bottom: 0; - width: 100%; - max-height: 100%; - overflow: auto; - padding: 3em 0.77em 0.7em; - color: $white; - text-align: center; - font-size: 0.8em; - background: linear-gradient(0deg, rgba($color: $black, $alpha: 0.7) 0, rgba($color: $black, $alpha: 0.3) 70%, transparent); - box-sizing: border-box; - margin: 0; img { - display: inline; + display: block; + max-width: 100%; + height: auto; + width: 100%; + // IE doesn't handle cropping, so we need an explicit width here. + // IE11 doesn't read rules inside this query. They are applied only to modern browsers. + @supports ( position: sticky ) { + width: auto; + } + } + + figcaption { + position: absolute; + margin-bottom: 0; + bottom: 0; + width: 100%; + max-height: 100%; + overflow: auto; + padding: 40px 10px 9px; + color: $white; + text-align: center; + font-size: $default-font-size; + background: linear-gradient( + 0deg, + rgba( $color: $black, $alpha: 0.7 ) 0, + rgba( $color: $black, $alpha: 0.3 ) 70%, + transparent + ); + + img { + display: inline; + } } } } @@ -75,8 +72,7 @@ } // Cropped - &.is-cropped .blocks-gallery-image, - &.is-cropped .blocks-gallery-item { + &.is-cropped ul.blocks-gallery-grid li.wp-block-image:not(#individual-image) { a, img { // IE11 doesn't support object-fit, so just make sure images aren't skewed. @@ -84,7 +80,7 @@ width: 100%; // IE11 doesn't read rules inside this query. They are applied only to modern browsers. - @supports (position: sticky) { + @supports ( position: sticky ) { height: 100%; flex: 1; object-fit: cover; @@ -92,8 +88,16 @@ } } - &.columns-1 .blocks-gallery-image, - &.columns-1 .blocks-gallery-item { + // On mobile and responsive viewports, we allow only 1 or 2 columns at the most. + & .wp-block-image:not(#individual-image) { + width: calc( 50% - #{$grid-unit-20} ); + + &:nth-of-type( even ) { + margin-right: 0; + } + } + + &.columns-1 .wp-block-image:not(#individual-image) { width: 100%; margin-right: 0; } @@ -101,28 +105,25 @@ // Beyond mobile viewports, we allow up to 8 columns. @include break-small { @for $i from 3 through 8 { - &.columns-#{ $i } .blocks-gallery-image, - &.columns-#{ $i } .blocks-gallery-item { - width: calc(#{ 100% / $i } - #{ 1em * ( $i - 1 ) / $i }); - margin-right: 1em; + &.columns-#{ $i } .wp-block-image:not(#individual-image) { + width: calc( + #{100% / $i} - #{$grid-unit-20 * ( $i - 1 ) / $i} + ); + margin-right: $grid-unit-20; } } // Unset the right margin on every rightmost gallery item to ensure center balance. @for $column-count from 1 through 8 { - &.columns-#{ $column-count } .blocks-gallery-image:nth-of-type(#{ $column-count }n), - &.columns-#{ $column-count } .blocks-gallery-item:nth-of-type(#{ $column-count }n) { + &.columns-#{ + $column-count + } + .wp-block-image:not(#individual-image):nth-of-type( #{ $column-count }n ) { margin-right: 0; } } } - // Last item always needs margins reset. - .blocks-gallery-image:last-child, - .blocks-gallery-item:last-child { - margin-right: 0; - } - // Apply max-width to floated items that have no intrinsic width. &.alignleft, &.alignright { @@ -132,7 +133,7 @@ // If the gallery is centered, center the content inside as well. &.aligncenter { - .blocks-gallery-item figure { + figure.wp-block-image { justify-content: center; } } diff --git a/packages/block-library/src/gallery/transforms.js b/packages/block-library/src/gallery/transforms.js index fa7fff8d46f9f..19b006c2d81a7 100644 --- a/packages/block-library/src/gallery/transforms.js +++ b/packages/block-library/src/gallery/transforms.js @@ -108,7 +108,7 @@ const transforms = { }, transform( files ) { const block = createBlock( 'core/gallery', { - images: files.map( ( file ) => + imageUploads: files.map( ( file ) => pickRelevantMediaFiles( { url: createBlobURL( file ), } ) diff --git a/packages/block-library/src/gallery/use-image-sizes.js b/packages/block-library/src/gallery/use-image-sizes.js new file mode 100644 index 0000000000000..e5888bb2e79ae --- /dev/null +++ b/packages/block-library/src/gallery/use-image-sizes.js @@ -0,0 +1,54 @@ +/** + * External dependencies + */ +import { get, reduce, map, filter, some } from 'lodash'; + +export default function useImageSizes( images, isSelected, getSettings ) { + const { imageSizes } = getSettings(); + + let resizedImages = {}; + + if ( isSelected ) { + resizedImages = reduce( + images, + ( currentResizedImages, img ) => { + if ( ! img.id ) { + return currentResizedImages; + } + const image = img.imageData; + const sizes = reduce( + imageSizes, + ( currentSizes, size ) => { + const defaultUrl = get( image, [ + 'sizes', + size.slug, + 'url', + ] ); + const mediaDetailsUrl = get( image, [ + 'media_details', + 'sizes', + size.slug, + 'source_url', + ] ); + return { + ...currentSizes, + [ size.slug ]: defaultUrl || mediaDetailsUrl, + }; + }, + {} + ); + return { + ...currentResizedImages, + [ parseInt( img.id, 10 ) ]: sizes, + }; + }, + {} + ); + } + return map( + filter( imageSizes, ( { slug } ) => + some( resizedImages, ( sizes ) => sizes[ slug ] ) + ), + ( { name, slug } ) => ( { value: slug, label: name } ) + ); +} diff --git a/packages/block-library/src/gallery/utils.js b/packages/block-library/src/gallery/utils.js new file mode 100644 index 0000000000000..60e952e212b23 --- /dev/null +++ b/packages/block-library/src/gallery/utils.js @@ -0,0 +1,68 @@ +/** + * External dependencies + */ +import { get } from 'lodash'; + +/** + * Internal dependencies + */ +import { + LINK_DESTINATION_ATTACHMENT, + LINK_DESTINATION_MEDIA, + LINK_DESTINATION_NONE, +} from './constants'; +import { + LINK_DESTINATION_ATTACHMENT as IMAGE_LINK_DESTINATION_ATTACHMENT, + LINK_DESTINATION_MEDIA as IMAGE_LINK_DESTINATION_MEDIA, + LINK_DESTINATION_NONE as IMAGE_LINK_DESTINATION_NONE, +} from '../image/constants'; + +/** + * Determines new href and linkDestination values for an image block from the + * supplied Gallery link destination. + * + * @param {Object} image Gallery image. + * @param {string} destination Gallery's selected link destination. + * @return {Object} New attributes to assign to image block. + */ +export function getHrefAndDestination( image, destination ) { + // Need to determine the URL that the selected destination maps to. + // Gutenberg and WordPress use different constants so the new link + // destination also needs to be tweaked. + switch ( destination ) { + case LINK_DESTINATION_MEDIA: + return { + href: image?.source_url || image?.url, // eslint-disable-line camelcase + linkDestination: IMAGE_LINK_DESTINATION_MEDIA, + }; + case LINK_DESTINATION_ATTACHMENT: + return { + href: image?.link, + linkDestination: IMAGE_LINK_DESTINATION_ATTACHMENT, + }; + case LINK_DESTINATION_NONE: + return { + href: undefined, + linkDestination: IMAGE_LINK_DESTINATION_NONE, + }; + } + + return {}; +} + +/** + * Determines new Image block attributes affected by a change in Gallery image + * size selection. + * + * @param {Object} image Media file object for gallery image. + * @param {string} size Gallery's selected size slug to apply. + */ +export function getImageSizeAttributes( image, size ) { + const url = get( image, [ 'media_details', 'sizes', size, 'source_url' ] ); + + if ( url ) { + return { url, width: undefined, height: undefined, sizeSlug: size }; + } + + return {}; +} diff --git a/packages/block-library/src/image/block.json b/packages/block-library/src/image/block.json index 3952230ded6a3..6fafddf148409 100644 --- a/packages/block-library/src/image/block.json +++ b/packages/block-library/src/image/block.json @@ -2,6 +2,7 @@ "apiVersion": 2, "name": "core/image", "category": "media", + "usesContext": [ "allowResize", "isListItem" ], "attributes": { "align": { "type": "string" @@ -68,6 +69,10 @@ "source": "attribute", "selector": "figure > a", "attribute": "target" + }, + "isListItem": { + "type": "boolean", + "default": false } }, "supports": { diff --git a/packages/block-library/src/image/edit.js b/packages/block-library/src/image/edit.js index d042bd4fc4a61..0e0221dd16607 100644 --- a/packages/block-library/src/image/edit.js +++ b/packages/block-library/src/image/edit.js @@ -18,7 +18,7 @@ import { useBlockProps, store as blockEditorStore, } from '@wordpress/block-editor'; -import { useEffect, useRef } from '@wordpress/element'; +import { useEffect, useRef, useState } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { image as icon } from '@wordpress/icons'; @@ -81,6 +81,7 @@ export function ImageEdit( { insertBlocksAfter, noticeOperations, onReplace, + context: { allowResize = true, isListItem = false }, } ) { const { url = '', @@ -93,6 +94,7 @@ export function ImageEdit( { sizeSlug, } = attributes; + const [ tempUrl, setTempUrl ] = useState(); const altRef = useRef(); useEffect( () => { altRef.current = alt; @@ -254,14 +256,18 @@ export function ImageEdit( { // If an image is temporary, revoke the Blob url when it is uploaded (and is // no longer temporary). useEffect( () => { - if ( ! isTemp ) { + if ( isTemp ) { + setTempUrl( url ); return; } + revokeBlobURL( tempUrl ); + }, [ isTemp, url ] ); - return () => { - revokeBlobURL( url ); - }; - }, [ isTemp ] ); + useEffect( () => { + if ( isListItem ) { + setAttributes( { isListItem } ); + } + }, [ isListItem ] ); const isExternal = isExternalImage( id, url ); const controls = ( @@ -309,23 +315,40 @@ export function ImageEdit( { className: classes, } ); + const image = url && ( + + ); + + if ( isListItem ) { + return ( + <> + { controls } +
      • +
        + { image } + { mediaPlaceholder } +
        +
      • + + ); + } + return ( <> { controls }
        - { url && ( - - ) } + { image } { mediaPlaceholder }
        diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js index 810c5172b44cd..9e2b82bf2e151 100644 --- a/packages/block-library/src/image/image.js +++ b/packages/block-library/src/image/image.js @@ -86,6 +86,7 @@ export default function Image( { onSelectURL, onUploadError, containerRef, + allowResize, } ) { const captionRef = useRef(); const prevUrl = usePrevious( url ); @@ -135,7 +136,7 @@ export default function Image( { const [ isEditingImage, setIsEditingImage ] = useState( false ); const [ externalBlob, setExternalBlob ] = useState(); const clientWidth = useClientWidth( containerRef, [ align ] ); - const isResizable = ! isWideAligned && isLargeViewport; + const isResizable = allowResize && ! ( isWideAligned && isLargeViewport ); const imageSizeOptions = map( filter( imageSizes, ( { slug } ) => get( image, [ 'media_details', 'sizes', slug, 'source_url' ] ) diff --git a/packages/block-library/src/image/save.js b/packages/block-library/src/image/save.js index ccf816c121e90..590ae7a10489f 100644 --- a/packages/block-library/src/image/save.js +++ b/packages/block-library/src/image/save.js @@ -24,6 +24,7 @@ export default function save( { attributes } ) { linkTarget, sizeSlug, title, + isListItem, } = attributes; const newRel = isEmpty( rel ) ? undefined : rel; @@ -65,9 +66,18 @@ export default function save( { attributes } ) { ); + const blockProps = useBlockProps.save(); + if ( isListItem ) { + return ( +
      • +
        { figure }
        +
      • + ); + } + if ( 'left' === align || 'right' === align || 'center' === align ) { return ( -
        +
        { figure }
        ); From 05283d99dbba3aa68b95df4cbbf7f7d2f3152057 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 4 Nov 2020 15:30:24 +1300 Subject: [PATCH 002/103] Fix issue with images not loading on first selection from media gallery --- packages/block-library/src/gallery/edit.js | 39 +++++++++------------- 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index 32e28050e18cb..838917739fe3b 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { toString, isEqual, isEmpty, find } from 'lodash'; +import { isEqual, isEmpty, find } from 'lodash'; /** * WordPress dependencies @@ -88,8 +88,6 @@ function GalleryEdit( props ) { ); const currentImageOptions = { linkTarget, linkTo, sizeSlug }; - - const [ images, setImages ] = useState( [] ); const [ imageSettings, setImageSettings ] = useState( currentImageOptions ); const [ dirtyImageOptions, setDirtyImageOptions ] = useState( false ); @@ -111,6 +109,20 @@ function GalleryEdit( props ) { }; }, [] ); + const images = useSelect( ( select ) => { + const newImages = select( 'core/block-editor' ) + .getBlock( clientId ) + .innerBlocks.map( ( block ) => { + return { + id: block.attributes.id, + url: block.attributes.url, + attributes: block.attributes, + imageData: getMedia( block.attributes.id ), + }; + } ); + return newImages; + } ); + const imageSizeOptions = useImageSizes( images, isSelected, getSettings ); const { replaceInnerBlocks, updateBlockAttributes } = useDispatch( @@ -156,12 +168,6 @@ function GalleryEdit( props ) { } ); } ); - setImages( - newImages.map( ( newImage ) => ( { - id: toString( newImage.id ), - url: newImage.url, - } ) ) - ); replaceInnerBlocks( clientId, newBlocks ); } @@ -227,21 +233,6 @@ function GalleryEdit( props ) { } }, [ imageUploads ] ); - useEffect( () => { - const newImages = getBlock( clientId ).innerBlocks.map( ( block ) => { - return { - id: block.attributes.id, - url: block.attributes.url, - attributes: block.attributes, - imageData: getMedia( block.attributes.id ), - }; - } ); - - if ( ! isEqual( newImages, images ) ) { - setImages( newImages ); - } - } ); - useEffect( () => { // linkTo attribute must be saved so blocks don't break when changing image_default_link_type in options.php if ( ! linkTo ) { From bca450154cb062c88c483b11a107516fe9bf19c5 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 4 Nov 2020 16:34:31 +1300 Subject: [PATCH 003/103] Remove the default columns setting as we don't have access to innerBlocks at the point that the block validation is run --- packages/block-library/src/gallery/edit.js | 8 +++++++- packages/block-library/src/gallery/gallery.js | 13 +------------ packages/block-library/src/gallery/save.js | 18 ++---------------- 3 files changed, 10 insertions(+), 29 deletions(-) diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index 838917739fe3b..ef1d1c90a2260 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -77,7 +77,7 @@ function GalleryEdit( props ) { const { linkTarget, linkTo, - columns = defaultColumnsNumber( images ), + columns, sizeSlug, imageUploads, imageCrop, @@ -123,6 +123,12 @@ function GalleryEdit( props ) { return newImages; } ); + useEffect( () => { + if ( ! columns && images.length > 0 ) { + setAttributes( { columns: defaultColumnsNumber( images ) } ); + } + }, [ images, columns ] ); + const imageSizeOptions = useImageSizes( images, isSelected, getSettings ); const { replaceInnerBlocks, updateBlockAttributes } = useDispatch( diff --git a/packages/block-library/src/gallery/gallery.js b/packages/block-library/src/gallery/gallery.js index d716d319e6df8..a9f6e84592c24 100644 --- a/packages/block-library/src/gallery/gallery.js +++ b/packages/block-library/src/gallery/gallery.js @@ -15,11 +15,6 @@ import { __ } from '@wordpress/i18n'; import { createBlock } from '@wordpress/blocks'; import { useRef, useEffect } from '@wordpress/element'; -/** - * Internal dependencies - */ -import { defaultColumnsNumber } from './shared'; - export const Gallery = ( props ) => { const { attributes, @@ -28,15 +23,9 @@ export const Gallery = ( props ) => { mediaPlaceholder, insertBlocksAfter, blockProps, - images, } = props; - const { - align, - columns = defaultColumnsNumber( images ), - caption, - imageCrop, - } = attributes; + const { align, columns, caption, imageCrop } = attributes; const galleryRef = useRef(); const innerBlocksProps = useInnerBlocksProps( { diff --git a/packages/block-library/src/gallery/save.js b/packages/block-library/src/gallery/save.js index 45cd8ac41ab4a..64f020d7ec910 100644 --- a/packages/block-library/src/gallery/save.js +++ b/packages/block-library/src/gallery/save.js @@ -1,24 +1,10 @@ -/** - * External dependencies - */ -import classnames from 'classnames'; - /** * WordPress dependencies */ import { RichText, useBlockProps, InnerBlocks } from '@wordpress/block-editor'; -/** - * Internal dependencies - */ -import { defaultColumnsNumber } from './shared'; - -export default function save( { attributes, innerBlocks } ) { - const { - columns = defaultColumnsNumber( innerBlocks ), - imageCrop, - caption, - } = attributes; +export default function save( { attributes } ) { + const { columns, imageCrop, caption } = attributes; const className = `columns-${ columns } ${ imageCrop ? 'is-cropped' : '' }`; return ( From 04c1d485aad88206077489f20182c0eda0e0f613 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 4 Nov 2020 16:40:27 +1300 Subject: [PATCH 004/103] Revert "Remove the default columns setting as we don't have access to innerBlocks at the point that the block validation is run" This reverts commit 4d95e95d50ae8410868a6d7aca6b9f4c4536d36b. --- packages/block-library/src/gallery/edit.js | 8 +------- packages/block-library/src/gallery/gallery.js | 13 ++++++++++++- packages/block-library/src/gallery/save.js | 18 ++++++++++++++++-- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index ef1d1c90a2260..838917739fe3b 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -77,7 +77,7 @@ function GalleryEdit( props ) { const { linkTarget, linkTo, - columns, + columns = defaultColumnsNumber( images ), sizeSlug, imageUploads, imageCrop, @@ -123,12 +123,6 @@ function GalleryEdit( props ) { return newImages; } ); - useEffect( () => { - if ( ! columns && images.length > 0 ) { - setAttributes( { columns: defaultColumnsNumber( images ) } ); - } - }, [ images, columns ] ); - const imageSizeOptions = useImageSizes( images, isSelected, getSettings ); const { replaceInnerBlocks, updateBlockAttributes } = useDispatch( diff --git a/packages/block-library/src/gallery/gallery.js b/packages/block-library/src/gallery/gallery.js index a9f6e84592c24..d716d319e6df8 100644 --- a/packages/block-library/src/gallery/gallery.js +++ b/packages/block-library/src/gallery/gallery.js @@ -15,6 +15,11 @@ import { __ } from '@wordpress/i18n'; import { createBlock } from '@wordpress/blocks'; import { useRef, useEffect } from '@wordpress/element'; +/** + * Internal dependencies + */ +import { defaultColumnsNumber } from './shared'; + export const Gallery = ( props ) => { const { attributes, @@ -23,9 +28,15 @@ export const Gallery = ( props ) => { mediaPlaceholder, insertBlocksAfter, blockProps, + images, } = props; - const { align, columns, caption, imageCrop } = attributes; + const { + align, + columns = defaultColumnsNumber( images ), + caption, + imageCrop, + } = attributes; const galleryRef = useRef(); const innerBlocksProps = useInnerBlocksProps( { diff --git a/packages/block-library/src/gallery/save.js b/packages/block-library/src/gallery/save.js index 64f020d7ec910..45cd8ac41ab4a 100644 --- a/packages/block-library/src/gallery/save.js +++ b/packages/block-library/src/gallery/save.js @@ -1,10 +1,24 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + /** * WordPress dependencies */ import { RichText, useBlockProps, InnerBlocks } from '@wordpress/block-editor'; -export default function save( { attributes } ) { - const { columns, imageCrop, caption } = attributes; +/** + * Internal dependencies + */ +import { defaultColumnsNumber } from './shared'; + +export default function save( { attributes, innerBlocks } ) { + const { + columns = defaultColumnsNumber( innerBlocks ), + imageCrop, + caption, + } = attributes; const className = `columns-${ columns } ${ imageCrop ? 'is-cropped' : '' }`; return ( From ab143d5216b514c6e6cad54a07a8455a0a653ae7 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 4 Nov 2020 16:49:19 +1300 Subject: [PATCH 005/103] Add image count so we can work out default columns as innerBlocks not available at point of block validation --- packages/block-library/src/gallery/block.json | 4 ++++ packages/block-library/src/gallery/edit.js | 9 ++++++++- packages/block-library/src/gallery/gallery.js | 4 ++-- packages/block-library/src/gallery/save.js | 10 +++------- packages/block-library/src/gallery/shared.js | 4 ++-- 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/packages/block-library/src/gallery/block.json b/packages/block-library/src/gallery/block.json index 44f7d069c8bef..8026ad6e7f14e 100644 --- a/packages/block-library/src/gallery/block.json +++ b/packages/block-library/src/gallery/block.json @@ -41,6 +41,10 @@ "isListItem": { "type": "boolean", "default": true + }, + "imageCount": { + "type": "number", + "default": 0 } }, "providesContext": { diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index 838917739fe3b..3c343421c30c0 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -75,9 +75,10 @@ function GalleryEdit( props ) { } = props; const { + imageCount, linkTarget, linkTo, - columns = defaultColumnsNumber( images ), + columns = defaultColumnsNumber( imageCount ), sizeSlug, imageUploads, imageCrop, @@ -123,6 +124,12 @@ function GalleryEdit( props ) { return newImages; } ); + useEffect( () => { + if ( images.length !== imageCount ) { + setAttributes( { imageCount: images.length } ); + } + }, [ images ] ); + const imageSizeOptions = useImageSizes( images, isSelected, getSettings ); const { replaceInnerBlocks, updateBlockAttributes } = useDispatch( diff --git a/packages/block-library/src/gallery/gallery.js b/packages/block-library/src/gallery/gallery.js index d716d319e6df8..9d36f2e4e0137 100644 --- a/packages/block-library/src/gallery/gallery.js +++ b/packages/block-library/src/gallery/gallery.js @@ -28,12 +28,12 @@ export const Gallery = ( props ) => { mediaPlaceholder, insertBlocksAfter, blockProps, - images, } = props; const { + imageCount, align, - columns = defaultColumnsNumber( images ), + columns = defaultColumnsNumber( imageCount ), caption, imageCrop, } = attributes; diff --git a/packages/block-library/src/gallery/save.js b/packages/block-library/src/gallery/save.js index 45cd8ac41ab4a..b4c5dc8e770f6 100644 --- a/packages/block-library/src/gallery/save.js +++ b/packages/block-library/src/gallery/save.js @@ -1,8 +1,3 @@ -/** - * External dependencies - */ -import classnames from 'classnames'; - /** * WordPress dependencies */ @@ -13,9 +8,10 @@ import { RichText, useBlockProps, InnerBlocks } from '@wordpress/block-editor'; */ import { defaultColumnsNumber } from './shared'; -export default function save( { attributes, innerBlocks } ) { +export default function save( { attributes } ) { const { - columns = defaultColumnsNumber( innerBlocks ), + imageCount, + columns = defaultColumnsNumber( imageCount ), imageCrop, caption, } = attributes; diff --git a/packages/block-library/src/gallery/shared.js b/packages/block-library/src/gallery/shared.js index d356403ca1d8f..4c1852280effe 100644 --- a/packages/block-library/src/gallery/shared.js +++ b/packages/block-library/src/gallery/shared.js @@ -8,8 +8,8 @@ import { get, pick } from 'lodash'; */ import { __ } from '@wordpress/i18n'; -export function defaultColumnsNumber( images ) { - return images?.length ? Math.min( 3, images.length ) : 3; +export function defaultColumnsNumber( imageCount ) { + return imageCount ? Math.min( 3, imageCount ) : 3; } export const pickRelevantMediaFiles = ( image, sizeSlug = 'large' ) => { From 35c963d712d7badec11554487aaa499900ec1e6a Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Thu, 5 Nov 2020 17:26:32 +1300 Subject: [PATCH 006/103] Disable the innerBlocks dropzones so drag drop works same as existing gallery - with the idea that we will improve the innerblocks drag and drop in a later PR --- packages/block-editor/src/components/inner-blocks/index.js | 4 +++- .../components/inner-blocks/use-nested-settings-update.js | 7 ++++++- .../src/components/use-block-drop-zone/index.js | 6 ++++-- packages/block-library/src/gallery/editor.scss | 5 +++++ packages/block-library/src/gallery/gallery.js | 1 + 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/packages/block-editor/src/components/inner-blocks/index.js b/packages/block-editor/src/components/inner-blocks/index.js index 5485df3227af6..a8be7a24e6ff0 100644 --- a/packages/block-editor/src/components/inner-blocks/index.js +++ b/packages/block-editor/src/components/inner-blocks/index.js @@ -46,6 +46,7 @@ function UncontrolledInnerBlocks( props ) { __experimentalAppenderTagName, renderAppender, orientation, + dropZonesDisabled, placeholder, __experimentalLayout: layout = defaultLayout, } = props; @@ -55,7 +56,8 @@ function UncontrolledInnerBlocks( props ) { allowedBlocks, templateLock, captureToolbars, - orientation + orientation, + dropZonesDisabled, ); useInnerBlockTemplateSync( diff --git a/packages/block-editor/src/components/inner-blocks/use-nested-settings-update.js b/packages/block-editor/src/components/inner-blocks/use-nested-settings-update.js index ff0f94f637cea..9e99b8dfef3c3 100644 --- a/packages/block-editor/src/components/inner-blocks/use-nested-settings-update.js +++ b/packages/block-editor/src/components/inner-blocks/use-nested-settings-update.js @@ -33,7 +33,8 @@ export default function useNestedSettingsUpdate( allowedBlocks, templateLock, captureToolbars, - orientation + orientation, + dropZonesDisabled, ) { const { updateBlockListSettings } = useDispatch( blockEditorStore ); @@ -70,6 +71,9 @@ export default function useNestedSettingsUpdate( if ( orientation !== undefined ) { newSettings.orientation = orientation; } + if ( dropZonesDisabled !== undefined ) { + newSettings.dropZonesDisabled = dropZonesDisabled; + } if ( ! isShallowEqual( blockListSettings, newSettings ) ) { updateBlockListSettings( clientId, newSettings ); @@ -82,6 +86,7 @@ export default function useNestedSettingsUpdate( parentLock, captureToolbars, orientation, + dropZonesDisabled, updateBlockListSettings, ] ); } diff --git a/packages/block-editor/src/components/use-block-drop-zone/index.js b/packages/block-editor/src/components/use-block-drop-zone/index.js index 717907a72f484..39975a6be90e7 100644 --- a/packages/block-editor/src/components/use-block-drop-zone/index.js +++ b/packages/block-editor/src/components/use-block-drop-zone/index.js @@ -99,12 +99,14 @@ export default function useBlockDropZone( { } ) { const [ targetBlockIndex, setTargetBlockIndex ] = useState( null ); - const { isLockedAll, orientation } = useSelect( + const { isLockedAll, orientation, isDropZonesDisabled } = useSelect( ( select ) => { const { getBlockListSettings, getTemplateLock } = select( blockEditorStore ); return { + isDropZonesDisabled: getBlockListSettings( targetRootClientId ) + ?.dropZonesDisabled, isLockedAll: getTemplateLock( targetRootClientId ) === 'all', orientation: getBlockListSettings( targetRootClientId ) ?.orientation, @@ -120,7 +122,7 @@ export default function useBlockDropZone( { const { position } = useDropZone( { element, - isDisabled: isLockedAll, + isDisabled: isLockedAll || isDropZonesDisabled, withPosition: true, ...dropEventHandlers, } ); diff --git a/packages/block-library/src/gallery/editor.scss b/packages/block-library/src/gallery/editor.scss index a4ad23f5dad34..47fb41ad04b68 100644 --- a/packages/block-library/src/gallery/editor.scss +++ b/packages/block-library/src/gallery/editor.scss @@ -2,8 +2,13 @@ // Override the default list style type _only in the editor_ // to avoid :not() selector specificity issues. // See https://github.com/WordPress/gutenberg/pull/10358 + li { list-style-type: none; + .components-drop-zone { + display: none; + pointer-events: none; + } } // @todo: this deserves a refactor, by being moved to the toolbar. diff --git a/packages/block-library/src/gallery/gallery.js b/packages/block-library/src/gallery/gallery.js index 9d36f2e4e0137..3e52e1671efbe 100644 --- a/packages/block-library/src/gallery/gallery.js +++ b/packages/block-library/src/gallery/gallery.js @@ -44,6 +44,7 @@ export const Gallery = ( props ) => { }, { allowedBlocks: [ 'core/image' ], + dropZonesDisabled: true, orientation: 'horizontal', renderAppender: false, __experimentalLayout: { type: 'default', alignments: [] }, From 575d31b5f2e3d0b568cb66b7a54d4e194ef1cdb0 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Thu, 5 Nov 2020 17:27:07 +1300 Subject: [PATCH 007/103] Lint changes --- packages/block-editor/src/components/inner-blocks/index.js | 2 +- .../src/components/inner-blocks/use-nested-settings-update.js | 2 +- .../block-editor/src/components/use-block-drop-zone/index.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/components/inner-blocks/index.js b/packages/block-editor/src/components/inner-blocks/index.js index a8be7a24e6ff0..b5f9585bd90d2 100644 --- a/packages/block-editor/src/components/inner-blocks/index.js +++ b/packages/block-editor/src/components/inner-blocks/index.js @@ -57,7 +57,7 @@ function UncontrolledInnerBlocks( props ) { templateLock, captureToolbars, orientation, - dropZonesDisabled, + dropZonesDisabled ); useInnerBlockTemplateSync( diff --git a/packages/block-editor/src/components/inner-blocks/use-nested-settings-update.js b/packages/block-editor/src/components/inner-blocks/use-nested-settings-update.js index 9e99b8dfef3c3..bb3fbc931a6e7 100644 --- a/packages/block-editor/src/components/inner-blocks/use-nested-settings-update.js +++ b/packages/block-editor/src/components/inner-blocks/use-nested-settings-update.js @@ -34,7 +34,7 @@ export default function useNestedSettingsUpdate( templateLock, captureToolbars, orientation, - dropZonesDisabled, + dropZonesDisabled ) { const { updateBlockListSettings } = useDispatch( blockEditorStore ); diff --git a/packages/block-editor/src/components/use-block-drop-zone/index.js b/packages/block-editor/src/components/use-block-drop-zone/index.js index 39975a6be90e7..ffc17c8e776e0 100644 --- a/packages/block-editor/src/components/use-block-drop-zone/index.js +++ b/packages/block-editor/src/components/use-block-drop-zone/index.js @@ -106,7 +106,7 @@ export default function useBlockDropZone( { ); return { isDropZonesDisabled: getBlockListSettings( targetRootClientId ) - ?.dropZonesDisabled, + ?.dropZonesDisabled, isLockedAll: getTemplateLock( targetRootClientId ) === 'all', orientation: getBlockListSettings( targetRootClientId ) ?.orientation, From 92b4ba746c395d096ba152d05d8299b10596046a Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Fri, 6 Nov 2020 13:32:25 +1300 Subject: [PATCH 008/103] Revert "Lint changes" This reverts commit 9b0abccdc4dc706011e315457a95418f5325f5c1. --- packages/block-editor/src/components/inner-blocks/index.js | 2 +- .../src/components/inner-blocks/use-nested-settings-update.js | 2 +- .../block-editor/src/components/use-block-drop-zone/index.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/components/inner-blocks/index.js b/packages/block-editor/src/components/inner-blocks/index.js index b5f9585bd90d2..a8be7a24e6ff0 100644 --- a/packages/block-editor/src/components/inner-blocks/index.js +++ b/packages/block-editor/src/components/inner-blocks/index.js @@ -57,7 +57,7 @@ function UncontrolledInnerBlocks( props ) { templateLock, captureToolbars, orientation, - dropZonesDisabled + dropZonesDisabled, ); useInnerBlockTemplateSync( diff --git a/packages/block-editor/src/components/inner-blocks/use-nested-settings-update.js b/packages/block-editor/src/components/inner-blocks/use-nested-settings-update.js index bb3fbc931a6e7..9e99b8dfef3c3 100644 --- a/packages/block-editor/src/components/inner-blocks/use-nested-settings-update.js +++ b/packages/block-editor/src/components/inner-blocks/use-nested-settings-update.js @@ -34,7 +34,7 @@ export default function useNestedSettingsUpdate( templateLock, captureToolbars, orientation, - dropZonesDisabled + dropZonesDisabled, ) { const { updateBlockListSettings } = useDispatch( blockEditorStore ); diff --git a/packages/block-editor/src/components/use-block-drop-zone/index.js b/packages/block-editor/src/components/use-block-drop-zone/index.js index ffc17c8e776e0..39975a6be90e7 100644 --- a/packages/block-editor/src/components/use-block-drop-zone/index.js +++ b/packages/block-editor/src/components/use-block-drop-zone/index.js @@ -106,7 +106,7 @@ export default function useBlockDropZone( { ); return { isDropZonesDisabled: getBlockListSettings( targetRootClientId ) - ?.dropZonesDisabled, + ?.dropZonesDisabled, isLockedAll: getTemplateLock( targetRootClientId ) === 'all', orientation: getBlockListSettings( targetRootClientId ) ?.orientation, From 98e87f537a016d41d3fd3beeb1c4bea2abc2191f Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Fri, 6 Nov 2020 13:32:40 +1300 Subject: [PATCH 009/103] Revert "Disable the innerBlocks dropzones so drag drop works same as existing gallery - with the idea that we will improve the innerblocks drag and drop in a later PR" This reverts commit cc05d60627d4c4970afef73306970762f39c4785. --- packages/block-editor/src/components/inner-blocks/index.js | 4 +--- .../components/inner-blocks/use-nested-settings-update.js | 7 +------ .../src/components/use-block-drop-zone/index.js | 6 ++---- packages/block-library/src/gallery/editor.scss | 5 ----- packages/block-library/src/gallery/gallery.js | 1 - 5 files changed, 4 insertions(+), 19 deletions(-) diff --git a/packages/block-editor/src/components/inner-blocks/index.js b/packages/block-editor/src/components/inner-blocks/index.js index a8be7a24e6ff0..5485df3227af6 100644 --- a/packages/block-editor/src/components/inner-blocks/index.js +++ b/packages/block-editor/src/components/inner-blocks/index.js @@ -46,7 +46,6 @@ function UncontrolledInnerBlocks( props ) { __experimentalAppenderTagName, renderAppender, orientation, - dropZonesDisabled, placeholder, __experimentalLayout: layout = defaultLayout, } = props; @@ -56,8 +55,7 @@ function UncontrolledInnerBlocks( props ) { allowedBlocks, templateLock, captureToolbars, - orientation, - dropZonesDisabled, + orientation ); useInnerBlockTemplateSync( diff --git a/packages/block-editor/src/components/inner-blocks/use-nested-settings-update.js b/packages/block-editor/src/components/inner-blocks/use-nested-settings-update.js index 9e99b8dfef3c3..ff0f94f637cea 100644 --- a/packages/block-editor/src/components/inner-blocks/use-nested-settings-update.js +++ b/packages/block-editor/src/components/inner-blocks/use-nested-settings-update.js @@ -33,8 +33,7 @@ export default function useNestedSettingsUpdate( allowedBlocks, templateLock, captureToolbars, - orientation, - dropZonesDisabled, + orientation ) { const { updateBlockListSettings } = useDispatch( blockEditorStore ); @@ -71,9 +70,6 @@ export default function useNestedSettingsUpdate( if ( orientation !== undefined ) { newSettings.orientation = orientation; } - if ( dropZonesDisabled !== undefined ) { - newSettings.dropZonesDisabled = dropZonesDisabled; - } if ( ! isShallowEqual( blockListSettings, newSettings ) ) { updateBlockListSettings( clientId, newSettings ); @@ -86,7 +82,6 @@ export default function useNestedSettingsUpdate( parentLock, captureToolbars, orientation, - dropZonesDisabled, updateBlockListSettings, ] ); } diff --git a/packages/block-editor/src/components/use-block-drop-zone/index.js b/packages/block-editor/src/components/use-block-drop-zone/index.js index 39975a6be90e7..717907a72f484 100644 --- a/packages/block-editor/src/components/use-block-drop-zone/index.js +++ b/packages/block-editor/src/components/use-block-drop-zone/index.js @@ -99,14 +99,12 @@ export default function useBlockDropZone( { } ) { const [ targetBlockIndex, setTargetBlockIndex ] = useState( null ); - const { isLockedAll, orientation, isDropZonesDisabled } = useSelect( + const { isLockedAll, orientation } = useSelect( ( select ) => { const { getBlockListSettings, getTemplateLock } = select( blockEditorStore ); return { - isDropZonesDisabled: getBlockListSettings( targetRootClientId ) - ?.dropZonesDisabled, isLockedAll: getTemplateLock( targetRootClientId ) === 'all', orientation: getBlockListSettings( targetRootClientId ) ?.orientation, @@ -122,7 +120,7 @@ export default function useBlockDropZone( { const { position } = useDropZone( { element, - isDisabled: isLockedAll || isDropZonesDisabled, + isDisabled: isLockedAll, withPosition: true, ...dropEventHandlers, } ); diff --git a/packages/block-library/src/gallery/editor.scss b/packages/block-library/src/gallery/editor.scss index 47fb41ad04b68..a4ad23f5dad34 100644 --- a/packages/block-library/src/gallery/editor.scss +++ b/packages/block-library/src/gallery/editor.scss @@ -2,13 +2,8 @@ // Override the default list style type _only in the editor_ // to avoid :not() selector specificity issues. // See https://github.com/WordPress/gutenberg/pull/10358 - li { list-style-type: none; - .components-drop-zone { - display: none; - pointer-events: none; - } } // @todo: this deserves a refactor, by being moved to the toolbar. diff --git a/packages/block-library/src/gallery/gallery.js b/packages/block-library/src/gallery/gallery.js index 3e52e1671efbe..9d36f2e4e0137 100644 --- a/packages/block-library/src/gallery/gallery.js +++ b/packages/block-library/src/gallery/gallery.js @@ -44,7 +44,6 @@ export const Gallery = ( props ) => { }, { allowedBlocks: [ 'core/image' ], - dropZonesDisabled: true, orientation: 'horizontal', renderAppender: false, __experimentalLayout: { type: 'default', alignments: [] }, From 60eee0f390ec3108417e50a1608fe6a1fbb0a9c3 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Fri, 6 Nov 2020 16:41:51 +1300 Subject: [PATCH 010/103] Suggested solution for handling multiple file drop into gallery --- .../src/components/use-on-block-drop/index.js | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/use-on-block-drop/index.js b/packages/block-editor/src/components/use-on-block-drop/index.js index f2ee0ee1c0182..d63681cfad1de 100644 --- a/packages/block-editor/src/components/use-on-block-drop/index.js +++ b/packages/block-editor/src/components/use-on-block-drop/index.js @@ -6,7 +6,7 @@ import { getBlockTransforms, pasteHandler, } from '@wordpress/blocks'; -import { useDispatch, useSelect } from '@wordpress/data'; +import { useDispatch, useSelect, select } from '@wordpress/data'; /** * Internal dependencies @@ -161,6 +161,27 @@ export function onFilesDrop( return; } + const parentBlock = select( 'core/block-editor' ).getBlock( + targetRootClientId + ); + + if ( parentBlock?.name === 'core/gallery' && files?.length > 1 ) { + const transformation = findTransform( + getBlockTransforms( 'from' ), + ( transform ) => + transform.type === 'files' && + transform.isMatch( [ files[ 0 ] ] ) + ); + if ( transformation ) { + const blocks = files.map( ( file ) => + transformation.transform( [ file ], updateBlockAttributes ) + ); + + insertBlocks( blocks, targetBlockIndex, targetRootClientId ); + } + return; + } + const transformation = findTransform( getBlockTransforms( 'from' ), ( transform ) => From 142f3993cbd1422fe43be09fb9f513de8ae0253b Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Fri, 22 Jan 2021 11:28:20 +1300 Subject: [PATCH 011/103] Remove non image files from drag and drop and disable individual image drop zone --- .../src/components/use-on-block-drop/index.js | 9 ++++++--- packages/block-library/src/gallery/editor.scss | 18 ++++++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/packages/block-editor/src/components/use-on-block-drop/index.js b/packages/block-editor/src/components/use-on-block-drop/index.js index d63681cfad1de..4db79178b050f 100644 --- a/packages/block-editor/src/components/use-on-block-drop/index.js +++ b/packages/block-editor/src/components/use-on-block-drop/index.js @@ -165,15 +165,18 @@ export function onFilesDrop( targetRootClientId ); - if ( parentBlock?.name === 'core/gallery' && files?.length > 1 ) { + const imageFiles = files.filter( + ( file ) => file.type.indexOf( 'image/' ) === 0 + ); + if ( parentBlock?.name === 'core/gallery' && imageFiles?.length > 0 ) { const transformation = findTransform( getBlockTransforms( 'from' ), ( transform ) => transform.type === 'files' && - transform.isMatch( [ files[ 0 ] ] ) + transform.isMatch( [ imageFiles[ 0 ] ] ) ); if ( transformation ) { - const blocks = files.map( ( file ) => + const blocks = imageFiles.map( ( file ) => transformation.transform( [ file ], updateBlockAttributes ) ); diff --git a/packages/block-library/src/gallery/editor.scss b/packages/block-library/src/gallery/editor.scss index a4ad23f5dad34..899594708d923 100644 --- a/packages/block-library/src/gallery/editor.scss +++ b/packages/block-library/src/gallery/editor.scss @@ -4,6 +4,10 @@ // See https://github.com/WordPress/gutenberg/pull/10358 li { list-style-type: none; + .components-drop-zone { + display: none; + pointer-events: none; + } } // @todo: this deserves a refactor, by being moved to the toolbar. @@ -30,14 +34,17 @@ figure.wp-block-gallery { } .blocks-gallery-item { - // Hide the focus outline that otherwise briefly appears when selecting a block. - figure:not(.is-selected):focus, + figure:not( .is-selected ):focus, img:focus { outline: none; } figure.is-selected { + box-shadow: 0 0 0 $border-width $white, + 0 0 0 3px var( --wp-admin-theme-color ); + border-radius: $radius-block-ui; + outline: 2px solid transparent; &::before { box-shadow: 0 0 0 $border-width $white inset, 0 0 0 3px var(--wp-admin-theme-color) inset; @@ -79,9 +86,9 @@ figure.wp-block-gallery { position: absolute; top: -2px; margin: $grid-unit-10; - z-index: z-index(".block-library-gallery-item__inline-menu"); + z-index: z-index( '.block-library-gallery-item__inline-menu' ); transition: box-shadow 0.2s ease-out; - @include reduce-motion("transition"); + @include reduce-motion( 'transition' ); border-radius: $radius-block-ui; background: $white; border: $border-width solid $gray-900; @@ -99,7 +106,7 @@ figure.wp-block-gallery { } .components-button.has-icon { - &:not(:focus) { + &:not( :focus ) { border: none; box-shadow: none; } @@ -124,7 +131,6 @@ figure.wp-block-gallery { } } - .blocks-gallery-item .components-spinner { position: absolute; top: 50%; From b01200d75b7ce6e111e5e38cac478b0dd1ac05b3 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Mon, 9 Nov 2020 09:36:23 +1300 Subject: [PATCH 012/103] Fix transform to individual images --- .../block-library/src/gallery/transforms.js | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/packages/block-library/src/gallery/transforms.js b/packages/block-library/src/gallery/transforms.js index 19b006c2d81a7..1f6a52619b48f 100644 --- a/packages/block-library/src/gallery/transforms.js +++ b/packages/block-library/src/gallery/transforms.js @@ -122,17 +122,20 @@ const transforms = { { type: 'block', blocks: [ 'core/image' ], - transform: ( { images, align, sizeSlug, ids } ) => { - if ( images.length > 0 ) { - return images.map( ( { url, alt, caption }, index ) => - createBlock( 'core/image', { - id: ids[ index ], - url, - alt, - caption, - align, - sizeSlug, - } ) + transform: ( { align }, innerBlocks ) => { + if ( innerBlocks.length > 0 ) { + return innerBlocks.map( + ( { + attributes: { id, url, alt, caption, sizeSlug }, + } ) => + createBlock( 'core/image', { + id, + url, + alt, + caption, + sizeSlug, + align, + } ) ); } return createBlock( 'core/image', { align } ); From 35367caccf1ba624d63c52e53ecd5ff1489c9bc6 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Mon, 9 Nov 2020 09:59:40 +1300 Subject: [PATCH 013/103] Fix transform from individual images --- .../block-library/src/gallery/transforms.js | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/packages/block-library/src/gallery/transforms.js b/packages/block-library/src/gallery/transforms.js index 1f6a52619b48f..1af7f6689ee16 100644 --- a/packages/block-library/src/gallery/transforms.js +++ b/packages/block-library/src/gallery/transforms.js @@ -41,20 +41,19 @@ const transforms = { : undefined; const validImages = filter( attributes, ( { url } ) => url ); - - return createBlock( 'core/gallery', { - images: validImages.map( - ( { id, url, alt, caption } ) => ( { - id: toString( id ), - url, - alt, - caption, - } ) - ), - ids: validImages.map( ( { id } ) => parseInt( id, 10 ) ), - align, - sizeSlug, + const innerBlocks = validImages.map( ( image ) => { + return createBlock( 'core/image', image ); } ); + + return createBlock( + 'core/gallery', + { + imageCount: innerBlocks.length, + align, + sizeSlug, + }, + innerBlocks + ); }, }, { From f37b8088e5b942ec5f64ae32c8d0c6542214d315 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Tue, 10 Nov 2020 10:38:31 +1300 Subject: [PATCH 014/103] Revert drag and drop transform changes --- .../src/components/use-on-block-drop/index.js | 26 +------------------ 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/packages/block-editor/src/components/use-on-block-drop/index.js b/packages/block-editor/src/components/use-on-block-drop/index.js index 4db79178b050f..f2ee0ee1c0182 100644 --- a/packages/block-editor/src/components/use-on-block-drop/index.js +++ b/packages/block-editor/src/components/use-on-block-drop/index.js @@ -6,7 +6,7 @@ import { getBlockTransforms, pasteHandler, } from '@wordpress/blocks'; -import { useDispatch, useSelect, select } from '@wordpress/data'; +import { useDispatch, useSelect } from '@wordpress/data'; /** * Internal dependencies @@ -161,30 +161,6 @@ export function onFilesDrop( return; } - const parentBlock = select( 'core/block-editor' ).getBlock( - targetRootClientId - ); - - const imageFiles = files.filter( - ( file ) => file.type.indexOf( 'image/' ) === 0 - ); - if ( parentBlock?.name === 'core/gallery' && imageFiles?.length > 0 ) { - const transformation = findTransform( - getBlockTransforms( 'from' ), - ( transform ) => - transform.type === 'files' && - transform.isMatch( [ imageFiles[ 0 ] ] ) - ); - if ( transformation ) { - const blocks = imageFiles.map( ( file ) => - transformation.transform( [ file ], updateBlockAttributes ) - ); - - insertBlocks( blocks, targetBlockIndex, targetRootClientId ); - } - return; - } - const transformation = findTransform( getBlockTransforms( 'from' ), ( transform ) => From 48aafa4b0ae4b83e992df35d1fe3a800ccc3fba1 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Tue, 10 Nov 2020 11:10:14 +1300 Subject: [PATCH 015/103] Add gallery transform to image block to override the default gallery transform when dragging multiple images onto the gallery --- .../block-library/src/gallery/transforms.js | 1 + .../block-library/src/image/transforms.js | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/packages/block-library/src/gallery/transforms.js b/packages/block-library/src/gallery/transforms.js index 1af7f6689ee16..1d0b64d77445c 100644 --- a/packages/block-library/src/gallery/transforms.js +++ b/packages/block-library/src/gallery/transforms.js @@ -96,6 +96,7 @@ const transforms = { { // When created by drag and dropping multiple files on an insertion point type: 'files', + priority: 1, isMatch( files ) { return ( files.length !== 1 && diff --git a/packages/block-library/src/image/transforms.js b/packages/block-library/src/image/transforms.js index 80750e8601bf5..e3b39810bda7f 100644 --- a/packages/block-library/src/image/transforms.js +++ b/packages/block-library/src/image/transforms.js @@ -1,3 +1,8 @@ +/** + * External dependencies + */ +import { every } from 'lodash'; + /** * WordPress dependencies */ @@ -140,6 +145,29 @@ const transforms = { } ); }, }, + { + // When drag and dropping multiple files onto a gallery this overrrides the + // gallery transform in order to add new images to the gallery instead of + // creating a new gallery. + type: 'files', + isMatch( files ) { + return ( + files.length !== 1 && + every( + files, + ( file ) => file.type.indexOf( 'image/' ) === 0 + ) + ); + }, + transform( files ) { + const blocks = files.map( ( file ) => { + return createBlock( 'core/image', { + url: createBlobURL( file ), + } ); + } ); + return blocks; + }, + }, { type: 'shortcode', tag: 'caption', From 8113dee795a7f0129fa83b30493097a19bad0c88 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Tue, 17 Nov 2020 11:55:14 +1300 Subject: [PATCH 016/103] Move handling of file uploads to Gallery from media placeholder --- .../src/components/media-placeholder/index.js | 45 +++---------------- packages/block-library/src/gallery/edit.js | 42 +++++++++++++++-- 2 files changed, 45 insertions(+), 42 deletions(-) diff --git a/packages/block-editor/src/components/media-placeholder/index.js b/packages/block-editor/src/components/media-placeholder/index.js index c602c4ca8fea7..4cc634fcaa9e6 100644 --- a/packages/block-editor/src/components/media-placeholder/index.js +++ b/packages/block-editor/src/components/media-placeholder/index.js @@ -118,47 +118,16 @@ export function MediaPlaceholder( { }; const onFilesUpload = ( files ) => { + if ( addToGallery ) { + // Because the Gallery hands the files over to Image component InnerBlocks just + // hand the handling of the files over to the Gallery + onSelect( files ); + return; + } onFilesPreUpload( files ); let setMedia; if ( multiple ) { - if ( addToGallery ) { - // 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 = []; - setMedia = ( newMedia ) => { - // Remove any images this upload group is responsible for (lastMediaPassed). - // Their replacements are contained in newMedia. - const filteredMedia = ( value ?? [] ).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 }; - } ); - }; - } else { - setMedia = onSelect; - } + setMedia = onSelect; } else { setMedia = ( [ media ] ) => onSelect( media ); } diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index 3c343421c30c0..21143812afbd1 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { isEqual, isEmpty, find } from 'lodash'; +import { isEqual, isEmpty, find, uniqBy, concat } from 'lodash'; /** * WordPress dependencies @@ -27,6 +27,7 @@ import { useSelect, useDispatch } from '@wordpress/data'; import { withViewportMatch } from '@wordpress/viewport'; import { View } from '@wordpress/primitives'; import { createBlock } from '@wordpress/blocks'; +import { createBlobURL } from '@wordpress/blob'; /** * Internal dependencies @@ -162,8 +163,41 @@ function GalleryEdit( props ) { }; } - function onSelectImages( newImages ) { - const newBlocks = newImages.map( ( image ) => { + function onSelectImages( selectedImages ) { + const imageArray = + Object.prototype.toString.call( selectedImages ) === + '[object FileList]' + ? Array.from( selectedImages ).map( ( file ) => { + if ( ! file.url ) { + return pickRelevantMediaFiles( { + url: createBlobURL( file ), + } ); + } + + return file; + } ) + : selectedImages; + + const newImages = imageArray + .filter( + ( file ) => file.url || file.type?.indexOf( 'image/' ) === 0 + ) + .map( ( file ) => { + if ( ! file.url ) { + return pickRelevantMediaFiles( { + url: createBlobURL( file ), + } ); + } + + return file; + } ); + + const newAndExistingImages = uniqBy( + concat( newImages, images ), + 'url' + ); + + const newBlocks = newAndExistingImages.map( ( image ) => { const existingBlock = find( images, ( img ) => img.id === image.id @@ -256,7 +290,7 @@ function GalleryEdit( props ) { const mediaPlaceholder = ( Date: Tue, 17 Nov 2020 13:57:02 +1300 Subject: [PATCH 017/103] split innerblocks mapping into separate effect to reduce chatter --- packages/block-library/src/gallery/edit.js | 28 ++++++++++++---------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index 21143812afbd1..875b4b28c9fda 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -92,6 +92,7 @@ function GalleryEdit( props ) { const currentImageOptions = { linkTarget, linkTo, sizeSlug }; const [ imageSettings, setImageSettings ] = useState( currentImageOptions ); const [ dirtyImageOptions, setDirtyImageOptions ] = useState( false ); + const [ images, setImages ] = useState( [] ); useEffect( () => { const currentOptionsState = ! isEqual( @@ -111,20 +112,22 @@ function GalleryEdit( props ) { }; }, [] ); - const images = useSelect( ( select ) => { - const newImages = select( 'core/block-editor' ) - .getBlock( clientId ) - .innerBlocks.map( ( block ) => { - return { - id: block.attributes.id, - url: block.attributes.url, - attributes: block.attributes, - imageData: getMedia( block.attributes.id ), - }; - } ); - return newImages; + const innerBlockImages = useSelect( ( select ) => { + return select( 'core/block-editor' ).getBlock( clientId ).innerBlocks; } ); + useEffect( () => { + const newImages = innerBlockImages.map( ( block ) => { + return { + id: block.attributes.id, + url: block.attributes.url, + attributes: block.attributes, + imageData: getMedia( block.attributes.id ), + }; + } ); + setImages( newImages ); + }, [ innerBlockImages ] ); + useEffect( () => { if ( images.length !== imageCount ) { setAttributes( { imageCount: images.length } ); @@ -208,7 +211,6 @@ function GalleryEdit( props ) { id: image.id, } ); } ); - replaceInnerBlocks( clientId, newBlocks ); } From 7a1a78dcdbebbcaaf55d8ddae0babc2f5377c989 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 18 Nov 2020 09:59:37 +1300 Subject: [PATCH 018/103] Add useMemo to currentImageOptions --- packages/block-library/src/gallery/edit.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index 875b4b28c9fda..c3beb5cffcaf1 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -89,7 +89,14 @@ function GalleryEdit( props ) { blockEditorStore ); - const currentImageOptions = { linkTarget, linkTo, sizeSlug }; + const currentImageOptions = useMemo( + () => ( { + linkTarget, + linkTo, + sizeSlug, + } ), + [ linkTarget, linkTo, sizeSlug ] + ); const [ imageSettings, setImageSettings ] = useState( currentImageOptions ); const [ dirtyImageOptions, setDirtyImageOptions ] = useState( false ); const [ images, setImages ] = useState( [] ); From 9ed0e6a1d8c147a85b06d2788c0a394ba39013f2 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 18 Nov 2020 11:03:00 +1300 Subject: [PATCH 019/103] reuse existing innerBlocks rather than recreating with every new image selection --- .../src/components/media-placeholder/index.js | 10 +++++- packages/block-library/src/gallery/edit.js | 32 +++++++++++-------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/packages/block-editor/src/components/media-placeholder/index.js b/packages/block-editor/src/components/media-placeholder/index.js index 4cc634fcaa9e6..68a97cd6686df 100644 --- a/packages/block-editor/src/components/media-placeholder/index.js +++ b/packages/block-editor/src/components/media-placeholder/index.js @@ -117,6 +117,14 @@ export function MediaPlaceholder( { } }; + const onMediaLibrarySelection = ( files ) => { + if ( addToGallery ) { + onSelect( files, true ); + return; + } + onSelect( files ); + }; + const onFilesUpload = ( files ) => { if ( addToGallery ) { // Because the Gallery hands the files over to Image component InnerBlocks just @@ -275,7 +283,7 @@ export function MediaPlaceholder( { addToGallery={ addToGallery } gallery={ multiple && onlyAllowsImages() } multiple={ multiple } - onSelect={ onSelect } + onSelect={ onMediaLibrarySelection } allowedTypes={ allowedTypes } value={ Array.isArray( value ) diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index c3beb5cffcaf1..376e188edfc42 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { isEqual, isEmpty, find, uniqBy, concat } from 'lodash'; +import { isEqual, isEmpty, find, concat, differenceBy } from 'lodash'; /** * WordPress dependencies @@ -173,7 +173,7 @@ function GalleryEdit( props ) { }; } - function onSelectImages( selectedImages ) { + function onSelectImages( selectedImages, replace = false ) { const imageArray = Object.prototype.toString.call( selectedImages ) === '[object FileList]' @@ -188,7 +188,7 @@ function GalleryEdit( props ) { } ) : selectedImages; - const newImages = imageArray + const processedImages = imageArray .filter( ( file ) => file.url || file.type?.indexOf( 'image/' ) === 0 ) @@ -202,23 +202,27 @@ function GalleryEdit( props ) { return file; } ); - const newAndExistingImages = uniqBy( - concat( newImages, images ), - 'url' - ); + const existingImageBlocks = replace + ? innerBlockImages.filter( ( block ) => + processedImages.find( + ( img ) => img.url === block.attributes.url + ) + ) + : innerBlockImages; - const newBlocks = newAndExistingImages.map( ( image ) => { - const existingBlock = find( - images, - ( img ) => img.id === image.id - ); + const newImages = differenceBy( processedImages, images, 'url' ); + const newBlocks = newImages.map( ( image ) => { return createBlock( 'core/image', { - ...buildImageAttributes( existingBlock, image ), + ...buildImageAttributes( false, image ), id: image.id, } ); } ); - replaceInnerBlocks( clientId, newBlocks ); + + replaceInnerBlocks( + clientId, + concat( existingImageBlocks, newBlocks ) + ); } function onUploadError( message ) { From 1f205a755bad5db12da49aab649016f4c26d5fbb Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 18 Nov 2020 11:12:11 +1300 Subject: [PATCH 020/103] Switch to useMemo for updating local image const instead of local component state --- packages/block-library/src/gallery/edit.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index 376e188edfc42..1c57be240f498 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -99,7 +99,6 @@ function GalleryEdit( props ) { ); const [ imageSettings, setImageSettings ] = useState( currentImageOptions ); const [ dirtyImageOptions, setDirtyImageOptions ] = useState( false ); - const [ images, setImages ] = useState( [] ); useEffect( () => { const currentOptionsState = ! isEqual( @@ -123,17 +122,16 @@ function GalleryEdit( props ) { return select( 'core/block-editor' ).getBlock( clientId ).innerBlocks; } ); - useEffect( () => { - const newImages = innerBlockImages.map( ( block ) => { - return { + const images = useMemo( + () => + innerBlockImages.map( ( block ) => ( { id: block.attributes.id, url: block.attributes.url, attributes: block.attributes, imageData: getMedia( block.attributes.id ), - }; - } ); - setImages( newImages ); - }, [ innerBlockImages ] ); + } ) ), + [ innerBlockImages ] + ); useEffect( () => { if ( images.length !== imageCount ) { From c94c23127685e547dad57fbf4cfc568f75b12fb9 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 18 Nov 2020 11:36:21 +1300 Subject: [PATCH 021/103] Fix issue with image sizing not being available on initial load of component some times --- packages/block-library/src/gallery/edit.js | 11 +++++++++-- packages/block-library/src/gallery/use-image-sizes.js | 11 +++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index 1c57be240f498..daef668bd6272 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -139,7 +139,12 @@ function GalleryEdit( props ) { } }, [ images ] ); - const imageSizeOptions = useImageSizes( images, isSelected, getSettings ); + const imageSizeOptions = useImageSizes( + images, + isSelected, + getSettings, + getMedia + ); const { replaceInnerBlocks, updateBlockAttributes } = useDispatch( 'core/block-editor' @@ -255,7 +260,9 @@ function GalleryEdit( props ) { const image = block.attributes.id ? find( images, { id: block.attributes.id } ) : null; - + if ( ! image.imageData ) { + image.imageData = getMedia( image.id ); + } updateBlockAttributes( block.clientId, { ...getHrefAndDestination( image.imageData, linkTo ), ...getUpdatedLinkTargetSettings( linkTarget, block.attributes ), diff --git a/packages/block-library/src/gallery/use-image-sizes.js b/packages/block-library/src/gallery/use-image-sizes.js index e5888bb2e79ae..591d96e767b44 100644 --- a/packages/block-library/src/gallery/use-image-sizes.js +++ b/packages/block-library/src/gallery/use-image-sizes.js @@ -3,7 +3,12 @@ */ import { get, reduce, map, filter, some } from 'lodash'; -export default function useImageSizes( images, isSelected, getSettings ) { +export default function useImageSizes( + images, + isSelected, + getSettings, + getMedia +) { const { imageSizes } = getSettings(); let resizedImages = {}; @@ -15,7 +20,9 @@ export default function useImageSizes( images, isSelected, getSettings ) { if ( ! img.id ) { return currentResizedImages; } - const image = img.imageData; + const image = img.imageData + ? img.imageData + : getMedia( img.id ); const sizes = reduce( imageSizes, ( currentSizes, size ) => { From 3fbd034af00f68cdb47e22ca604bbc1be3955967 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 18 Nov 2020 11:52:15 +1300 Subject: [PATCH 022/103] Memoise the useImageSizes hook --- .../src/gallery/use-image-sizes.js | 98 ++++++++++--------- 1 file changed, 53 insertions(+), 45 deletions(-) diff --git a/packages/block-library/src/gallery/use-image-sizes.js b/packages/block-library/src/gallery/use-image-sizes.js index 591d96e767b44..a563663f6af9b 100644 --- a/packages/block-library/src/gallery/use-image-sizes.js +++ b/packages/block-library/src/gallery/use-image-sizes.js @@ -3,59 +3,67 @@ */ import { get, reduce, map, filter, some } from 'lodash'; +/** + * WordPress dependencies + */ +import { useMemo } from '@wordpress/element'; + export default function useImageSizes( images, isSelected, getSettings, getMedia ) { - const { imageSizes } = getSettings(); + return useMemo( () => getImageSizing(), [ images, isSelected ] ); - let resizedImages = {}; + function getImageSizing() { + const { imageSizes } = getSettings(); + let resizedImages = {}; - if ( isSelected ) { - resizedImages = reduce( - images, - ( currentResizedImages, img ) => { - if ( ! img.id ) { - return currentResizedImages; - } - const image = img.imageData - ? img.imageData - : getMedia( img.id ); - const sizes = reduce( - imageSizes, - ( currentSizes, size ) => { - const defaultUrl = get( image, [ - 'sizes', - size.slug, - 'url', - ] ); - const mediaDetailsUrl = get( image, [ - 'media_details', - 'sizes', - size.slug, - 'source_url', - ] ); - return { - ...currentSizes, - [ size.slug ]: defaultUrl || mediaDetailsUrl, - }; - }, - {} - ); - return { - ...currentResizedImages, - [ parseInt( img.id, 10 ) ]: sizes, - }; - }, - {} + if ( isSelected ) { + resizedImages = reduce( + images, + ( currentResizedImages, img ) => { + if ( ! img.id ) { + return currentResizedImages; + } + const image = img.imageData + ? img.imageData + : getMedia( img.id ); + const sizes = reduce( + imageSizes, + ( currentSizes, size ) => { + const defaultUrl = get( image, [ + 'sizes', + size.slug, + 'url', + ] ); + const mediaDetailsUrl = get( image, [ + 'media_details', + 'sizes', + size.slug, + 'source_url', + ] ); + return { + ...currentSizes, + [ size.slug ]: defaultUrl || mediaDetailsUrl, + }; + }, + {} + ); + return { + ...currentResizedImages, + [ parseInt( img.id, 10 ) ]: sizes, + }; + }, + {} + ); + } + return map( + filter( imageSizes, ( { slug } ) => + some( resizedImages, ( sizes ) => sizes[ slug ] ) + ), + ( { name, slug } ) => ( { value: slug, label: name } ) ); } - return map( - filter( imageSizes, ( { slug } ) => - some( resizedImages, ( sizes ) => sizes[ slug ] ) - ), - ( { name, slug } ) => ( { value: slug, label: name } ) - ); } From cb62535d24294be496d5f39c10444b59e59adf3a Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 18 Nov 2020 12:23:04 +1300 Subject: [PATCH 023/103] Fix issue with media browser defaulting to edit gallery view --- .../block-editor/src/components/media-placeholder/index.js | 3 ++- packages/block-library/src/gallery/edit.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/components/media-placeholder/index.js b/packages/block-editor/src/components/media-placeholder/index.js index 68a97cd6686df..d57309b69e040 100644 --- a/packages/block-editor/src/components/media-placeholder/index.js +++ b/packages/block-editor/src/components/media-placeholder/index.js @@ -63,6 +63,7 @@ export function MediaPlaceholder( { isAppender, accept, addToGallery, + isGallery = false, multiple = false, dropZoneUIOnly, disableDropZone, @@ -126,7 +127,7 @@ export function MediaPlaceholder( { }; const onFilesUpload = ( files ) => { - if ( addToGallery ) { + if ( isGallery ) { // Because the Gallery hands the files over to Image component InnerBlocks just // hand the handling of the files over to the Gallery onSelect( files ); diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index daef668bd6272..2c11b65a0615c 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -308,7 +308,8 @@ function GalleryEdit( props ) { const mediaPlaceholder = ( Date: Wed, 18 Nov 2020 12:42:31 +1300 Subject: [PATCH 024/103] Fix missed incorrect use of addToGallery --- packages/block-editor/src/components/media-placeholder/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/media-placeholder/index.js b/packages/block-editor/src/components/media-placeholder/index.js index d57309b69e040..99edaadbd16ec 100644 --- a/packages/block-editor/src/components/media-placeholder/index.js +++ b/packages/block-editor/src/components/media-placeholder/index.js @@ -119,7 +119,7 @@ export function MediaPlaceholder( { }; const onMediaLibrarySelection = ( files ) => { - if ( addToGallery ) { + if ( isGallery ) { onSelect( files, true ); return; } From b6b93ad387d64f689074036683f8b0c1e28054e5 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Thu, 19 Nov 2020 12:44:08 +1300 Subject: [PATCH 025/103] Add some extra effects for getting the imageData as the getMedia call is async so need to keep circling through the innerblocks updates until we have all the data we need --- packages/block-library/src/gallery/edit.js | 67 ++++++++++++++++--- .../src/gallery/use-image-sizes.js | 14 ++-- 2 files changed, 62 insertions(+), 19 deletions(-) diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index 2c11b65a0615c..1bbdbdadf627f 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -1,7 +1,15 @@ /** * External dependencies */ -import { isEqual, isEmpty, find, concat, differenceBy } from 'lodash'; +import { + isEqual, + isEmpty, + find, + concat, + differenceBy, + some, + every, +} from 'lodash'; /** * WordPress dependencies @@ -99,6 +107,7 @@ function GalleryEdit( props ) { ); const [ imageSettings, setImageSettings ] = useState( currentImageOptions ); const [ dirtyImageOptions, setDirtyImageOptions ] = useState( false ); + const [ imageData, setImageData ] = useState( [] ); useEffect( () => { const currentOptionsState = ! isEqual( @@ -128,11 +137,50 @@ function GalleryEdit( props ) { id: block.attributes.id, url: block.attributes.url, attributes: block.attributes, - imageData: getMedia( block.attributes.id ), } ) ), [ innerBlockImages ] ); + // Wait until all the blocks have an image id before we save the imageData array. + useEffect( () => { + if ( + innerBlockImages.length === 0 || + some( + innerBlockImages, + ( imageBlock ) => ! imageBlock.attributes.id + ) + ) { + return; + } + + const newImageData = innerBlockImages.map( ( imageBlock ) => { + return { + id: imageBlock.attributes.id, + data: getMedia( imageBlock.attributes.id ), + }; + } ); + setImageData( newImageData ); + }, [ innerBlockImages ] ); + + // The getMedia call is async so we need to keep resetting the imageData array until we + // have the imageData returned for every image. + useEffect( () => { + if ( + imageData.length === 0 || + every( imageData, ( img ) => img.data ) + ) { + return; + } + + const newImageData = imageData.map( ( img ) => { + return { + id: img.id, + data: img.data || getMedia( img.id ), + }; + } ); + setImageData( newImageData ); + }, [ imageData ] ); + useEffect( () => { if ( images.length !== imageCount ) { setAttributes( { imageCount: images.length } ); @@ -140,10 +188,9 @@ function GalleryEdit( props ) { }, [ images ] ); const imageSizeOptions = useImageSizes( - images, + imageData, isSelected, - getSettings, - getMedia + getSettings ); const { replaceInnerBlocks, updateBlockAttributes } = useDispatch( @@ -258,15 +305,15 @@ function GalleryEdit( props ) { function applyImageOptions() { getBlock( clientId ).innerBlocks.forEach( ( block ) => { const image = block.attributes.id - ? find( images, { id: block.attributes.id } ) + ? find( imageData, { id: block.attributes.id } ) : null; - if ( ! image.imageData ) { - image.imageData = getMedia( image.id ); + if ( ! image.data ) { + image.data = getMedia( image.id ); } updateBlockAttributes( block.clientId, { - ...getHrefAndDestination( image.imageData, linkTo ), + ...getHrefAndDestination( image.data, linkTo ), ...getUpdatedLinkTargetSettings( linkTarget, block.attributes ), - ...getImageSizeAttributes( image.imageData, sizeSlug ), + ...getImageSizeAttributes( image.data, sizeSlug ), } ); } ); setDirtyImageOptions( false ); diff --git a/packages/block-library/src/gallery/use-image-sizes.js b/packages/block-library/src/gallery/use-image-sizes.js index a563663f6af9b..cd41e7e54a8a8 100644 --- a/packages/block-library/src/gallery/use-image-sizes.js +++ b/packages/block-library/src/gallery/use-image-sizes.js @@ -8,15 +8,13 @@ import { get, reduce, map, filter, some } from 'lodash'; */ import { useMemo } from '@wordpress/element'; -export default function useImageSizes( - images, - isSelected, - getSettings, - getMedia -) { +export default function useImageSizes( images, isSelected, getSettings ) { return useMemo( () => getImageSizing(), [ images, isSelected ] ); function getImageSizing() { + if ( some( images, ( img ) => ! img.data ) ) { + return []; + } const { imageSizes } = getSettings(); let resizedImages = {}; @@ -27,9 +25,7 @@ export default function useImageSizes( if ( ! img.id ) { return currentResizedImages; } - const image = img.imageData - ? img.imageData - : getMedia( img.id ); + const image = img.data; const sizes = reduce( imageSizes, ( currentSizes, size ) => { From 9494b74c33504be3f4ba1121153fe8c3fe708094 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Thu, 19 Nov 2020 14:51:36 +1300 Subject: [PATCH 026/103] Simplify the imageData by using a useSelect --- packages/block-library/src/gallery/edit.js | 76 ++++++------------- .../src/gallery/use-image-sizes.js | 6 +- 2 files changed, 28 insertions(+), 54 deletions(-) diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index 1bbdbdadf627f..611b8cbb9f10d 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -1,15 +1,7 @@ /** * External dependencies */ -import { - isEqual, - isEmpty, - find, - concat, - differenceBy, - some, - every, -} from 'lodash'; +import { isEqual, isEmpty, find, concat, differenceBy, some } from 'lodash'; /** * WordPress dependencies @@ -107,7 +99,6 @@ function GalleryEdit( props ) { ); const [ imageSettings, setImageSettings ] = useState( currentImageOptions ); const [ dirtyImageOptions, setDirtyImageOptions ] = useState( false ); - const [ imageData, setImageData ] = useState( [] ); useEffect( () => { const currentOptionsState = ! isEqual( @@ -119,11 +110,10 @@ function GalleryEdit( props ) { } }, [ currentImageOptions, imageSettings ] ); - const { getBlock, getMedia, getSettings } = useSelect( ( select ) => { + const { getBlock, getSettings } = useSelect( ( select ) => { return { getBlock: select( 'core/block-editor' ).getBlock, getSettings: select( 'core/block-editor' ).getSettings, - getMedia: select( 'core' ).getMedia, }; }, [] ); @@ -141,45 +131,28 @@ function GalleryEdit( props ) { [ innerBlockImages ] ); - // Wait until all the blocks have an image id before we save the imageData array. - useEffect( () => { - if ( - innerBlockImages.length === 0 || - some( - innerBlockImages, - ( imageBlock ) => ! imageBlock.attributes.id - ) - ) { - return; - } - - const newImageData = innerBlockImages.map( ( imageBlock ) => { - return { - id: imageBlock.attributes.id, - data: getMedia( imageBlock.attributes.id ), - }; - } ); - setImageData( newImageData ); - }, [ innerBlockImages ] ); - - // The getMedia call is async so we need to keep resetting the imageData array until we - // have the imageData returned for every image. - useEffect( () => { - if ( - imageData.length === 0 || - every( imageData, ( img ) => img.data ) - ) { - return; - } + const imageData = useSelect( + ( select ) => { + if ( + innerBlockImages.length === 0 || + some( + innerBlockImages, + ( imageBlock ) => ! imageBlock.attributes.id + ) + ) { + return imageData; + } - const newImageData = imageData.map( ( img ) => { - return { - id: img.id, - data: img.data || getMedia( img.id ), - }; - } ); - setImageData( newImageData ); - }, [ imageData ] ); + const getMedia = select( 'core' ).getMedia; + return innerBlockImages.map( ( imageBlock ) => { + return { + id: imageBlock.attributes.id, + data: getMedia( imageBlock.attributes.id ), + }; + } ); + }, + [ innerBlockImages ] + ); useEffect( () => { if ( images.length !== imageCount ) { @@ -307,9 +280,6 @@ function GalleryEdit( props ) { const image = block.attributes.id ? find( imageData, { id: block.attributes.id } ) : null; - if ( ! image.data ) { - image.data = getMedia( image.id ); - } updateBlockAttributes( block.clientId, { ...getHrefAndDestination( image.data, linkTo ), ...getUpdatedLinkTargetSettings( linkTarget, block.attributes ), diff --git a/packages/block-library/src/gallery/use-image-sizes.js b/packages/block-library/src/gallery/use-image-sizes.js index cd41e7e54a8a8..dd6de3dcc8ea5 100644 --- a/packages/block-library/src/gallery/use-image-sizes.js +++ b/packages/block-library/src/gallery/use-image-sizes.js @@ -12,7 +12,11 @@ export default function useImageSizes( images, isSelected, getSettings ) { return useMemo( () => getImageSizing(), [ images, isSelected ] ); function getImageSizing() { - if ( some( images, ( img ) => ! img.data ) ) { + if ( + ! images || + images.length === 0 || + some( images, ( img ) => ! img.data ) + ) { return []; } const { imageSizes } = getSettings(); From 9c148fdead044d7860984328e1388bb3619fb295 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Thu, 19 Nov 2020 15:37:47 +1300 Subject: [PATCH 027/103] Another optimisation - only return a new imageData reference if all images have data resolved --- packages/block-library/src/gallery/edit.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index 611b8cbb9f10d..281e4ccfd8a2f 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -1,7 +1,15 @@ /** * External dependencies */ -import { isEqual, isEmpty, find, concat, differenceBy, some } from 'lodash'; +import { + isEqual, + isEmpty, + find, + concat, + differenceBy, + some, + every, +} from 'lodash'; /** * WordPress dependencies @@ -144,12 +152,18 @@ function GalleryEdit( props ) { } const getMedia = select( 'core' ).getMedia; - return innerBlockImages.map( ( imageBlock ) => { + const newImageData = innerBlockImages.map( ( imageBlock ) => { return { id: imageBlock.attributes.id, data: getMedia( imageBlock.attributes.id ), }; } ); + + if ( every( newImageData, ( img ) => img.data ) ) { + return newImageData; + } + + return imageData; }, [ innerBlockImages ] ); From 924dae094480768967c96e4120dd526510d2f409 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Fri, 20 Nov 2020 05:08:11 +1000 Subject: [PATCH 028/103] Refactored Gallery: Add loading state to gallery image size options (#27087) * Add loading spinner for image size options Co-authored-by: Glen Davies --- packages/block-library/src/gallery/edit.js | 20 +++++++++--- .../block-library/src/gallery/editor.scss | 31 +++++++++++++++---- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index 281e4ccfd8a2f..13e9fb2adf97f 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -16,12 +16,14 @@ import { */ import { compose } from '@wordpress/compose'; import { + BaseControl, Button, PanelBody, SelectControl, ToggleControl, withNotices, RangeControl, + Spinner, } from '@wordpress/components'; import { MediaPlaceholder, @@ -364,7 +366,7 @@ function GalleryEdit( props ) { return { mediaPlaceholder }; } - const shouldShowSizeOptions = hasImages && ! isEmpty( imageSizeOptions ); + const shouldShowSizeOptions = ! isEmpty( imageSizeOptions ); const hasLinkTo = linkTo && linkTo !== 'none'; return ( @@ -401,16 +403,26 @@ function GalleryEdit( props ) { onChange={ toggleOpenInNewTab } /> ) } - { shouldShowSizeOptions && ( + { shouldShowSizeOptions ? ( + ) : ( + + + { __( 'Image size' ) } + + + + { __( 'Loading options…' ) } + + ) } { dirtyImageOptions && ( -
        + @@ -421,7 +433,7 @@ function GalleryEdit( props ) { > { __( 'Cancel' ) } -
        + ) } diff --git a/packages/block-library/src/gallery/editor.scss b/packages/block-library/src/gallery/editor.scss index 899594708d923..402cab6eca2e5 100644 --- a/packages/block-library/src/gallery/editor.scss +++ b/packages/block-library/src/gallery/editor.scss @@ -35,14 +35,15 @@ figure.wp-block-gallery { .blocks-gallery-item { // Hide the focus outline that otherwise briefly appears when selecting a block. - figure:not( .is-selected ):focus, + figure:not(.is-selected):focus, img:focus { outline: none; } figure.is-selected { - box-shadow: 0 0 0 $border-width $white, - 0 0 0 3px var( --wp-admin-theme-color ); + box-shadow: + 0 0 0 $border-width $white, + 0 0 0 3px var(--wp-admin-theme-color); border-radius: $radius-block-ui; outline: 2px solid transparent; @@ -86,9 +87,9 @@ figure.wp-block-gallery { position: absolute; top: -2px; margin: $grid-unit-10; - z-index: z-index( '.block-library-gallery-item__inline-menu' ); + z-index: z-index(".block-library-gallery-item__inline-menu"); transition: box-shadow 0.2s ease-out; - @include reduce-motion( 'transition' ); + @include reduce-motion( "transition" ); border-radius: $radius-block-ui; background: $white; border: $border-width solid $gray-900; @@ -106,7 +107,7 @@ figure.wp-block-gallery { } .components-button.has-icon { - &:not( :focus ) { + &:not(:focus) { border: none; box-shadow: none; } @@ -144,3 +145,21 @@ figure.wp-block-gallery { margin-right: 8px; } } + +.gallery-image-sizes { + .components-base-control__label { + display: block; + margin-bottom: 4px; + } + + .gallery-image-sizes__loading { + display: flex; + align-items: center; + color: $gray-700; + font-size: $helptext-font-size; + } + + .components-spinner { + margin: 0 8px 0 4px; + } +} From 2487d7100de6f56cd4e6441b289c1b232480e611 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 13 Jan 2021 13:52:02 +1300 Subject: [PATCH 029/103] Initial deprecations commit --- .../block-library/src/gallery/deprecated.js | 1696 +++++++++-------- 1 file changed, 877 insertions(+), 819 deletions(-) diff --git a/packages/block-library/src/gallery/deprecated.js b/packages/block-library/src/gallery/deprecated.js index 84bc9fca5bd97..057dae47228b4 100644 --- a/packages/block-library/src/gallery/deprecated.js +++ b/packages/block-library/src/gallery/deprecated.js @@ -7,832 +7,890 @@ import { map, some } from 'lodash'; /** * WordPress dependencies */ -import { RichText } from '@wordpress/block-editor'; +import { RichText, useBlockProps } from '@wordpress/block-editor'; +import { createBlock } from '@wordpress/blocks'; /** * Internal dependencies */ import { defaultColumnsNumber } from './shared'; +import { + LINK_DESTINATION_ATTACHMENT, + LINK_DESTINATION_MEDIA, +} from './constants'; +import { getHrefAndDestination } from './utils'; const deprecated = [ - // Just temporarily comment these out until new structure is finalised - // { - // attributes: { - // images: { - // type: 'array', - // default: [], - // source: 'query', - // selector: '.blocks-gallery-item', - // query: { - // url: { - // type: 'string', - // source: 'attribute', - // selector: 'img', - // attribute: 'src', - // }, - // fullUrl: { - // type: 'string', - // source: 'attribute', - // selector: 'img', - // attribute: 'data-full-url', - // }, - // link: { - // type: 'string', - // source: 'attribute', - // selector: 'img', - // attribute: 'data-link', - // }, - // alt: { - // type: 'string', - // source: 'attribute', - // selector: 'img', - // attribute: 'alt', - // default: '', - // }, - // id: { - // type: 'string', - // source: 'attribute', - // selector: 'img', - // attribute: 'data-id', - // }, - // caption: { - // type: 'string', - // source: 'html', - // selector: '.blocks-gallery-item__caption', - // }, - // }, - // }, - // ids: { - // type: 'array', - // items: { - // type: 'number', - // }, - // default: [], - // }, - // columns: { - // type: 'number', - // minimum: 1, - // maximum: 8, - // }, - // caption: { - // type: 'string', - // source: 'html', - // selector: '.blocks-gallery-caption', - // }, - // imageCrop: { - // type: 'boolean', - // default: true, - // }, - // linkTo: { - // type: 'string', - // }, - // sizeSlug: { - // type: 'string', - // default: 'large', - // }, - // }, - // save( { attributes } ) { - // const { - // images, - // columns = defaultColumnsNumber( attributes ), - // imageCrop, - // caption, - // linkTo, - // } = attributes; - // return ( - //
        - //
          - // { images.map( ( image ) => { - // let href; - // switch ( linkTo ) { - // case LINK_DESTINATION_MEDIA: - // href = image.fullUrl || image.url; - // break; - // case LINK_DESTINATION_ATTACHMENT: - // href = image.link; - // break; - // } - // const img = ( - // { - // ); - // return ( - //
        • - //
          - // { href ? ( - // { img } - // ) : ( - // img - // ) } - // { ! RichText.isEmpty( - // image.caption - // ) && ( - // - // ) } - //
          - //
        • - // ); - // } ) } - //
        - // { ! RichText.isEmpty( caption ) && ( - // - // ) } - //
        - // ); - // }, - // }, - // { - // attributes: { - // images: { - // type: 'array', - // default: [], - // source: 'query', - // selector: '.blocks-gallery-item', - // query: { - // url: { - // type: 'string', - // source: 'attribute', - // selector: 'img', - // attribute: 'src', - // }, - // fullUrl: { - // type: 'string', - // source: 'attribute', - // selector: 'img', - // attribute: 'data-full-url', - // }, - // link: { - // type: 'string', - // source: 'attribute', - // selector: 'img', - // attribute: 'data-link', - // }, - // alt: { - // type: 'string', - // source: 'attribute', - // selector: 'img', - // attribute: 'alt', - // default: '', - // }, - // id: { - // type: 'string', - // source: 'attribute', - // selector: 'img', - // attribute: 'data-id', - // }, - // caption: { - // type: 'string', - // source: 'html', - // selector: '.blocks-gallery-item__caption', - // }, - // }, - // }, - // ids: { - // type: 'array', - // items: { - // type: 'number', - // }, - // default: [], - // }, - // columns: { - // type: 'number', - // minimum: 1, - // maximum: 8, - // }, - // caption: { - // type: 'string', - // source: 'html', - // selector: '.blocks-gallery-caption', - // }, - // imageCrop: { - // type: 'boolean', - // default: true, - // }, - // linkTo: { - // type: 'string', - // default: 'none', - // }, - // sizeSlug: { - // type: 'string', - // default: 'large', - // }, - // }, - // supports: { - // align: true, - // }, - // isEligible( { linkTo } ) { - // return ! linkTo || linkTo === 'attachment' || linkTo === 'media'; - // }, - // migrate( attributes ) { - // let linkTo = attributes.linkTo; - // if ( ! attributes.linkTo ) { - // linkTo = 'none'; - // } else if ( attributes.linkTo === 'attachment' ) { - // linkTo = 'post'; - // } else if ( attributes.linkTo === 'media' ) { - // linkTo = 'file'; - // } - // return { - // ...attributes, - // linkTo, - // }; - // }, - // save( { attributes } ) { - // const { - // images, - // columns = defaultColumnsNumber( attributes ), - // imageCrop, - // caption, - // linkTo, - // } = attributes; - // return ( - //
        - //
          - // { images.map( ( image ) => { - // let href; - // switch ( linkTo ) { - // case 'media': - // href = image.fullUrl || image.url; - // break; - // case 'attachment': - // href = image.link; - // break; - // } - // const img = ( - // { - // ); - // return ( - //
        • - //
          - // { href ? ( - // { img } - // ) : ( - // img - // ) } - // { ! RichText.isEmpty( - // image.caption - // ) && ( - // - // ) } - //
          - //
        • - // ); - // } ) } - //
        - // { ! RichText.isEmpty( caption ) && ( - // - // ) } - //
        - // ); - // }, - // }, - // { - // attributes: { - // images: { - // type: 'array', - // default: [], - // source: 'query', - // selector: '.blocks-gallery-item', - // query: { - // url: { - // source: 'attribute', - // selector: 'img', - // attribute: 'src', - // }, - // fullUrl: { - // source: 'attribute', - // selector: 'img', - // attribute: 'data-full-url', - // }, - // link: { - // source: 'attribute', - // selector: 'img', - // attribute: 'data-link', - // }, - // alt: { - // source: 'attribute', - // selector: 'img', - // attribute: 'alt', - // default: '', - // }, - // id: { - // source: 'attribute', - // selector: 'img', - // attribute: 'data-id', - // }, - // caption: { - // type: 'string', - // source: 'html', - // selector: '.blocks-gallery-item__caption', - // }, - // }, - // }, - // ids: { - // type: 'array', - // default: [], - // }, - // columns: { - // type: 'number', - // }, - // caption: { - // type: 'string', - // source: 'html', - // selector: '.blocks-gallery-caption', - // }, - // imageCrop: { - // type: 'boolean', - // default: true, - // }, - // linkTo: { - // type: 'string', - // default: 'none', - // }, - // }, - // supports: { - // align: true, - // }, - // isEligible( { ids } ) { - // return ids && ids.some( ( id ) => typeof id === 'string' ); - // }, - // migrate( attributes ) { - // return { - // ...attributes, - // ids: map( attributes.ids, ( id ) => { - // const parsedId = parseInt( id, 10 ); - // return Number.isInteger( parsedId ) ? parsedId : null; - // } ), - // }; - // }, - // save( { attributes } ) { - // const { - // images, - // columns = defaultColumnsNumber( attributes ), - // imageCrop, - // caption, - // linkTo, - // } = attributes; - // return ( - //
        - //
          - // { images.map( ( image ) => { - // let href; - // switch ( linkTo ) { - // case 'media': - // href = image.fullUrl || image.url; - // break; - // case 'attachment': - // href = image.link; - // break; - // } - // const img = ( - // { - // ); - // return ( - //
        • - //
          - // { href ? ( - // { img } - // ) : ( - // img - // ) } - // { ! RichText.isEmpty( - // image.caption - // ) && ( - // - // ) } - //
          - //
        • - // ); - // } ) } - //
        - // { ! RichText.isEmpty( caption ) && ( - // - // ) } - //
        - // ); - // }, - // }, - // { - // attributes: { - // images: { - // type: 'array', - // default: [], - // source: 'query', - // selector: 'ul.wp-block-gallery .blocks-gallery-item', - // query: { - // url: { - // source: 'attribute', - // selector: 'img', - // attribute: 'src', - // }, - // fullUrl: { - // source: 'attribute', - // selector: 'img', - // attribute: 'data-full-url', - // }, - // alt: { - // source: 'attribute', - // selector: 'img', - // attribute: 'alt', - // default: '', - // }, - // id: { - // source: 'attribute', - // selector: 'img', - // attribute: 'data-id', - // }, - // link: { - // source: 'attribute', - // selector: 'img', - // attribute: 'data-link', - // }, - // caption: { - // type: 'array', - // source: 'children', - // selector: 'figcaption', - // }, - // }, - // }, - // ids: { - // type: 'array', - // default: [], - // }, - // columns: { - // type: 'number', - // }, - // imageCrop: { - // type: 'boolean', - // default: true, - // }, - // linkTo: { - // type: 'string', - // default: 'none', - // }, - // }, - // supports: { - // align: true, - // }, - // save( { attributes } ) { - // const { - // images, - // columns = defaultColumnsNumber( attributes ), - // imageCrop, - // linkTo, - // } = attributes; - // return ( - //
          - // { images.map( ( image ) => { - // let href; - // switch ( linkTo ) { - // case 'media': - // href = image.fullUrl || image.url; - // break; - // case 'attachment': - // href = image.link; - // break; - // } - // const img = ( - // { - // ); - // return ( - //
        • - //
          - // { href ? ( - // { img } - // ) : ( - // img - // ) } - // { image.caption && - // image.caption.length > 0 && ( - // - // ) } - //
          - //
        • - // ); - // } ) } - //
        - // ); - // }, - // }, - // { - // attributes: { - // images: { - // type: 'array', - // default: [], - // source: 'query', - // selector: 'ul.wp-block-gallery .blocks-gallery-item', - // query: { - // url: { - // source: 'attribute', - // selector: 'img', - // attribute: 'src', - // }, - // alt: { - // source: 'attribute', - // selector: 'img', - // attribute: 'alt', - // default: '', - // }, - // id: { - // source: 'attribute', - // selector: 'img', - // attribute: 'data-id', - // }, - // link: { - // source: 'attribute', - // selector: 'img', - // attribute: 'data-link', - // }, - // caption: { - // type: 'array', - // source: 'children', - // selector: 'figcaption', - // }, - // }, - // }, - // columns: { - // type: 'number', - // }, - // imageCrop: { - // type: 'boolean', - // default: true, - // }, - // linkTo: { - // type: 'string', - // default: 'none', - // }, - // }, - // isEligible( { images, ids } ) { - // return ( - // images && - // images.length > 0 && - // ( ( ! ids && images ) || - // ( ids && images && ids.length !== images.length ) || - // some( images, ( id, index ) => { - // if ( ! id && ids[ index ] !== null ) { - // return true; - // } - // return parseInt( id, 10 ) !== ids[ index ]; - // } ) ) - // ); - // }, - // migrate( attributes ) { - // return { - // ...attributes, - // ids: map( attributes.images, ( { id } ) => { - // if ( ! id ) { - // return null; - // } - // return parseInt( id, 10 ); - // } ), - // }; - // }, - // supports: { - // align: true, - // }, - // save( { attributes } ) { - // const { - // images, - // columns = defaultColumnsNumber( attributes ), - // imageCrop, - // linkTo, - // } = attributes; - // return ( - //
          - // { images.map( ( image ) => { - // let href; - // switch ( linkTo ) { - // case 'media': - // href = image.url; - // break; - // case 'attachment': - // href = image.link; - // break; - // } - // const img = ( - // { - // ); - // return ( - //
        • - //
          - // { href ? ( - // { img } - // ) : ( - // img - // ) } - // { image.caption && - // image.caption.length > 0 && ( - // - // ) } - //
          - //
        • - // ); - // } ) } - //
        - // ); - // }, - // }, - // { - // attributes: { - // images: { - // type: 'array', - // default: [], - // source: 'query', - // selector: - // 'div.wp-block-gallery figure.blocks-gallery-image img', - // query: { - // url: { - // source: 'attribute', - // attribute: 'src', - // }, - // alt: { - // source: 'attribute', - // attribute: 'alt', - // default: '', - // }, - // id: { - // source: 'attribute', - // attribute: 'data-id', - // }, - // }, - // }, - // columns: { - // type: 'number', - // }, - // imageCrop: { - // type: 'boolean', - // default: true, - // }, - // linkTo: { - // type: 'string', - // default: 'none', - // }, - // align: { - // type: 'string', - // default: 'none', - // }, - // }, - // supports: { - // align: true, - // }, - // save( { attributes } ) { - // const { - // images, - // columns = defaultColumnsNumber( attributes ), - // align, - // imageCrop, - // linkTo, - // } = attributes; - // const className = classnames( `columns-${ columns }`, { - // alignnone: align === 'none', - // 'is-cropped': imageCrop, - // } ); - // return ( - //
        - // { images.map( ( image ) => { - // let href; - // switch ( linkTo ) { - // case 'media': - // href = image.url; - // break; - // case 'attachment': - // href = image.link; - // break; - // } - // const img = ( - // { - // ); - // return ( - //
        - // { href ? { img } : img } - //
        - // ); - // } ) } - //
        - // ); - // }, - // }, + { + attributes: { + images: { + type: 'array', + default: [], + source: 'query', + selector: '.blocks-gallery-item', + query: { + url: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'src', + }, + fullUrl: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'data-full-url', + }, + link: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'data-link', + }, + alt: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'alt', + default: '', + }, + id: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'data-id', + }, + caption: { + type: 'string', + source: 'html', + selector: '.blocks-gallery-item__caption', + }, + }, + }, + ids: { + type: 'array', + items: { + type: 'number', + }, + default: [], + }, + columns: { + type: 'number', + minimum: 1, + maximum: 8, + }, + caption: { + type: 'string', + source: 'html', + selector: '.blocks-gallery-caption', + }, + imageCrop: { + type: 'boolean', + default: true, + }, + linkTo: { + type: 'string', + default: 'none', + }, + sizeSlug: { + type: 'string', + default: 'large', + }, + }, + supports: { + align: true, + }, + isEligible( { linkTo } ) { + return ! linkTo || linkTo === 'attachment' || linkTo === 'media'; + }, + migrate( attributes ) { + let linkTo = attributes.linkTo; + if ( ! attributes.linkTo ) { + linkTo = 'none'; + } else if ( attributes.linkTo === 'attachment' ) { + linkTo = 'post'; + } else if ( attributes.linkTo === 'media' ) { + linkTo = 'file'; + } + return { + ...attributes, + linkTo, + }; + }, + save( { attributes } ) { + const { + images, + columns = defaultColumnsNumber( attributes.images.length ), + imageCrop, + caption, + linkTo, + } = attributes; + + return ( +
        +
          + { images.map( ( image ) => { + let href; + + switch ( linkTo ) { + case 'media': + href = image.fullUrl || image.url; + break; + case 'attachment': + href = image.link; + break; + } + + const img = ( + { + ); + + return ( +
        • +
          + { href ? ( + { img } + ) : ( + img + ) } + { ! RichText.isEmpty( + image.caption + ) && ( + + ) } +
          +
        • + ); + } ) } +
        + { ! RichText.isEmpty( caption ) && ( + + ) } +
        + ); + }, + }, + { + attributes: { + images: { + type: 'array', + default: [], + source: 'query', + selector: '.blocks-gallery-item', + query: { + url: { + source: 'attribute', + selector: 'img', + attribute: 'src', + }, + fullUrl: { + source: 'attribute', + selector: 'img', + attribute: 'data-full-url', + }, + link: { + source: 'attribute', + selector: 'img', + attribute: 'data-link', + }, + alt: { + source: 'attribute', + selector: 'img', + attribute: 'alt', + default: '', + }, + id: { + source: 'attribute', + selector: 'img', + attribute: 'data-id', + }, + caption: { + type: 'string', + source: 'html', + selector: '.blocks-gallery-item__caption', + }, + }, + }, + ids: { + type: 'array', + default: [], + }, + columns: { + type: 'number', + }, + caption: { + type: 'string', + source: 'html', + selector: '.blocks-gallery-caption', + }, + imageCrop: { + type: 'boolean', + default: true, + }, + linkTo: { + type: 'string', + default: 'none', + }, + }, + supports: { + align: true, + }, + isEligible( { ids } ) { + return ids && ids.some( ( id ) => typeof id === 'string' ); + }, + migrate( attributes ) { + return { + ...attributes, + ids: map( attributes.ids, ( id ) => { + const parsedId = parseInt( id, 10 ); + return Number.isInteger( parsedId ) ? parsedId : null; + } ), + }; + }, + save( { attributes } ) { + const { + images, + columns = defaultColumnsNumber( attributes?.images.length ), + imageCrop, + caption, + linkTo, + } = attributes; + + return ( +
        +
          + { images.map( ( image ) => { + let href; + + switch ( linkTo ) { + case 'media': + href = image.fullUrl || image.url; + break; + case 'attachment': + href = image.link; + break; + } + + const img = ( + { + ); + + return ( +
        • +
          + { href ? ( + { img } + ) : ( + img + ) } + { ! RichText.isEmpty( + image.caption + ) && ( + + ) } +
          +
        • + ); + } ) } +
        + { ! RichText.isEmpty( caption ) && ( + + ) } +
        + ); + }, + }, + { + attributes: { + images: { + type: 'array', + default: [], + source: 'query', + selector: 'ul.wp-block-gallery .blocks-gallery-item', + query: { + url: { + source: 'attribute', + selector: 'img', + attribute: 'src', + }, + fullUrl: { + source: 'attribute', + selector: 'img', + attribute: 'data-full-url', + }, + alt: { + source: 'attribute', + selector: 'img', + attribute: 'alt', + default: '', + }, + id: { + source: 'attribute', + selector: 'img', + attribute: 'data-id', + }, + link: { + source: 'attribute', + selector: 'img', + attribute: 'data-link', + }, + caption: { + type: 'array', + source: 'children', + selector: 'figcaption', + }, + }, + }, + ids: { + type: 'array', + default: [], + }, + columns: { + type: 'number', + }, + imageCrop: { + type: 'boolean', + default: true, + }, + linkTo: { + type: 'string', + default: 'none', + }, + }, + supports: { + align: true, + }, + save( { attributes } ) { + const { + images, + columns = defaultColumnsNumber( attributes?.images.length ), + imageCrop, + linkTo, + } = attributes; + return ( +
          + { images.map( ( image ) => { + let href; + + switch ( linkTo ) { + case 'media': + href = image.fullUrl || image.url; + break; + case 'attachment': + href = image.link; + break; + } + + const img = ( + { + ); + + return ( +
        • +
          + { href ? ( + { img } + ) : ( + img + ) } + { image.caption && + image.caption.length > 0 && ( + + ) } +
          +
        • + ); + } ) } +
        + ); + }, + }, + { + attributes: { + images: { + type: 'array', + default: [], + source: 'query', + selector: 'ul.wp-block-gallery .blocks-gallery-item', + query: { + url: { + source: 'attribute', + selector: 'img', + attribute: 'src', + }, + alt: { + source: 'attribute', + selector: 'img', + attribute: 'alt', + default: '', + }, + id: { + source: 'attribute', + selector: 'img', + attribute: 'data-id', + }, + link: { + source: 'attribute', + selector: 'img', + attribute: 'data-link', + }, + caption: { + type: 'array', + source: 'children', + selector: 'figcaption', + }, + }, + }, + columns: { + type: 'number', + }, + imageCrop: { + type: 'boolean', + default: true, + }, + linkTo: { + type: 'string', + default: 'none', + }, + }, + isEligible( { images, ids } ) { + return ( + images && + images.length > 0 && + ( ( ! ids && images ) || + ( ids && images && ids.length !== images.length ) || + some( images, ( id, index ) => { + if ( ! id && ids[ index ] !== null ) { + return true; + } + return parseInt( id, 10 ) !== ids[ index ]; + } ) ) + ); + }, + migrate( attributes ) { + return { + ...attributes, + ids: map( attributes.images, ( { id } ) => { + if ( ! id ) { + return null; + } + return parseInt( id, 10 ); + } ), + }; + }, + supports: { + align: true, + }, + save( { attributes } ) { + const { + images, + columns = defaultColumnsNumber( attributes?.images.length ), + imageCrop, + linkTo, + } = attributes; + return ( +
          + { images.map( ( image ) => { + let href; + + switch ( linkTo ) { + case 'media': + href = image.url; + break; + case 'attachment': + href = image.link; + break; + } + + const img = ( + { + ); + + return ( +
        • +
          + { href ? ( + { img } + ) : ( + img + ) } + { image.caption && + image.caption.length > 0 && ( + + ) } +
          +
        • + ); + } ) } +
        + ); + }, + }, + { + attributes: { + images: { + type: 'array', + default: [], + source: 'query', + selector: + 'div.wp-block-gallery figure.blocks-gallery-image img', + query: { + url: { + source: 'attribute', + attribute: 'src', + }, + alt: { + source: 'attribute', + attribute: 'alt', + default: '', + }, + id: { + source: 'attribute', + attribute: 'data-id', + }, + }, + }, + columns: { + type: 'number', + }, + imageCrop: { + type: 'boolean', + default: true, + }, + linkTo: { + type: 'string', + default: 'none', + }, + align: { + type: 'string', + default: 'none', + }, + }, + supports: { + align: true, + }, + save( { attributes } ) { + const { + images, + columns = defaultColumnsNumber( attributes?.images.length ), + align, + imageCrop, + linkTo, + } = attributes; + const className = classnames( `columns-${ columns }`, { + alignnone: align === 'none', + 'is-cropped': imageCrop, + } ); + return ( +
        + { images.map( ( image ) => { + let href; + + switch ( linkTo ) { + case 'media': + href = image.url; + break; + case 'attachment': + href = image.link; + break; + } + + const img = ( + { + ); + + return ( +
        + { href ? { img } : img } +
        + ); + } ) } +
        + ); + }, + }, + { + attributes: { + images: { + type: 'array', + default: [], + source: 'query', + selector: '.blocks-gallery-item', + query: { + url: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'src', + }, + fullUrl: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'data-full-url', + }, + link: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'data-link', + }, + alt: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'alt', + default: '', + }, + id: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'data-id', + }, + caption: { + type: 'string', + source: 'html', + selector: '.blocks-gallery-item__caption', + }, + }, + }, + ids: { + type: 'array', + items: { + type: 'number', + }, + default: [], + }, + columns: { + type: 'number', + minimum: 1, + maximum: 8, + }, + caption: { + type: 'string', + source: 'html', + selector: '.blocks-gallery-caption', + }, + imageCrop: { + type: 'boolean', + default: true, + }, + linkTo: { + type: 'string', + }, + sizeSlug: { + type: 'string', + default: 'large', + }, + }, + supports: { + anchor: true, + align: true, + }, + save( { attributes } ) { + const { + images, + columns = defaultColumnsNumber( attributes?.images.length ), + imageCrop, + caption, + linkTo, + } = attributes; + const className = `columns-${ columns } ${ + imageCrop ? 'is-cropped' : '' + }`; + + return ( +
        +
          + { images.map( ( image ) => { + let href; + + switch ( linkTo ) { + case LINK_DESTINATION_MEDIA: + href = image.fullUrl || image.url; + break; + case LINK_DESTINATION_ATTACHMENT: + href = image.link; + break; + } + + const img = ( + { + ); + + return ( +
        • +
          + { href ? ( + { img } + ) : ( + img + ) } + { ! RichText.isEmpty( + image.caption + ) && ( + + ) } +
          +
        • + ); + } ) } +
        + { ! RichText.isEmpty( caption ) && ( + + ) } +
        + ); + }, + isEligible( { ids } ) { + return !! ids; + }, + migrate( { images, imageCrop, linkTo, sizeSlug } ) { + const imageBlocks = images.map( ( image ) => { + const { linkDestination } = getHrefAndDestination( + image, + linkTo + ); + return createBlock( 'core/image', { + id: parseInt( image.id ), + url: image.url, + alt: image.alt, + caption: image.caption, + sizeSlug, + linkDestination, + } ); + } ); + return [ + { + imageCrop, + linkTo, + sizeSlug, + imageCount: imageBlocks.length, + isListItem: true, + }, + imageBlocks, + ]; + }, + }, ]; export default deprecated; From 1956b508de81761151a9de05bb82246c798553c0 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Fri, 20 Nov 2020 12:04:22 +1300 Subject: [PATCH 030/103] Fix issue with linkDestination not being applied in migration --- packages/block-library/src/gallery/deprecated.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/block-library/src/gallery/deprecated.js b/packages/block-library/src/gallery/deprecated.js index 057dae47228b4..07e76250bc9f8 100644 --- a/packages/block-library/src/gallery/deprecated.js +++ b/packages/block-library/src/gallery/deprecated.js @@ -866,17 +866,13 @@ const deprecated = [ }, migrate( { images, imageCrop, linkTo, sizeSlug } ) { const imageBlocks = images.map( ( image ) => { - const { linkDestination } = getHrefAndDestination( - image, - linkTo - ); return createBlock( 'core/image', { id: parseInt( image.id ), url: image.url, alt: image.alt, caption: image.caption, sizeSlug, - linkDestination, + ...getHrefAndDestination( image, linkTo ), } ); } ); return [ From 230eb3871d5e30e1331e9ced278340c7afa3b6b1 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Fri, 20 Nov 2020 10:23:59 +1000 Subject: [PATCH 031/103] Refactor gallery deprecations --- .../block-library/src/gallery/deprecated.js | 892 ------------------ .../src/gallery/deprecated/index.js | 13 + .../src/gallery/deprecated/v1/index.js | 181 ++++ .../src/gallery/deprecated/v2/index.js | 167 ++++ .../src/gallery/deprecated/v3/index.js | 129 +++ .../src/gallery/deprecated/v4/index.js | 149 +++ .../src/gallery/deprecated/v5/index.js | 99 ++ .../src/gallery/deprecated/v6/index.js | 194 ++++ 8 files changed, 932 insertions(+), 892 deletions(-) delete mode 100644 packages/block-library/src/gallery/deprecated.js create mode 100644 packages/block-library/src/gallery/deprecated/index.js create mode 100644 packages/block-library/src/gallery/deprecated/v1/index.js create mode 100644 packages/block-library/src/gallery/deprecated/v2/index.js create mode 100644 packages/block-library/src/gallery/deprecated/v3/index.js create mode 100644 packages/block-library/src/gallery/deprecated/v4/index.js create mode 100644 packages/block-library/src/gallery/deprecated/v5/index.js create mode 100644 packages/block-library/src/gallery/deprecated/v6/index.js diff --git a/packages/block-library/src/gallery/deprecated.js b/packages/block-library/src/gallery/deprecated.js deleted file mode 100644 index 07e76250bc9f8..0000000000000 --- a/packages/block-library/src/gallery/deprecated.js +++ /dev/null @@ -1,892 +0,0 @@ -/** - * External dependencies - */ -import classnames from 'classnames'; -import { map, some } from 'lodash'; - -/** - * WordPress dependencies - */ -import { RichText, useBlockProps } from '@wordpress/block-editor'; -import { createBlock } from '@wordpress/blocks'; - -/** - * Internal dependencies - */ -import { defaultColumnsNumber } from './shared'; -import { - LINK_DESTINATION_ATTACHMENT, - LINK_DESTINATION_MEDIA, -} from './constants'; -import { getHrefAndDestination } from './utils'; - -const deprecated = [ - { - attributes: { - images: { - type: 'array', - default: [], - source: 'query', - selector: '.blocks-gallery-item', - query: { - url: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'src', - }, - fullUrl: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'data-full-url', - }, - link: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'data-link', - }, - alt: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'alt', - default: '', - }, - id: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'data-id', - }, - caption: { - type: 'string', - source: 'html', - selector: '.blocks-gallery-item__caption', - }, - }, - }, - ids: { - type: 'array', - items: { - type: 'number', - }, - default: [], - }, - columns: { - type: 'number', - minimum: 1, - maximum: 8, - }, - caption: { - type: 'string', - source: 'html', - selector: '.blocks-gallery-caption', - }, - imageCrop: { - type: 'boolean', - default: true, - }, - linkTo: { - type: 'string', - default: 'none', - }, - sizeSlug: { - type: 'string', - default: 'large', - }, - }, - supports: { - align: true, - }, - isEligible( { linkTo } ) { - return ! linkTo || linkTo === 'attachment' || linkTo === 'media'; - }, - migrate( attributes ) { - let linkTo = attributes.linkTo; - if ( ! attributes.linkTo ) { - linkTo = 'none'; - } else if ( attributes.linkTo === 'attachment' ) { - linkTo = 'post'; - } else if ( attributes.linkTo === 'media' ) { - linkTo = 'file'; - } - return { - ...attributes, - linkTo, - }; - }, - save( { attributes } ) { - const { - images, - columns = defaultColumnsNumber( attributes.images.length ), - imageCrop, - caption, - linkTo, - } = attributes; - - return ( -
        -
          - { images.map( ( image ) => { - let href; - - switch ( linkTo ) { - case 'media': - href = image.fullUrl || image.url; - break; - case 'attachment': - href = image.link; - break; - } - - const img = ( - { - ); - - return ( -
        • -
          - { href ? ( - { img } - ) : ( - img - ) } - { ! RichText.isEmpty( - image.caption - ) && ( - - ) } -
          -
        • - ); - } ) } -
        - { ! RichText.isEmpty( caption ) && ( - - ) } -
        - ); - }, - }, - { - attributes: { - images: { - type: 'array', - default: [], - source: 'query', - selector: '.blocks-gallery-item', - query: { - url: { - source: 'attribute', - selector: 'img', - attribute: 'src', - }, - fullUrl: { - source: 'attribute', - selector: 'img', - attribute: 'data-full-url', - }, - link: { - source: 'attribute', - selector: 'img', - attribute: 'data-link', - }, - alt: { - source: 'attribute', - selector: 'img', - attribute: 'alt', - default: '', - }, - id: { - source: 'attribute', - selector: 'img', - attribute: 'data-id', - }, - caption: { - type: 'string', - source: 'html', - selector: '.blocks-gallery-item__caption', - }, - }, - }, - ids: { - type: 'array', - default: [], - }, - columns: { - type: 'number', - }, - caption: { - type: 'string', - source: 'html', - selector: '.blocks-gallery-caption', - }, - imageCrop: { - type: 'boolean', - default: true, - }, - linkTo: { - type: 'string', - default: 'none', - }, - }, - supports: { - align: true, - }, - isEligible( { ids } ) { - return ids && ids.some( ( id ) => typeof id === 'string' ); - }, - migrate( attributes ) { - return { - ...attributes, - ids: map( attributes.ids, ( id ) => { - const parsedId = parseInt( id, 10 ); - return Number.isInteger( parsedId ) ? parsedId : null; - } ), - }; - }, - save( { attributes } ) { - const { - images, - columns = defaultColumnsNumber( attributes?.images.length ), - imageCrop, - caption, - linkTo, - } = attributes; - - return ( -
        -
          - { images.map( ( image ) => { - let href; - - switch ( linkTo ) { - case 'media': - href = image.fullUrl || image.url; - break; - case 'attachment': - href = image.link; - break; - } - - const img = ( - { - ); - - return ( -
        • -
          - { href ? ( - { img } - ) : ( - img - ) } - { ! RichText.isEmpty( - image.caption - ) && ( - - ) } -
          -
        • - ); - } ) } -
        - { ! RichText.isEmpty( caption ) && ( - - ) } -
        - ); - }, - }, - { - attributes: { - images: { - type: 'array', - default: [], - source: 'query', - selector: 'ul.wp-block-gallery .blocks-gallery-item', - query: { - url: { - source: 'attribute', - selector: 'img', - attribute: 'src', - }, - fullUrl: { - source: 'attribute', - selector: 'img', - attribute: 'data-full-url', - }, - alt: { - source: 'attribute', - selector: 'img', - attribute: 'alt', - default: '', - }, - id: { - source: 'attribute', - selector: 'img', - attribute: 'data-id', - }, - link: { - source: 'attribute', - selector: 'img', - attribute: 'data-link', - }, - caption: { - type: 'array', - source: 'children', - selector: 'figcaption', - }, - }, - }, - ids: { - type: 'array', - default: [], - }, - columns: { - type: 'number', - }, - imageCrop: { - type: 'boolean', - default: true, - }, - linkTo: { - type: 'string', - default: 'none', - }, - }, - supports: { - align: true, - }, - save( { attributes } ) { - const { - images, - columns = defaultColumnsNumber( attributes?.images.length ), - imageCrop, - linkTo, - } = attributes; - return ( -
          - { images.map( ( image ) => { - let href; - - switch ( linkTo ) { - case 'media': - href = image.fullUrl || image.url; - break; - case 'attachment': - href = image.link; - break; - } - - const img = ( - { - ); - - return ( -
        • -
          - { href ? ( - { img } - ) : ( - img - ) } - { image.caption && - image.caption.length > 0 && ( - - ) } -
          -
        • - ); - } ) } -
        - ); - }, - }, - { - attributes: { - images: { - type: 'array', - default: [], - source: 'query', - selector: 'ul.wp-block-gallery .blocks-gallery-item', - query: { - url: { - source: 'attribute', - selector: 'img', - attribute: 'src', - }, - alt: { - source: 'attribute', - selector: 'img', - attribute: 'alt', - default: '', - }, - id: { - source: 'attribute', - selector: 'img', - attribute: 'data-id', - }, - link: { - source: 'attribute', - selector: 'img', - attribute: 'data-link', - }, - caption: { - type: 'array', - source: 'children', - selector: 'figcaption', - }, - }, - }, - columns: { - type: 'number', - }, - imageCrop: { - type: 'boolean', - default: true, - }, - linkTo: { - type: 'string', - default: 'none', - }, - }, - isEligible( { images, ids } ) { - return ( - images && - images.length > 0 && - ( ( ! ids && images ) || - ( ids && images && ids.length !== images.length ) || - some( images, ( id, index ) => { - if ( ! id && ids[ index ] !== null ) { - return true; - } - return parseInt( id, 10 ) !== ids[ index ]; - } ) ) - ); - }, - migrate( attributes ) { - return { - ...attributes, - ids: map( attributes.images, ( { id } ) => { - if ( ! id ) { - return null; - } - return parseInt( id, 10 ); - } ), - }; - }, - supports: { - align: true, - }, - save( { attributes } ) { - const { - images, - columns = defaultColumnsNumber( attributes?.images.length ), - imageCrop, - linkTo, - } = attributes; - return ( -
          - { images.map( ( image ) => { - let href; - - switch ( linkTo ) { - case 'media': - href = image.url; - break; - case 'attachment': - href = image.link; - break; - } - - const img = ( - { - ); - - return ( -
        • -
          - { href ? ( - { img } - ) : ( - img - ) } - { image.caption && - image.caption.length > 0 && ( - - ) } -
          -
        • - ); - } ) } -
        - ); - }, - }, - { - attributes: { - images: { - type: 'array', - default: [], - source: 'query', - selector: - 'div.wp-block-gallery figure.blocks-gallery-image img', - query: { - url: { - source: 'attribute', - attribute: 'src', - }, - alt: { - source: 'attribute', - attribute: 'alt', - default: '', - }, - id: { - source: 'attribute', - attribute: 'data-id', - }, - }, - }, - columns: { - type: 'number', - }, - imageCrop: { - type: 'boolean', - default: true, - }, - linkTo: { - type: 'string', - default: 'none', - }, - align: { - type: 'string', - default: 'none', - }, - }, - supports: { - align: true, - }, - save( { attributes } ) { - const { - images, - columns = defaultColumnsNumber( attributes?.images.length ), - align, - imageCrop, - linkTo, - } = attributes; - const className = classnames( `columns-${ columns }`, { - alignnone: align === 'none', - 'is-cropped': imageCrop, - } ); - return ( -
        - { images.map( ( image ) => { - let href; - - switch ( linkTo ) { - case 'media': - href = image.url; - break; - case 'attachment': - href = image.link; - break; - } - - const img = ( - { - ); - - return ( -
        - { href ? { img } : img } -
        - ); - } ) } -
        - ); - }, - }, - { - attributes: { - images: { - type: 'array', - default: [], - source: 'query', - selector: '.blocks-gallery-item', - query: { - url: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'src', - }, - fullUrl: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'data-full-url', - }, - link: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'data-link', - }, - alt: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'alt', - default: '', - }, - id: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'data-id', - }, - caption: { - type: 'string', - source: 'html', - selector: '.blocks-gallery-item__caption', - }, - }, - }, - ids: { - type: 'array', - items: { - type: 'number', - }, - default: [], - }, - columns: { - type: 'number', - minimum: 1, - maximum: 8, - }, - caption: { - type: 'string', - source: 'html', - selector: '.blocks-gallery-caption', - }, - imageCrop: { - type: 'boolean', - default: true, - }, - linkTo: { - type: 'string', - }, - sizeSlug: { - type: 'string', - default: 'large', - }, - }, - supports: { - anchor: true, - align: true, - }, - save( { attributes } ) { - const { - images, - columns = defaultColumnsNumber( attributes?.images.length ), - imageCrop, - caption, - linkTo, - } = attributes; - const className = `columns-${ columns } ${ - imageCrop ? 'is-cropped' : '' - }`; - - return ( -
        -
          - { images.map( ( image ) => { - let href; - - switch ( linkTo ) { - case LINK_DESTINATION_MEDIA: - href = image.fullUrl || image.url; - break; - case LINK_DESTINATION_ATTACHMENT: - href = image.link; - break; - } - - const img = ( - { - ); - - return ( -
        • -
          - { href ? ( - { img } - ) : ( - img - ) } - { ! RichText.isEmpty( - image.caption - ) && ( - - ) } -
          -
        • - ); - } ) } -
        - { ! RichText.isEmpty( caption ) && ( - - ) } -
        - ); - }, - isEligible( { ids } ) { - return !! ids; - }, - migrate( { images, imageCrop, linkTo, sizeSlug } ) { - const imageBlocks = images.map( ( image ) => { - return createBlock( 'core/image', { - id: parseInt( image.id ), - url: image.url, - alt: image.alt, - caption: image.caption, - sizeSlug, - ...getHrefAndDestination( image, linkTo ), - } ); - } ); - return [ - { - imageCrop, - linkTo, - sizeSlug, - imageCount: imageBlocks.length, - isListItem: true, - }, - imageBlocks, - ]; - }, - }, -]; - -export default deprecated; diff --git a/packages/block-library/src/gallery/deprecated/index.js b/packages/block-library/src/gallery/deprecated/index.js new file mode 100644 index 0000000000000..a3a13cc6bbcf7 --- /dev/null +++ b/packages/block-library/src/gallery/deprecated/index.js @@ -0,0 +1,13 @@ +/** + * Internal dependencies + */ +import v1 from './v1'; +import v2 from './v2'; +import v3 from './v3'; +import v4 from './v4'; +import v5 from './v5'; +import v6 from './v6'; + +const deprecated = [ v1, v2, v3, v4, v5, v6 ]; + +export default deprecated; diff --git a/packages/block-library/src/gallery/deprecated/v1/index.js b/packages/block-library/src/gallery/deprecated/v1/index.js new file mode 100644 index 0000000000000..c5859d76eb52d --- /dev/null +++ b/packages/block-library/src/gallery/deprecated/v1/index.js @@ -0,0 +1,181 @@ +/** + * Internal dependencies + */ +import { defaultColumnsNumber } from '../../shared'; + +/** + * WordPress dependencies + */ +import { RichText } from '@wordpress/block-editor'; + +export default { + attributes: { + images: { + type: 'array', + default: [], + source: 'query', + selector: '.blocks-gallery-item', + query: { + url: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'src', + }, + fullUrl: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'data-full-url', + }, + link: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'data-link', + }, + alt: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'alt', + default: '', + }, + id: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'data-id', + }, + caption: { + type: 'string', + source: 'html', + selector: '.blocks-gallery-item__caption', + }, + }, + }, + ids: { + type: 'array', + items: { + type: 'number', + }, + default: [], + }, + columns: { + type: 'number', + minimum: 1, + maximum: 8, + }, + caption: { + type: 'string', + source: 'html', + selector: '.blocks-gallery-caption', + }, + imageCrop: { + type: 'boolean', + default: true, + }, + linkTo: { + type: 'string', + default: 'none', + }, + sizeSlug: { + type: 'string', + default: 'large', + }, + }, + supports: { + align: true, + }, + isEligible( { linkTo } ) { + return ! linkTo || linkTo === 'attachment' || linkTo === 'media'; + }, + migrate( attributes ) { + let linkTo = attributes.linkTo; + if ( ! attributes.linkTo ) { + linkTo = 'none'; + } else if ( attributes.linkTo === 'attachment' ) { + linkTo = 'post'; + } else if ( attributes.linkTo === 'media' ) { + linkTo = 'file'; + } + return { + ...attributes, + linkTo, + }; + }, + save( { attributes } ) { + const { + images, + columns = defaultColumnsNumber( attributes.images.length ), + imageCrop, + caption, + linkTo, + } = attributes; + + return ( +
        +
          + { images.map( ( image ) => { + let href; + + switch ( linkTo ) { + case 'media': + href = image.fullUrl || image.url; + break; + case 'attachment': + href = image.link; + break; + } + + const img = ( + { + ); + + return ( +
        • +
          + { href ? ( + { img } + ) : ( + img + ) } + { ! RichText.isEmpty( image.caption ) && ( + + ) } +
          +
        • + ); + } ) } +
        + { ! RichText.isEmpty( caption ) && ( + + ) } +
        + ); + }, +}; diff --git a/packages/block-library/src/gallery/deprecated/v2/index.js b/packages/block-library/src/gallery/deprecated/v2/index.js new file mode 100644 index 0000000000000..dc87def816bc0 --- /dev/null +++ b/packages/block-library/src/gallery/deprecated/v2/index.js @@ -0,0 +1,167 @@ +/** + * External dependencies + */ +import { map } from 'lodash'; + +/** + * Internal dependencies + */ +import { defaultColumnsNumber } from '../../shared'; + +/** + * WordPress dependencies + */ +import { RichText } from '@wordpress/block-editor'; + +export default { + attributes: { + images: { + type: 'array', + default: [], + source: 'query', + selector: '.blocks-gallery-item', + query: { + url: { + source: 'attribute', + selector: 'img', + attribute: 'src', + }, + fullUrl: { + source: 'attribute', + selector: 'img', + attribute: 'data-full-url', + }, + link: { + source: 'attribute', + selector: 'img', + attribute: 'data-link', + }, + alt: { + source: 'attribute', + selector: 'img', + attribute: 'alt', + default: '', + }, + id: { + source: 'attribute', + selector: 'img', + attribute: 'data-id', + }, + caption: { + type: 'string', + source: 'html', + selector: '.blocks-gallery-item__caption', + }, + }, + }, + ids: { + type: 'array', + default: [], + }, + columns: { + type: 'number', + }, + caption: { + type: 'string', + source: 'html', + selector: '.blocks-gallery-caption', + }, + imageCrop: { + type: 'boolean', + default: true, + }, + linkTo: { + type: 'string', + default: 'none', + }, + }, + supports: { + align: true, + }, + isEligible( { ids } ) { + return ids && ids.some( ( id ) => typeof id === 'string' ); + }, + migrate( attributes ) { + return { + ...attributes, + ids: map( attributes.ids, ( id ) => { + const parsedId = parseInt( id, 10 ); + return Number.isInteger( parsedId ) ? parsedId : null; + } ), + }; + }, + save( { attributes } ) { + const { + images, + columns = defaultColumnsNumber( attributes?.images.length ), + imageCrop, + caption, + linkTo, + } = attributes; + + return ( +
        +
          + { images.map( ( image ) => { + let href; + + switch ( linkTo ) { + case 'media': + href = image.fullUrl || image.url; + break; + case 'attachment': + href = image.link; + break; + } + + const img = ( + { + ); + + return ( +
        • +
          + { href ? ( + { img } + ) : ( + img + ) } + { ! RichText.isEmpty( image.caption ) && ( + + ) } +
          +
        • + ); + } ) } +
        + { ! RichText.isEmpty( caption ) && ( + + ) } +
        + ); + }, +}; diff --git a/packages/block-library/src/gallery/deprecated/v3/index.js b/packages/block-library/src/gallery/deprecated/v3/index.js new file mode 100644 index 0000000000000..9e4ca741f964b --- /dev/null +++ b/packages/block-library/src/gallery/deprecated/v3/index.js @@ -0,0 +1,129 @@ +/** + * Internal dependencies + */ +import { defaultColumnsNumber } from '../../shared'; + +/** + * WordPress dependencies + */ +import { RichText } from '@wordpress/block-editor'; + +export default { + attributes: { + images: { + type: 'array', + default: [], + source: 'query', + selector: 'ul.wp-block-gallery .blocks-gallery-item', + query: { + url: { + source: 'attribute', + selector: 'img', + attribute: 'src', + }, + fullUrl: { + source: 'attribute', + selector: 'img', + attribute: 'data-full-url', + }, + alt: { + source: 'attribute', + selector: 'img', + attribute: 'alt', + default: '', + }, + id: { + source: 'attribute', + selector: 'img', + attribute: 'data-id', + }, + link: { + source: 'attribute', + selector: 'img', + attribute: 'data-link', + }, + caption: { + type: 'array', + source: 'children', + selector: 'figcaption', + }, + }, + }, + ids: { + type: 'array', + default: [], + }, + columns: { + type: 'number', + }, + imageCrop: { + type: 'boolean', + default: true, + }, + linkTo: { + type: 'string', + default: 'none', + }, + }, + supports: { + align: true, + }, + save( { attributes } ) { + const { + images, + columns = defaultColumnsNumber( attributes?.images.length ), + imageCrop, + linkTo, + } = attributes; + return ( +
          + { images.map( ( image ) => { + let href; + + switch ( linkTo ) { + case 'media': + href = image.fullUrl || image.url; + break; + case 'attachment': + href = image.link; + break; + } + + const img = ( + { + ); + + return ( +
        • +
          + { href ? { img } : img } + { image.caption && image.caption.length > 0 && ( + + ) } +
          +
        • + ); + } ) } +
        + ); + }, +}; diff --git a/packages/block-library/src/gallery/deprecated/v4/index.js b/packages/block-library/src/gallery/deprecated/v4/index.js new file mode 100644 index 0000000000000..e5df2a80ed5eb --- /dev/null +++ b/packages/block-library/src/gallery/deprecated/v4/index.js @@ -0,0 +1,149 @@ +/** + * External dependencies + */ +import { map, some } from 'lodash'; + +/** + * Internal dependencies + */ +import { defaultColumnsNumber } from '../../shared'; + +/** + * WordPress dependencies + */ +import { RichText } from '@wordpress/block-editor'; + +export default { + attributes: { + images: { + type: 'array', + default: [], + source: 'query', + selector: 'ul.wp-block-gallery .blocks-gallery-item', + query: { + url: { + source: 'attribute', + selector: 'img', + attribute: 'src', + }, + alt: { + source: 'attribute', + selector: 'img', + attribute: 'alt', + default: '', + }, + id: { + source: 'attribute', + selector: 'img', + attribute: 'data-id', + }, + link: { + source: 'attribute', + selector: 'img', + attribute: 'data-link', + }, + caption: { + type: 'array', + source: 'children', + selector: 'figcaption', + }, + }, + }, + columns: { + type: 'number', + }, + imageCrop: { + type: 'boolean', + default: true, + }, + linkTo: { + type: 'string', + default: 'none', + }, + }, + isEligible( { images, ids } ) { + return ( + images && + images.length > 0 && + ( ( ! ids && images ) || + ( ids && images && ids.length !== images.length ) || + some( images, ( id, index ) => { + if ( ! id && ids[ index ] !== null ) { + return true; + } + return parseInt( id, 10 ) !== ids[ index ]; + } ) ) + ); + }, + migrate( attributes ) { + return { + ...attributes, + ids: map( attributes.images, ( { id } ) => { + if ( ! id ) { + return null; + } + return parseInt( id, 10 ); + } ), + }; + }, + supports: { + align: true, + }, + save( { attributes } ) { + const { + images, + columns = defaultColumnsNumber( attributes?.images.length ), + imageCrop, + linkTo, + } = attributes; + return ( +
          + { images.map( ( image ) => { + let href; + + switch ( linkTo ) { + case 'media': + href = image.url; + break; + case 'attachment': + href = image.link; + break; + } + + const img = ( + { + ); + + return ( +
        • +
          + { href ? { img } : img } + { image.caption && image.caption.length > 0 && ( + + ) } +
          +
        • + ); + } ) } +
        + ); + }, +}; diff --git a/packages/block-library/src/gallery/deprecated/v5/index.js b/packages/block-library/src/gallery/deprecated/v5/index.js new file mode 100644 index 0000000000000..9d30b126dee00 --- /dev/null +++ b/packages/block-library/src/gallery/deprecated/v5/index.js @@ -0,0 +1,99 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + +/** + * Internal dependencies + */ +import { defaultColumnsNumber } from '../../shared'; + +export default { + attributes: { + images: { + type: 'array', + default: [], + source: 'query', + selector: 'div.wp-block-gallery figure.blocks-gallery-image img', + query: { + url: { + source: 'attribute', + attribute: 'src', + }, + alt: { + source: 'attribute', + attribute: 'alt', + default: '', + }, + id: { + source: 'attribute', + attribute: 'data-id', + }, + }, + }, + columns: { + type: 'number', + }, + imageCrop: { + type: 'boolean', + default: true, + }, + linkTo: { + type: 'string', + default: 'none', + }, + align: { + type: 'string', + default: 'none', + }, + }, + supports: { + align: true, + }, + save( { attributes } ) { + const { + images, + columns = defaultColumnsNumber( attributes?.images.length ), + align, + imageCrop, + linkTo, + } = attributes; + const className = classnames( `columns-${ columns }`, { + alignnone: align === 'none', + 'is-cropped': imageCrop, + } ); + return ( +
        + { images.map( ( image ) => { + let href; + + switch ( linkTo ) { + case 'media': + href = image.url; + break; + case 'attachment': + href = image.link; + break; + } + + const img = ( + { + ); + + return ( +
        + { href ? { img } : img } +
        + ); + } ) } +
        + ); + }, +}; diff --git a/packages/block-library/src/gallery/deprecated/v6/index.js b/packages/block-library/src/gallery/deprecated/v6/index.js new file mode 100644 index 0000000000000..d7ad303f20132 --- /dev/null +++ b/packages/block-library/src/gallery/deprecated/v6/index.js @@ -0,0 +1,194 @@ +/** + * WordPress dependencies + */ +import { RichText, useBlockProps } from '@wordpress/block-editor'; +import { createBlock } from '@wordpress/blocks'; + +/** + * Internal dependencies + */ +import { defaultColumnsNumber } from '../../shared'; +import { + LINK_DESTINATION_ATTACHMENT, + LINK_DESTINATION_MEDIA, +} from '../../constants'; +import { getHrefAndDestination } from '../../utils'; + +export default { + attributes: { + images: { + type: 'array', + default: [], + source: 'query', + selector: '.blocks-gallery-item', + query: { + url: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'src', + }, + fullUrl: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'data-full-url', + }, + link: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'data-link', + }, + alt: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'alt', + default: '', + }, + id: { + type: 'string', + source: 'attribute', + selector: 'img', + attribute: 'data-id', + }, + caption: { + type: 'string', + source: 'html', + selector: '.blocks-gallery-item__caption', + }, + }, + }, + ids: { + type: 'array', + items: { + type: 'number', + }, + default: [], + }, + columns: { + type: 'number', + minimum: 1, + maximum: 8, + }, + caption: { + type: 'string', + source: 'html', + selector: '.blocks-gallery-caption', + }, + imageCrop: { + type: 'boolean', + default: true, + }, + linkTo: { + type: 'string', + }, + sizeSlug: { + type: 'string', + default: 'large', + }, + }, + supports: { + anchor: true, + align: true, + }, + save( { attributes } ) { + const { + images, + columns = defaultColumnsNumber( attributes?.images.length ), + imageCrop, + caption, + linkTo, + } = attributes; + const className = `columns-${ columns } ${ + imageCrop ? 'is-cropped' : '' + }`; + + return ( +
        +
          + { images.map( ( image ) => { + let href; + + switch ( linkTo ) { + case LINK_DESTINATION_MEDIA: + href = image.fullUrl || image.url; + break; + case LINK_DESTINATION_ATTACHMENT: + href = image.link; + break; + } + + const img = ( + { + ); + + return ( +
        • +
          + { href ? ( + { img } + ) : ( + img + ) } + { ! RichText.isEmpty( image.caption ) && ( + + ) } +
          +
        • + ); + } ) } +
        + { ! RichText.isEmpty( caption ) && ( + + ) } +
        + ); + }, + isEligible( { ids } ) { + return !! ids; + }, + migrate( { images, imageCrop, linkTo, sizeSlug } ) { + const imageBlocks = images.map( ( image ) => { + return createBlock( 'core/image', { + id: parseInt( image.id ), + url: image.url, + alt: image.alt, + caption: image.caption, + sizeSlug, + ...getHrefAndDestination( image, linkTo ), + } ); + } ); + return [ + { + imageCrop, + linkTo, + sizeSlug, + imageCount: imageBlocks.length, + isListItem: true, + }, + imageBlocks, + ]; + }, +}; From c158077a9c2ab576ad5f73135665b014bab0197f Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Fri, 20 Nov 2020 12:14:52 +1000 Subject: [PATCH 032/103] Fix missing attributes from migration --- packages/block-library/src/gallery/deprecated/v6/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/gallery/deprecated/v6/index.js b/packages/block-library/src/gallery/deprecated/v6/index.js index d7ad303f20132..5d779023fae12 100644 --- a/packages/block-library/src/gallery/deprecated/v6/index.js +++ b/packages/block-library/src/gallery/deprecated/v6/index.js @@ -169,7 +169,7 @@ export default { isEligible( { ids } ) { return !! ids; }, - migrate( { images, imageCrop, linkTo, sizeSlug } ) { + migrate( { images, imageCrop, linkTo, sizeSlug, columns, caption } ) { const imageBlocks = images.map( ( image ) => { return createBlock( 'core/image', { id: parseInt( image.id ), @@ -182,6 +182,8 @@ export default { } ); return [ { + caption, + columns, imageCrop, linkTo, sizeSlug, From 16fd6be2341eadb68f287bb4c02642aafb96f1dc Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Sun, 22 Nov 2020 18:20:53 +1000 Subject: [PATCH 033/103] Update deprecation to set allowResize The imageEdit component defaults the context value for allowResize to true. The refactored gallery sets this to false by default. Setting allowResize to false when migrating a deprecated gallery allows images to be cropped in the display the same as the gallery when the post is saved and gallery reloaded. --- packages/block-library/src/gallery/deprecated/v6/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/block-library/src/gallery/deprecated/v6/index.js b/packages/block-library/src/gallery/deprecated/v6/index.js index 5d779023fae12..4532706965544 100644 --- a/packages/block-library/src/gallery/deprecated/v6/index.js +++ b/packages/block-library/src/gallery/deprecated/v6/index.js @@ -188,6 +188,7 @@ export default { linkTo, sizeSlug, imageCount: imageBlocks.length, + allowResize: false, isListItem: true, }, imageBlocks, From d1b0ffcc20f8d22b183d686a5493cbca4c91987c Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Mon, 23 Nov 2020 12:00:41 +1300 Subject: [PATCH 034/103] Fix issue with crop not working when certain plugins are loaded --- packages/block-library/src/gallery/style.scss | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/gallery/style.scss b/packages/block-library/src/gallery/style.scss index c6fa577831cea..bbd6cf3e592dd 100644 --- a/packages/block-library/src/gallery/style.scss +++ b/packages/block-library/src/gallery/style.scss @@ -73,8 +73,11 @@ // Cropped &.is-cropped ul.blocks-gallery-grid li.wp-block-image:not(#individual-image) { - a, - img { + figure > div { + display: flex; + } + + a, img { // IE11 doesn't support object-fit, so just make sure images aren't skewed. // The following rules are for all browsers. width: 100%; From 65201736529b7c43dd33eea8cc6f35d1e0f02bec Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Mon, 23 Nov 2020 09:42:27 +1000 Subject: [PATCH 035/103] Fix SCSS lint errors --- packages/block-library/src/gallery/style.scss | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/packages/block-library/src/gallery/style.scss b/packages/block-library/src/gallery/style.scss index bbd6cf3e592dd..bc31de11c13a8 100644 --- a/packages/block-library/src/gallery/style.scss +++ b/packages/block-library/src/gallery/style.scss @@ -7,7 +7,7 @@ // Some themes give all
          default margin instead of padding. margin: 0; - // Need to add the bogus :not(#individual-image) to override long not:() specificity chain + // Need to add the bogus :not(#individual-image) to override long not:() specificity chain // on default image block on front end. // Add space between thumbnails, and unset right most thumbnails later. li.wp-block-image:not(#individual-image) { @@ -53,12 +53,7 @@ color: $white; text-align: center; font-size: $default-font-size; - background: linear-gradient( - 0deg, - rgba( $color: $black, $alpha: 0.7 ) 0, - rgba( $color: $black, $alpha: 0.3 ) 70%, - transparent - ); + background: linear-gradient(0deg, rgba($color: $black, $alpha: 0.7) 0, rgba($color: $black, $alpha: 0.3) 70%, transparent); img { display: inline; @@ -77,7 +72,8 @@ display: flex; } - a, img { + a, + img { // IE11 doesn't support object-fit, so just make sure images aren't skewed. // The following rules are for all browsers. width: 100%; @@ -93,9 +89,9 @@ // On mobile and responsive viewports, we allow only 1 or 2 columns at the most. & .wp-block-image:not(#individual-image) { - width: calc( 50% - #{$grid-unit-20} ); + width: calc(50% - #{$grid-unit-20}); - &:nth-of-type( even ) { + &:nth-of-type(even) { margin-right: 0; } } @@ -109,19 +105,14 @@ @include break-small { @for $i from 3 through 8 { &.columns-#{ $i } .wp-block-image:not(#individual-image) { - width: calc( - #{100% / $i} - #{$grid-unit-20 * ( $i - 1 ) / $i} - ); + width: calc(#{100% / $i} - #{$grid-unit-20 * ( $i - 1 ) / $i}); margin-right: $grid-unit-20; } } // Unset the right margin on every rightmost gallery item to ensure center balance. @for $column-count from 1 through 8 { - &.columns-#{ - $column-count - } - .wp-block-image:not(#individual-image):nth-of-type( #{ $column-count }n ) { + &.columns-#{$column-count} .wp-block-image:not(#individual-image):nth-of-type( #{ $column-count }n ) { margin-right: 0; } } From 5c4a98f55b58b13da7770d1071af0abfa8937d92 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Mon, 23 Nov 2020 16:51:31 +1300 Subject: [PATCH 036/103] Update the block example --- packages/block-library/src/gallery/index.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/block-library/src/gallery/index.js b/packages/block-library/src/gallery/index.js index 677291252e7ce..b434e51397d0a 100644 --- a/packages/block-library/src/gallery/index.js +++ b/packages/block-library/src/gallery/index.js @@ -25,17 +25,18 @@ export const settings = { example: { attributes: { columns: 2, - images: [ - { - url: - 'https://s.w.org/images/core/5.3/Glacial_lakes%2C_Bhutan.jpg', - }, - { - url: - 'https://s.w.org/images/core/5.3/Sediment_off_the_Yucatan_Peninsula.jpg', - }, - ], + imageCount: 2, }, + innerBlocks: [ + { + name: 'core/image', + attributes: { url: 'https://s.w.org/images/core/5.3/Glacial_lakes%2C_Bhutan.jpg' }, + }, + { + name: 'core/image', + attributes: { url: 'https://s.w.org/images/core/5.3/Sediment_off_the_Yucatan_Peninsula.jpg' }, + }, + ], }, transforms, edit, From 48abbc42558dc2d2b8f676acd94468677ff0180b Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Mon, 23 Nov 2020 16:52:06 +1300 Subject: [PATCH 037/103] Linting fixes --- packages/block-library/src/gallery/index.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/gallery/index.js b/packages/block-library/src/gallery/index.js index b434e51397d0a..4e6431c19dbc0 100644 --- a/packages/block-library/src/gallery/index.js +++ b/packages/block-library/src/gallery/index.js @@ -30,11 +30,17 @@ export const settings = { innerBlocks: [ { name: 'core/image', - attributes: { url: 'https://s.w.org/images/core/5.3/Glacial_lakes%2C_Bhutan.jpg' }, + attributes: { + url: + 'https://s.w.org/images/core/5.3/Glacial_lakes%2C_Bhutan.jpg', + }, }, { name: 'core/image', - attributes: { url: 'https://s.w.org/images/core/5.3/Sediment_off_the_Yucatan_Peninsula.jpg' }, + attributes: { + url: + 'https://s.w.org/images/core/5.3/Sediment_off_the_Yucatan_Peninsula.jpg', + }, }, ], }, From b66ed228105b23a1cc3706c7defa7ab99c0f2303 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Tue, 24 Nov 2020 01:30:27 +1300 Subject: [PATCH 038/103] Fix the e2e test and the accessibility issue with having aria group role on a list item --- packages/block-library/src/gallery/style.scss | 14 +++++++------- packages/block-library/src/image/edit.js | 4 ++-- packages/block-library/src/image/save.js | 4 ++-- .../e2e-tests/specs/editor/blocks/gallery.test.js | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/block-library/src/gallery/style.scss b/packages/block-library/src/gallery/style.scss index bc31de11c13a8..68e4792dfb7ef 100644 --- a/packages/block-library/src/gallery/style.scss +++ b/packages/block-library/src/gallery/style.scss @@ -10,14 +10,14 @@ // Need to add the bogus :not(#individual-image) to override long not:() specificity chain // on default image block on front end. // Add space between thumbnails, and unset right most thumbnails later. - li.wp-block-image:not(#individual-image) { + li.list-image:not(#individual-image) { margin: 0 $grid-unit-20 $grid-unit-20 0; &:last-child { margin-right: 0; } } - li.wp-block-image { + li.list-image { display: flex; flex-grow: 1; flex-direction: column; @@ -67,7 +67,7 @@ } // Cropped - &.is-cropped ul.blocks-gallery-grid li.wp-block-image:not(#individual-image) { + &.is-cropped ul.blocks-gallery-grid li.list-image:not(#individual-image) { figure > div { display: flex; } @@ -88,7 +88,7 @@ } // On mobile and responsive viewports, we allow only 1 or 2 columns at the most. - & .wp-block-image:not(#individual-image) { + & li:not(#individual-image) { width: calc(50% - #{$grid-unit-20}); &:nth-of-type(even) { @@ -96,7 +96,7 @@ } } - &.columns-1 .wp-block-image:not(#individual-image) { + &.columns-1 li:not(#individual-image) { width: 100%; margin-right: 0; } @@ -104,7 +104,7 @@ // Beyond mobile viewports, we allow up to 8 columns. @include break-small { @for $i from 3 through 8 { - &.columns-#{ $i } .wp-block-image:not(#individual-image) { + &.columns-#{ $i } li.list-image:not(#individual-image) { width: calc(#{100% / $i} - #{$grid-unit-20 * ( $i - 1 ) / $i}); margin-right: $grid-unit-20; } @@ -112,7 +112,7 @@ // Unset the right margin on every rightmost gallery item to ensure center balance. @for $column-count from 1 through 8 { - &.columns-#{$column-count} .wp-block-image:not(#individual-image):nth-of-type( #{ $column-count }n ) { + &.columns-#{$column-count} li.list-image:not(#individual-image):nth-of-type( #{ $column-count }n ) { margin-right: 0; } } diff --git a/packages/block-library/src/image/edit.js b/packages/block-library/src/image/edit.js index 0e0221dd16607..54537954634d2 100644 --- a/packages/block-library/src/image/edit.js +++ b/packages/block-library/src/image/edit.js @@ -334,8 +334,8 @@ export function ImageEdit( { return ( <> { controls } -
        • -
          +
        • +
          { image } { mediaPlaceholder }
          diff --git a/packages/block-library/src/image/save.js b/packages/block-library/src/image/save.js index 590ae7a10489f..4ac47c68772b8 100644 --- a/packages/block-library/src/image/save.js +++ b/packages/block-library/src/image/save.js @@ -69,8 +69,8 @@ export default function save( { attributes } ) { const blockProps = useBlockProps.save(); if ( isListItem ) { return ( -
        • -
          { figure }
          +
        • +
          { figure }
        • ); } diff --git a/packages/e2e-tests/specs/editor/blocks/gallery.test.js b/packages/e2e-tests/specs/editor/blocks/gallery.test.js index eff1b56a5d714..2b4e2d0218a33 100644 --- a/packages/e2e-tests/specs/editor/blocks/gallery.test.js +++ b/packages/e2e-tests/specs/editor/blocks/gallery.test.js @@ -47,7 +47,7 @@ describe( 'Gallery', () => { const filename = await upload( '.wp-block-gallery input[type="file"]' ); const regex = new RegExp( - `\\s*
        ); }; diff --git a/packages/block-library/src/gallery/save.js b/packages/block-library/src/gallery/save.js index b7ce05431b59a..06964ec5389f1 100644 --- a/packages/block-library/src/gallery/save.js +++ b/packages/block-library/src/gallery/save.js @@ -20,17 +20,17 @@ export default function save( { attributes } ) { }`; return ( -
        -
          +
          +
          -
        - { ! RichText.isEmpty( caption ) && ( - - ) } -
        + { ! RichText.isEmpty( caption ) && ( + + ) } +
    + ); } diff --git a/packages/block-library/src/gallery/style.scss b/packages/block-library/src/gallery/style.scss index 3d8339f1bf610..b0df78b3eb0a6 100644 --- a/packages/block-library/src/gallery/style.scss +++ b/packages/block-library/src/gallery/style.scss @@ -3,16 +3,14 @@ // Styles for current version of gallery block. .wp-block-gallery.has-nested-images { - ul.blocks-gallery-grid { + display: block; + + figure.blocks-gallery-grid { display: flex; flex-wrap: wrap; - list-style-type: none; - margin: 0; // Some themes give all
      default margin instead of padding. - padding: 0; - // Need bogus :not(#individual-image) to override long :not() // specificity chain on default image block on front end. - li.list-image:not(#individual-image) { + figure.wp-block-image:not(#individual-image) { // Add space between thumbnails, and unset right most thumbnails later. margin: 0 $grid-unit-20 $grid-unit-20 0; @@ -21,7 +19,7 @@ } } - li.list-image { + figure.wp-block-image { display: flex; flex-grow: 1; justify-content: center; @@ -32,23 +30,8 @@ flex-direction: column; } - // Again, we need :not(#individual-image) to override long :not() - // chain on frontend styles. - figure:not(#individual-image) { - display: block; // IE11's lack of object-fit cover means flex will distort image as it fills space. - margin: 0; - max-width: 100%; // When aligned wide or full, this allows image to fill row. - - // Avoid applying flex styles to IE11. - @supports ( position: sticky ) { - display: flex; - flex-direction: column; // Needed for frontend when img isn't wrapped in div. - flex-grow: 1; - } - } - - figure > div, - figure > a { + > div, + > a { margin: 0; // Avoid applying flex styles to IE11. @@ -97,9 +80,9 @@ } // Cropped Images. - &.is-cropped ul.blocks-gallery-grid li.list-image:not(#individual-image) { - figure > div:not(.components-drop-zone), - figure > a { + &.is-cropped figure.blocks-gallery-grid figure.wp-block-image:not(#individual-image) { + > div:not(.components-drop-zone), + > a { display: block; // Thanks to IE11 not supporting object-fit fall back to display: block. // Without IE11 object-fit support "display: flex;" here causes distortion of aspect ratio. @@ -122,7 +105,7 @@ } // On mobile and responsive viewports, we allow only 1 or 2 columns at the most. - & li:not(#individual-image) { + & figure.wp-block-image:not(#individual-image) { width: calc(50% - #{$grid-unit-20}); &:nth-of-type(even) { @@ -130,7 +113,7 @@ } } - &.columns-1 li:not(#individual-image) { + &.columns-1 figure.wp-block-image:not(#individual-image) { margin-right: 0; width: 100%; } @@ -138,7 +121,7 @@ // Beyond mobile viewports, we allow up to 8 columns. @include break-small { @for $i from 3 through 8 { - &.columns-#{ $i } li.list-image:not(#individual-image) { + &.columns-#{ $i } figure.wp-block-image:not(#individual-image) { margin-right: $grid-unit-20; width: calc(#{100% / $i} - #{$grid-unit-20 * ( $i - 1 ) / $i}); } @@ -146,7 +129,7 @@ // Unset the right margin on every rightmost gallery item to ensure center balance. @for $column-count from 1 through 8 { - &.columns-#{$column-count} li.list-image:not(#individual-image):nth-of-type( #{ $column-count }n ) { + &.columns-#{$column-count} figure.wp-block-image:not(#individual-image):nth-of-type( #{ $column-count }n ) { margin-right: 0; } } diff --git a/packages/block-library/src/image/block.json b/packages/block-library/src/image/block.json index 11ac962e287e7..3053673f9dc3a 100644 --- a/packages/block-library/src/image/block.json +++ b/packages/block-library/src/image/block.json @@ -4,7 +4,7 @@ "category": "media", "usesContext": [ "allowResize", - "isListItem", + "isGrouped", "linkTo", "linkTarget", "sizeSlug" @@ -76,10 +76,6 @@ "selector": "figure > a", "attribute": "target" }, - "isListItem": { - "type": "boolean", - "default": false - }, "inheritedAttributes": { "type": "object", "default": { diff --git a/packages/block-library/src/image/edit.js b/packages/block-library/src/image/edit.js index 3fbc9b509b639..4e10b027eb763 100644 --- a/packages/block-library/src/image/edit.js +++ b/packages/block-library/src/image/edit.js @@ -95,7 +95,7 @@ export function ImageEdit( { sizeSlug, inhertedAttributes, } = attributes; - const { isListItem } = context; + const { isGrouped } = context; const [ tempUrl, setTempUrl ] = useState(); const altRef = useRef(); useEffect( () => { @@ -163,7 +163,7 @@ export function ImageEdit( { // Check if default link setting, or the one inherited from parent block should be used. let linkDestination = - isListItem && context.linkTo + isGrouped && context.linkTo ? context.linkTo : attributes.linkDestination; @@ -204,7 +204,7 @@ export function ImageEdit( { } mediaAttributes.href = href; - if ( isListItem ) { + if ( isGrouped ) { const parentSizeAttributes = getImageSizeAttributes( media, context.sizeSlug @@ -291,12 +291,6 @@ export function ImageEdit( { revokeBlobURL( tempUrl ); }, [ isTemp, url ] ); - useEffect( () => { - if ( isListItem ) { - setAttributes( { isListItem } ); - } - }, [ isListItem ] ); - const isExternal = isExternalImage( id, url ); const controls = ( @@ -336,7 +330,6 @@ export function ImageEdit( { 'is-resized': !! width || !! height, 'is-focused': isSelected, [ `size-${ sizeSlug }` ]: sizeSlug, - 'list-image': isListItem, } ); const blockProps = useBlockProps( { @@ -360,20 +353,6 @@ export function ImageEdit( { /> ); - if ( isListItem ) { - return ( - <> - { controls } -
    • -
      - { image } - { mediaPlaceholder } -
      -
    • - - ); - } - return ( <> { controls } diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js index b204e11fa6805..5f755e10c19fb 100644 --- a/packages/block-library/src/image/image.js +++ b/packages/block-library/src/image/image.js @@ -92,7 +92,7 @@ export default function Image( { } ) { const captionRef = useRef(); const prevUrl = usePrevious( url ); - const { allowResize = true, isListItem = false } = context; + const { allowResize = true, isGrouped = false } = context; const { block, currentId, image, multiImageSelection } = useSelect( ( select ) => { const { getMedia } = select( coreStore ); @@ -107,7 +107,7 @@ export default function Image( { block: getSelectedBlock(), currentId: getSelectedBlockClientId(), image: - id && ( isSelected || isListItem ) ? getMedia( id ) : null, + id && ( isSelected || isGrouped ) ? getMedia( id ) : null, multiImageSelection: multiSelectedClientIds.length && multiSelectedClientIds.every( @@ -116,7 +116,7 @@ export default function Image( { ), }; }, - [ id, isSelected, isListItem ] + [ id, isSelected, isGrouped ] ); const { imageEditing, imageSizes, maxWidth, mediaUpload } = useSelect( ( select ) => { diff --git a/packages/block-library/src/image/save.js b/packages/block-library/src/image/save.js index 868db590e9a58..65ecc35c4f8c5 100644 --- a/packages/block-library/src/image/save.js +++ b/packages/block-library/src/image/save.js @@ -24,7 +24,6 @@ export default function save( { attributes } ) { linkTarget, sizeSlug, title, - isListItem, } = attributes; const newRel = isEmpty( rel ) ? undefined : rel; @@ -33,7 +32,6 @@ export default function save( { attributes } ) { [ `align${ align }` ]: align, [ `size-${ sizeSlug }` ]: sizeSlug, 'is-resized': width || height, - 'list-image': isListItem, } ); const image = ( @@ -68,13 +66,6 @@ export default function save( { attributes } ) { ); const blockProps = useBlockProps.save( { className: classes } ); - if ( isListItem ) { - return ( -
    • -
      { figure }
      -
    • - ); - } if ( 'left' === align || 'right' === align || 'center' === align ) { return ( diff --git a/packages/block-library/src/image/use-parent-attributes.js b/packages/block-library/src/image/use-parent-attributes.js index 754315c7d6d2a..c837ae3b76e9f 100644 --- a/packages/block-library/src/image/use-parent-attributes.js +++ b/packages/block-library/src/image/use-parent-attributes.js @@ -24,14 +24,14 @@ export default function useParentAttributes( setAttributes ) { const { - isListItem, + isGrouped, linkTo: parentLinkDestination, linkTarget: parentLinkTarget, sizeSlug: parentSizeSlug, } = context; useEffect( () => { - if ( ! isListItem ) { + if ( ! isGrouped ) { return; } if ( inheritedAttributes.linkDestination && image ) { @@ -41,10 +41,10 @@ export default function useParentAttributes( linkDestination: parentLinkDestination, } ); } - }, [ image, parentLinkDestination, isListItem ] ); + }, [ image, parentLinkDestination, isGrouped ] ); useEffect( () => { - if ( ! isListItem ) { + if ( ! isGrouped ) { return; } if ( inheritedAttributes.linkTarget ) { @@ -52,10 +52,10 @@ export default function useParentAttributes( linkTarget: parentLinkTarget, } ); } - }, [ parentLinkTarget, isListItem ] ); + }, [ parentLinkTarget, isGrouped ] ); useEffect( () => { - if ( ! isListItem ) { + if ( ! isGrouped ) { return; } @@ -69,5 +69,5 @@ export default function useParentAttributes( ...sizeAttributes, } ); } - }, [ parentSizeSlug, isListItem ] ); + }, [ parentSizeSlug, isGrouped ] ); } From 9128e46edb87c09744f5ff446d1c7f56ba84cc38 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Fri, 22 Jan 2021 11:33:46 +1300 Subject: [PATCH 059/103] Remove wrapper div --- .../block-library/src/gallery/editor.scss | 4 + packages/block-library/src/gallery/gallery.js | 41 +++--- packages/block-library/src/gallery/save.js | 24 ++-- packages/block-library/src/gallery/style.scss | 123 +++++++++--------- 4 files changed, 95 insertions(+), 97 deletions(-) diff --git a/packages/block-library/src/gallery/editor.scss b/packages/block-library/src/gallery/editor.scss index ed2b9be725af4..c62120f3d70ad 100644 --- a/packages/block-library/src/gallery/editor.scss +++ b/packages/block-library/src/gallery/editor.scss @@ -78,6 +78,10 @@ figure.wp-block-gallery { .components-placeholder__label { display: flex; } + .media-placeholder { + display: block; + width: 100%; + } } } diff --git a/packages/block-library/src/gallery/gallery.js b/packages/block-library/src/gallery/gallery.js index 4586e015351ba..85c0650b2dc65 100644 --- a/packages/block-library/src/gallery/gallery.js +++ b/packages/block-library/src/gallery/gallery.js @@ -13,7 +13,7 @@ import { import { VisuallyHidden } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { createBlock } from '@wordpress/blocks'; -import { useRef, useEffect } from '@wordpress/element'; +import { useRef, useEffect, Fragment } from '@wordpress/element'; /** * Internal dependencies @@ -57,7 +57,7 @@ export const Gallery = ( props ) => { }, [ isSelected ] ); return ( -
      { 'is-cropped': imageCrop, } ) } > -
      - - { mediaPlaceholder } - setAttributes( { caption: value } ) } - inlineToolbar - __unstableOnSplitAtEnd={ () => - insertBlocksAfter( createBlock( 'core/paragraph' ) ) - } - /> -
      + +
      + { mediaPlaceholder } + + setAttributes( { caption: value } ) + } + inlineToolbar + __unstableOnSplitAtEnd={ () => + insertBlocksAfter( createBlock( 'core/paragraph' ) ) + } + /> +
      +
); }; diff --git a/packages/block-library/src/gallery/save.js b/packages/block-library/src/gallery/save.js index 06964ec5389f1..aa870938cdb1c 100644 --- a/packages/block-library/src/gallery/save.js +++ b/packages/block-library/src/gallery/save.js @@ -15,22 +15,20 @@ export default function save( { attributes } ) { imageCrop, caption, } = attributes; - const className = `has-nested-images columns-${ columns } ${ + const className = `blocks-gallery-grid has-nested-images columns-${ columns } ${ imageCrop ? 'is-cropped' : '' }`; return ( -
-
- - { ! RichText.isEmpty( caption ) && ( - - ) } -
-
+
+ + { ! RichText.isEmpty( caption ) && ( + + ) } +
); } diff --git a/packages/block-library/src/gallery/style.scss b/packages/block-library/src/gallery/style.scss index b0df78b3eb0a6..32d1eee2e0546 100644 --- a/packages/block-library/src/gallery/style.scss +++ b/packages/block-library/src/gallery/style.scss @@ -3,74 +3,76 @@ // Styles for current version of gallery block. .wp-block-gallery.has-nested-images { - display: block; + display: flex; + flex-wrap: wrap; + // Need bogus :not(#individual-image) to override long :not() + // specificity chain on default image block on front end. + figure.wp-block-image:not(#individual-image) { + // Add space between thumbnails, and unset right most thumbnails later. + margin: 0 $grid-unit-20 $grid-unit-20 0; + + &:last-child { + margin-right: 0; + } + + width: calc(50% - #{$grid-unit-20}); + + &:nth-of-type(even) { + margin-right: 0; + } + } - figure.blocks-gallery-grid { + figure.wp-block-image { display: flex; - flex-wrap: wrap; - // Need bogus :not(#individual-image) to override long :not() - // specificity chain on default image block on front end. - figure.wp-block-image:not(#individual-image) { - // Add space between thumbnails, and unset right most thumbnails later. - margin: 0 $grid-unit-20 $grid-unit-20 0; - - &:last-child { - margin-right: 0; - } + flex-grow: 1; + justify-content: center; + position: relative; + + // IE11 doesn't like the "flex-direction: column;" here. + @supports ( position: sticky ) { + flex-direction: column; } - figure.wp-block-image { - display: flex; - flex-grow: 1; - justify-content: center; - position: relative; + > div, + > a { + margin: 0; - // IE11 doesn't like the "flex-direction: column;" here. + // Avoid applying flex styles to IE11. @supports ( position: sticky ) { flex-direction: column; + flex-grow: 1; } + } - > div, - > a { - margin: 0; + img { + display: block; + height: auto; + max-width: 100%; + width: 100%; - // Avoid applying flex styles to IE11. - @supports ( position: sticky ) { - flex-direction: column; - flex-grow: 1; - } + // IE doesn't handle cropping, so we need an explicit width here. + // IE11 doesn't read rules inside this query. They are applied only to modern browsers. + @supports ( position: sticky ) { + width: auto; } + } - img { - display: block; - height: auto; - max-width: 100%; - width: 100%; - - // IE doesn't handle cropping, so we need an explicit width here. - // IE11 doesn't read rules inside this query. They are applied only to modern browsers. - @supports ( position: sticky ) { - width: auto; - } - } + figcaption { + background: linear-gradient(0deg, rgba($color: $black, $alpha: 0.7) 0, rgba($color: $black, $alpha: 0.3) 70%, transparent); + bottom: 0; + color: $white; + font-size: $default-font-size; + left: 0; + margin-bottom: 0; + max-height: 100%; + overflow: auto; + padding: 40px 10px 9px; + position: absolute; + text-align: center; + width: 100%; - figcaption { - background: linear-gradient(0deg, rgba($color: $black, $alpha: 0.7) 0, rgba($color: $black, $alpha: 0.3) 70%, transparent); - bottom: 0; - color: $white; - font-size: $default-font-size; - left: 0; - margin-bottom: 0; - max-height: 100%; - overflow: auto; - padding: 40px 10px 9px; - position: absolute; - text-align: center; - width: 100%; - - img { - display: inline; - } + img { + display: inline; } } } @@ -80,7 +82,7 @@ } // Cropped Images. - &.is-cropped figure.blocks-gallery-grid figure.wp-block-image:not(#individual-image) { + &.is-cropped figure.wp-block-image:not(#individual-image) { > div:not(.components-drop-zone), > a { display: block; // Thanks to IE11 not supporting object-fit fall back to display: block. @@ -104,15 +106,6 @@ } } - // On mobile and responsive viewports, we allow only 1 or 2 columns at the most. - & figure.wp-block-image:not(#individual-image) { - width: calc(50% - #{$grid-unit-20}); - - &:nth-of-type(even) { - margin-right: 0; - } - } - &.columns-1 figure.wp-block-image:not(#individual-image) { margin-right: 0; width: 100%; From 71f6cb376493802eba52ea7f36d1ee712f9ba8be Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 13 Jan 2021 14:00:34 +1300 Subject: [PATCH 060/103] remove extra wrapper around media placeholder and caption and use flex css instead --- .../block-library/src/gallery/editor.scss | 5 ++- packages/block-library/src/gallery/gallery.js | 33 +++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/block-library/src/gallery/editor.scss b/packages/block-library/src/gallery/editor.scss index c62120f3d70ad..4fdb3ec238d24 100644 --- a/packages/block-library/src/gallery/editor.scss +++ b/packages/block-library/src/gallery/editor.scss @@ -8,7 +8,10 @@ pointer-events: none; } } - + .components-form-file-upload, + .blocks-gallery-caption { + flex: 0 0 100%; + } // @todo: this deserves a refactor, by being moved to the toolbar. .block-editor-media-placeholder.is-appender { .components-placeholder__label { diff --git a/packages/block-library/src/gallery/gallery.js b/packages/block-library/src/gallery/gallery.js index 85c0650b2dc65..f47131c4eeb47 100644 --- a/packages/block-library/src/gallery/gallery.js +++ b/packages/block-library/src/gallery/gallery.js @@ -67,24 +67,21 @@ export const Gallery = ( props ) => { } ) } > -
- { mediaPlaceholder } - - setAttributes( { caption: value } ) - } - inlineToolbar - __unstableOnSplitAtEnd={ () => - insertBlocksAfter( createBlock( 'core/paragraph' ) ) - } - /> -
+ + { mediaPlaceholder } + setAttributes( { caption: value } ) } + inlineToolbar + __unstableOnSplitAtEnd={ () => + insertBlocksAfter( createBlock( 'core/paragraph' ) ) + } + /> ); }; From 7bbe7f806406511ab08e88f219659b6199faec36 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 13 Jan 2021 14:01:23 +1300 Subject: [PATCH 061/103] Revert "remove extra wrapper around media placeholder and caption and use flex css instead --- .../block-library/src/gallery/editor.scss | 5 +-- packages/block-library/src/gallery/gallery.js | 33 ++++++++++--------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/block-library/src/gallery/editor.scss b/packages/block-library/src/gallery/editor.scss index 4fdb3ec238d24..c62120f3d70ad 100644 --- a/packages/block-library/src/gallery/editor.scss +++ b/packages/block-library/src/gallery/editor.scss @@ -8,10 +8,7 @@ pointer-events: none; } } - .components-form-file-upload, - .blocks-gallery-caption { - flex: 0 0 100%; - } + // @todo: this deserves a refactor, by being moved to the toolbar. .block-editor-media-placeholder.is-appender { .components-placeholder__label { diff --git a/packages/block-library/src/gallery/gallery.js b/packages/block-library/src/gallery/gallery.js index f47131c4eeb47..85c0650b2dc65 100644 --- a/packages/block-library/src/gallery/gallery.js +++ b/packages/block-library/src/gallery/gallery.js @@ -67,21 +67,24 @@ export const Gallery = ( props ) => { } ) } > - - { mediaPlaceholder } - setAttributes( { caption: value } ) } - inlineToolbar - __unstableOnSplitAtEnd={ () => - insertBlocksAfter( createBlock( 'core/paragraph' ) ) - } - /> +
+ { mediaPlaceholder } + + setAttributes( { caption: value } ) + } + inlineToolbar + __unstableOnSplitAtEnd={ () => + insertBlocksAfter( createBlock( 'core/paragraph' ) ) + } + /> +
); }; From 3e5c05e2362c9bfe69ca9084e44d0dc529e5b167 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Fri, 22 Jan 2021 11:34:36 +1300 Subject: [PATCH 062/103] Revert "Remove external div wrapper by moving InnerBlocks to a fragment" --- packages/block-library/src/gallery/gallery.js | 41 +++--- packages/block-library/src/gallery/save.js | 24 ++-- packages/block-library/src/gallery/style.scss | 123 +++++++++--------- 3 files changed, 97 insertions(+), 91 deletions(-) diff --git a/packages/block-library/src/gallery/gallery.js b/packages/block-library/src/gallery/gallery.js index 85c0650b2dc65..4586e015351ba 100644 --- a/packages/block-library/src/gallery/gallery.js +++ b/packages/block-library/src/gallery/gallery.js @@ -13,7 +13,7 @@ import { import { VisuallyHidden } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { createBlock } from '@wordpress/blocks'; -import { useRef, useEffect, Fragment } from '@wordpress/element'; +import { useRef, useEffect } from '@wordpress/element'; /** * Internal dependencies @@ -57,7 +57,7 @@ export const Gallery = ( props ) => { }, [ isSelected ] ); return ( -
{ 'is-cropped': imageCrop, } ) } > - -
- { mediaPlaceholder } - - setAttributes( { caption: value } ) - } - inlineToolbar - __unstableOnSplitAtEnd={ () => - insertBlocksAfter( createBlock( 'core/paragraph' ) ) - } - /> -
-
+
+ + { mediaPlaceholder } + setAttributes( { caption: value } ) } + inlineToolbar + __unstableOnSplitAtEnd={ () => + insertBlocksAfter( createBlock( 'core/paragraph' ) ) + } + /> + ); }; diff --git a/packages/block-library/src/gallery/save.js b/packages/block-library/src/gallery/save.js index aa870938cdb1c..06964ec5389f1 100644 --- a/packages/block-library/src/gallery/save.js +++ b/packages/block-library/src/gallery/save.js @@ -15,20 +15,22 @@ export default function save( { attributes } ) { imageCrop, caption, } = attributes; - const className = `blocks-gallery-grid has-nested-images columns-${ columns } ${ + const className = `has-nested-images columns-${ columns } ${ imageCrop ? 'is-cropped' : '' }`; return ( -
- - { ! RichText.isEmpty( caption ) && ( - - ) } -
+
+
+ + { ! RichText.isEmpty( caption ) && ( + + ) } +
+
); } diff --git a/packages/block-library/src/gallery/style.scss b/packages/block-library/src/gallery/style.scss index 32d1eee2e0546..b0df78b3eb0a6 100644 --- a/packages/block-library/src/gallery/style.scss +++ b/packages/block-library/src/gallery/style.scss @@ -3,76 +3,74 @@ // Styles for current version of gallery block. .wp-block-gallery.has-nested-images { - display: flex; - flex-wrap: wrap; - // Need bogus :not(#individual-image) to override long :not() - // specificity chain on default image block on front end. - figure.wp-block-image:not(#individual-image) { - // Add space between thumbnails, and unset right most thumbnails later. - margin: 0 $grid-unit-20 $grid-unit-20 0; - - &:last-child { - margin-right: 0; - } - - width: calc(50% - #{$grid-unit-20}); - - &:nth-of-type(even) { - margin-right: 0; - } - } + display: block; - figure.wp-block-image { + figure.blocks-gallery-grid { display: flex; - flex-grow: 1; - justify-content: center; - position: relative; - - // IE11 doesn't like the "flex-direction: column;" here. - @supports ( position: sticky ) { - flex-direction: column; + flex-wrap: wrap; + // Need bogus :not(#individual-image) to override long :not() + // specificity chain on default image block on front end. + figure.wp-block-image:not(#individual-image) { + // Add space between thumbnails, and unset right most thumbnails later. + margin: 0 $grid-unit-20 $grid-unit-20 0; + + &:last-child { + margin-right: 0; + } } - > div, - > a { - margin: 0; + figure.wp-block-image { + display: flex; + flex-grow: 1; + justify-content: center; + position: relative; - // Avoid applying flex styles to IE11. + // IE11 doesn't like the "flex-direction: column;" here. @supports ( position: sticky ) { flex-direction: column; - flex-grow: 1; } - } - img { - display: block; - height: auto; - max-width: 100%; - width: 100%; + > div, + > a { + margin: 0; - // IE doesn't handle cropping, so we need an explicit width here. - // IE11 doesn't read rules inside this query. They are applied only to modern browsers. - @supports ( position: sticky ) { - width: auto; + // Avoid applying flex styles to IE11. + @supports ( position: sticky ) { + flex-direction: column; + flex-grow: 1; + } } - } - - figcaption { - background: linear-gradient(0deg, rgba($color: $black, $alpha: 0.7) 0, rgba($color: $black, $alpha: 0.3) 70%, transparent); - bottom: 0; - color: $white; - font-size: $default-font-size; - left: 0; - margin-bottom: 0; - max-height: 100%; - overflow: auto; - padding: 40px 10px 9px; - position: absolute; - text-align: center; - width: 100%; img { - display: inline; + display: block; + height: auto; + max-width: 100%; + width: 100%; + + // IE doesn't handle cropping, so we need an explicit width here. + // IE11 doesn't read rules inside this query. They are applied only to modern browsers. + @supports ( position: sticky ) { + width: auto; + } + } + + figcaption { + background: linear-gradient(0deg, rgba($color: $black, $alpha: 0.7) 0, rgba($color: $black, $alpha: 0.3) 70%, transparent); + bottom: 0; + color: $white; + font-size: $default-font-size; + left: 0; + margin-bottom: 0; + max-height: 100%; + overflow: auto; + padding: 40px 10px 9px; + position: absolute; + text-align: center; + width: 100%; + + img { + display: inline; + } } } } @@ -82,7 +80,7 @@ } // Cropped Images. - &.is-cropped figure.wp-block-image:not(#individual-image) { + &.is-cropped figure.blocks-gallery-grid figure.wp-block-image:not(#individual-image) { > div:not(.components-drop-zone), > a { display: block; // Thanks to IE11 not supporting object-fit fall back to display: block. @@ -106,6 +104,15 @@ } } + // On mobile and responsive viewports, we allow only 1 or 2 columns at the most. + & figure.wp-block-image:not(#individual-image) { + width: calc(50% - #{$grid-unit-20}); + + &:nth-of-type(even) { + margin-right: 0; + } + } + &.columns-1 figure.wp-block-image:not(#individual-image) { margin-right: 0; width: 100%; From 8bb8ca5f53ca3f21f53d3524897b1d142791489f Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 13 Jan 2021 14:03:00 +1300 Subject: [PATCH 063/103] another update to image wrapper --- .../block-library/src/gallery/editor.scss | 4 ++ packages/block-library/src/gallery/gallery.js | 37 ++++++++++--------- packages/block-library/src/gallery/style.scss | 4 +- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/packages/block-library/src/gallery/editor.scss b/packages/block-library/src/gallery/editor.scss index c62120f3d70ad..fbb2275583bae 100644 --- a/packages/block-library/src/gallery/editor.scss +++ b/packages/block-library/src/gallery/editor.scss @@ -7,6 +7,10 @@ display: none; pointer-events: none; } + > .components-form-file-upload, + > .blocks-gallery-caption { + flex: 0 0 100%; + } } // @todo: this deserves a refactor, by being moved to the toolbar. diff --git a/packages/block-library/src/gallery/gallery.js b/packages/block-library/src/gallery/gallery.js index 4586e015351ba..36f5d16fd0c7d 100644 --- a/packages/block-library/src/gallery/gallery.js +++ b/packages/block-library/src/gallery/gallery.js @@ -38,7 +38,7 @@ export const Gallery = ( props ) => { imageCrop, } = attributes; const galleryRef = useRef(); - const innerBlocksProps = useInnerBlocksProps( + const { children, ...innerBlocksProps } = useInnerBlocksProps( { className: 'blocks-gallery-grid', }, @@ -66,22 +66,25 @@ export const Gallery = ( props ) => { 'is-cropped': imageCrop, } ) } > -
- - { mediaPlaceholder } - setAttributes( { caption: value } ) } - inlineToolbar - __unstableOnSplitAtEnd={ () => - insertBlocksAfter( createBlock( 'core/paragraph' ) ) - } - /> +
+ { children } + { mediaPlaceholder } + + setAttributes( { caption: value } ) + } + inlineToolbar + __unstableOnSplitAtEnd={ () => + insertBlocksAfter( createBlock( 'core/paragraph' ) ) + } + /> +
); }; diff --git a/packages/block-library/src/gallery/style.scss b/packages/block-library/src/gallery/style.scss index b0df78b3eb0a6..3b575edcac747 100644 --- a/packages/block-library/src/gallery/style.scss +++ b/packages/block-library/src/gallery/style.scss @@ -14,7 +14,7 @@ // Add space between thumbnails, and unset right most thumbnails later. margin: 0 $grid-unit-20 $grid-unit-20 0; - &:last-child { + &:last-of-type { margin-right: 0; } } @@ -129,7 +129,7 @@ // Unset the right margin on every rightmost gallery item to ensure center balance. @for $column-count from 1 through 8 { - &.columns-#{$column-count} figure.wp-block-image:not(#individual-image):nth-of-type( #{ $column-count }n ) { + &.columns-#{$column-count} figure.blocks-gallery-grid figure.wp-block-image:not(#individual-image):nth-of-type( #{ $column-count }n ) { margin-right: 0; } } From 25863126f349b0d82ea5700144e41664b8b0e351 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Fri, 18 Dec 2020 09:37:02 +1300 Subject: [PATCH 064/103] put media uploader outside figure so structure matches front end --- packages/block-library/src/gallery/editor.scss | 1 - packages/block-library/src/gallery/gallery.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/block-library/src/gallery/editor.scss b/packages/block-library/src/gallery/editor.scss index fbb2275583bae..3bd5aea8567bd 100644 --- a/packages/block-library/src/gallery/editor.scss +++ b/packages/block-library/src/gallery/editor.scss @@ -7,7 +7,6 @@ display: none; pointer-events: none; } - > .components-form-file-upload, > .blocks-gallery-caption { flex: 0 0 100%; } diff --git a/packages/block-library/src/gallery/gallery.js b/packages/block-library/src/gallery/gallery.js index 36f5d16fd0c7d..ceefe62801212 100644 --- a/packages/block-library/src/gallery/gallery.js +++ b/packages/block-library/src/gallery/gallery.js @@ -68,7 +68,6 @@ export const Gallery = ( props ) => { >
{ children } - { mediaPlaceholder } { } />
+ { mediaPlaceholder } ); }; From 7d49db3c3bfc8e16dda04596f9455b92115486d7 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Fri, 18 Dec 2020 09:45:05 +1300 Subject: [PATCH 065/103] Replace div with View for the sake of native code --- packages/block-library/src/gallery/gallery.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/gallery/gallery.js b/packages/block-library/src/gallery/gallery.js index ceefe62801212..a0d1cb5e40714 100644 --- a/packages/block-library/src/gallery/gallery.js +++ b/packages/block-library/src/gallery/gallery.js @@ -14,6 +14,7 @@ import { VisuallyHidden } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { createBlock } from '@wordpress/blocks'; import { useRef, useEffect } from '@wordpress/element'; +import { View } from '@wordpress/primitives'; /** * Internal dependencies @@ -57,7 +58,7 @@ export const Gallery = ( props ) => { }, [ isSelected ] ); return ( -
{ />
{ mediaPlaceholder } - + ); }; From 04630f38a802bc5ce815d0ca9ed335f789ee8dac Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Tue, 26 Jan 2021 15:17:26 +1300 Subject: [PATCH 066/103] Move setting of attributes to the child images --- packages/block-library/src/image/block.json | 8 +--- packages/block-library/src/image/edit.js | 12 +++--- packages/block-library/src/image/image.js | 13 +++++-- .../src/image/use-parent-attributes.js | 37 ++++++++----------- 4 files changed, 31 insertions(+), 39 deletions(-) diff --git a/packages/block-library/src/image/block.json b/packages/block-library/src/image/block.json index 3053673f9dc3a..d2014d8a3c091 100644 --- a/packages/block-library/src/image/block.json +++ b/packages/block-library/src/image/block.json @@ -2,13 +2,7 @@ "apiVersion": 2, "name": "core/image", "category": "media", - "usesContext": [ - "allowResize", - "isGrouped", - "linkTo", - "linkTarget", - "sizeSlug" - ], + "usesContext": [ "allowResize", "linkTo", "linkTarget", "sizeSlug" ], "attributes": { "align": { "type": "string" diff --git a/packages/block-library/src/image/edit.js b/packages/block-library/src/image/edit.js index 4e10b027eb763..0f13ec0ea63b1 100644 --- a/packages/block-library/src/image/edit.js +++ b/packages/block-library/src/image/edit.js @@ -2,7 +2,7 @@ * External dependencies */ import classnames from 'classnames'; -import { get, omit, pick } from 'lodash'; +import { get, omit, pick, isEmpty } from 'lodash'; /** * WordPress dependencies @@ -95,7 +95,6 @@ export function ImageEdit( { sizeSlug, inhertedAttributes, } = attributes; - const { isGrouped } = context; const [ tempUrl, setTempUrl ] = useState(); const altRef = useRef(); useEffect( () => { @@ -162,10 +161,9 @@ export function ImageEdit( { } // Check if default link setting, or the one inherited from parent block should be used. - let linkDestination = - isGrouped && context.linkTo - ? context.linkTo - : attributes.linkDestination; + let linkDestination = context.linkTo + ? context.linkTo + : attributes.linkDestination; if ( ! linkDestination ) { // Use the WordPress option to determine the proper default. @@ -204,7 +202,7 @@ export function ImageEdit( { } mediaAttributes.href = href; - if ( isGrouped ) { + if ( ! isEmpty( context ) ) { const parentSizeAttributes = getImageSizeAttributes( media, context.sizeSlug diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js index 5f755e10c19fb..92ffd427ab203 100644 --- a/packages/block-library/src/image/image.js +++ b/packages/block-library/src/image/image.js @@ -92,7 +92,11 @@ export default function Image( { } ) { const captionRef = useRef(); const prevUrl = usePrevious( url ); - const { allowResize = true, isGrouped = false } = context; + const { + allowResize = true, + linkTo: parentLinkDestination, + sizeSlug: parentSizeSlug, + } = context; const { block, currentId, image, multiImageSelection } = useSelect( ( select ) => { const { getMedia } = select( coreStore ); @@ -107,7 +111,10 @@ export default function Image( { block: getSelectedBlock(), currentId: getSelectedBlockClientId(), image: - id && ( isSelected || isGrouped ) ? getMedia( id ) : null, + id && + ( isSelected || parentLinkDestination || parentSizeSlug ) + ? getMedia( id ) + : null, multiImageSelection: multiSelectedClientIds.length && multiSelectedClientIds.every( @@ -116,7 +123,7 @@ export default function Image( { ), }; }, - [ id, isSelected, isGrouped ] + [ id, isSelected, parentLinkDestination ] ); const { imageEditing, imageSizes, maxWidth, mediaUpload } = useSelect( ( select ) => { diff --git a/packages/block-library/src/image/use-parent-attributes.js b/packages/block-library/src/image/use-parent-attributes.js index c837ae3b76e9f..f17d4edba2421 100644 --- a/packages/block-library/src/image/use-parent-attributes.js +++ b/packages/block-library/src/image/use-parent-attributes.js @@ -24,50 +24,43 @@ export default function useParentAttributes( setAttributes ) { const { - isGrouped, linkTo: parentLinkDestination, linkTarget: parentLinkTarget, sizeSlug: parentSizeSlug, } = context; useEffect( () => { - if ( ! isGrouped ) { + if ( ! inheritedAttributes.linkDestination ) { return; } - if ( inheritedAttributes.linkDestination && image ) { + if ( image ) { const href = getUrl( image, parentLinkDestination ); setAttributes( { href, linkDestination: parentLinkDestination, } ); } - }, [ image, parentLinkDestination, isGrouped ] ); + }, [ image, parentLinkDestination ] ); useEffect( () => { - if ( ! isGrouped ) { + if ( ! inheritedAttributes.linkTarget ) { return; } - if ( inheritedAttributes.linkTarget ) { - setAttributes( { - linkTarget: parentLinkTarget, - } ); - } - }, [ parentLinkTarget, isGrouped ] ); + + setAttributes( { + linkTarget: parentLinkTarget, + } ); + }, [ parentLinkTarget ] ); useEffect( () => { - if ( ! isGrouped ) { + if ( ! inheritedAttributes.sizeSlug ) { return; } - if ( inheritedAttributes.sizeSlug ) { - const sizeAttributes = getImageSizeAttributes( - image, - parentSizeSlug - ); + const sizeAttributes = getImageSizeAttributes( image, parentSizeSlug ); - setAttributes( { - ...sizeAttributes, - } ); - } - }, [ parentSizeSlug, isGrouped ] ); + setAttributes( { + ...sizeAttributes, + } ); + }, [ parentSizeSlug ] ); } From 0a99f11b978807fdfa2bcf509436a217979e1aa5 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 23 Dec 2020 09:05:22 +1300 Subject: [PATCH 067/103] Gallery Block Refactor: Account for null image ids in gallery migrations (#27855) Co-authored-by: Glen Davies --- .../block-library/src/gallery/deprecated.js | 65 +++++++------------ 1 file changed, 25 insertions(+), 40 deletions(-) diff --git a/packages/block-library/src/gallery/deprecated.js b/packages/block-library/src/gallery/deprecated.js index db306e258eb9b..41753817dc783 100644 --- a/packages/block-library/src/gallery/deprecated.js +++ b/packages/block-library/src/gallery/deprecated.js @@ -80,6 +80,26 @@ export function getHrefAndDestination( image, destination ) { return {}; } +/** + * Gets an Image block from gallery image data + * + * Used to migrate Galleries to nested Image InnerBlocks. + * + * @param {Object} image Image properties. + * @param {string} sizeSlug Gallery sizeSlug attribute. + * @param {string} linkTo Gallery linkTo attribute. + * @return {Object} Image block. + */ +export function getImageBlock( image, sizeSlug, linkTo ) { + return createBlock( 'core/image', { + ...( image.id && { id: parseInt( image.id ) } ), + url: image.url, + alt: image.alt, + caption: image.caption, + sizeSlug, + ...getHrefAndDestination( image, linkTo ), + } ); +} const v1 = { attributes: { images: { @@ -173,14 +193,7 @@ const v1 = { }, migrate( { images, imageCrop, linkTo, sizeSlug, columns, caption } ) { const imageBlocks = images.map( ( image ) => { - return createBlock( 'core/image', { - id: parseInt( image.id ), - url: image.url, - alt: image.alt, - caption: image.caption, - sizeSlug, - ...getHrefAndDestination( image, linkTo ), - } ); + return getImageBlock( image, sizeSlug, linkTo ); } ); return [ { @@ -456,14 +469,7 @@ const v3 = { }, migrate( { images, imageCrop, linkTo, sizeSlug, columns, caption } ) { const imageBlocks = images.map( ( image ) => { - return createBlock( 'core/image', { - id: parseInt( image.id ), - url: image.url, - alt: image.alt, - caption: image.caption, - sizeSlug, - ...getHrefAndDestination( image, linkTo ), - } ); + return getImageBlock( image, sizeSlug, linkTo ); } ); return [ @@ -552,14 +558,7 @@ const v4 = { }, migrate( { images, imageCrop, linkTo, sizeSlug, columns, caption } ) { const imageBlocks = images.map( ( image ) => { - return createBlock( 'core/image', { - id: parseInt( image.id ), - url: image.url, - alt: image.alt, - caption: image.caption, - sizeSlug, - ...getHrefAndDestination( image, linkTo ), - } ); + return getImageBlock( image, sizeSlug, linkTo ); } ); return [ @@ -743,14 +742,7 @@ const v5 = { linkTo = 'none'; } const imageBlocks = attributes.images.map( ( image ) => { - return createBlock( 'core/image', { - id: parseInt( image.id ), - url: image.url, - alt: image.alt, - caption: image.caption, - sizeSlug: attributes.sizeSlug, - ...getHrefAndDestination( image, linkTo ), - } ); + return getImageBlock( image, attributes.sizeSlug, linkTo ); } ); return [ { @@ -1004,14 +996,7 @@ const v6 = { linkTo = 'media'; } const imageBlocks = images.map( ( image ) => { - return createBlock( 'core/image', { - id: parseInt( image.id ), - url: image.url, - alt: image.alt, - caption: image.caption, - sizeSlug, - ...getHrefAndDestination( image, linkTo ), - } ); + return getImageBlock( image, sizeSlug, linkTo ); } ); return [ { From c3843330a241d6c9178df73516e05bf12ff4bcaf Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Thu, 24 Dec 2020 15:28:03 +1300 Subject: [PATCH 068/103] Remove the gradient and put caption under image if is-rounded style applied (#27869) * Add alignment fixes for non cropped images Co-authored-by: Glen Davies --- packages/block-library/src/gallery/style.scss | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/gallery/style.scss b/packages/block-library/src/gallery/style.scss index 3b575edcac747..2849ea90c954d 100644 --- a/packages/block-library/src/gallery/style.scss +++ b/packages/block-library/src/gallery/style.scss @@ -24,7 +24,8 @@ flex-grow: 1; justify-content: center; position: relative; - + margin-top: auto; + margin-bottom: auto; // IE11 doesn't like the "flex-direction: column;" here. @supports ( position: sticky ) { flex-direction: column; @@ -72,6 +73,28 @@ display: inline; } } + + &.is-style-rounded { + > div, + > a { + // Not supported in IE11. + @supports ( position: sticky ) { + flex: 1 1 auto; + } + } + figcaption { + background: none; + // Not supported in IE11. + @supports ( position: sticky ) { + flex: initial; + background: none; + color: inherit; + margin: 0; + padding: 10px 10px 9px; + position: relative; + } + } + } } } @@ -79,6 +102,23 @@ flex-grow: 1; } + // Non cropped images. + &:not(.is-cropped) { + figure.blocks-gallery-grid { + figure.wp-block-image:not(#individual-image) { + margin-top: auto; + margin-bottom: auto; + img { + margin-bottom: $grid-unit-20; + } + + figcaption { + bottom: $grid-unit-20; + } + } + } + } + // Cropped Images. &.is-cropped figure.blocks-gallery-grid figure.wp-block-image:not(#individual-image) { > div:not(.components-drop-zone), From eaa2db11ac1d3d6cfefd49991fbaf483b8582bb3 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Fri, 22 Jan 2021 11:37:01 +1300 Subject: [PATCH 069/103] Remove outer div wrapper --- .../block-library/src/gallery/editor.scss | 28 +-- packages/block-library/src/gallery/gallery.js | 70 +++---- packages/block-library/src/gallery/save.js | 24 ++- packages/block-library/src/gallery/style.scss | 185 +++++++++--------- 4 files changed, 145 insertions(+), 162 deletions(-) diff --git a/packages/block-library/src/gallery/editor.scss b/packages/block-library/src/gallery/editor.scss index 3bd5aea8567bd..199675178bfd2 100644 --- a/packages/block-library/src/gallery/editor.scss +++ b/packages/block-library/src/gallery/editor.scss @@ -1,17 +1,22 @@ -.wp-block-gallery { +figure.wp-block-gallery { // Override the default list style type _only in the editor_ // to avoid :not() selector specificity issues. // See https://github.com/WordPress/gutenberg/pull/10358 - figure { - .components-drop-zone { - display: none; - pointer-events: none; - } - > .blocks-gallery-caption { - flex: 0 0 100%; - } + + display: block; + margin: 0; + + .components-drop-zone { + display: none; + pointer-events: none; + } + > .blocks-gallery-caption { + flex: 0 0 100%; } + .components-form-file-upload { + flex-basis: 100%; + } // @todo: this deserves a refactor, by being moved to the toolbar. .block-editor-media-placeholder.is-appender { .components-placeholder__label { @@ -23,11 +28,6 @@ } } -figure.wp-block-gallery { - display: block; - margin: 0; -} - // Necessary to to override default editor ul styles. .blocks-gallery-grid.blocks-gallery-grid { padding-left: 0; diff --git a/packages/block-library/src/gallery/gallery.js b/packages/block-library/src/gallery/gallery.js index a0d1cb5e40714..1461cbe8cbfaf 100644 --- a/packages/block-library/src/gallery/gallery.js +++ b/packages/block-library/src/gallery/gallery.js @@ -14,7 +14,6 @@ import { VisuallyHidden } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { createBlock } from '@wordpress/blocks'; import { useRef, useEffect } from '@wordpress/element'; -import { View } from '@wordpress/primitives'; /** * Internal dependencies @@ -39,17 +38,12 @@ export const Gallery = ( props ) => { imageCrop, } = attributes; const galleryRef = useRef(); - const { children, ...innerBlocksProps } = useInnerBlocksProps( - { - className: 'blocks-gallery-grid', - }, - { - allowedBlocks: [ 'core/image' ], - orientation: 'horizontal', - renderAppender: false, - __experimentalLayout: { type: 'default', alignments: [] }, - } - ); + const { children, ...innerBlocksProps } = useInnerBlocksProps( blockProps, { + allowedBlocks: [ 'core/image' ], + orientation: 'horizontal', + renderAppender: false, + __experimentalLayout: { type: 'default', alignments: [] }, + } ); useEffect( () => { if ( galleryRef.current && isSelected ) { @@ -58,35 +52,35 @@ export const Gallery = ( props ) => { }, [ isSelected ] ); return ( - -
- { children } - - setAttributes( { caption: value } ) - } - inlineToolbar - __unstableOnSplitAtEnd={ () => - insertBlocksAfter( createBlock( 'core/paragraph' ) ) - } - /> -
+ { children } + setAttributes( { caption: value } ) } + inlineToolbar + __unstableOnSplitAtEnd={ () => + insertBlocksAfter( createBlock( 'core/paragraph' ) ) + } + /> { mediaPlaceholder } -
+
); }; diff --git a/packages/block-library/src/gallery/save.js b/packages/block-library/src/gallery/save.js index 06964ec5389f1..aa870938cdb1c 100644 --- a/packages/block-library/src/gallery/save.js +++ b/packages/block-library/src/gallery/save.js @@ -15,22 +15,20 @@ export default function save( { attributes } ) { imageCrop, caption, } = attributes; - const className = `has-nested-images columns-${ columns } ${ + const className = `blocks-gallery-grid has-nested-images columns-${ columns } ${ imageCrop ? 'is-cropped' : '' }`; return ( -
-
- - { ! RichText.isEmpty( caption ) && ( - - ) } -
-
+
+ + { ! RichText.isEmpty( caption ) && ( + + ) } +
); } diff --git a/packages/block-library/src/gallery/style.scss b/packages/block-library/src/gallery/style.scss index 2849ea90c954d..d4f06a34a2e4d 100644 --- a/packages/block-library/src/gallery/style.scss +++ b/packages/block-library/src/gallery/style.scss @@ -2,97 +2,99 @@ @import "./deprecated.scss"; // Styles for current version of gallery block. -.wp-block-gallery.has-nested-images { - display: block; +.wp-block-gallery.blocks-gallery-grid.has-nested-images { + display: flex; + flex-wrap: wrap; + // Need bogus :not(#individual-image) to override long :not() + // specificity chain on default image block on front end. + figure.wp-block-image:not(#individual-image) { + // Add space between thumbnails, and unset right most thumbnails later. + margin: 0 $grid-unit-20 $grid-unit-20 0; + + &:last-of-type:not(#individual-image) { + margin-right: 0; + } - figure.blocks-gallery-grid { - display: flex; - flex-wrap: wrap; - // Need bogus :not(#individual-image) to override long :not() - // specificity chain on default image block on front end. - figure.wp-block-image:not(#individual-image) { - // Add space between thumbnails, and unset right most thumbnails later. - margin: 0 $grid-unit-20 $grid-unit-20 0; + width: calc(50% - #{$grid-unit-20}); - &:last-of-type { - margin-right: 0; - } + &:nth-of-type(even) { + margin-right: 0; } + } - figure.wp-block-image { - display: flex; - flex-grow: 1; - justify-content: center; - position: relative; - margin-top: auto; - margin-bottom: auto; - // IE11 doesn't like the "flex-direction: column;" here. + figure.wp-block-image { + display: flex; + flex-grow: 1; + justify-content: center; + position: relative; + margin-top: auto; + margin-bottom: auto; + // IE11 doesn't like the "flex-direction: column;" here. + @supports ( position: sticky ) { + flex-direction: column; + } + + > div, + > a { + margin: 0; + + // Avoid applying flex styles to IE11. @supports ( position: sticky ) { flex-direction: column; + flex-grow: 1; } + } - > div, - > a { - margin: 0; + img { + display: block; + height: auto; + max-width: 100%; + width: 100%; - // Avoid applying flex styles to IE11. - @supports ( position: sticky ) { - flex-direction: column; - flex-grow: 1; - } + // IE doesn't handle cropping, so we need an explicit width here. + // IE11 doesn't read rules inside this query. They are applied only to modern browsers. + @supports ( position: sticky ) { + width: auto; } + } + + figcaption { + background: linear-gradient(0deg, rgba($color: $black, $alpha: 0.7) 0, rgba($color: $black, $alpha: 0.3) 70%, transparent); + bottom: 0; + color: $white; + font-size: $default-font-size; + left: 0; + margin-bottom: 0; + max-height: 100%; + overflow: auto; + padding: 40px 10px 9px; + position: absolute; + text-align: center; + width: 100%; img { - display: block; - height: auto; - max-width: 100%; - width: 100%; + display: inline; + } + } - // IE doesn't handle cropping, so we need an explicit width here. - // IE11 doesn't read rules inside this query. They are applied only to modern browsers. + &.is-style-rounded { + > div, + > a { + // Not supported in IE11. @supports ( position: sticky ) { - width: auto; + flex: 1 1 auto; } } - figcaption { - background: linear-gradient(0deg, rgba($color: $black, $alpha: 0.7) 0, rgba($color: $black, $alpha: 0.3) 70%, transparent); - bottom: 0; - color: $white; - font-size: $default-font-size; - left: 0; - margin-bottom: 0; - max-height: 100%; - overflow: auto; - padding: 40px 10px 9px; - position: absolute; - text-align: center; - width: 100%; - - img { - display: inline; - } - } - - &.is-style-rounded { - > div, - > a { - // Not supported in IE11. - @supports ( position: sticky ) { - flex: 1 1 auto; - } - } - figcaption { + background: none; + // Not supported in IE11. + @supports ( position: sticky ) { + flex: initial; background: none; - // Not supported in IE11. - @supports ( position: sticky ) { - flex: initial; - background: none; - color: inherit; - margin: 0; - padding: 10px 10px 9px; - position: relative; - } + color: inherit; + margin: 0; + padding: 10px 10px 9px; + position: relative; } } } @@ -100,27 +102,27 @@ figcaption { flex-grow: 1; + flex-basis: 100%; } // Non cropped images. &:not(.is-cropped) { - figure.blocks-gallery-grid { - figure.wp-block-image:not(#individual-image) { - margin-top: auto; - margin-bottom: auto; - img { - margin-bottom: $grid-unit-20; - } - figcaption { - bottom: $grid-unit-20; - } + figure.wp-block-image:not(#individual-image) { + margin-top: auto; + margin-bottom: auto; + img { + margin-bottom: $grid-unit-20; + } + + figcaption { + bottom: $grid-unit-20; } } } // Cropped Images. - &.is-cropped figure.blocks-gallery-grid figure.wp-block-image:not(#individual-image) { + &.is-cropped figure.wp-block-image:not(#individual-image) { > div:not(.components-drop-zone), > a { display: block; // Thanks to IE11 not supporting object-fit fall back to display: block. @@ -144,15 +146,6 @@ } } - // On mobile and responsive viewports, we allow only 1 or 2 columns at the most. - & figure.wp-block-image:not(#individual-image) { - width: calc(50% - #{$grid-unit-20}); - - &:nth-of-type(even) { - margin-right: 0; - } - } - &.columns-1 figure.wp-block-image:not(#individual-image) { margin-right: 0; width: 100%; @@ -169,7 +162,7 @@ // Unset the right margin on every rightmost gallery item to ensure center balance. @for $column-count from 1 through 8 { - &.columns-#{$column-count} figure.blocks-gallery-grid figure.wp-block-image:not(#individual-image):nth-of-type( #{ $column-count }n ) { + &.columns-#{$column-count} figure.wp-block-image:not(#individual-image):nth-of-type( #{ $column-count }n ) { margin-right: 0; } } @@ -184,8 +177,6 @@ // If the gallery is centered, center the content inside as well. &.aligncenter { - figure.wp-block-image { - justify-content: center; - } + justify-content: center; } } From 8f887763cf89083259f1c5784164bad621212d1d Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Thu, 14 Jan 2021 16:52:19 +1000 Subject: [PATCH 070/103] Keep image margins while dragging sibling --- packages/block-library/src/gallery/style.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/block-library/src/gallery/style.scss b/packages/block-library/src/gallery/style.scss index d4f06a34a2e4d..dcbd90b2086da 100644 --- a/packages/block-library/src/gallery/style.scss +++ b/packages/block-library/src/gallery/style.scss @@ -158,6 +158,11 @@ margin-right: $grid-unit-20; width: calc(#{100% / $i} - #{$grid-unit-20 * ( $i - 1 ) / $i}); } + + // Prevent collapsing margin while sibling is being dragged. + &.columns-#{$i} figure.wp-block-image:not(#individual-image).is-dragging ~ figure.wp-block-image:not(#individual-image) { + margin-right: $grid-unit-20; + } } // Unset the right margin on every rightmost gallery item to ensure center balance. From b74c0f03aa5976efd9c3b5dc29b46a14a103420f Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Mon, 18 Jan 2021 14:12:21 +1300 Subject: [PATCH 071/103] Fix e2e test expected markup to match new structure --- packages/e2e-tests/specs/editor/blocks/gallery.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/e2e-tests/specs/editor/blocks/gallery.test.js b/packages/e2e-tests/specs/editor/blocks/gallery.test.js index f383089b65740..12148aa8bf9b8 100644 --- a/packages/e2e-tests/specs/editor/blocks/gallery.test.js +++ b/packages/e2e-tests/specs/editor/blocks/gallery.test.js @@ -47,7 +47,7 @@ describe( 'Gallery', () => { const filename = await upload( '.wp-block-gallery input[type="file"]' ); const regex = new RegExp( - `\\s* - ); + ); + }, }, -}; - -const v5 = { - attributes: { - images: { - type: 'array', - default: [], - source: 'query', - selector: '.blocks-gallery-item', - query: { - url: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'src', - }, - fullUrl: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'data-full-url', - }, - link: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'data-link', - }, - alt: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'alt', - default: '', - }, - id: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'data-id', - }, - caption: { - type: 'string', - source: 'html', - selector: '.blocks-gallery-item__caption', + { + attributes: { + images: { + type: 'array', + default: [], + source: 'query', + selector: 'ul.wp-block-gallery .blocks-gallery-item', + query: { + url: { + source: 'attribute', + selector: 'img', + attribute: 'src', + }, + alt: { + source: 'attribute', + selector: 'img', + attribute: 'alt', + default: '', + }, + id: { + source: 'attribute', + selector: 'img', + attribute: 'data-id', + }, + link: { + source: 'attribute', + selector: 'img', + attribute: 'data-link', + }, + caption: { + type: 'array', + source: 'children', + selector: 'figcaption', + }, }, }, - }, - ids: { - type: 'array', - items: { + columns: { type: 'number', }, - default: [], - }, - columns: { - type: 'number', - minimum: 1, - maximum: 8, - }, - caption: { - type: 'string', - source: 'html', - selector: '.blocks-gallery-caption', + imageCrop: { + type: 'boolean', + default: true, + }, + linkTo: { + type: 'string', + default: 'none', + }, }, - imageCrop: { - type: 'boolean', - default: true, + isEligible( { images, ids } ) { + return ( + images && + images.length > 0 && + ( ( ! ids && images ) || + ( ids && images && ids.length !== images.length ) || + some( images, ( id, index ) => { + if ( ! id && ids[ index ] !== null ) { + return true; + } + return parseInt( id, 10 ) !== ids[ index ]; + } ) ) + ); }, - linkTo: { - type: 'string', - default: 'none', + migrate( attributes ) { + return { + ...attributes, + ids: map( attributes.images, ( { id } ) => { + if ( ! id ) { + return null; + } + return parseInt( id, 10 ); + } ), + }; }, - sizeSlug: { - type: 'string', - default: 'large', + supports: { + align: true, }, - }, - supports: { - align: true, - }, - isEligible( { linkTo, imageCount } ) { - return ( - ! imageCount && - ( ! linkTo || linkTo === 'attachment' || linkTo === 'media' ) - ); - }, - migrate( attributes ) { - let linkTo = attributes.linkTo; - if ( ! attributes.linkTo ) { - linkTo = 'none'; - } - const imageBlocks = attributes.images.map( ( image ) => { - return getImageBlock( image, attributes.sizeSlug, linkTo ); - } ); - return [ - { - caption: attributes.caption, - columns: attributes.columns, - imageCrop: attributes.imageCrop, + save( { attributes } ) { + const { + images, + columns = defaultColumnsNumberV1( attributes ), + imageCrop, linkTo, - sizeSlug: attributes.sizeSlug, - imageCount: imageBlocks.length, - allowResize: false, - isGrouped: true, - }, - imageBlocks, - ]; - }, - save( { attributes } ) { - const { - images, - columns = defaultColumnsNumberV1( attributes ), - imageCrop, - caption, - linkTo, - } = attributes; - - return ( -
-
    + } = attributes; + return ( +
      { images.map( ( image ) => { let href; switch ( linkTo ) { case 'media': - href = image.fullUrl || image.url; + href = image.url; break; case 'attachment': href = image.link; @@ -791,7 +584,6 @@ const v5 = { src={ image.url } alt={ image.alt } data-id={ image.id } - data-full-url={ image.fullUrl } data-link={ image.link } className={ image.id ? `wp-image-${ image.id }` : null @@ -810,132 +602,86 @@ const v5 = { ) : ( img ) } - { ! RichText.isEmpty( image.caption ) && ( - - ) } + { image.caption && + image.caption.length > 0 && ( + + ) }
); } ) } - { ! RichText.isEmpty( caption ) && ( - - ) } - - ); + ); + }, }, -}; - -const v6 = { - attributes: { - images: { - type: 'array', - default: [], - source: 'query', - selector: '.blocks-gallery-item', - query: { - url: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'src', - }, - fullUrl: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'data-full-url', - }, - link: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'data-link', - }, - alt: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'alt', - default: '', - }, - id: { - type: 'string', - source: 'attribute', - selector: 'img', - attribute: 'data-id', - }, - caption: { - type: 'string', - source: 'html', - selector: '.blocks-gallery-item__caption', + { + attributes: { + images: { + type: 'array', + default: [], + source: 'query', + selector: + 'div.wp-block-gallery figure.blocks-gallery-image img', + query: { + url: { + source: 'attribute', + attribute: 'src', + }, + alt: { + source: 'attribute', + attribute: 'alt', + default: '', + }, + id: { + source: 'attribute', + attribute: 'data-id', + }, }, }, - }, - ids: { - type: 'array', - items: { + columns: { type: 'number', }, - default: [], - }, - columns: { - type: 'number', - minimum: 1, - maximum: 8, - }, - caption: { - type: 'string', - source: 'html', - selector: '.blocks-gallery-caption', - }, - imageCrop: { - type: 'boolean', - default: true, - }, - linkTo: { - type: 'string', + imageCrop: { + type: 'boolean', + default: true, + }, + linkTo: { + type: 'string', + default: 'none', + }, + align: { + type: 'string', + default: 'none', + }, }, - sizeSlug: { - type: 'string', - default: 'large', + supports: { + align: true, }, - }, - supports: { - anchor: true, - align: true, - }, - save( { attributes } ) { - const { - images, - columns = defaultColumnsNumberV1( attributes ), - imageCrop, - caption, - linkTo, - } = attributes; - const className = `columns-${ columns } ${ - imageCrop ? 'is-cropped' : '' - }`; - - return ( -
-
    + save( { attributes } ) { + const { + images, + columns = defaultColumnsNumberV1( attributes ), + align, + imageCrop, + linkTo, + } = attributes; + const className = classnames( `columns-${ columns }`, { + alignnone: align === 'none', + 'is-cropped': imageCrop, + } ); + return ( +
    { images.map( ( image ) => { let href; switch ( linkTo ) { - case DEPRECATED_LINK_DESTINATION_MEDIA: - href = image.fullUrl || image.url; + case 'media': + href = image.url; break; - case DEPRECATED_LINK_DESTINATION_ATTACHMENT: + case 'attachment': href = image.link; break; } @@ -945,73 +691,22 @@ const v6 = { src={ image.url } alt={ image.alt } data-id={ image.id } - data-full-url={ image.fullUrl } - data-link={ image.link } - className={ - image.id ? `wp-image-${ image.id }` : null - } /> ); return ( -
  • -
    - { href ? ( - { img } - ) : ( - img - ) } - { ! RichText.isEmpty( image.caption ) && ( - - ) } -
    -
  • + { href ? { img } : img } +
); } ) } - - { ! RichText.isEmpty( caption ) && ( - - ) } - - ); - }, - isEligible( { imageCount } ) { - return ! imageCount; - }, - migrate( { images, imageCrop, linkTo, sizeSlug, columns, caption } ) { - if ( linkTo === 'post' ) { - linkTo = 'attachment'; - } else if ( linkTo === 'file' ) { - linkTo = 'media'; - } - const imageBlocks = images.map( ( image ) => { - return getImageBlock( image, sizeSlug, linkTo ); - } ); - return [ - { - caption, - columns, - imageCrop, - linkTo, - sizeSlug, - imageCount: imageBlocks.length, - allowResize: false, - isGrouped: true, - }, - imageBlocks, - ]; + + ); + }, }, -}; +]; -export default [ v6, v5, v4, v3, v2, v1 ]; +export default deprecated; diff --git a/packages/block-library/src/gallery/edit-wrapper.js b/packages/block-library/src/gallery/edit-wrapper.js new file mode 100644 index 0000000000000..b29b50eeb1e97 --- /dev/null +++ b/packages/block-library/src/gallery/edit-wrapper.js @@ -0,0 +1,35 @@ +/** + * WordPress dependencies + */ +import { store as blockEditorStore } from '@wordpress/block-editor'; +import { useSelect } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import GalleryEdit from './edit'; +import GalleryEditV1 from './v1/edit'; + +/* + * Using a wrapper around the logic to load the edit for v1 of Gallery block + * or the refactored version with InnerBlocks. This is to prevent conditional + * use of hooks lint errors if adding this logic to the top of the edit component. + */ +export default function GalleryEditWrapper( props ) { + const { attributes } = props; + + const __experimentalGalleryRefactor = useSelect( ( select ) => { + const settings = select( blockEditorStore ).getSettings(); + return settings.__experimentalGalleryRefactor; + }, [] ); + + if ( + ! __experimentalGalleryRefactor || + attributes?.ids?.length > 0 || + attributes?.images?.length > 0 + ) { + return ; + } + + return ; +} diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index 5c3ba33400229..1d67431b65978 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -18,11 +18,13 @@ import { Spinner, } from '@wordpress/components'; import { + store as blockEditorStore, MediaPlaceholder, InspectorControls, useBlockProps, store as blockEditorStore, } from '@wordpress/block-editor'; +import { store as coreStore } from '@wordpress/core-data'; import { Platform, useEffect, useMemo } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { useSelect, useDispatch } from '@wordpress/data'; @@ -98,23 +100,22 @@ function GalleryEdit( props ) { const { __unstableMarkNextChangeAsNotPersistent, replaceInnerBlocks, - } = useDispatch( 'core/block-editor' ); + } = useDispatch( blockEditorStore ); const { getSettings, preferredStyle } = useSelect( ( select ) => { - const settings = select( 'core/block-editor' ).getSettings(); + const settings = select( blockEditorStore ).getSettings(); const preferredStyleVariations = settings.__experimentalPreferredStyleVariations; return { - getBlock: select( 'core/block-editor' ).getBlock, - getSettings: select( 'core/block-editor' ).getSettings, + getBlock: select( blockEditorStore ).getBlock, + getSettings: select( blockEditorStore ).getSettings, preferredStyle: preferredStyleVariations?.value?.[ 'core/image' ], }; }, [] ); const innerBlockImages = useSelect( ( select ) => { - return select( 'core/block-editor' ).getBlock( clientId ) - ?.innerBlocks; + return select( blockEditorStore ).getBlock( clientId )?.innerBlocks; }, [ clientId ] ); @@ -140,7 +141,7 @@ function GalleryEdit( props ) { ) { return imageData; } - const getMedia = select( 'core' ).getMedia; + const getMedia = select( coreStore ).getMedia; const newImageData = innerBlockImages.map( ( imageBlock ) => { return { id: imageBlock.attributes.id, diff --git a/packages/block-library/src/gallery/editor.scss b/packages/block-library/src/gallery/editor.scss index 3f23d81f2656d..65b9e86692de8 100644 --- a/packages/block-library/src/gallery/editor.scss +++ b/packages/block-library/src/gallery/editor.scss @@ -5,11 +5,13 @@ figure.wp-block-gallery { display: block; margin: 0; - - .components-drop-zone { - display: none; - pointer-events: none; + &.has-nested-images { + .components-drop-zone { + display: none; + pointer-events: none; + } } + > .blocks-gallery-caption { flex: 0 0 100%; } @@ -68,3 +70,104 @@ figure.wp-block-gallery { margin: 0 8px 0 4px; } } + +/** + * Deprecated css past this point. This can be removed once all galleries are migrated + * to V2. + */ +.blocks-gallery-item { + // Hide the focus outline that otherwise briefly appears when selecting a block. + figure:not(.is-selected):focus, + img:focus { + outline: none; + } + + figure.is-selected { + + &::before { + box-shadow: 0 0 0 $border-width $white inset, 0 0 0 3px var(--wp-admin-theme-color) inset; + content: ""; + // Shown in Windows 10 high contrast mode. + outline: 2px solid transparent; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1; + } + } + + figure.is-transient img { + opacity: 0.3; + } + + .is-selected .block-library-gallery-item__inline-menu { + display: inline-flex; + } + + .block-editor-media-placeholder { + margin: 0; + height: 100%; + + .components-placeholder__label { + display: flex; + } + } +} + +.block-library-gallery-item__inline-menu { + display: none; + position: absolute; + top: -2px; + margin: $grid-unit-10; + z-index: z-index(".block-library-gallery-item__inline-menu"); + transition: box-shadow 0.2s ease-out; + @include reduce-motion("transition"); + border-radius: $radius-block-ui; + background: $white; + border: $border-width solid $gray-900; + + &:hover { + box-shadow: $shadow-popover; + } + + @include break-small() { + // Use smaller buttons to fit when there are many columns. + .columns-7 &, + .columns-8 & { + padding: $grid-unit-05 / 2; + } + } + + .components-button.has-icon { + &:not(:focus) { + border: none; + box-shadow: none; + } + + @include break-small() { + // Use smaller buttons to fit when there are many columns. + .columns-7 &, + .columns-8 & { + padding: 0; + width: inherit; + height: inherit; + } + } + } + + &.is-left { + left: -2px; + } + + &.is-right { + right: -2px; + } +} + +.wp-block-gallery ul.blocks-gallery-grid { + padding: 0; + // Some themes give all
    default margin instead of padding. + margin: 0; +} \ No newline at end of file diff --git a/packages/block-library/src/gallery/index.js b/packages/block-library/src/gallery/index.js index 4e6431c19dbc0..224688ddfdd68 100644 --- a/packages/block-library/src/gallery/index.js +++ b/packages/block-library/src/gallery/index.js @@ -8,7 +8,7 @@ import { gallery as icon } from '@wordpress/icons'; * Internal dependencies */ import deprecated from './deprecated'; -import edit from './edit'; +import edit from './edit-wrapper'; import metadata from './block.json'; import save from './save'; import transforms from './transforms'; diff --git a/packages/block-library/src/gallery/save.js b/packages/block-library/src/gallery/save.js index dfb21461e31dc..242dcabf986ac 100644 --- a/packages/block-library/src/gallery/save.js +++ b/packages/block-library/src/gallery/save.js @@ -7,8 +7,12 @@ import { RichText, useBlockProps, InnerBlocks } from '@wordpress/block-editor'; * Internal dependencies */ import { defaultColumnsNumber } from './shared'; +import saveV1 from './v1/save'; export default function save( { attributes } ) { + if ( attributes?.ids?.length > 0 || attributes?.images?.length > 0 ) { + return saveV1( { attributes } ); + } const { imageCount, caption, diff --git a/packages/block-library/src/gallery/v1/edit.js b/packages/block-library/src/gallery/v1/edit.js new file mode 100644 index 0000000000000..15563f51795d7 --- /dev/null +++ b/packages/block-library/src/gallery/v1/edit.js @@ -0,0 +1,470 @@ +/** + * External dependencies + */ +import { + every, + filter, + find, + forEach, + get, + isEmpty, + map, + reduce, + some, + toString, +} from 'lodash'; + +/** + * WordPress dependencies + */ +import { compose } from '@wordpress/compose'; +import { + PanelBody, + SelectControl, + ToggleControl, + withNotices, + RangeControl, +} from '@wordpress/components'; +import { + store as blockEditorStore, + MediaPlaceholder, + InspectorControls, + useBlockProps, +} from '@wordpress/block-editor'; +import { Platform, useEffect, useState, useMemo } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; +import { getBlobByURL, isBlobURL, revokeBlobURL } from '@wordpress/blob'; +import { useDispatch, withSelect } from '@wordpress/data'; +import { store as coreStore } from '@wordpress/core-data'; +import { withViewportMatch } from '@wordpress/viewport'; +import { View } from '@wordpress/primitives'; + +/** + * Internal dependencies + */ +import { sharedIcon } from '../shared-icon'; +import { pickRelevantMediaFiles } from '../shared'; +import { defaultColumnsNumberV1 } from '../deprecated'; +import Gallery from './gallery'; +import { + LINK_DESTINATION_ATTACHMENT, + LINK_DESTINATION_MEDIA, + LINK_DESTINATION_NONE, +} from '../constants'; + +const MAX_COLUMNS = 8; +const linkOptions = [ + { value: LINK_DESTINATION_ATTACHMENT, label: __( 'Attachment Page' ) }, + { value: LINK_DESTINATION_MEDIA, label: __( 'Media File' ) }, + { value: LINK_DESTINATION_NONE, label: __( 'None' ) }, +]; +const ALLOWED_MEDIA_TYPES = [ 'image' ]; + +const PLACEHOLDER_TEXT = Platform.select( { + web: __( + 'Drag images, upload new ones or select files from your library.' + ), + native: __( 'ADD MEDIA' ), +} ); + +const MOBILE_CONTROL_PROPS_RANGE_CONTROL = Platform.select( { + web: {}, + native: { type: 'stepper' }, +} ); + +export function GalleryEditV1( props ) { + const { + attributes, + isSelected, + noticeUI, + noticeOperations, + mediaUpload, + imageSizes, + resizedImages, + onFocus, + } = props; + const { + columns = defaultColumnsNumberV1( attributes ), + imageCrop, + images, + linkTo, + sizeSlug, + } = attributes; + const [ selectedImage, setSelectedImage ] = useState(); + const [ attachmentCaptions, setAttachmentCaptions ] = useState(); + const { __unstableMarkNextChangeAsNotPersistent } = useDispatch( + blockEditorStore + ); + + function setAttributes( newAttrs ) { + if ( newAttrs.ids ) { + throw new Error( + 'The "ids" attribute should not be changed directly. It is managed automatically when "images" attribute changes' + ); + } + + if ( newAttrs.images ) { + newAttrs = { + ...newAttrs, + // Unlike images[ n ].id which is a string, always ensure the + // ids array contains numbers as per its attribute type. + ids: map( newAttrs.images, ( { id } ) => parseInt( id, 10 ) ), + }; + } + + props.setAttributes( newAttrs ); + } + + function onSelectImage( index ) { + return () => { + setSelectedImage( index ); + }; + } + + function onDeselectImage() { + return () => { + setSelectedImage(); + }; + } + + function onMove( oldIndex, newIndex ) { + const newImages = [ ...images ]; + newImages.splice( newIndex, 1, images[ oldIndex ] ); + newImages.splice( oldIndex, 1, images[ newIndex ] ); + setSelectedImage( newIndex ); + setAttributes( { images: newImages } ); + } + + function onMoveForward( oldIndex ) { + return () => { + if ( oldIndex === images.length - 1 ) { + return; + } + onMove( oldIndex, oldIndex + 1 ); + }; + } + + function onMoveBackward( oldIndex ) { + return () => { + if ( oldIndex === 0 ) { + return; + } + onMove( oldIndex, oldIndex - 1 ); + }; + } + + function onRemoveImage( index ) { + return () => { + const newImages = filter( images, ( img, i ) => index !== i ); + setSelectedImage(); + setAttributes( { + images: newImages, + columns: attributes.columns + ? Math.min( newImages.length, attributes.columns ) + : attributes.columns, + } ); + }; + } + + function selectCaption( newImage ) { + // The image id in both the images and attachmentCaptions arrays is a + // string, so ensure comparison works correctly by converting the + // newImage.id to a string. + const newImageId = toString( newImage.id ); + const currentImage = find( images, { id: newImageId } ); + const currentImageCaption = currentImage + ? currentImage.caption + : newImage.caption; + + if ( ! attachmentCaptions ) { + return currentImageCaption; + } + + const attachment = find( attachmentCaptions, { + id: newImageId, + } ); + + // if the attachment caption is updated + if ( attachment && attachment.caption !== newImage.caption ) { + return newImage.caption; + } + + return currentImageCaption; + } + + function onSelectImages( newImages ) { + setAttachmentCaptions( + newImages.map( ( newImage ) => ( { + // Store the attachmentCaption id as a string for consistency + // with the type of the id in the images attribute. + id: toString( newImage.id ), + caption: newImage.caption, + } ) ) + ); + setAttributes( { + images: newImages.map( ( newImage ) => ( { + ...pickRelevantMediaFiles( newImage, sizeSlug ), + caption: selectCaption( newImage, images, attachmentCaptions ), + // The id value is stored in a data attribute, so when the + // block is parsed it's converted to a string. Converting + // to a string here ensures it's type is consistent. + id: toString( newImage.id ), + } ) ), + columns: attributes.columns + ? Math.min( newImages.length, attributes.columns ) + : attributes.columns, + } ); + } + + function onUploadError( message ) { + noticeOperations.removeAllNotices(); + noticeOperations.createErrorNotice( message ); + } + + function setLinkTo( value ) { + setAttributes( { linkTo: value } ); + } + + function setColumnsNumber( value ) { + setAttributes( { columns: value } ); + } + + function toggleImageCrop() { + setAttributes( { imageCrop: ! imageCrop } ); + } + + function getImageCropHelp( checked ) { + return checked + ? __( 'Thumbnails are cropped to align.' ) + : __( 'Thumbnails are not cropped.' ); + } + + function onFocusGalleryCaption() { + setSelectedImage(); + } + + function setImageAttributes( index, newAttributes ) { + if ( ! images[ index ] ) { + return; + } + + setAttributes( { + images: [ + ...images.slice( 0, index ), + { + ...images[ index ], + ...newAttributes, + }, + ...images.slice( index + 1 ), + ], + } ); + } + + function getImagesSizeOptions() { + return map( + filter( imageSizes, ( { slug } ) => + some( resizedImages, ( sizes ) => sizes[ slug ] ) + ), + ( { name, slug } ) => ( { value: slug, label: name } ) + ); + } + + function updateImagesSize( newSizeSlug ) { + const updatedImages = map( images, ( image ) => { + if ( ! image.id ) { + return image; + } + const url = get( resizedImages, [ + parseInt( image.id, 10 ), + newSizeSlug, + ] ); + return { + ...image, + ...( url && { url } ), + }; + } ); + + setAttributes( { images: updatedImages, sizeSlug: newSizeSlug } ); + } + + useEffect( () => { + if ( + Platform.OS === 'web' && + images && + images.length > 0 && + every( images, ( { url } ) => isBlobURL( url ) ) + ) { + const filesList = map( images, ( { url } ) => getBlobByURL( url ) ); + forEach( images, ( { url } ) => revokeBlobURL( url ) ); + mediaUpload( { + filesList, + onFileChange: onSelectImages, + allowedTypes: [ 'image' ], + } ); + } + }, [] ); + + useEffect( () => { + // Deselect images when deselecting the block + if ( ! isSelected ) { + setSelectedImage(); + } + }, [ isSelected ] ); + + useEffect( () => { + // linkTo attribute must be saved so blocks don't break when changing + // image_default_link_type in options.php + if ( ! linkTo ) { + __unstableMarkNextChangeAsNotPersistent(); + setAttributes( { + linkTo: + window?.wp?.media?.view?.settings?.defaultProps?.link || + LINK_DESTINATION_NONE, + } ); + } + }, [ linkTo ] ); + + const hasImages = !! images.length; + + const mediaPlaceholder = ( + + ); + + const blockProps = useBlockProps(); + + if ( ! hasImages ) { + return { mediaPlaceholder }; + } + + const imageSizeOptions = getImagesSizeOptions(); + const shouldShowSizeOptions = hasImages && ! isEmpty( imageSizeOptions ); + + return ( + <> + + + { images.length > 1 && ( + + ) } + + + { shouldShowSizeOptions && ( + + ) } + + + { noticeUI } + + + ); +} + +export default compose( [ + withSelect( ( select, { attributes: { ids }, isSelected } ) => { + const { getMedia } = select( coreStore ); + const { getSettings } = select( blockEditorStore ); + const { imageSizes, mediaUpload } = getSettings(); + + const resizedImages = useMemo( () => { + if ( isSelected ) { + return reduce( + ids, + ( currentResizedImages, id ) => { + if ( ! id ) { + return currentResizedImages; + } + const image = getMedia( id ); + const sizes = reduce( + imageSizes, + ( currentSizes, size ) => { + const defaultUrl = get( image, [ + 'sizes', + size.slug, + 'url', + ] ); + const mediaDetailsUrl = get( image, [ + 'media_details', + 'sizes', + size.slug, + 'source_url', + ] ); + return { + ...currentSizes, + [ size.slug ]: + defaultUrl || mediaDetailsUrl, + }; + }, + {} + ); + return { + ...currentResizedImages, + [ parseInt( id, 10 ) ]: sizes, + }; + }, + {} + ); + } + return {}; + }, [ isSelected, ids, imageSizes ] ); + + return { + imageSizes, + mediaUpload, + resizedImages, + }; + } ), + withNotices, + withViewportMatch( { isNarrow: '< small' } ), +] )( GalleryEditV1 ); diff --git a/packages/block-library/src/gallery/v1/gallery-image.js b/packages/block-library/src/gallery/v1/gallery-image.js new file mode 100644 index 0000000000000..b358d845b3599 --- /dev/null +++ b/packages/block-library/src/gallery/v1/gallery-image.js @@ -0,0 +1,313 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; +import { get, omit } 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 } 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'; + +/** + * 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.onSelectCaption = this.onSelectCaption.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 = { + captionSelected: false, + isEditing: false, + }; + } + + bindContainer( ref ) { + this.container = ref; + } + + onSelectCaption() { + if ( ! this.state.captionSelected ) { + this.setState( { + captionSelected: true, + } ); + } + + if ( ! this.props.isSelected ) { + this.props.onSelect(); + } + } + + onSelectImage() { + if ( ! this.props.isSelected ) { + this.props.onSelect(); + } + + if ( this.state.captionSelected ) { + this.setState( { + captionSelected: false, + } ); + } + } + + onRemoveImage( event ) { + if ( + this.container === this.container.ownerDocument.activeElement && + this.props.isSelected && + [ BACKSPACE, DELETE ].indexOf( event.keyCode ) !== -1 + ) { + event.stopPropagation(); + event.preventDefault(); + this.props.onRemove(); + } + } + + onEdit() { + this.setState( { + isEditing: true, + } ); + } + + componentDidUpdate( prevProps ) { + const { + isSelected, + image, + url, + __unstableMarkNextChangeAsNotPersistent, + } = this.props; + if ( image && ! url ) { + __unstableMarkNextChangeAsNotPersistent(); + this.props.setAttributes( { + url: image.source_url, + alt: image.alt_text, + } ); + } + + // unselect the caption so when the user selects other image and comeback + // the caption is not immediately selected + if ( + this.state.captionSelected && + ! isSelected && + prevProps.isSelected + ) { + this.setState( { + captionSelected: false, + } ); + } + } + + 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 ) { + mediaAttributes = omit( mediaAttributes, [ 'alt' ] ); + } + } + + // 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' ] ) ) { + mediaAttributes = omit( mediaAttributes, [ 'caption' ] ); + } + + 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 */ + <> + { + { isBlobURL( url ) && } + + /* eslint-enable jsx-a11y/no-noninteractive-element-interactions */ + ); + + const className = classnames( { + 'is-selected': isSelected, + 'is-transient': isBlobURL( url ), + } ); + + return ( +
    + { ! isEditing && ( href ? { img } : img ) } + { isEditing && ( + + ) } + +
    + ); + } +} + +export default compose( [ + withSelect( ( select, ownProps ) => { + const { getMedia } = select( 'core' ); + const { id } = ownProps; + + return { + image: id ? getMedia( parseInt( id, 10 ) ) : null, + }; + } ), + withDispatch( ( dispatch ) => { + const { __unstableMarkNextChangeAsNotPersistent } = dispatch( + 'core/block-editor' + ); + return { + __unstableMarkNextChangeAsNotPersistent, + }; + } ), +] )( GalleryImage ); diff --git a/packages/block-library/src/gallery/v1/gallery.js b/packages/block-library/src/gallery/v1/gallery.js new file mode 100644 index 0000000000000..ee385651d8936 --- /dev/null +++ b/packages/block-library/src/gallery/v1/gallery.js @@ -0,0 +1,121 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + +/** + * WordPress dependencies + */ +import { RichText } from '@wordpress/block-editor'; +import { VisuallyHidden } from '@wordpress/components'; +import { __, sprintf } from '@wordpress/i18n'; +import { createBlock } from '@wordpress/blocks'; + +/** + * Internal dependencies + */ +import GalleryImage from './gallery-image'; +import { defaultColumnsNumberV1 } from '../deprecated'; + +export const Gallery = ( props ) => { + const { + attributes, + isSelected, + setAttributes, + selectedImage, + mediaPlaceholder, + onMoveBackward, + onMoveForward, + onRemoveImage, + onSelectImage, + onDeselectImage, + onSetImageAttributes, + onFocusGalleryCaption, + insertBlocksAfter, + blockProps, + } = props; + + const { + align, + columns = defaultColumnsNumberV1( attributes ), + caption, + imageCrop, + images, + } = attributes; + + return ( +
    +
      + { images.map( ( img, index ) => { + const ariaLabel = sprintf( + /* translators: 1: the order number of the image. 2: the total number of images. */ + __( 'image %1$d of %2$d in gallery' ), + index + 1, + images.length + ); + + return ( +
    • + + onSetImageAttributes( index, attrs ) + } + caption={ img.caption } + aria-label={ ariaLabel } + sizeSlug={ attributes.sizeSlug } + /> +
    • + ); + } ) } +
    + { mediaPlaceholder } + setAttributes( { caption: value } ) } + inlineToolbar + __unstableOnSplitAtEnd={ () => + insertBlocksAfter( createBlock( 'core/paragraph' ) ) + } + /> +
    + ); +}; + +function RichTextVisibilityHelper( { isHidden, ...richTextProps } ) { + return isHidden ? ( + + ) : ( + + ); +} + +export default Gallery; diff --git a/packages/block-library/src/gallery/v1/save.js b/packages/block-library/src/gallery/v1/save.js new file mode 100644 index 0000000000000..a053f5219be0d --- /dev/null +++ b/packages/block-library/src/gallery/v1/save.js @@ -0,0 +1,81 @@ +/** + * WordPress dependencies + */ +import { RichText, useBlockProps } from '@wordpress/block-editor'; + +/** + * Internal dependencies + */ +import { defaultColumnsNumberV1 } from '../deprecated'; +import { + LINK_DESTINATION_ATTACHMENT, + LINK_DESTINATION_MEDIA, +} from '../constants'; + +export default function saveV1( { attributes } ) { + const { + images, + columns = defaultColumnsNumberV1( attributes ), + imageCrop, + caption, + linkTo, + } = attributes; + const className = `columns-${ columns } ${ imageCrop ? 'is-cropped' : '' }`; + + return ( +
    +
      + { images.map( ( image ) => { + let href; + + switch ( linkTo ) { + case LINK_DESTINATION_MEDIA: + href = image.fullUrl || image.url; + break; + case LINK_DESTINATION_ATTACHMENT: + href = image.link; + break; + } + + const img = ( + { + ); + + return ( +
    • +
      + { href ? { img } : img } + { ! RichText.isEmpty( image.caption ) && ( + + ) } +
      +
    • + ); + } ) } +
    + { ! RichText.isEmpty( caption ) && ( + + ) } +
    + ); +} diff --git a/packages/editor/src/components/provider/use-block-editor-settings.js b/packages/editor/src/components/provider/use-block-editor-settings.js index 9e40ec1620949..c787c64379703 100644 --- a/packages/editor/src/components/provider/use-block-editor-settings.js +++ b/packages/editor/src/components/provider/use-block-editor-settings.js @@ -158,6 +158,7 @@ function useBlockEditorSettings( settings, hasTemplate ) { '__experimentalGlobalStylesBaseStyles', '__experimentalPreferredStyleVariations', '__experimentalSetIsInserterOpened', + '__experimentalGalleryRefactor', 'alignWide', 'allowedBlockTypes', 'availableLegacyWidgets', From 0c3dce084153bfdef22fda5b92db3360ee9c20cc Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Tue, 16 Feb 2021 09:35:39 +1300 Subject: [PATCH 087/103] Remove duplicate import --- packages/block-library/src/gallery/edit.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index 1d67431b65978..6e45616201337 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -22,7 +22,6 @@ import { MediaPlaceholder, InspectorControls, useBlockProps, - store as blockEditorStore, } from '@wordpress/block-editor'; import { store as coreStore } from '@wordpress/core-data'; import { Platform, useEffect, useMemo } from '@wordpress/element'; From f1ba92878cbd71472a89b298c6142de3cc92aaf5 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Tue, 16 Feb 2021 11:09:23 +1300 Subject: [PATCH 088/103] Remove need for temporary imageUploads attribute as we can just create the innerBlocks as part of transform --- packages/block-library/src/gallery/block.json | 7 ------- packages/block-library/src/gallery/edit.js | 12 ------------ packages/block-library/src/gallery/transforms.js | 16 +++++++--------- 3 files changed, 7 insertions(+), 28 deletions(-) diff --git a/packages/block-library/src/gallery/block.json b/packages/block-library/src/gallery/block.json index 68a16fde03b55..9be0fb8ba22d8 100644 --- a/packages/block-library/src/gallery/block.json +++ b/packages/block-library/src/gallery/block.json @@ -54,13 +54,6 @@ }, "default": [] }, - "imageUploads": { - "type": "array", - "default": [], - "items": { - "type": "object" - } - }, "shortCodeTransforms": { "type": "array", "default": [], diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index 6e45616201337..46516621c6700 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -89,7 +89,6 @@ function GalleryEdit( props ) { columns = defaultColumnsNumber( imageCount ), gutterSize, imageCrop, - imageUploads, linkTarget, linkTo, shortCodeTransforms, @@ -300,17 +299,6 @@ function GalleryEdit( props ) { setAttributes( { sizeSlug: newSizeSlug } ); } - useEffect( () => { - if ( - Platform.OS === 'web' && - imageUploads && - imageUploads.length > 0 - ) { - onSelectImages( imageUploads ); - setAttributes( { imageUploads: undefined } ); - } - }, [ imageUploads ] ); - useEffect( () => { // linkTo attribute must be saved so blocks don't break when changing image_default_link_type in options.php if ( ! linkTo ) { diff --git a/packages/block-library/src/gallery/transforms.js b/packages/block-library/src/gallery/transforms.js index 68fb9325e9cee..82dce89f2f88b 100644 --- a/packages/block-library/src/gallery/transforms.js +++ b/packages/block-library/src/gallery/transforms.js @@ -12,7 +12,6 @@ import { createBlobURL } from '@wordpress/blob'; /** * Internal dependencies */ -import { pickRelevantMediaFiles } from './shared'; import { LINK_DESTINATION_ATTACHMENT, LINK_DESTINATION_NONE, @@ -113,14 +112,13 @@ const transforms = { ); }, transform( files ) { - const block = createBlock( 'core/gallery', { - imageUploads: files.map( ( file ) => - pickRelevantMediaFiles( { - url: createBlobURL( file ), - } ) - ), - } ); - return block; + const innerBlocks = files.map( ( file ) => + createBlock( 'core/image', { + url: createBlobURL( file ), + } ) + ); + + return createBlock( 'core/gallery', {}, innerBlocks ); }, }, ], From 418168771423e0a91baf251323c514000c0b29ef Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Tue, 16 Feb 2021 14:01:34 +1300 Subject: [PATCH 089/103] Remove handling of gallery attribute updates from child images --- packages/block-library/src/gallery/block.json | 5 +- packages/block-library/src/image/block.json | 16 +--- packages/block-library/src/image/edit.js | 31 +------ packages/block-library/src/image/image.js | 25 +---- .../src/image/use-parent-attributes.js | 92 ------------------- 5 files changed, 8 insertions(+), 161 deletions(-) delete mode 100644 packages/block-library/src/image/use-parent-attributes.js diff --git a/packages/block-library/src/gallery/block.json b/packages/block-library/src/gallery/block.json index 9be0fb8ba22d8..119afc32e7c82 100644 --- a/packages/block-library/src/gallery/block.json +++ b/packages/block-library/src/gallery/block.json @@ -103,10 +103,7 @@ }, "providesContext": { "allowResize": "allowResize", - "isGrouped": "isGrouped", - "linkTo": "linkTo", - "linkTarget": "linkTarget", - "sizeSlug": "sizeSlug" + "isGrouped": "isGrouped" }, "supports": { "anchor": true, diff --git a/packages/block-library/src/image/block.json b/packages/block-library/src/image/block.json index a5f45a399071f..9deae501b1cbb 100644 --- a/packages/block-library/src/image/block.json +++ b/packages/block-library/src/image/block.json @@ -2,13 +2,7 @@ "apiVersion": 2, "name": "core/image", "category": "media", - "usesContext": [ - "allowResize", - "linkTo", - "linkTarget", - "sizeSlug", - "isGrouped" - ], + "usesContext": [ "allowResize", "isGrouped" ], "attributes": { "align": { "type": "string" @@ -75,14 +69,6 @@ "source": "attribute", "selector": "figure > a", "attribute": "target" - }, - "inheritedAttributes": { - "type": "object", - "default": { - "linkTo": false, - "linkTarget": false, - "sizeSlug": false - } } }, "supports": { diff --git a/packages/block-library/src/image/edit.js b/packages/block-library/src/image/edit.js index 23d0b7108065c..acf106973cff4 100644 --- a/packages/block-library/src/image/edit.js +++ b/packages/block-library/src/image/edit.js @@ -2,7 +2,7 @@ * External dependencies */ import classnames from 'classnames'; -import { get, omit, pick, isEmpty } from 'lodash'; +import { get, omit, pick } from 'lodash'; /** * WordPress dependencies @@ -28,7 +28,6 @@ import { image as icon } from '@wordpress/icons'; * Internal dependencies */ import Image from './image'; -import { getImageSizeAttributes } from './utils'; /** * Module constants @@ -159,11 +158,8 @@ export function ImageEdit( { additionalAttributes = { url }; } - // Check if default link setting, or the one inherited from parent block should be used. - let linkDestination = context.linkTo - ? context.linkTo - : attributes.linkDestination; - + // Check if default link setting should be used. + let linkDestination = attributes.linkDestination; if ( ! linkDestination ) { // Use the WordPress option to determine the proper default. // The constants used in Gutenberg do not match WP options so a little more complicated than ideal. @@ -201,27 +197,6 @@ export function ImageEdit( { } mediaAttributes.href = href; - if ( ! isEmpty( context ) ) { - const parentSizeAttributes = getImageSizeAttributes( - media, - context.sizeSlug - ); - - if ( context.linkTarget ) { - additionalAttributes.linkTarget = context.linkTarget; - } - - additionalAttributes = { - ...additionalAttributes, - inheritedAttributes: { - linkDestination: true, - linkTarget: true, - sizeSlug: true, - }, - ...parentSizeAttributes, - }; - } - setAttributes( { ...mediaAttributes, ...additionalAttributes, diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js index b7a1959a93e5a..17f853ffc08b4 100644 --- a/packages/block-library/src/image/image.js +++ b/packages/block-library/src/image/image.js @@ -48,7 +48,6 @@ import { createUpgradedEmbedBlock } from '../embed/util'; import useClientWidth from './use-client-width'; import ImageEditor, { ImageEditingProvider } from './image-editing'; import { isExternalImage } from './edit'; -import useParentAttributes from './use-parent-attributes'; /** * Module constants @@ -92,12 +91,7 @@ export default function Image( { } ) { const captionRef = useRef(); const prevUrl = usePrevious( url ); - const { - allowResize = true, - linkTo: parentLinkDestination, - sizeSlug: parentSizeSlug, - isGrouped, - } = context; + const { allowResize = true, isGrouped } = context; const { block, currentId, image, multiImageSelection } = useSelect( ( select ) => { const { getMedia } = select( coreStore ); @@ -111,11 +105,7 @@ export default function Image( { return { block: getSelectedBlock(), currentId: getSelectedBlockClientId(), - image: - id && - ( isSelected || parentLinkDestination || parentSizeSlug ) - ? getMedia( id ) - : null, + image: id && isSelected ? getMedia( id ) : null, multiImageSelection: multiSelectedClientIds.length && multiSelectedClientIds.every( @@ -124,7 +114,7 @@ export default function Image( { ), }; }, - [ id, isSelected, parentLinkDestination ] + [ id, isSelected ] ); const { imageEditing, imageSizes, maxWidth, mediaUpload } = useSelect( ( select ) => { @@ -165,15 +155,6 @@ export default function Image( { } }, [ isSelected ] ); - const currentAttributes = { linkDestination, linkTarget, href }; - useParentAttributes( - image, - currentAttributes, - context, - inheritedAttributes, - setAttributes - ); - // If an image is externally hosted, try to fetch the image data. This may // fail if the image host doesn't allow CORS with the domain. If it works, // we can enable a button in the toolbar to upload the image. diff --git a/packages/block-library/src/image/use-parent-attributes.js b/packages/block-library/src/image/use-parent-attributes.js deleted file mode 100644 index 80e79fcb12d91..0000000000000 --- a/packages/block-library/src/image/use-parent-attributes.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * WordPress dependencies - */ -import { useEffect } from '@wordpress/element'; - -/** - * Internal dependencies - */ -import { getUrl, getImageSizeAttributes } from './utils'; - -/** - * Determines new linkDestination, linkTarget and sizeSlug values for an image block - * from changed values supplied by parent block context. - * - * @param {Object} image Image. - * @param {Object} currentAttributes Current values for inheritable attributes - * @param {Object} context Parent block context. - * @param {Object} inheritedAttributes Image block attribute that indicate which attributes are inherited from parent. - * @param {Function} setAttributes Image block setAttributes prop. - */ -export default function useParentAttributes( - image, - currentAttributes, - context, - inheritedAttributes, - setAttributes -) { - const { - linkTo: parentLinkDestination, - linkTarget: parentLinkTarget, - sizeSlug: parentSizeSlug, - isGrouped, - } = context; - - useEffect( () => { - if ( ! isGrouped && inheritedAttributes ) { - setAttributes( { - inheritedAttributes: undefined, - } ); - return; - } - if ( isGrouped && ! inheritedAttributes ) { - // Check current Image attributes to make sure we don't overwrite an custom - // links and targets. from Image blocks dragged into a new parent block with inheritable - // attributes - const { linkDestination, linkTarget, href } = currentAttributes; - setAttributes( { - inheritedAttributes: { - linkDestination: - linkDestination !== 'none' || href ? false : true, - linkTarget: linkTarget ? false : true, - sizeSlug: true, - }, - } ); - } - }, [ isGrouped, inheritedAttributes ] ); - - useEffect( () => { - if ( ! isGrouped || ! inheritedAttributes?.linkDestination ) { - return; - } - if ( image ) { - const href = getUrl( image, parentLinkDestination ); - setAttributes( { - href, - linkDestination: parentLinkDestination, - } ); - } - }, [ image, parentLinkDestination ] ); - - useEffect( () => { - if ( ! isGrouped || ! inheritedAttributes?.linkTarget ) { - return; - } - - setAttributes( { - linkTarget: parentLinkTarget, - } ); - }, [ parentLinkTarget ] ); - - useEffect( () => { - if ( ! isGrouped || ! inheritedAttributes?.sizeSlug ) { - return; - } - - const sizeAttributes = getImageSizeAttributes( image, parentSizeSlug ); - - setAttributes( { - ...sizeAttributes, - } ); - }, [ parentSizeSlug ] ); -} From abd84c59b7e8ee807100a0d7bd4f550d83cbb428 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Tue, 16 Feb 2021 16:45:24 +1300 Subject: [PATCH 090/103] Move updating of attributes back to gallery and show snackbar to indicated to user that change was made to all images in the gallery --- packages/block-library/src/gallery/edit.js | 79 ++++++++++++++++++++-- 1 file changed, 73 insertions(+), 6 deletions(-) diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index 46516621c6700..2409354e79499 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -2,7 +2,7 @@ * External dependencies */ import classnames from 'classnames'; -import { isEmpty, concat, differenceBy, some, every } from 'lodash'; +import { isEmpty, concat, differenceBy, some, every, find } from 'lodash'; /** * WordPress dependencies @@ -25,12 +25,13 @@ import { } from '@wordpress/block-editor'; import { store as coreStore } from '@wordpress/core-data'; import { Platform, useEffect, useMemo } from '@wordpress/element'; -import { __ } from '@wordpress/i18n'; +import { __, sprintf } from '@wordpress/i18n'; import { useSelect, useDispatch } from '@wordpress/data'; import { withViewportMatch } from '@wordpress/viewport'; import { View } from '@wordpress/primitives'; import { createBlock } from '@wordpress/blocks'; import { createBlobURL } from '@wordpress/blob'; +import { store as noticesStore } from '@wordpress/notices'; /** * Internal dependencies @@ -38,7 +39,10 @@ import { createBlobURL } from '@wordpress/blob'; import { sharedIcon } from './shared-icon'; import { defaultColumnsNumber, pickRelevantMediaFiles } from './shared'; import { getHrefAndDestination } from './utils'; -import { getUpdatedLinkTargetSettings } from '../image/utils'; +import { + getUpdatedLinkTargetSettings, + getImageSizeAttributes, +} from '../image/utils'; import Gallery from './gallery'; import { LINK_DESTINATION_ATTACHMENT, @@ -98,9 +102,11 @@ function GalleryEdit( props ) { const { __unstableMarkNextChangeAsNotPersistent, replaceInnerBlocks, + updateBlockAttributes, } = useDispatch( blockEditorStore ); + const { createSuccessNotice } = useDispatch( noticesStore ); - const { getSettings, preferredStyle } = useSelect( ( select ) => { + const { getBlock, getSettings, preferredStyle } = useSelect( ( select ) => { const settings = select( blockEditorStore ).getSettings(); const preferredStyleVariations = settings.__experimentalPreferredStyleVariations; @@ -275,6 +281,29 @@ function GalleryEdit( props ) { function setLinkTo( value ) { setAttributes( { linkTo: value } ); + getBlock( clientId ).innerBlocks.forEach( ( block ) => { + const image = block.attributes.id + ? find( imageData, { id: block.attributes.id } ) + : null; + updateBlockAttributes( block.clientId, { + ...getHrefAndDestination( image.data, value ), + } ); + } ); + + const linkToText = [ ...linkOptions ].find( + ( linkType ) => linkType.value === value + ); + + createSuccessNotice( + sprintf( + /* translators: %s: image size settings */ + __( 'All gallery image links updated to: %s' ), + linkToText.label + ), + { + type: 'snackbar', + } + ); } function setColumnsNumber( value ) { @@ -291,12 +320,50 @@ function GalleryEdit( props ) { : __( 'Thumbnails are not cropped.' ); } - function toggleOpenInNewTab() { - setAttributes( { linkTarget: linkTarget ? undefined : '_blank' } ); + function toggleOpenInNewTab( openInNewTab ) { + const newLinkTarget = openInNewTab ? '_blank' : undefined; + setAttributes( { linkTarget: newLinkTarget } ); + getBlock( clientId ).innerBlocks.forEach( ( block ) => { + updateBlockAttributes( block.clientId, { + ...getUpdatedLinkTargetSettings( + newLinkTarget, + block.attributes + ), + } ); + } ); + const noticeText = openInNewTab + ? __( 'All gallery images updated to open in new tab' ) + : __( 'All gallery images updated to not open in new tab' ); + createSuccessNotice( noticeText, { + type: 'snackbar', + } ); } function updateImagesSize( newSizeSlug ) { setAttributes( { sizeSlug: newSizeSlug } ); + getBlock( clientId ).innerBlocks.forEach( ( block ) => { + const image = block.attributes.id + ? find( imageData, { id: block.attributes.id } ) + : null; + updateBlockAttributes( block.clientId, { + ...getImageSizeAttributes( image.data, newSizeSlug ), + } ); + } ); + + const imageSize = imageSizeOptions.find( + ( size ) => size.value === newSizeSlug + ); + + createSuccessNotice( + sprintf( + /* translators: %s: image size settings */ + __( 'All gallery image sizes updated to: %s' ), + imageSize.label + ), + { + type: 'snackbar', + } + ); } useEffect( () => { From 31a5f3da564905d8d3f4780151e64f2506806d95 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 17 Feb 2021 10:40:09 +1300 Subject: [PATCH 091/103] Update transforms to work with both versions of gallery --- .../block-library/src/gallery/transforms.js | 155 ++++++++++++++---- 1 file changed, 119 insertions(+), 36 deletions(-) diff --git a/packages/block-library/src/gallery/transforms.js b/packages/block-library/src/gallery/transforms.js index 82dce89f2f88b..453f1629a9b8c 100644 --- a/packages/block-library/src/gallery/transforms.js +++ b/packages/block-library/src/gallery/transforms.js @@ -1,13 +1,15 @@ /** * External dependencies */ -import { filter, every } from 'lodash'; +import { filter, every, toString } from 'lodash'; /** * WordPress dependencies */ import { createBlock } from '@wordpress/blocks'; import { createBlobURL } from '@wordpress/blob'; +import { select } from '@wordpress/data'; +import { store as blockEditorStore } from '@wordpress/block-editor'; /** * Internal dependencies @@ -17,6 +19,7 @@ import { LINK_DESTINATION_NONE, LINK_DESTINATION_MEDIA, } from './constants'; +import { pickRelevantMediaFiles } from './shared'; const parseShortcodeIds = ( ids ) => { if ( ! ids ) { @@ -44,19 +47,37 @@ const transforms = { : undefined; const validImages = filter( attributes, ( { url } ) => url ); - const innerBlocks = validImages.map( ( image ) => { - return createBlock( 'core/image', image ); - } ); - return createBlock( - 'core/gallery', - { - imageCount: innerBlocks.length, - align, - sizeSlug, - }, - innerBlocks - ); + const settings = select( blockEditorStore ).getSettings(); + if ( settings.__experimentalGalleryRefactor ) { + const innerBlocks = validImages.map( ( image ) => { + return createBlock( 'core/image', image ); + } ); + + return createBlock( + 'core/gallery', + { + imageCount: innerBlocks.length, + align, + sizeSlug, + }, + innerBlocks + ); + } + + return createBlock( 'core/gallery', { + images: validImages.map( + ( { id, url, alt, caption } ) => ( { + id: toString( id ), + url, + alt, + caption, + } ) + ), + ids: validImages.map( ( { id } ) => parseInt( id, 10 ) ), + align, + sizeSlug, + } ); }, }, { @@ -64,12 +85,41 @@ const transforms = { tag: 'gallery', attributes: { + images: { + type: 'array', + shortcode: ( { named: { ids } } ) => { + const settings = select( + blockEditorStore + ).getSettings(); + if ( ! settings.__experimentalGalleryRefactor ) { + return parseShortcodeIds( ids ).map( ( id ) => ( { + id: toString( id ), + } ) ); + } + }, + }, + ids: { + type: 'array', + shortcode: ( { named: { ids } } ) => { + const settings = select( + blockEditorStore + ).getSettings(); + if ( ! settings.__experimentalGalleryRefactor ) { + return parseShortcodeIds( ids ); + } + }, + }, shortCodeTransforms: { type: 'array', shortcode: ( { named: { ids } } ) => { - return parseShortcodeIds( ids ).map( ( id ) => ( { - id: parseInt( id ), - } ) ); + const settings = select( + blockEditorStore + ).getSettings(); + if ( settings.__experimentalGalleryRefactor ) { + return parseShortcodeIds( ids ).map( ( id ) => ( { + id: parseInt( id ), + } ) ); + } }, }, columns: { @@ -112,13 +162,24 @@ const transforms = { ); }, transform( files ) { - const innerBlocks = files.map( ( file ) => - createBlock( 'core/image', { - url: createBlobURL( file ), - } ) - ); + const settings = select( blockEditorStore ).getSettings(); + if ( settings.__experimentalGalleryRefactor ) { + const innerBlocks = files.map( ( file ) => + createBlock( 'core/image', { + url: createBlobURL( file ), + } ) + ); - return createBlock( 'core/gallery', {}, innerBlocks ); + return createBlock( 'core/gallery', {}, innerBlocks ); + } + const block = createBlock( 'core/gallery', { + images: files.map( ( file ) => + pickRelevantMediaFiles( { + url: createBlobURL( file ), + } ) + ), + } ); + return block; }, }, ], @@ -126,20 +187,42 @@ const transforms = { { type: 'block', blocks: [ 'core/image' ], - transform: ( { align }, innerBlocks ) => { - if ( innerBlocks.length > 0 ) { - return innerBlocks.map( - ( { - attributes: { id, url, alt, caption, sizeSlug }, - } ) => - createBlock( 'core/image', { - id, - url, - alt, - caption, - sizeSlug, - align, - } ) + transform: ( { align, images, ids, sizeSlug }, innerBlocks ) => { + const settings = select( blockEditorStore ).getSettings(); + if ( settings.__experimentalGalleryRefactor ) { + if ( innerBlocks.length > 0 ) { + return innerBlocks.map( + ( { + attributes: { + id, + url, + alt, + caption, + imageSizeSlug, + }, + } ) => + createBlock( 'core/image', { + id, + url, + alt, + caption, + sizeSlug: imageSizeSlug, + align, + } ) + ); + } + return createBlock( 'core/image', { align } ); + } + if ( images.length > 0 ) { + return images.map( ( { url, alt, caption }, index ) => + createBlock( 'core/image', { + id: ids[ index ], + url, + alt, + caption, + align, + sizeSlug, + } ) ); } return createBlock( 'core/image', { align } ); From 0bc0292eb2486ffc59079420f379f23f684431c5 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 17 Feb 2021 11:12:25 +1300 Subject: [PATCH 092/103] Remove redundant changes --- packages/block-library/src/image/image.js | 27 ----------------------- 1 file changed, 27 deletions(-) diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js index 17f853ffc08b4..57a18680f023b 100644 --- a/packages/block-library/src/image/image.js +++ b/packages/block-library/src/image/image.js @@ -77,7 +77,6 @@ export default function Image( { height, linkTarget, sizeSlug, - inheritedAttributes, }, setAttributes, isSelected, @@ -196,24 +195,6 @@ export default function Image( { } function onSetHref( props ) { - if ( - inheritedAttributes?.linkDestination || - inheritedAttributes?.linkTarget - ) { - setAttributes( { - inheritedAttributes: { - ...inheritedAttributes, - linkDestination: - props.linkDestination || props.href - ? false - : inheritedAttributes.linkDestination, - linkTarget: - props.linkTarget || props.linkTarget !== linkTarget - ? false - : inheritedAttributes.linkTarget, - }, - } ); - } setAttributes( props ); } @@ -240,14 +221,6 @@ export default function Image( { } function updateImage( newSizeSlug ) { - if ( inheritedAttributes?.sizeSlug ) { - setAttributes( { - inheritedAttributes: { - ...inheritedAttributes, - sizeSlug: false, - }, - } ); - } const newUrl = get( image, [ 'media_details', 'sizes', From 784baaed533ea7ee28ac57c7541cfc0319daa448 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 17 Feb 2021 11:18:51 +1300 Subject: [PATCH 093/103] Remove redundant changes --- packages/block-library/src/image/save.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/block-library/src/image/save.js b/packages/block-library/src/image/save.js index 65ecc35c4f8c5..ccf816c121e90 100644 --- a/packages/block-library/src/image/save.js +++ b/packages/block-library/src/image/save.js @@ -65,8 +65,6 @@ export default function save( { attributes } ) { ); - const blockProps = useBlockProps.save( { className: classes } ); - if ( 'left' === align || 'right' === align || 'center' === align ) { return (
    @@ -75,5 +73,9 @@ export default function save( { attributes } ) { ); } - return
    { figure }
    ; + return ( +
    + { figure } +
    + ); } From d1a1a4e27a677cd5d0e22544e8705770f558951e Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 17 Feb 2021 11:25:39 +1300 Subject: [PATCH 094/103] Remove unused method --- packages/block-library/src/image/utils.js | 28 +---------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/packages/block-library/src/image/utils.js b/packages/block-library/src/image/utils.js index fb2a9708c4cb5..c1176ff7a9807 100644 --- a/packages/block-library/src/image/utils.js +++ b/packages/block-library/src/image/utils.js @@ -6,12 +6,7 @@ import { isEmpty, each, get } from 'lodash'; /** * Internal dependencies */ -import { - NEW_TAB_REL, - LINK_DESTINATION_MEDIA, - LINK_DESTINATION_ATTACHMENT, - LINK_DESTINATION_NONE, -} from './constants'; +import { NEW_TAB_REL } from './constants'; export function removeNewTabRel( currentRel ) { let newRel = currentRel; @@ -62,27 +57,6 @@ export function getUpdatedLinkTargetSettings( value, { rel } ) { }; } -/** - * Determines new href and linkDestination values for an image block from the - * supplied link destination. - * - * @param {Object} image Image. - * @param {string} destination Link destination. - * @return {string} New url attributes to assign to image block. - */ -export function getUrl( image, destination ) { - switch ( destination ) { - case LINK_DESTINATION_MEDIA: - return image?.source_url || image?.url; // eslint-disable-line camelcase - case LINK_DESTINATION_ATTACHMENT: - return image?.link; - case LINK_DESTINATION_NONE: - return undefined; - } - - return {}; -} - /** * Determines new Image block attributes size selection. * From 62256c8c25d6bab40b1c061d3a21847bfc4a657e Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 17 Feb 2021 11:35:45 +1300 Subject: [PATCH 095/103] Merge similar Image transforms. --- .../block-library/src/image/transforms.js | 29 +++---------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/packages/block-library/src/image/transforms.js b/packages/block-library/src/image/transforms.js index e3b39810bda7f..94bc8ed1b2bba 100644 --- a/packages/block-library/src/image/transforms.js +++ b/packages/block-library/src/image/transforms.js @@ -128,35 +128,14 @@ const transforms = { }, }, { - type: 'files', - isMatch( files ) { - return ( - files.length === 1 && - files[ 0 ].type.indexOf( 'image/' ) === 0 - ); - }, - transform( files ) { - const file = files[ 0 ]; - // We don't need to upload the media directly here - // It's already done as part of the `componentDidMount` - // int the image block - return createBlock( 'core/image', { - url: createBlobURL( file ), - } ); - }, - }, - { - // When drag and dropping multiple files onto a gallery this overrrides the + // Note: when dragging and dropping multiple files onto a gallery this overrrides the // gallery transform in order to add new images to the gallery instead of // creating a new gallery. type: 'files', isMatch( files ) { - return ( - files.length !== 1 && - every( - files, - ( file ) => file.type.indexOf( 'image/' ) === 0 - ) + return every( + files, + ( file ) => file.type.indexOf( 'image/' ) === 0 ); }, transform( files ) { From b7d8965408b19d48f6a66a78cee2830fdebb185f Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Fri, 19 Feb 2021 11:09:39 +1300 Subject: [PATCH 096/103] Fix some issues missed when moving attribute setting back to gallery. --- packages/block-library/src/gallery/edit.js | 5 ----- packages/block-library/src/image/image.js | 7 ++++--- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index 2409354e79499..aa13137269497 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -259,11 +259,6 @@ function GalleryEdit( props ) { const newBlocks = newImages.map( ( image ) => { return createBlock( 'core/image', { ...buildImageAttributes( false, image ), - inheritedAttributes: { - linkDestination: true, - linkTarget: true, - sizeSlug: true, - }, id: image.id, } ); } ); diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js index 57a18680f023b..2a6edf108f966 100644 --- a/packages/block-library/src/image/image.js +++ b/packages/block-library/src/image/image.js @@ -90,7 +90,7 @@ export default function Image( { } ) { const captionRef = useRef(); const prevUrl = usePrevious( url ); - const { allowResize = true, isGrouped } = context; + const { allowResize = true, isGrouped = false } = context; const { block, currentId, image, multiImageSelection } = useSelect( ( select ) => { const { getMedia } = select( coreStore ); @@ -104,7 +104,8 @@ export default function Image( { return { block: getSelectedBlock(), currentId: getSelectedBlockClientId(), - image: id && isSelected ? getMedia( id ) : null, + image: + id && ( isSelected || isGrouped ) ? getMedia( id ) : null, multiImageSelection: multiSelectedClientIds.length && multiSelectedClientIds.every( @@ -113,7 +114,7 @@ export default function Image( { ), }; }, - [ id, isSelected ] + [ id, isSelected, isGrouped ] ); const { imageEditing, imageSizes, maxWidth, mediaUpload } = useSelect( ( select ) => { From b35939316874acf22d5f0ad9096a3594d44af834 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Fri, 19 Feb 2021 14:48:28 +1300 Subject: [PATCH 097/103] Simplify handling of images from media placeholder now that drag and drop files handled by transform --- .../src/components/media-placeholder/index.js | 21 +++--------- packages/block-library/src/gallery/edit.js | 34 +++++-------------- 2 files changed, 12 insertions(+), 43 deletions(-) diff --git a/packages/block-editor/src/components/media-placeholder/index.js b/packages/block-editor/src/components/media-placeholder/index.js index 0a03a0689f10c..a75520476b9eb 100644 --- a/packages/block-editor/src/components/media-placeholder/index.js +++ b/packages/block-editor/src/components/media-placeholder/index.js @@ -63,8 +63,8 @@ export function MediaPlaceholder( { isAppender, accept, addToGallery, - isGallery = false, multiple = false, + handleUpload = true, dropZoneUIOnly, disableDropZone, disableMediaButtons, @@ -118,26 +118,13 @@ export function MediaPlaceholder( { } }; - const onMediaLibrarySelection = ( files ) => { - if ( isGallery ) { - onSelect( files, true ); - return; - } - onSelect( files ); - }; - const onFilesUpload = ( files ) => { - if ( isGallery ) { - // Because the refactored Gallery hands the files over to Image component InnerBlocks just - // hand the handling of the files over to the Gallery - onSelect( files ); - return; + if ( ! handleUpload ) { + return onSelect( files ); } onFilesPreUpload( files ); let setMedia; if ( multiple ) { - // This is still needed to handle v1 versions of the Gallery block. It can be removed - // once all Gallery instances are forced to migrate. if ( addToGallery ) { // Since the setMedia function runs multiple times per upload group // and is passed newMedia containing every item in its group each time, we must @@ -323,7 +310,7 @@ export function MediaPlaceholder( { addToGallery={ addToGallery } gallery={ multiple && onlyAllowsImages() } multiple={ multiple } - onSelect={ onMediaLibrarySelection } + onSelect={ onSelect } allowedTypes={ allowedTypes } value={ Array.isArray( value ) diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index aa13137269497..e31d73f7d43e2 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -168,7 +168,7 @@ function GalleryEdit( props ) { if ( ! shortCodeTransforms || ! shortCodeImages ) { return; } - onSelectImages( shortCodeImages ); + updateImages( shortCodeImages ); setAttributes( { shortCodeTransforms: undefined } ); }, [ shortCodeTransforms, shortCodeImages ] ); @@ -217,22 +217,8 @@ function GalleryEdit( props ) { }; } - function onSelectImages( selectedImages, replace = false ) { - const imageArray = - Object.prototype.toString.call( selectedImages ) === - '[object FileList]' - ? Array.from( selectedImages ).map( ( file ) => { - if ( ! file.url ) { - return pickRelevantMediaFiles( { - url: createBlobURL( file ), - } ); - } - - return file; - } ) - : selectedImages; - - const processedImages = imageArray + function updateImages( selectedImages ) { + const processedImages = selectedImages .filter( ( file ) => file.url || file.type?.indexOf( 'image/' ) === 0 ) @@ -246,13 +232,9 @@ function GalleryEdit( props ) { return file; } ); - const existingImageBlocks = replace - ? innerBlockImages.filter( ( block ) => - processedImages.find( - ( img ) => img.url === block.attributes.url - ) - ) - : innerBlockImages; + const existingImageBlocks = innerBlockImages.filter( ( block ) => + processedImages.find( ( img ) => img.url === block.attributes.url ) + ); const newImages = differenceBy( processedImages, images, 'url' ); @@ -378,7 +360,7 @@ function GalleryEdit( props ) { const mediaPlaceholder = ( Date: Fri, 19 Feb 2021 12:04:55 +1000 Subject: [PATCH 098/103] Fix typo --- packages/block-library/src/gallery/edit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index e31d73f7d43e2..0493cd33fccb5 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -360,7 +360,7 @@ function GalleryEdit( props ) { const mediaPlaceholder = ( Date: Fri, 19 Feb 2021 15:46:00 +1300 Subject: [PATCH 099/103] Fix broken upload from media placeholder --- packages/block-library/src/gallery/edit.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index 0493cd33fccb5..04481aba90215 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -218,7 +218,21 @@ function GalleryEdit( props ) { } function updateImages( selectedImages ) { - const processedImages = selectedImages + const imageArray = + Object.prototype.toString.call( selectedImages ) === + '[object FileList]' + ? Array.from( selectedImages ).map( ( file ) => { + if ( ! file.url ) { + return pickRelevantMediaFiles( { + url: createBlobURL( file ), + } ); + } + + return file; + } ) + : selectedImages; + + const processedImages = imageArray .filter( ( file ) => file.url || file.type?.indexOf( 'image/' ) === 0 ) From 66332839b8cc861dd38ae6bd7e0a946f9e3b9066 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Fri, 19 Feb 2021 16:01:26 +1300 Subject: [PATCH 100/103] Fix issue with new file uploads overwriting existing blocks --- packages/block-library/src/gallery/edit.js | 34 +++++++++++++--------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index 04481aba90215..df4f875212f2f 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -218,19 +218,21 @@ function GalleryEdit( props ) { } function updateImages( selectedImages ) { - const imageArray = + const newFileUploads = Object.prototype.toString.call( selectedImages ) === - '[object FileList]' - ? Array.from( selectedImages ).map( ( file ) => { - if ( ! file.url ) { - return pickRelevantMediaFiles( { - url: createBlobURL( file ), - } ); - } + '[object FileList]'; + + const imageArray = newFileUploads + ? Array.from( selectedImages ).map( ( file ) => { + if ( ! file.url ) { + return pickRelevantMediaFiles( { + url: createBlobURL( file ), + } ); + } - return file; - } ) - : selectedImages; + return file; + } ) + : selectedImages; const processedImages = imageArray .filter( @@ -246,9 +248,13 @@ function GalleryEdit( props ) { return file; } ); - const existingImageBlocks = innerBlockImages.filter( ( block ) => - processedImages.find( ( img ) => img.url === block.attributes.url ) - ); + const existingImageBlocks = ! newFileUploads + ? innerBlockImages.filter( ( block ) => + processedImages.find( + ( img ) => img.url === block.attributes.url + ) + ) + : innerBlockImages; const newImages = differenceBy( processedImages, images, 'url' ); From 5307562d35cf288e7a2411fbfe9a2d4e16278c0c Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Mon, 22 Feb 2021 19:42:35 +1300 Subject: [PATCH 101/103] Remove isGrouped dependency from call to get image as not needed now attributes handled by gallery --- packages/block-library/src/image/image.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js index 2a6edf108f966..2fdf202c0448e 100644 --- a/packages/block-library/src/image/image.js +++ b/packages/block-library/src/image/image.js @@ -104,8 +104,7 @@ export default function Image( { return { block: getSelectedBlock(), currentId: getSelectedBlockClientId(), - image: - id && ( isSelected || isGrouped ) ? getMedia( id ) : null, + image: id && isSelected ? getMedia( id ) : null, multiImageSelection: multiSelectedClientIds.length && multiSelectedClientIds.every( @@ -114,7 +113,7 @@ export default function Image( { ), }; }, - [ id, isSelected, isGrouped ] + [ id, isSelected ] ); const { imageEditing, imageSizes, maxWidth, mediaUpload } = useSelect( ( select ) => { From 658db60d05b5dfc1cd33c23cd4cc0b9ef8b5b35c Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Mon, 22 Feb 2021 21:47:16 +1000 Subject: [PATCH 102/103] Remove custom gutter size feature Reasoning for removal can be found at https://github.com/WordPress/gutenberg/pull/25940#discussion_r574299055 --- packages/block-library/src/gallery/block.json | 3 --- packages/block-library/src/gallery/edit.js | 22 ------------------- packages/block-library/src/gallery/save.js | 9 ++------ 3 files changed, 2 insertions(+), 32 deletions(-) diff --git a/packages/block-library/src/gallery/block.json b/packages/block-library/src/gallery/block.json index 119afc32e7c82..aa9214d5aab78 100644 --- a/packages/block-library/src/gallery/block.json +++ b/packages/block-library/src/gallery/block.json @@ -96,9 +96,6 @@ "imageCount": { "type": "number", "default": 0 - }, - "gutterSize": { - "type": "number" } }, "providesContext": { diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index df4f875212f2f..d8d1f9bdaecaa 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -72,10 +72,6 @@ const MOBILE_CONTROL_PROPS_RANGE_CONTROL = Platform.select( { native: { type: 'stepper' }, } ); -const DEFAULT_GUTTER_SIZE = 16; -const MAX_GUTTER_SIZE = 100; -const MIN_GUTTER_SIZE = 0; - function GalleryEdit( props ) { const { setAttributes, @@ -91,7 +87,6 @@ function GalleryEdit( props ) { const { imageCount, columns = defaultColumnsNumber( imageCount ), - gutterSize, imageCrop, linkTarget, linkTo, @@ -400,10 +395,6 @@ function GalleryEdit( props ) { const blockProps = useBlockProps( { className: classnames( className, 'has-nested-images' ), - style: { - '--gallery-block--gutter-size': - gutterSize !== undefined ? `${ gutterSize }px` : undefined, - }, } ); if ( ! hasImages ) { @@ -428,19 +419,6 @@ function GalleryEdit( props ) { required /> ) } - - setAttributes( { gutterSize: newGutterSize } ) - } - initialPosition={ DEFAULT_GUTTER_SIZE } - min={ MIN_GUTTER_SIZE } - max={ MAX_GUTTER_SIZE } - { ...MOBILE_CONTROL_PROPS_RANGE_CONTROL } - resetFallbackValue={ DEFAULT_GUTTER_SIZE } - allowReset - /> 0 || attributes?.images?.length > 0 ) { return saveV1( { attributes } ); } + const { imageCount, caption, columns = defaultColumnsNumber( imageCount ), - gutterSize, imageCrop, } = attributes; @@ -25,13 +25,8 @@ export default function save( { attributes } ) { imageCrop ? 'is-cropped' : '' }`; - const style = { - '--gallery-block--gutter-size': - gutterSize !== undefined ? `${ gutterSize }px` : undefined, - }; - return ( -
    +
    { ! RichText.isEmpty( caption ) && ( Date: Mon, 22 Feb 2021 21:51:51 +1000 Subject: [PATCH 103/103] Re-apply original approach to custom gallery gutters These changes re-apply the custom gutter size feature that was removed from the refactored gallery block PR so it could be discussed independently. --- packages/block-library/src/gallery/block.json | 3 +++ packages/block-library/src/gallery/edit.js | 22 +++++++++++++++++++ packages/block-library/src/gallery/save.js | 8 ++++++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/gallery/block.json b/packages/block-library/src/gallery/block.json index aa9214d5aab78..119afc32e7c82 100644 --- a/packages/block-library/src/gallery/block.json +++ b/packages/block-library/src/gallery/block.json @@ -96,6 +96,9 @@ "imageCount": { "type": "number", "default": 0 + }, + "gutterSize": { + "type": "number" } }, "providesContext": { diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index d8d1f9bdaecaa..df4f875212f2f 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -72,6 +72,10 @@ const MOBILE_CONTROL_PROPS_RANGE_CONTROL = Platform.select( { native: { type: 'stepper' }, } ); +const DEFAULT_GUTTER_SIZE = 16; +const MAX_GUTTER_SIZE = 100; +const MIN_GUTTER_SIZE = 0; + function GalleryEdit( props ) { const { setAttributes, @@ -87,6 +91,7 @@ function GalleryEdit( props ) { const { imageCount, columns = defaultColumnsNumber( imageCount ), + gutterSize, imageCrop, linkTarget, linkTo, @@ -395,6 +400,10 @@ function GalleryEdit( props ) { const blockProps = useBlockProps( { className: classnames( className, 'has-nested-images' ), + style: { + '--gallery-block--gutter-size': + gutterSize !== undefined ? `${ gutterSize }px` : undefined, + }, } ); if ( ! hasImages ) { @@ -419,6 +428,19 @@ function GalleryEdit( props ) { required /> ) } + + setAttributes( { gutterSize: newGutterSize } ) + } + initialPosition={ DEFAULT_GUTTER_SIZE } + min={ MIN_GUTTER_SIZE } + max={ MAX_GUTTER_SIZE } + { ...MOBILE_CONTROL_PROPS_RANGE_CONTROL } + resetFallbackValue={ DEFAULT_GUTTER_SIZE } + allowReset + /> +
    { ! RichText.isEmpty( caption ) && (