From d70856b4b0cea364231c0981ada552723a3bb4c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20=28On=20Vacation=29?= <583546+oandregal@users.noreply.github.com> Date: Fri, 15 Jul 2022 17:50:07 +0200 Subject: [PATCH] Quote: add support for nested blocks (#25892) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements nested blocks support for Quotes. This allows the display of lists, headings, images, and virtually any other block within a blockquote. Co-authored-by: Ella van Durpe Co-authored-by: André <583546+oandregal@users.noreply.github.com> --- .../block-editor-settings-mobile.php | 4 +- lib/experimental/blocks.php | 13 - lib/experiments-page.php | 11 - packages/block-library/src/index.native.js | 13 +- packages/block-library/src/list/transforms.js | 30 -- .../block-library/src/quote/deprecated.js | 312 ++++++++++++------ packages/block-library/src/quote/edit.js | 129 +++++--- packages/block-library/src/quote/index.js | 43 +-- packages/block-library/src/quote/save.js | 10 +- .../src/quote/{v2 => }/test/migrate.js | 9 +- .../block-library/src/quote/transforms.js | 264 +++++++-------- .../block-library/src/quote/v2/deprecated.js | 107 ------ packages/block-library/src/quote/v2/edit.js | 139 -------- packages/block-library/src/quote/v2/index.js | 36 -- packages/block-library/src/quote/v2/save.js | 26 -- .../block-library/src/quote/v2/transforms.js | 155 --------- .../e2e-test-utils/src/transform-block-to.js | 5 +- packages/e2e-tests/plugins/cpt-locking.php | 32 +- .../blocks/__snapshots__/quote.test.js.snap | 168 +++------- .../specs/editor/blocks/quote.test.js | 113 +------ .../__snapshots__/cpt-locking.test.js.snap | 32 +- .../inner-blocks-render-appender.test.js.snap | 8 +- .../__snapshots__/templates.test.js.snap | 8 +- .../editor/plugins/block-variations.test.js | 2 + .../specs/editor/plugins/cpt-locking.test.js | 6 +- .../inner-blocks-render-appender.test.js | 3 + .../multi-block-selection.test.js.snap | 16 - .../__snapshots__/writing-flow.test.js.snap | 6 +- .../editor/various/block-switcher.test.js | 1 - .../various/multi-block-selection.test.js | 24 -- .../editor/various/reusable-blocks.test.js | 2 + .../specs/editor/various/writing-flow.test.js | 2 +- packages/edit-post/src/test/editor.native.js | 4 +- packages/react-native-editor/src/setup.js | 11 +- .../src/test/index.test.js | 3 +- test/e2e/specs/editor/blocks/list.spec.js | 21 +- test/e2e/specs/editor/blocks/quote.spec.js | 4 +- .../editor/various/style-variation.spec.js | 7 +- .../blocks-raw-handling.test.js.snap | 28 +- test/integration/blocks-raw-handling.test.js | 109 +----- .../blocks/core__quote__deprecated-1.json | 13 +- .../core__quote__deprecated-1.serialized.html | 4 +- .../blocks/core__quote__deprecated-2.json | 13 +- .../core__quote__deprecated-2.serialized.html | 4 +- .../fixtures/blocks/core__quote__style-1.html | 8 +- .../fixtures/blocks/core__quote__style-1.json | 14 +- .../blocks/core__quote__style-1.parsed.json | 18 +- .../core__quote__style-1.serialized.html | 4 +- .../fixtures/blocks/core__quote__style-2.html | 8 +- .../fixtures/blocks/core__quote__style-2.json | 14 +- .../blocks/core__quote__style-2.parsed.json | 18 +- .../core__quote__style-2.serialized.html | 4 +- .../fixtures/documents/markdown-out.html | 8 +- 53 files changed, 708 insertions(+), 1338 deletions(-) rename packages/block-library/src/quote/{v2 => }/test/migrate.js (89%) delete mode 100644 packages/block-library/src/quote/v2/deprecated.js delete mode 100644 packages/block-library/src/quote/v2/edit.js delete mode 100644 packages/block-library/src/quote/v2/index.js delete mode 100644 packages/block-library/src/quote/v2/save.js delete mode 100644 packages/block-library/src/quote/v2/transforms.js diff --git a/lib/experimental/block-editor-settings-mobile.php b/lib/experimental/block-editor-settings-mobile.php index bd05e24e4acc9..d0a0e7add5319 100644 --- a/lib/experimental/block-editor-settings-mobile.php +++ b/lib/experimental/block-editor-settings-mobile.php @@ -26,9 +26,9 @@ function gutenberg_get_block_editor_settings_mobile( $settings ) { $settings['__experimentalStyles'] = gutenberg_get_global_styles(); } - // To be set to true when the web makes quote v2 (inner blocks) the default. + // To tell mobile that the site uses quote v2 (inner blocks). // See https://github.com/WordPress/gutenberg/pull/25892. - $settings['__experimentalEnableQuoteBlockV2'] = gutenberg_is_quote_v2_enabled(); + $settings['__experimentalEnableQuoteBlockV2'] = true; } return $settings; diff --git a/lib/experimental/blocks.php b/lib/experimental/blocks.php index b9ac0a6c71583..c92358621c5de 100644 --- a/lib/experimental/blocks.php +++ b/lib/experimental/blocks.php @@ -5,15 +5,6 @@ * @package gutenberg */ -/** - * Returns whether the quote v2 is enabled by the user. - * - * @return boolean - */ -function gutenberg_is_quote_v2_enabled() { - return get_option( 'gutenberg-experiments' ) && array_key_exists( 'gutenberg-quote-v2', get_option( 'gutenberg-experiments' ) ); -} - /** * Sets a global JS variable used to trigger the availability of the experimental blocks. */ @@ -21,10 +12,6 @@ function gutenberg_enable_experimental_blocks() { if ( get_option( 'gutenberg-experiments' ) && array_key_exists( 'gutenberg-list-v2', get_option( 'gutenberg-experiments' ) ) ) { wp_add_inline_script( 'wp-block-library', 'window.__experimentalEnableListBlockV2 = true', 'before' ); } - - if ( gutenberg_is_quote_v2_enabled() ) { - wp_add_inline_script( 'wp-block-library', 'window.__experimentalEnableQuoteBlockV2 = true', 'before' ); - } } add_action( 'admin_init', 'gutenberg_enable_experimental_blocks' ); diff --git a/lib/experiments-page.php b/lib/experiments-page.php index 0c9e8eba38d72..581b6afebdf21 100644 --- a/lib/experiments-page.php +++ b/lib/experiments-page.php @@ -52,17 +52,6 @@ function gutenberg_initialize_experiments_settings() { 'id' => 'gutenberg-list-v2', ) ); - add_settings_field( - 'gutenberg-quote-v2', - __( 'Quote block v2', 'gutenberg' ), - 'gutenberg_display_experiment_field', - 'gutenberg-experiments', - 'gutenberg_experiments_section', - array( - 'label' => __( 'Test a new quote block that allows nested blocks (Warning: The new block is not ready. You may experience content loss, avoid using it on production sites)', 'gutenberg' ), - 'id' => 'gutenberg-quote-v2', - ) - ); register_setting( 'gutenberg-experiments', 'gutenberg-experiments' diff --git a/packages/block-library/src/index.native.js b/packages/block-library/src/index.native.js index 984e5c290135d..863cd4ef3315d 100644 --- a/packages/block-library/src/index.native.js +++ b/packages/block-library/src/index.native.js @@ -179,14 +179,6 @@ const devOnly = ( block ) => ( !! __DEV__ ? block : null ); const iOSOnly = ( block ) => Platform.OS === 'ios' ? block : devOnly( block ); -// To be removed once Quote V2 is released on the web editor. -function quoteCheck( quoteBlock, blocksFlags ) { - if ( blocksFlags?.__experimentalEnableQuoteBlockV2 ) { - quoteBlock.settings = quoteBlock?.settingsV2; - } - return quoteBlock; -} - // Hide the Classic block and SocialLink block addFilter( 'blocks.registerBlockType', @@ -238,10 +230,9 @@ addFilter( * * registerCoreBlocks(); * ``` - * @param {Object} [blocksFlags] Experimental flags * */ -export const registerCoreBlocks = ( blocksFlags ) => { +export const registerCoreBlocks = () => { // When adding new blocks to this list please also consider updating /src/block-support/supported-blocks.json in the Gutenberg-Mobile repo [ paragraph, @@ -254,7 +245,7 @@ export const registerCoreBlocks = ( blocksFlags ) => { nextpage, separator, list, - quoteCheck( quote, blocksFlags ), + quote, mediaText, preformatted, gallery, diff --git a/packages/block-library/src/list/transforms.js b/packages/block-library/src/list/transforms.js index 5d67e6cee0c67..32667a99a735a 100644 --- a/packages/block-library/src/list/transforms.js +++ b/packages/block-library/src/list/transforms.js @@ -65,19 +65,6 @@ const transforms = { } ); }, }, - { - type: 'block', - blocks: [ 'core/quote', 'core/pullquote' ], - transform: ( { value, anchor } ) => { - return createBlock( 'core/list', { - values: toHTMLString( { - value: create( { html: value, multilineTag: 'p' } ), - multilineTag: 'li', - } ), - anchor, - } ); - }, - }, { type: 'raw', selector: 'ol,ul', @@ -174,23 +161,6 @@ const transforms = { } ) ), }, - { - type: 'block', - blocks: [ 'core/quote' ], - transform: ( { values, anchor } ) => { - return createBlock( 'core/quote', { - value: toHTMLString( { - value: create( { - html: values, - multilineTag: 'li', - multilineWrapperTags: [ 'ul', 'ol' ], - } ), - multilineTag: 'p', - } ), - anchor, - } ); - }, - }, { type: 'block', blocks: [ 'core/pullquote' ], diff --git a/packages/block-library/src/quote/deprecated.js b/packages/block-library/src/quote/deprecated.js index cd1443038002b..f9cd8d581b962 100644 --- a/packages/block-library/src/quote/deprecated.js +++ b/packages/block-library/src/quote/deprecated.js @@ -1,127 +1,241 @@ /** * External dependencies */ +import classnames from 'classnames'; import { omit } from 'lodash'; /** * WordPress dependencies */ -import { RichText } from '@wordpress/block-editor'; - -const blockAttributes = { - value: { - type: 'string', - source: 'html', - selector: 'blockquote', - multiline: 'p', - default: '', - }, - citation: { - type: 'string', - source: 'html', - selector: 'cite', - default: '', - }, - align: { - type: 'string', - }, +import { createBlock, parseWithAttributeSchema } from '@wordpress/blocks'; +import { RichText, useBlockProps } from '@wordpress/block-editor'; + +export const migrateToQuoteV2 = ( attributes ) => { + const { value } = attributes; + + return [ + { + ...omit( attributes, [ 'value' ] ), + }, + value + ? parseWithAttributeSchema( value, { + type: 'array', + source: 'query', + selector: 'p', + query: { + content: { + type: 'string', + source: 'html', + }, + }, + } ).map( ( { content } ) => + createBlock( 'core/paragraph', { content } ) + ) + : createBlock( 'core/paragraph' ), + ]; }; -const deprecated = [ - { - attributes: blockAttributes, - save( { attributes } ) { - const { align, value, citation } = attributes; - - return ( -
- - { ! RichText.isEmpty( citation ) && ( - - ) } -
- ); +const v3 = { + attributes: { + value: { + type: 'string', + source: 'html', + selector: 'blockquote', + multiline: 'p', + default: '', + __experimentalRole: 'content', + }, + citation: { + type: 'string', + source: 'html', + selector: 'cite', + default: '', + __experimentalRole: 'content', + }, + align: { + type: 'string', }, }, - { - attributes: { - ...blockAttributes, - style: { - type: 'number', - default: 1, + supports: { + anchor: true, + __experimentalSlashInserter: true, + typography: { + fontSize: true, + lineHeight: true, + __experimentalFontStyle: true, + __experimentalFontWeight: true, + __experimentalLetterSpacing: true, + __experimentalTextTransform: true, + __experimentalDefaultControls: { + fontSize: true, + fontAppearance: true, }, }, + }, + save( { attributes } ) { + const { align, value, citation } = attributes; + + const className = classnames( { + [ `has-text-align-${ align }` ]: align, + } ); - migrate( attributes ) { - if ( attributes.style === 2 ) { - return { - ...omit( attributes, [ 'style' ] ), - className: attributes.className - ? attributes.className + ' is-style-large' - : 'is-style-large', - }; - } + return ( +
+ + { ! RichText.isEmpty( citation ) && ( + + ) } +
+ ); + }, + migrate: migrateToQuoteV2, +}; - return attributes; +const v2 = { + attributes: { + value: { + type: 'string', + source: 'html', + selector: 'blockquote', + multiline: 'p', + default: '', + }, + citation: { + type: 'string', + source: 'html', + selector: 'cite', + default: '', }, + align: { + type: 'string', + }, + }, + migrate: migrateToQuoteV2, + save( { attributes } ) { + const { align, value, citation } = attributes; - save( { attributes } ) { - const { align, value, citation, style } = attributes; + return ( +
+ + { ! RichText.isEmpty( citation ) && ( + + ) } +
+ ); + }, +}; - return ( -
- - { ! RichText.isEmpty( citation ) && ( - - ) } -
- ); +const v1 = { + attributes: { + value: { + type: 'string', + source: 'html', + selector: 'blockquote', + multiline: 'p', + default: '', }, - }, - { - attributes: { - ...blockAttributes, - citation: { - type: 'string', - source: 'html', - selector: 'footer', - default: '', - }, - style: { - type: 'number', - default: 1, - }, + citation: { + type: 'string', + source: 'html', + selector: 'cite', + default: '', }, + align: { + type: 'string', + }, + style: { + type: 'number', + default: 1, + }, + }, - migrate( attributes ) { - if ( ! isNaN( parseInt( attributes.style ) ) ) { - return { - ...omit( attributes, [ 'style' ] ), - }; - } + migrate( attributes ) { + if ( attributes.style === 2 ) { + return migrateToQuoteV2( { + ...omit( attributes, [ 'style' ] ), + className: attributes.className + ? attributes.className + ' is-style-large' + : 'is-style-large', + } ); + } - return attributes; - }, + return migrateToQuoteV2( attributes ); + }, - save( { attributes } ) { - const { align, value, citation, style } = attributes; + save( { attributes } ) { + const { align, value, citation, style } = attributes; - return ( -
- - { ! RichText.isEmpty( citation ) && ( - - ) } -
- ); + return ( +
+ + { ! RichText.isEmpty( citation ) && ( + + ) } +
+ ); + }, +}; + +const v0 = { + attributes: { + value: { + type: 'string', + source: 'html', + selector: 'blockquote', + multiline: 'p', + default: '', + }, + citation: { + type: 'string', + source: 'html', + selector: 'footer', + default: '', + }, + align: { + type: 'string', }, + style: { + type: 'number', + default: 1, + }, + }, + + migrate( attributes ) { + if ( ! isNaN( parseInt( attributes.style ) ) ) { + return migrateToQuoteV2( { + ...omit( attributes, [ 'style' ] ), + } ); + } + + return migrateToQuoteV2( attributes ); + }, + + save( { attributes } ) { + const { align, value, citation, style } = attributes; + + return ( +
+ + { ! RichText.isEmpty( citation ) && ( + + ) } +
+ ); }, -]; +}; -export default deprecated; +/** + * New deprecations need to be placed first + * for them to have higher priority. + * + * Old deprecations may need to be updated as well. + * + * See block-deprecation.md + */ +export default [ v3, v2, v1, v0 ]; diff --git a/packages/block-library/src/quote/edit.js b/packages/block-library/src/quote/edit.js index 8bd50b68ae978..e6c560078e501 100644 --- a/packages/block-library/src/quote/edit.js +++ b/packages/block-library/src/quote/edit.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import classnames from 'classnames'; +import classNames from 'classnames'; /** * WordPress dependencies @@ -12,29 +12,87 @@ import { BlockControls, RichText, useBlockProps, + useInnerBlocksProps, + store as blockEditorStore, } from '@wordpress/block-editor'; import { BlockQuotation } from '@wordpress/components'; +import { useDispatch, useSelect, useRegistry } from '@wordpress/data'; import { createBlock, getDefaultBlockName } from '@wordpress/blocks'; -import { Platform } from '@wordpress/element'; +import { Platform, useEffect } from '@wordpress/element'; +import deprecated from '@wordpress/deprecated'; + +/** + * Internal dependencies + */ +import { migrateToQuoteV2 } from './deprecated'; const isWebPlatform = Platform.OS === 'web'; +const TEMPLATE = [ [ 'core/paragraph', {} ] ]; + +/** + * At the moment, deprecations don't handle create blocks from attributes + * (like when using CPT templates). For this reason, this hook is necessary + * to avoid breaking templates using the old quote block format. + * + * @param {Object} attributes Block attributes. + * @param {string} clientId Block client ID. + */ +const useMigrateOnLoad = ( attributes, clientId ) => { + const registry = useRegistry(); + const { updateBlockAttributes, replaceInnerBlocks } = + useDispatch( blockEditorStore ); + useEffect( () => { + // As soon as the block is loaded, migrate it to the new version. + + if ( ! attributes.value ) { + // No need to migrate if it doesn't have the value attribute. + return; + } + + const [ newAttributes, newInnerBlocks ] = + migrateToQuoteV2( attributes ); + + deprecated( 'Value attribute on the quote block', { + since: '6.0', + version: '6.5', + alternative: 'inner blocks', + } ); + + registry.batch( () => { + updateBlockAttributes( clientId, newAttributes ); + replaceInnerBlocks( clientId, newInnerBlocks ); + } ); + }, [ attributes.value ] ); +}; + export default function QuoteEdit( { attributes, setAttributes, - isSelected, - mergeBlocks, - onReplace, - className, insertBlocksAfter, + clientId, + className, style, } ) { - const { align, value, citation } = attributes; + const { align, citation } = attributes; + + useMigrateOnLoad( attributes, clientId ); + + const hasSelection = useSelect( ( select ) => { + const { isBlockSelected, hasSelectedInnerBlock } = + select( blockEditorStore ); + return hasSelectedInnerBlock( clientId ) || isBlockSelected( clientId ); + }, [] ); + const blockProps = useBlockProps( { - className: classnames( className, { + className: classNames( className, { [ `has-text-align-${ align }` ]: align, } ), - style, + ...( ! isWebPlatform && { style } ), + } ); + const innerBlocksProps = useInnerBlocksProps( blockProps, { + template: TEMPLATE, + templateInsertUpdatesSelection: true, } ); return ( @@ -47,66 +105,33 @@ export default function QuoteEdit( { } } /> - - - setAttributes( { - value: nextValue, - } ) - } - onMerge={ mergeBlocks } - onRemove={ ( forward ) => { - const hasEmptyCitation = - ! citation || citation.length === 0; - if ( ! forward && hasEmptyCitation ) { - onReplace( [] ); - } - } } - aria-label={ __( 'Quote text' ) } - placeholder={ - // translators: placeholder text used for the quote - __( 'Add quote' ) - } - onReplace={ onReplace } - onSplit={ ( piece ) => - createBlock( 'core/quote', { - ...attributes, - value: piece, - } ) - } - __unstableOnSplitMiddle={ () => - createBlock( 'core/paragraph' ) - } - textAlign={ align } - __unstableEmbedURLOnPaste - /> - { ( ! RichText.isEmpty( citation ) || isSelected ) && ( + + { innerBlocksProps.children } + { ( ! RichText.isEmpty( citation ) || hasSelection ) && ( + onChange={ ( nextCitation ) => { setAttributes( { citation: nextCitation, - } ) - } + } ); + } } __unstableMobileNoFocusOnMount - aria-label={ __( 'Quote citation text' ) } + aria-label={ __( 'Quote citation' ) } placeholder={ - // translators: placeholder text used for the citation + // translators: placeholder text used for the + // citation __( 'Add citation' ) } className="wp-block-quote__citation" - textAlign={ align } __unstableOnSplitAtEnd={ () => insertBlocksAfter( createBlock( getDefaultBlockName() ) ) } + { ...( ! isWebPlatform ? { textAlign: align } : {} ) } /> ) } diff --git a/packages/block-library/src/quote/index.js b/packages/block-library/src/quote/index.js index 2490462b8a963..8140ad49f3495 100644 --- a/packages/block-library/src/quote/index.js +++ b/packages/block-library/src/quote/index.js @@ -12,51 +12,28 @@ import edit from './edit'; import metadata from './block.json'; import save from './save'; import transforms from './transforms'; -import settingsV2 from './v2'; const { name } = metadata; -export { metadata, name, settingsV2 }; +export { metadata, name }; -export const settingsV1 = { +export const settings = { icon, example: { attributes: { - value: - '

' + __( 'In quoting others, we cite ourselves.' ) + '

', citation: 'Julio Cortázar', }, + innerBlocks: [ + { + name: 'core/paragraph', + attributes: { + content: __( 'In quoting others, we cite ourselves.' ), + }, + }, + ], }, transforms, edit, save, - merge( attributes, { value, citation } ) { - // Quote citations cannot be merged. Pick the second one unless it's - // empty. - if ( ! citation ) { - citation = attributes.citation; - } - - if ( ! value || value === '

' ) { - return { - ...attributes, - citation, - }; - } - - return { - ...attributes, - value: attributes.value + value, - citation, - }; - }, deprecated, }; - -let settings = settingsV1; -if ( process.env.IS_GUTENBERG_PLUGIN ) { - settings = window?.__experimentalEnableQuoteBlockV2 - ? settingsV2 - : settingsV1; -} -export { settings }; diff --git a/packages/block-library/src/quote/save.js b/packages/block-library/src/quote/save.js index fafbec8df5221..7b6ecab8762eb 100644 --- a/packages/block-library/src/quote/save.js +++ b/packages/block-library/src/quote/save.js @@ -1,23 +1,23 @@ /** * External dependencies */ -import classnames from 'classnames'; +import classNames from 'classnames'; /** * WordPress dependencies */ -import { RichText, useBlockProps } from '@wordpress/block-editor'; +import { InnerBlocks, RichText, useBlockProps } from '@wordpress/block-editor'; export default function save( { attributes } ) { - const { align, value, citation } = attributes; + const { align, citation } = attributes; - const className = classnames( { + const className = classNames( { [ `has-text-align-${ align }` ]: align, } ); return (
- + { ! RichText.isEmpty( citation ) && ( ) } diff --git a/packages/block-library/src/quote/v2/test/migrate.js b/packages/block-library/src/quote/test/migrate.js similarity index 89% rename from packages/block-library/src/quote/v2/test/migrate.js rename to packages/block-library/src/quote/test/migrate.js index 475344b51d3be..d1107473c1b5d 100644 --- a/packages/block-library/src/quote/v2/test/migrate.js +++ b/packages/block-library/src/quote/test/migrate.js @@ -11,9 +11,8 @@ import { * Internal dependencies */ import { migrateToQuoteV2 } from '../deprecated'; -import * as paragraph from '../../../paragraph'; -import * as quote from '../../../quote'; -import * as quoteV2 from '../../../quote/v2'; +import * as paragraph from '../../paragraph'; +import * as quote from '../../quote'; describe( 'Migrate quote block', () => { beforeAll( () => { @@ -21,10 +20,6 @@ describe( 'Migrate quote block', () => { { name: paragraph.name, ...paragraph.metadata }, paragraph.settings ); - registerBlockType( - { name: quote.name, ...quote.metadata }, - quoteV2.settings - ); } ); afterAll( () => { diff --git a/packages/block-library/src/quote/transforms.js b/packages/block-library/src/quote/transforms.js index 134aff4339eda..18716d3b11308 100644 --- a/packages/block-library/src/quote/transforms.js +++ b/packages/block-library/src/quote/transforms.js @@ -1,188 +1,158 @@ /** * WordPress dependencies */ -import { createBlock } from '@wordpress/blocks'; -import { create, join, split, toHTMLString } from '@wordpress/rich-text'; +import { + createBlock, + parseWithAttributeSchema, + rawHandler, +} from '@wordpress/blocks'; const transforms = { from: [ { type: 'block', - isMultiBlock: true, - blocks: [ 'core/paragraph' ], - transform: ( attributes ) => { - return createBlock( 'core/quote', { - value: toHTMLString( { - value: join( - attributes.map( ( { content } ) => - create( { html: content } ) - ), - '\u2028' - ), - multilineTag: 'p', - } ), - anchor: attributes.anchor, - } ); + blocks: [ 'core/pullquote' ], + transform: ( { value, citation, anchor, fontSize, style } ) => { + return createBlock( + 'core/quote', + { + citation, + anchor, + fontSize, + style, + }, + parseWithAttributeSchema( value, { + type: 'array', + source: 'query', + selector: 'p', + query: { + content: { + type: 'string', + source: 'html', + }, + }, + } ).map( ( { content } ) => + createBlock( 'core/paragraph', { content } ) + ) + ); }, }, { type: 'block', - blocks: [ 'core/heading' ], - transform: ( { content, anchor } ) => { - return createBlock( 'core/quote', { - value: `

${ content }

`, - anchor, - } ); - }, - }, - { - type: 'block', - blocks: [ 'core/pullquote' ], - transform: ( { value, citation, anchor } ) => - createBlock( 'core/quote', { - value, - citation, - anchor, - } ), + blocks: [ 'core/group' ], + transform: ( { anchor }, innerBlocks ) => + createBlock( 'core/quote', { anchor }, innerBlocks ), }, { type: 'prefix', prefix: '>', - transform: ( content ) => { - return createBlock( 'core/quote', { - value: `

${ content }

`, - } ); - }, + transform: ( content ) => + createBlock( 'core/quote', {}, [ + createBlock( 'core/paragraph', { content } ), + ] ), }, { type: 'raw', - isMatch: ( node ) => { - const isParagraphOrSingleCite = ( () => { - let hasCitation = false; - return ( child ) => { - // Child is a paragraph. - if ( child.nodeName === 'P' ) { - return true; - } - // Child is a cite and no other cite child exists before it. - if ( ! hasCitation && child.nodeName === 'CITE' ) { - hasCitation = true; - return true; - } - }; - } )(); - return ( - node.nodeName === 'BLOCKQUOTE' && - // The quote block can only handle multiline paragraph - // content with an optional cite child. - Array.from( node.childNodes ).every( - isParagraphOrSingleCite - ) - ); - }, - schema: ( { phrasingContentSchema } ) => ( { + schema: () => ( { blockquote: { - children: { - p: { - children: phrasingContentSchema, - }, - cite: { - children: phrasingContentSchema, - }, - }, + children: '*', }, } ), - }, - ], - to: [ - { - type: 'block', - blocks: [ 'core/paragraph' ], - transform: ( { value, citation } ) => { - const paragraphs = []; - if ( value && value !== '

' ) { - paragraphs.push( - ...split( - create( { html: value, multilineTag: 'p' } ), - '\u2028' - ).map( ( piece ) => - createBlock( 'core/paragraph', { - content: toHTMLString( { value: piece } ), - } ) - ) - ); - } - if ( citation && citation !== '

' ) { - paragraphs.push( - createBlock( 'core/paragraph', { - content: citation, - } ) - ); - } - - if ( paragraphs.length === 0 ) { - return createBlock( 'core/paragraph', { - content: '', - } ); - } - return paragraphs; + selector: 'blockquote', + transform: ( node ) => { + return createBlock( + 'core/quote', + // Don't try to parse any `cite` out of this content. + // * There may be more than one cite. + // * There may be more attribution text than just the cite. + // * If the cite is nested in the quoted text, it's wrong to + // remove it. + {}, + rawHandler( { + HTML: node.innerHTML, + mode: 'BLOCKS', + } ) + ); }, }, - { type: 'block', - blocks: [ 'core/heading' ], - transform: ( { value, citation, ...attrs } ) => { - // If there is no quote content, use the citation as the - // content of the resulting heading. A nonexistent citation - // will result in an empty heading. - if ( value === '

' ) { - return createBlock( 'core/heading', { - content: citation, - } ); - } - - const pieces = split( - create( { html: value, multilineTag: 'p' } ), - '\u2028' - ); - - const headingBlock = createBlock( 'core/heading', { - content: toHTMLString( { value: pieces[ 0 ] } ), - } ); - - if ( ! citation && pieces.length === 1 ) { - return headingBlock; - } - - const quotePieces = pieces.slice( 1 ); - - const quoteBlock = createBlock( 'core/quote', { - ...attrs, - citation, - value: toHTMLString( { - value: quotePieces.length - ? join( pieces.slice( 1 ), '\u2028' ) - : create(), - multilineTag: 'p', - } ), - } ); - - return [ headingBlock, quoteBlock ]; + isMultiBlock: true, + blocks: [ '*' ], + isMatch: ( {}, blocks ) => { + return ! blocks.some( ( { name } ) => name === 'core/quote' ); }, + __experimentalConvert: ( blocks ) => + createBlock( + 'core/quote', + {}, + blocks.map( ( block ) => + createBlock( + block.name, + block.attributes, + block.innerBlocks + ) + ) + ), }, - + ], + to: [ { type: 'block', blocks: [ 'core/pullquote' ], - transform: ( { value, citation, anchor } ) => { + isMatch: ( {}, block ) => { + return block.innerBlocks.every( + ( { name } ) => name === 'core/paragraph' + ); + }, + transform: ( + { citation, anchor, fontSize, style }, + innerBlocks + ) => { + const value = innerBlocks + .map( + ( { attributes } ) => `

${ attributes.content }

` + ) + .join( '' ); return createBlock( 'core/pullquote', { value, citation, anchor, + fontSize, + style, } ); }, }, + { + type: 'block', + blocks: [ 'core/group' ], + transform: ( { citation, anchor }, innerBlocks ) => + createBlock( + 'core/group', + { anchor }, + citation + ? [ + ...innerBlocks, + createBlock( 'core/paragraph', { + content: citation, + } ), + ] + : innerBlocks + ), + }, + { + type: 'block', + blocks: [ '*' ], + transform: ( { citation }, innerBlocks ) => + citation + ? [ + ...innerBlocks, + createBlock( 'core/paragraph', { + content: citation, + } ), + ] + : innerBlocks, + }, ], }; diff --git a/packages/block-library/src/quote/v2/deprecated.js b/packages/block-library/src/quote/v2/deprecated.js deleted file mode 100644 index a9950e4a22548..0000000000000 --- a/packages/block-library/src/quote/v2/deprecated.js +++ /dev/null @@ -1,107 +0,0 @@ -/** - * External dependencies - */ -import classnames from 'classnames'; -import { omit } from 'lodash'; - -/** - * WordPress dependencies - */ -import { createBlock, parseWithAttributeSchema } from '@wordpress/blocks'; -import { RichText, useBlockProps } from '@wordpress/block-editor'; - -/** - * Internal dependencies - */ -import deprecationsForV1Block from '../deprecated'; - -export const migrateToQuoteV2 = ( attributes ) => { - const { value } = attributes; - - return [ - { - ...omit( attributes, [ 'value' ] ), - }, - value - ? parseWithAttributeSchema( value, { - type: 'array', - source: 'query', - selector: 'p', - query: { - content: { - type: 'string', - source: 'html', - }, - }, - } ).map( ( { content } ) => - createBlock( 'core/paragraph', { content } ) - ) - : createBlock( 'core/paragraph' ), - ]; -}; - -const v3 = { - attributes: { - value: { - type: 'string', - source: 'html', - selector: 'blockquote', - multiline: 'p', - default: '', - __experimentalRole: 'content', - }, - citation: { - type: 'string', - source: 'html', - selector: 'cite', - default: '', - __experimentalRole: 'content', - }, - align: { - type: 'string', - }, - }, - supports: { - anchor: true, - __experimentalSlashInserter: true, - typography: { - fontSize: true, - lineHeight: true, - __experimentalFontStyle: true, - __experimentalFontWeight: true, - __experimentalLetterSpacing: true, - __experimentalTextTransform: true, - __experimentalDefaultControls: { - fontSize: true, - fontAppearance: true, - }, - }, - }, - save( { attributes } ) { - const { align, value, citation } = attributes; - - const className = classnames( { - [ `has-text-align-${ align }` ]: align, - } ); - - return ( -
- - { ! RichText.isEmpty( citation ) && ( - - ) } -
- ); - }, - migrate: migrateToQuoteV2, -}; - -/** - * New deprecations need to be placed first - * for them to have higher priority. - * - * Old deprecations may need to be updated as well. - * - * See block-deprecation.md - */ -export default [ v3, ...deprecationsForV1Block ]; diff --git a/packages/block-library/src/quote/v2/edit.js b/packages/block-library/src/quote/v2/edit.js deleted file mode 100644 index 911d3346e5070..0000000000000 --- a/packages/block-library/src/quote/v2/edit.js +++ /dev/null @@ -1,139 +0,0 @@ -/** - * External dependencies - */ -import classNames from 'classnames'; - -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; -import { - AlignmentControl, - BlockControls, - RichText, - useBlockProps, - useInnerBlocksProps, - store as blockEditorStore, -} from '@wordpress/block-editor'; -import { BlockQuotation } from '@wordpress/components'; -import { useDispatch, useSelect, useRegistry } from '@wordpress/data'; -import { createBlock, getDefaultBlockName } from '@wordpress/blocks'; -import { Platform, useEffect } from '@wordpress/element'; -import deprecated from '@wordpress/deprecated'; - -/** - * Internal dependencies - */ -import { migrateToQuoteV2 } from './deprecated'; - -const isWebPlatform = Platform.OS === 'web'; -const TEMPLATE = [ [ 'core/paragraph', {} ] ]; - -/** - * At the moment, deprecations don't handle create blocks from attributes - * (like when using CPT templates). For this reason, this hook is necessary - * to avoid breaking templates using the old quote block format. - * - * @param {Object} attributes Block attributes. - * @param {string} clientId Block client ID. - */ -const useMigrateOnLoad = ( attributes, clientId ) => { - const registry = useRegistry(); - const { updateBlockAttributes, replaceInnerBlocks } = - useDispatch( blockEditorStore ); - useEffect( () => { - // As soon as the block is loaded, migrate it to the new version. - - if ( ! attributes.value ) { - // No need to migrate if it doesn't have the value attribute. - return; - } - - const [ newAttributes, newInnerBlocks ] = - migrateToQuoteV2( attributes ); - - deprecated( 'Value attribute on the quote block', { - since: '6.0', - version: '6.5', - alternative: 'inner blocks', - } ); - - registry.batch( () => { - updateBlockAttributes( clientId, newAttributes ); - replaceInnerBlocks( clientId, newInnerBlocks ); - } ); - }, [ attributes.value ] ); -}; - -export default function QuoteEdit( { - attributes, - setAttributes, - isSelected, - insertBlocksAfter, - clientId, - className, - style, -} ) { - const { citation, align } = attributes; - - useMigrateOnLoad( attributes, clientId ); - - const isAncestorOfSelectedBlock = useSelect( ( select ) => - select( blockEditorStore ).hasSelectedInnerBlock( clientId ) - ); - const hasSelection = isSelected || isAncestorOfSelectedBlock; - - const blockProps = useBlockProps( { - className: classNames( className, { - [ `has-text-align-${ align }` ]: align, - } ), - ...( ! isWebPlatform && { style } ), - } ); - const innerBlocksProps = useInnerBlocksProps( blockProps, { - template: TEMPLATE, - templateInsertUpdatesSelection: true, - } ); - - return ( - <> - - { - setAttributes( { align: nextAlign } ); - } } - /> - - - { innerBlocksProps.children } - { ( ! RichText.isEmpty( citation ) || hasSelection ) && ( - { - setAttributes( { - citation: nextCitation, - } ); - } } - __unstableMobileNoFocusOnMount - aria-label={ __( 'Quote citation' ) } - placeholder={ - // translators: placeholder text used for the - // citation - __( 'Add citation' ) - } - className="wp-block-quote__citation" - __unstableOnSplitAtEnd={ () => - insertBlocksAfter( - createBlock( getDefaultBlockName() ) - ) - } - { ...( ! isWebPlatform ? { textAlign: align } : {} ) } - /> - ) } - - - ); -} diff --git a/packages/block-library/src/quote/v2/index.js b/packages/block-library/src/quote/v2/index.js deleted file mode 100644 index 7019fe59db646..0000000000000 --- a/packages/block-library/src/quote/v2/index.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; -import { quote as icon } from '@wordpress/icons'; - -/** - * Internal dependencies - */ -import edit from './edit'; -import save from './save'; -import transforms from './transforms'; -import deprecated from './deprecated'; - -const settings = { - icon, - example: { - attributes: { - citation: 'Julio Cortázar', - }, - innerBlocks: [ - { - name: 'core/paragraph', - attributes: { - content: __( 'In quoting others, we cite ourselves.' ), - }, - }, - ], - }, - transforms, - edit, - save, - deprecated, -}; - -export default settings; diff --git a/packages/block-library/src/quote/v2/save.js b/packages/block-library/src/quote/v2/save.js deleted file mode 100644 index 52db0c5cb5328..0000000000000 --- a/packages/block-library/src/quote/v2/save.js +++ /dev/null @@ -1,26 +0,0 @@ -/** - * External dependencies - */ -import classNames from 'classnames'; - -/** - * WordPress dependencies - */ -import { InnerBlocks, RichText, useBlockProps } from '@wordpress/block-editor'; - -export default function save( { attributes } ) { - const { align, citation } = attributes; - const blockProps = useBlockProps.save( { - className: classNames( { - [ `has-text-align-${ align }` ]: align, - } ), - } ); - return ( -
- - { ! RichText.isEmpty( citation ) && ( - - ) } -
- ); -} diff --git a/packages/block-library/src/quote/v2/transforms.js b/packages/block-library/src/quote/v2/transforms.js deleted file mode 100644 index 0479beecf7d68..0000000000000 --- a/packages/block-library/src/quote/v2/transforms.js +++ /dev/null @@ -1,155 +0,0 @@ -/** - * WordPress dependencies - */ -import { - createBlock, - parseWithAttributeSchema, - rawHandler, - serialize, -} from '@wordpress/blocks'; - -const transforms = { - from: [ - { - type: 'block', - blocks: [ 'core/pullquote' ], - transform: ( { value, citation, anchor, fontSize, style } ) => { - return createBlock( - 'core/quote', - { - citation, - anchor, - fontSize, - style, - }, - parseWithAttributeSchema( value, { - type: 'array', - source: 'query', - selector: 'p', - query: { - content: { - type: 'string', - source: 'html', - }, - }, - } ).map( ( { content } ) => - createBlock( 'core/paragraph', { content } ) - ) - ); - }, - }, - { - type: 'block', - blocks: [ 'core/group' ], - transform: ( { anchor }, innerBlocks ) => - createBlock( 'core/quote', { anchor }, innerBlocks ), - }, - { - type: 'prefix', - prefix: '>', - transform: ( content ) => - createBlock( 'core/quote', {}, [ - createBlock( 'core/paragraph', { content } ), - ] ), - }, - { - type: 'raw', - schema: () => ( { - blockquote: { - children: '*', - }, - } ), - selector: 'blockquote', - transform: ( node ) => { - return createBlock( - 'core/quote', - // Don't try to parse any `cite` out of this content. - // * There may be more than one cite. - // * There may be more attribution text than just the cite. - // * If the cite is nested in the quoted text, it's wrong to - // remove it. - {}, - rawHandler( { - HTML: node.innerHTML, - mode: 'BLOCKS', - } ) - ); - }, - }, - { - type: 'block', - isMultiBlock: true, - blocks: [ '*' ], - isMatch: ( {}, blocks ) => { - return ! blocks.some( ( { name } ) => name === 'core/quote' ); - }, - __experimentalConvert: ( blocks ) => - createBlock( - 'core/quote', - {}, - blocks.map( ( block ) => - createBlock( - block.name, - block.attributes, - block.innerBlocks - ) - ) - ), - }, - ], - to: [ - { - type: 'block', - blocks: [ 'core/pullquote' ], - isMatch: ( {}, block ) => { - return block.innerBlocks.every( - ( { name } ) => name === 'core/paragraph' - ); - }, - transform: ( - { citation, anchor, fontSize, style }, - innerBlocks - ) => { - return createBlock( 'core/pullquote', { - value: serialize( innerBlocks ), - citation, - anchor, - fontSize, - style, - } ); - }, - }, - { - type: 'block', - blocks: [ 'core/group' ], - transform: ( { citation, anchor }, innerBlocks ) => - createBlock( - 'core/group', - { anchor }, - citation - ? [ - ...innerBlocks, - createBlock( 'core/paragraph', { - content: citation, - } ), - ] - : innerBlocks - ), - }, - { - type: 'block', - blocks: [ '*' ], - transform: ( { citation }, innerBlocks ) => - citation - ? [ - ...innerBlocks, - createBlock( 'core/paragraph', { - content: citation, - } ), - ] - : innerBlocks, - }, - ], -}; - -export default transforms; diff --git a/packages/e2e-test-utils/src/transform-block-to.js b/packages/e2e-test-utils/src/transform-block-to.js index 4a6968c684904..1989698c001e4 100644 --- a/packages/e2e-test-utils/src/transform-block-to.js +++ b/packages/e2e-test-utils/src/transform-block-to.js @@ -30,8 +30,5 @@ export async function transformBlockTo( name ) { await insertButton.evaluate( ( element ) => element.scrollIntoView() ); await insertButton.click(); - // Wait for the transformed block to appear. - const BLOCK_SELECTOR = '.block-editor-block-list__block'; - const BLOCK_NAME_SELECTOR = `[data-title="${ name }"]`; - await page.waitForSelector( `${ BLOCK_SELECTOR }${ BLOCK_NAME_SELECTOR }` ); + await page.evaluate( () => new Promise( requestIdleCallback ) ); } diff --git a/packages/e2e-tests/plugins/cpt-locking.php b/packages/e2e-tests/plugins/cpt-locking.php index f4fbdb99ffb25..5ac97c9cfae52 100644 --- a/packages/e2e-tests/plugins/cpt-locking.php +++ b/packages/e2e-tests/plugins/cpt-locking.php @@ -19,7 +19,13 @@ function gutenberg_test_cpt_locking() { 'placeholder' => 'Add a description', ), ), - array( 'core/quote' ), + array( + 'core/quote', + array(), + array( + array( 'core/paragraph' ), + ), + ), array( 'core/columns' ), ); register_post_type( @@ -65,7 +71,13 @@ function gutenberg_test_cpt_locking() { 'templateLock' => false, ), array( - array( 'core/quote' ), + array( + 'core/quote', + array(), + array( + array( 'core/paragraph' ), + ), + ), array( 'core/paragraph', array( @@ -91,7 +103,13 @@ function gutenberg_test_cpt_locking() { 'templateLock' => 'all', ), array( - array( 'core/quote' ), + array( + 'core/quote', + array(), + array( + array( 'core/paragraph' ), + ), + ), array( 'core/paragraph', array( @@ -115,7 +133,13 @@ function gutenberg_test_cpt_locking() { 'core/group', array(), array( - array( 'core/quote' ), + array( + 'core/quote', + array(), + array( + array( 'core/paragraph' ), + ), + ), array( 'core/paragraph', array( diff --git a/packages/e2e-tests/specs/editor/blocks/__snapshots__/quote.test.js.snap b/packages/e2e-tests/specs/editor/blocks/__snapshots__/quote.test.js.snap index 57fcc6c61dbdd..d1121eebc29bd 100644 --- a/packages/e2e-tests/specs/editor/blocks/__snapshots__/quote.test.js.snap +++ b/packages/e2e-tests/specs/editor/blocks/__snapshots__/quote.test.js.snap @@ -34,180 +34,86 @@ exports[`Quote can be converted to paragraphs and renders one paragraph block pe exports[`Quote can be converted to paragraphs and renders only one paragraph for the cite, if the quote is void 1`] = ` " +

+ + +

cite

" `; exports[`Quote can be created by converting a heading 1`] = ` " -

test

+
+

test

+
" `; exports[`Quote can be created by converting a paragraph 1`] = ` " -

test

+
+

test

+
" `; exports[`Quote can be created by converting multiple paragraphs 1`] = ` " -

one

two

+
+

one

+ + + +

two

+
" `; exports[`Quote can be created by typing "/quote" 1`] = ` " -

I’m a quote

+
+

I’m a quote

+
" `; exports[`Quote can be created by typing > in front of text of a paragraph block 1`] = ` " -

test

+
+

test

+
" `; exports[`Quote can be created by using > at the start of a paragraph block 1`] = ` " -

A quote

Another paragraph

-" -`; - -exports[`Quote can be merged into from a paragraph 1`] = ` -" -

test

-" -`; - -exports[`Quote can be split at the end and merged back 1`] = ` -" -

1

- +
+

A quote

+ -

-" -`; - -exports[`Quote can be split at the end and merged back 2`] = ` -" -

1

+

Another paragraph

+
" `; -exports[`Quote can be split at the end and merged back 3`] = ` +exports[`Quote can be split at the end 1`] = ` " -

1

-" -`; - -exports[`Quote can be split in the middle and merged back 1`] = ` -" -

1

c
+
+

1

+

- - - -

2

c
-" -`; - -exports[`Quote can be split in the middle and merged back 2`] = ` -" -

1

c
- - - -

2

c
-" -`; - -exports[`Quote can be split in the middle and merged back 3`] = ` -" -

1

c
- - - -

2

c
-" +" `; -exports[`Quote can be split in the middle and merged back 4`] = ` +exports[`Quote can be split at the end 2`] = ` " -

1

2

c
-" -`; - -exports[`Quote is transformed to a heading and a quote if the quote contains a citation 1`] = ` -" -

one

- - - -

cite
-" -`; - -exports[`Quote is transformed to a heading and a quote if the quote contains multiple paragraphs 1`] = ` -" -

one

- - - -

two

three

+
+

1

+
" `; - -exports[`Quote is transformed to a heading if the quote just contains one paragraph 1`] = ` -" -

one

-" -`; - -exports[`Quote is transformed to an empty heading if the quote is empty 1`] = ` -" -

-" -`; - -exports[`Quote the resuling quote after transforming to a heading can be transformed again 1`] = ` -" -

one

- - - -

two

cite
-" -`; - -exports[`Quote the resuling quote after transforming to a heading can be transformed again 2`] = ` -" -

one

- - - -

two

- - - -

cite
-" -`; - -exports[`Quote the resuling quote after transforming to a heading can be transformed again 3`] = ` -" -

one

- - - -

two

- - - -

cite

-" -`; diff --git a/packages/e2e-tests/specs/editor/blocks/quote.test.js b/packages/e2e-tests/specs/editor/blocks/quote.test.js index da4efefb38de1..7086a09ac3136 100644 --- a/packages/e2e-tests/specs/editor/blocks/quote.test.js +++ b/packages/e2e-tests/specs/editor/blocks/quote.test.js @@ -77,7 +77,9 @@ describe( 'Quote', () => { await page.keyboard.type( 'one' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( 'two' ); - await transformBlockTo( 'Paragraph' ); + // Navigate to the citation to select the block. + await page.keyboard.press( 'ArrowRight' ); + await transformBlockTo( 'Unwrap' ); expect( await getEditedPostContent() ).toMatchSnapshot(); } ); @@ -89,7 +91,7 @@ describe( 'Quote', () => { await page.keyboard.type( 'two' ); await page.keyboard.press( 'ArrowRight' ); await page.keyboard.type( 'cite' ); - await transformBlockTo( 'Paragraph' ); + await transformBlockTo( 'Unwrap' ); expect( await getEditedPostContent() ).toMatchSnapshot(); } ); @@ -98,14 +100,15 @@ describe( 'Quote', () => { await insertBlock( 'Quote' ); await page.keyboard.press( 'ArrowRight' ); await page.keyboard.type( 'cite' ); - await transformBlockTo( 'Paragraph' ); + await transformBlockTo( 'Unwrap' ); expect( await getEditedPostContent() ).toMatchSnapshot(); } ); it( 'and renders a void paragraph if both the cite and quote are void', async () => { await insertBlock( 'Quote' ); - await transformBlockTo( 'Paragraph' ); + await page.keyboard.press( 'ArrowRight' ); // Select the quote + await transformBlockTo( 'Unwrap' ); expect( await getEditedPostContent() ).toMatchSnapshot(); } ); @@ -119,56 +122,6 @@ describe( 'Quote', () => { expect( await getEditedPostContent() ).toMatchSnapshot(); } ); - it( 'is transformed to an empty heading if the quote is empty', async () => { - await insertBlock( 'Quote' ); - await transformBlockTo( 'Heading' ); - expect( await getEditedPostContent() ).toMatchSnapshot(); - } ); - - it( 'is transformed to a heading if the quote just contains one paragraph', async () => { - await insertBlock( 'Quote' ); - await page.keyboard.type( 'one' ); - await transformBlockTo( 'Heading' ); - expect( await getEditedPostContent() ).toMatchSnapshot(); - } ); - - it( 'is transformed to a heading and a quote if the quote contains multiple paragraphs', async () => { - await insertBlock( 'Quote' ); - await page.keyboard.type( 'one' ); - await page.keyboard.press( 'Enter' ); - await page.keyboard.type( 'two' ); - await page.keyboard.press( 'Enter' ); - await page.keyboard.type( 'three' ); - await transformBlockTo( 'Heading' ); - expect( await getEditedPostContent() ).toMatchSnapshot(); - } ); - - it( 'is transformed to a heading and a quote if the quote contains a citation', async () => { - await insertBlock( 'Quote' ); - await page.keyboard.type( 'one' ); - await page.keyboard.press( 'ArrowRight' ); - await page.keyboard.type( 'cite' ); - await transformBlockTo( 'Heading' ); - expect( await getEditedPostContent() ).toMatchSnapshot(); - } ); - - it( 'the resuling quote after transforming to a heading can be transformed again', async () => { - await insertBlock( 'Quote' ); - await page.keyboard.type( 'one' ); - await page.keyboard.press( 'Enter' ); - await page.keyboard.type( 'two' ); - await page.keyboard.press( 'ArrowRight' ); - await page.keyboard.type( 'cite' ); - await transformBlockTo( 'Heading' ); - expect( await getEditedPostContent() ).toMatchSnapshot(); - await page.click( '[data-type="core/quote"]' ); - await transformBlockTo( 'Heading' ); - expect( await getEditedPostContent() ).toMatchSnapshot(); - await page.click( '[data-type="core/quote"]' ); - await transformBlockTo( 'Heading' ); - expect( await getEditedPostContent() ).toMatchSnapshot(); - } ); - it( 'can be converted to a pullquote', async () => { await insertBlock( 'Quote' ); await page.keyboard.type( 'one' ); @@ -180,16 +133,7 @@ describe( 'Quote', () => { expect( await getEditedPostContent() ).toMatchSnapshot(); } ); - it( 'can be merged into from a paragraph', async () => { - await insertBlock( 'Quote' ); - await insertBlock( 'Paragraph' ); - await page.keyboard.type( 'test' ); - await pressKeyTimes( 'ArrowLeft', 'test'.length ); - await page.keyboard.press( 'Backspace' ); - expect( await getEditedPostContent() ).toMatchSnapshot(); - } ); - - it( 'can be split at the end and merged back', async () => { + it( 'can be split at the end', async () => { await insertBlock( 'Quote' ); await page.keyboard.type( '1' ); await page.keyboard.press( 'Enter' ); @@ -200,46 +144,7 @@ describe( 'Quote', () => { await page.keyboard.press( 'Backspace' ); - // Expect empty paragraph inside quote block. - expect( await getEditedPostContent() ).toMatchSnapshot(); - - await page.keyboard.press( 'Backspace' ); - - // Expect quote without empty paragraphs. - expect( await getEditedPostContent() ).toMatchSnapshot(); - } ); - - it( 'can be split in the middle and merged back', async () => { - await insertBlock( 'Quote' ); - await page.keyboard.type( '1' ); - await page.keyboard.press( 'Enter' ); - await page.keyboard.type( '2' ); - await page.keyboard.press( 'ArrowRight' ); - await page.keyboard.type( 'c' ); - await page.keyboard.press( 'ArrowUp' ); - await page.keyboard.press( 'ArrowUp' ); - await page.keyboard.press( 'Enter' ); - await page.keyboard.press( 'Enter' ); - - // Expect two quote blocks and empty paragraph in the middle. - expect( await getEditedPostContent() ).toMatchSnapshot(); - - await page.keyboard.press( 'Backspace' ); - - // Expect two quote blocks and empty paragraph in the first quote. - expect( await getEditedPostContent() ).toMatchSnapshot(); - - await page.keyboard.press( 'Backspace' ); - - // Expect two quote blocks. - expect( await getEditedPostContent() ).toMatchSnapshot(); - - await page.keyboard.press( 'ArrowLeft' ); - await page.keyboard.press( 'ArrowDown' ); - await page.keyboard.press( 'ArrowDown' ); - await page.keyboard.press( 'ArrowDown' ); - await page.keyboard.press( 'Backspace' ); - + // Expect the paragraph to be deleted. expect( await getEditedPostContent() ).toMatchSnapshot(); } ); } ); diff --git a/packages/e2e-tests/specs/editor/plugins/__snapshots__/cpt-locking.test.js.snap b/packages/e2e-tests/specs/editor/plugins/__snapshots__/cpt-locking.test.js.snap index a7d34618db0de..4f502b2fd29b0 100644 --- a/packages/e2e-tests/specs/editor/plugins/__snapshots__/cpt-locking.test.js.snap +++ b/packages/e2e-tests/specs/editor/plugins/__snapshots__/cpt-locking.test.js.snap @@ -10,7 +10,9 @@ exports[`cpt locking template_lock all should insert line breaks when using ente -

+
+

+
@@ -28,7 +30,9 @@ exports[`cpt locking template_lock all should not error when deleting the cotent -

+
+

+
@@ -43,7 +47,9 @@ exports[`cpt locking template_lock all unlocked group should allow blocks to be -

+
+

+
" `; @@ -51,7 +57,9 @@ exports[`cpt locking template_lock all unlocked group should allow blocks to be exports[`cpt locking template_lock all unlocked group should allow blocks to be removed 1`] = ` "
-

+
+

+
" `; @@ -66,7 +74,9 @@ exports[`cpt locking template_lock false should allow blocks to be inserted 1`] -

+
+

+
@@ -88,7 +98,9 @@ exports[`cpt locking template_lock false should allow blocks to be moved 1`] = ` -

+
+

+
@@ -102,7 +114,9 @@ exports[`cpt locking template_lock false should allow blocks to be removed 1`] = -

+
+

+
@@ -120,7 +134,9 @@ exports[`cpt locking template_lock insert should allow blocks to be moved 1`] = -

+
+

+
diff --git a/packages/e2e-tests/specs/editor/plugins/__snapshots__/inner-blocks-render-appender.test.js.snap b/packages/e2e-tests/specs/editor/plugins/__snapshots__/inner-blocks-render-appender.test.js.snap index 231ef215354a8..480121a3ceb8f 100644 --- a/packages/e2e-tests/specs/editor/plugins/__snapshots__/inner-blocks-render-appender.test.js.snap +++ b/packages/e2e-tests/specs/editor/plugins/__snapshots__/inner-blocks-render-appender.test.js.snap @@ -3,7 +3,9 @@ exports[`RenderAppender prop of InnerBlocks Users can customize the appender and can still insert blocks using exposed components 1`] = ` "
-

+
+

+
" `; @@ -11,7 +13,9 @@ exports[`RenderAppender prop of InnerBlocks Users can customize the appender and exports[`RenderAppender prop of InnerBlocks Users can dynamically customize the appender 1`] = ` "
-

+
+

+
diff --git a/packages/e2e-tests/specs/editor/plugins/__snapshots__/templates.test.js.snap b/packages/e2e-tests/specs/editor/plugins/__snapshots__/templates.test.js.snap index f089390857781..054e38c501a4f 100644 --- a/packages/e2e-tests/specs/editor/plugins/__snapshots__/templates.test.js.snap +++ b/packages/e2e-tests/specs/editor/plugins/__snapshots__/templates.test.js.snap @@ -10,7 +10,9 @@ exports[`templates Using a CPT with a predefined template Should add a custom po -

+
+

+
@@ -36,7 +38,9 @@ exports[`templates Using a CPT with a predefined template Should respect user ed -

+
+

+
diff --git a/packages/e2e-tests/specs/editor/plugins/block-variations.test.js b/packages/e2e-tests/specs/editor/plugins/block-variations.test.js index 090e4f2a9214c..886382a4667b1 100644 --- a/packages/e2e-tests/specs/editor/plugins/block-variations.test.js +++ b/packages/e2e-tests/specs/editor/plugins/block-variations.test.js @@ -148,6 +148,8 @@ describe( 'Block variations', () => { it( 'should show block information when no matching variation is found', async () => { await insertBlock( 'Large Quote' ); + // Select the quote block. + await page.keyboard.press( 'ArrowDown' ); const breadcrumb = await getActiveBreadcrumb(); expect( breadcrumb ).toEqual( 'Quote' ); const navigationItem = await getFirstNavigationItem(); diff --git a/packages/e2e-tests/specs/editor/plugins/cpt-locking.test.js b/packages/e2e-tests/specs/editor/plugins/cpt-locking.test.js index 6af9aeac8754b..dbb4b8348f7c7 100644 --- a/packages/e2e-tests/specs/editor/plugins/cpt-locking.test.js +++ b/packages/e2e-tests/specs/editor/plugins/cpt-locking.test.js @@ -49,12 +49,12 @@ describe( 'cpt locking', () => { const shouldAllowBlocksToBeMoved = async () => { await page.click( - '.block-editor-rich-text__editable[data-type="core/paragraph"]' + 'div > .block-editor-rich-text__editable[data-type="core/paragraph"]' ); expect( await page.$( 'button[aria-label="Move up"]' ) ).not.toBeNull(); await page.click( 'button[aria-label="Move up"]' ); await page.type( - '.block-editor-rich-text__editable[data-type="core/paragraph"]', + 'div > .block-editor-rich-text__editable[data-type="core/paragraph"]', 'p1' ); expect( await getEditedPostContent() ).toMatchSnapshot(); @@ -193,7 +193,7 @@ describe( 'cpt locking', () => { it( 'should allow blocks to be removed', async () => { await page.type( - '.block-editor-rich-text__editable[data-type="core/paragraph"]', + 'div > .block-editor-rich-text__editable[data-type="core/paragraph"]', 'p1' ); await clickBlockToolbarButton( 'Options' ); diff --git a/packages/e2e-tests/specs/editor/plugins/inner-blocks-render-appender.test.js b/packages/e2e-tests/specs/editor/plugins/inner-blocks-render-appender.test.js index 3c25fd93541ca..81a7d943331bb 100644 --- a/packages/e2e-tests/specs/editor/plugins/inner-blocks-render-appender.test.js +++ b/packages/e2e-tests/specs/editor/plugins/inner-blocks-render-appender.test.js @@ -98,6 +98,9 @@ describe( 'RenderAppender prop of InnerBlocks', () => { // Insert a quote block. await quoteButton.click(); + // Select the quote block. + await page.keyboard.press( 'ArrowDown' ); + // Verify if the custom block appender text changed as expected. await page.waitForXPath( `//*[contains(@class, "${ DYNAMIC_APPENDER_SELECTOR }")]/span[contains(@class, "single-blocks-appender")][contains(text(), "Single Blocks Appender")]` diff --git a/packages/e2e-tests/specs/editor/various/__snapshots__/multi-block-selection.test.js.snap b/packages/e2e-tests/specs/editor/various/__snapshots__/multi-block-selection.test.js.snap index b75df36d20904..6923de7cc83f3 100644 --- a/packages/e2e-tests/specs/editor/various/__snapshots__/multi-block-selection.test.js.snap +++ b/packages/e2e-tests/specs/editor/various/__snapshots__/multi-block-selection.test.js.snap @@ -146,22 +146,6 @@ exports[`Multi-block selection should handle Enter across blocks 2`] = ` " `; -exports[`Multi-block selection should merge into quote with correct selection 1`] = ` -" -

1[

- - - -

]2

-" -`; - -exports[`Multi-block selection should merge into quote with correct selection 2`] = ` -" -

1

&2

-" -`; - exports[`Multi-block selection should multi-select from within the list block 1`] = ` "

1

diff --git a/packages/e2e-tests/specs/editor/various/__snapshots__/writing-flow.test.js.snap b/packages/e2e-tests/specs/editor/various/__snapshots__/writing-flow.test.js.snap index 71943003cf923..37328170c07e1 100644 --- a/packages/e2e-tests/specs/editor/various/__snapshots__/writing-flow.test.js.snap +++ b/packages/e2e-tests/specs/editor/various/__snapshots__/writing-flow.test.js.snap @@ -207,9 +207,9 @@ exports[`Writing Flow should navigate empty paragraphs 1`] = ` `; exports[`Writing Flow should not create extra line breaks in multiline value 1`] = ` -" -

-" +" +
+" `; exports[`Writing Flow should not delete surrounding space when deleting a selected word 1`] = ` diff --git a/packages/e2e-tests/specs/editor/various/block-switcher.test.js b/packages/e2e-tests/specs/editor/various/block-switcher.test.js index 945cd21252887..7adbac136cd2e 100644 --- a/packages/e2e-tests/specs/editor/various/block-switcher.test.js +++ b/packages/e2e-tests/specs/editor/various/block-switcher.test.js @@ -28,7 +28,6 @@ describe( 'Block Switcher', () => { expect.arrayContaining( [ 'Group', 'Paragraph', - 'Quote', 'Heading', 'Pullquote', 'Columns', diff --git a/packages/e2e-tests/specs/editor/various/multi-block-selection.test.js b/packages/e2e-tests/specs/editor/various/multi-block-selection.test.js index 5e14d57dcd759..c9d633a521a4d 100644 --- a/packages/e2e-tests/specs/editor/various/multi-block-selection.test.js +++ b/packages/e2e-tests/specs/editor/various/multi-block-selection.test.js @@ -906,30 +906,6 @@ describe( 'Multi-block selection', () => { expect( await getEditedPostContent() ).toMatchSnapshot(); } ); - it( 'should merge into quote with correct selection', async () => { - await clickBlockAppender(); - await page.keyboard.type( '> 1[' ); - await page.keyboard.press( 'Enter' ); - await page.keyboard.press( 'Enter' ); - await page.keyboard.type( ']2' ); - await page.keyboard.press( 'ArrowLeft' ); - // Select everything between []. - await pressKeyWithModifier( 'shift', 'ArrowLeft' ); - await pressKeyWithModifier( 'shift', 'ArrowLeft' ); - await pressKeyWithModifier( 'shift', 'ArrowLeft' ); - - // Test setup. - expect( await getEditedPostContent() ).toMatchSnapshot(); - - await page.keyboard.press( 'Backspace' ); - - // Ensure selection is in the correct place. - await page.keyboard.type( '&' ); - - // Expect two blocks with "&" in between. - expect( await getEditedPostContent() ).toMatchSnapshot(); - } ); - it( 'should select separator (single element block)', async () => { await clickBlockAppender(); await page.keyboard.type( '/hr' ); diff --git a/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js b/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js index 16f8347b0fea5..9e2dfb5098e45 100644 --- a/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js +++ b/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js @@ -364,6 +364,8 @@ describe( 'Reusable blocks', () => { '.block-editor-block-list__block[aria-label="Block: Quote"]' ); await quoteBlock.click(); + // Select the quote block. + await page.keyboard.press( 'ArrowDown' ); await openDocumentSettingsSidebar(); await page.waitForXPath( '//*[@role="region"][@aria-label="Editor settings"]//button[.="Styles"]' diff --git a/packages/e2e-tests/specs/editor/various/writing-flow.test.js b/packages/e2e-tests/specs/editor/various/writing-flow.test.js index d9535183848c6..322f64f0fcffe 100644 --- a/packages/e2e-tests/specs/editor/various/writing-flow.test.js +++ b/packages/e2e-tests/specs/editor/various/writing-flow.test.js @@ -282,7 +282,7 @@ describe( 'Writing Flow', () => { } ); it( 'should not create extra line breaks in multiline value', async () => { - await insertBlock( 'Quote' ); + await insertBlock( 'List' ); await page.keyboard.type( 'a' ); await page.keyboard.press( 'Backspace' ); expect( await getEditedPostContent() ).toMatchSnapshot(); diff --git a/packages/edit-post/src/test/editor.native.js b/packages/edit-post/src/test/editor.native.js index c3e35e9259898..28aac9d3ae423 100644 --- a/packages/edit-post/src/test/editor.native.js +++ b/packages/edit-post/src/test/editor.native.js @@ -35,9 +35,7 @@ afterAll( () => { } ); describe( 'Editor', () => { - beforeAll( () => { - registerCoreBlocks(); - } ); + beforeAll( registerCoreBlocks ); it( 'detects unsupported block and sends hasUnsupportedBlocks true to native', () => { RNReactNativeGutenbergBridge.editorDidMount = jest.fn(); diff --git a/packages/react-native-editor/src/setup.js b/packages/react-native-editor/src/setup.js index f31538b70f24b..c9a71ef6c8960 100644 --- a/packages/react-native-editor/src/setup.js +++ b/packages/react-native-editor/src/setup.js @@ -58,12 +58,9 @@ const gutenbergSetup = () => { const setupInitHooks = () => { addAction( 'native.pre-render', 'core/react-native-editor', ( props ) => { - const capabilities = props.capabilities ?? {}; - const blocksFlags = { - __experimentalEnableQuoteBlockV2: props?.quoteBlockV2, - }; + registerBlocks(); - registerBlocks( blocksFlags ); + const capabilities = props.capabilities ?? {}; // Unregister non-supported blocks by capabilities if ( @@ -119,12 +116,12 @@ const setupInitHooks = () => { }; let blocksRegistered = false; -const registerBlocks = ( blocksFlags ) => { +const registerBlocks = () => { if ( blocksRegistered ) { return; } - registerCoreBlocks( blocksFlags ); + registerCoreBlocks(); blocksRegistered = true; }; diff --git a/packages/react-native-editor/src/test/index.test.js b/packages/react-native-editor/src/test/index.test.js index 05412dcfafcda..cc7a301421af7 100644 --- a/packages/react-native-editor/src/test/index.test.js +++ b/packages/react-native-editor/src/test/index.test.js @@ -190,7 +190,8 @@ describe( 'Register Gutenberg', () => { {}, { component: EditorComponent } ); - const blockList = screen.getByTestId( 'block-list-wrapper' ); + // Inner blocks create BlockLists so let's take into account selecting the main one + const blockList = screen.getAllByTestId( 'block-list-wrapper' )[ 0 ]; expect( blockList ).toBeVisible(); expect( console ).toHaveLoggedWith( 'Hermes is: true' ); diff --git a/test/e2e/specs/editor/blocks/list.spec.js b/test/e2e/specs/editor/blocks/list.spec.js index eb5fec4d1d129..99f60ae49693b 100644 --- a/test/e2e/specs/editor/blocks/list.spec.js +++ b/test/e2e/specs/editor/blocks/list.spec.js @@ -313,23 +313,6 @@ test.describe( 'List', () => { ); } ); - test( 'can be created by converting a quote', async ( { - editor, - page, - } ) => { - await editor.insertBlock( { name: 'core/quote' } ); - await page.keyboard.type( 'one' ); - await page.keyboard.press( 'Enter' ); - await page.keyboard.type( 'two' ); - await editor.transformBlockTo( 'core/list' ); - - await expect.poll( editor.getEditedPostContent ).toBe( - ` -
  • one
  • two
-` - ); - } ); - test( 'can be converted to a quote', async ( { editor, page } ) => { await editor.insertBlock( { name: 'core/list' } ); await page.keyboard.type( 'one' ); @@ -339,7 +322,9 @@ test.describe( 'List', () => { await expect.poll( editor.getEditedPostContent ).toBe( ` -

one

two

+
+
  • one
  • two
+
` ); } ); diff --git a/test/e2e/specs/editor/blocks/quote.spec.js b/test/e2e/specs/editor/blocks/quote.spec.js index 843a2b8db67ee..69d69f0003489 100644 --- a/test/e2e/specs/editor/blocks/quote.spec.js +++ b/test/e2e/specs/editor/blocks/quote.spec.js @@ -23,7 +23,9 @@ test.describe( 'adding a quote', () => { const content = await editor.getEditedPostContent(); expect( content ).toBe( ` -

Quote content

+
+

Quote content

+
` ); } ); diff --git a/test/e2e/specs/editor/various/style-variation.spec.js b/test/e2e/specs/editor/various/style-variation.spec.js index 3971ab4888ddc..cc13dd1ad9238 100644 --- a/test/e2e/specs/editor/various/style-variation.spec.js +++ b/test/e2e/specs/editor/various/style-variation.spec.js @@ -17,6 +17,9 @@ test.describe( 'adding blocks', () => { attributes: { value: '

Quote content

' }, } ); + // Select the quote block. + await page.keyboard.press( 'ArrowDown' ); + await editor.clickBlockToolbarButton( 'Quote' ); await page.click( 'role=menuitem[name="Plain"i]' ); @@ -25,7 +28,9 @@ test.describe( 'adding blocks', () => { const content = await editor.getEditedPostContent(); expect( content ).toBe( ` -

Quote content

+
+

Quote content

+
` ); } ); diff --git a/test/integration/__snapshots__/blocks-raw-handling.test.js.snap b/test/integration/__snapshots__/blocks-raw-handling.test.js.snap index 3bfd162ddddcc..06f7a8d80716b 100644 --- a/test/integration/__snapshots__/blocks-raw-handling.test.js.snap +++ b/test/integration/__snapshots__/blocks-raw-handling.test.js.snap @@ -28,6 +28,18 @@ exports[`Blocks raw handling pasteHandler should strip windows data 1`] = ` " `; +exports[`Blocks raw handling should correctly handle quotes with mixed content 1`] = ` +" +
+

chicken

+ + + +

ribs

+
+" +`; + exports[`rawHandler should convert HTML post to blocks with minimal content changes 1`] = ` "

Howdy

@@ -77,12 +89,20 @@ exports[`rawHandler should convert HTML post to blocks with minimal content chan -

Text.

+
+

Text.

+
- -

Heading

Text.

-" + +
+

Heading

+ + + +

Text.

+
+" `; exports[`rawHandler should convert a caption shortcode 1`] = ` diff --git a/test/integration/blocks-raw-handling.test.js b/test/integration/blocks-raw-handling.test.js index 34d6aaae3f6d3..6e3f0e63aba94 100644 --- a/test/integration/blocks-raw-handling.test.js +++ b/test/integration/blocks-raw-handling.test.js @@ -288,110 +288,15 @@ describe( 'Blocks raw handling', () => { expect( console ).toHaveLogged(); } ); - it( 'should correctly handle quotes with one paragraphs and no citation', () => { - const filtered = pasteHandler( { - HTML: '

chicken

', - mode: 'AUTO', - } ) - .map( getBlockContent ) - .join( '' ); - - expect( filtered ).toBe( - '

chicken

' - ); - expect( console ).toHaveLogged(); - } ); - it( 'should correctly handle quotes with multiple paragraphs and no citation', () => { - const filtered = pasteHandler( { - HTML: '

chicken

ribs

', - mode: 'AUTO', - } ) - .map( getBlockContent ) - .join( '' ); - - expect( filtered ).toBe( - '

chicken

ribs

' - ); - expect( console ).toHaveLogged(); - } ); - - it( 'should correctly handle quotes with paragraph and citation at the end', () => { - const filtered = pasteHandler( { - HTML: '

chicken

ribs
', - mode: 'AUTO', - } ) - .map( getBlockContent ) - .join( '' ); - - expect( filtered ).toBe( - '

chicken

ribs
' - ); - expect( console ).toHaveLogged(); - } ); - - it( 'should handle a citation before the content', () => { - const filtered = pasteHandler( { - HTML: '
ribs

ribs

', - mode: 'AUTO', - } ) - .map( getBlockContent ) - .join( '' ); - - expect( filtered ).toBe( - '

ribs

ribs
' + it( 'should correctly handle quotes with mixed content', () => { + const filtered = serialize( + pasteHandler( { + HTML: '

chicken

ribs

', + mode: 'AUTO', + } ) ); - expect( console ).toHaveLogged(); - } ); - - it( 'should handle a citation in the middle of the content', () => { - const filtered = pasteHandler( { - HTML: '

chicken

ribs

ribs

', - mode: 'AUTO', - } ) - .map( getBlockContent ) - .join( '' ); - - expect( filtered ).toBe( - '

chicken

ribs

ribs
' - ); - expect( console ).toHaveLogged(); - } ); - - it( 'should correctly handle quotes with only a citation', () => { - const filtered = pasteHandler( { - HTML: '
ribs
', - mode: 'AUTO', - } ) - .map( getBlockContent ) - .join( '' ); - - expect( filtered ).toBe( - '

ribs
' - ); - expect( console ).toHaveLogged(); - } ); - - it( 'should convert to paragraph quotes with more than one cite', () => { - const filtered = pasteHandler( { - HTML: '
ribsribs
', - mode: 'AUTO', - } ) - .map( getBlockContent ) - .join( '' ); - - expect( filtered ).toBe( '

ribsribs

' ); - expect( console ).toHaveLogged(); - } ); - - it( 'should convert to paragraph quotes with more than one cite and at least one paragraph', () => { - const filtered = pasteHandler( { - HTML: '

chicken

ribsribs
', - mode: 'AUTO', - } ) - .map( getBlockContent ) - .join( '' ); - expect( filtered ).toBe( '

chickenribsribs

' ); + expect( filtered ).toMatchSnapshot(); expect( console ).toHaveLogged(); } ); diff --git a/test/integration/fixtures/blocks/core__quote__deprecated-1.json b/test/integration/fixtures/blocks/core__quote__deprecated-1.json index f7d321059a622..ea4a9a2319658 100644 --- a/test/integration/fixtures/blocks/core__quote__deprecated-1.json +++ b/test/integration/fixtures/blocks/core__quote__deprecated-1.json @@ -3,9 +3,18 @@ "name": "core/quote", "isValid": true, "attributes": { - "value": "

Testing deprecated quote block...

", "citation": "...with a caption" }, - "innerBlocks": [] + "innerBlocks": [ + { + "name": "core/paragraph", + "isValid": true, + "attributes": { + "content": "Testing deprecated quote block...", + "dropCap": false + }, + "innerBlocks": [] + } + ] } ] diff --git a/test/integration/fixtures/blocks/core__quote__deprecated-1.serialized.html b/test/integration/fixtures/blocks/core__quote__deprecated-1.serialized.html index d865a5f09d901..9f06d2409dc7a 100644 --- a/test/integration/fixtures/blocks/core__quote__deprecated-1.serialized.html +++ b/test/integration/fixtures/blocks/core__quote__deprecated-1.serialized.html @@ -1,3 +1,5 @@ -

Testing deprecated quote block...

...with a caption
+
+

Testing deprecated quote block...

+...with a caption
diff --git a/test/integration/fixtures/blocks/core__quote__deprecated-2.json b/test/integration/fixtures/blocks/core__quote__deprecated-2.json index 00631ad17dd7f..2599674eeec7f 100644 --- a/test/integration/fixtures/blocks/core__quote__deprecated-2.json +++ b/test/integration/fixtures/blocks/core__quote__deprecated-2.json @@ -3,10 +3,19 @@ "name": "core/quote", "isValid": true, "attributes": { - "value": "

Testing deprecated quote block...

", "citation": "...with a caption", "align": "right" }, - "innerBlocks": [] + "innerBlocks": [ + { + "name": "core/paragraph", + "isValid": true, + "attributes": { + "content": "Testing deprecated quote block...", + "dropCap": false + }, + "innerBlocks": [] + } + ] } ] diff --git a/test/integration/fixtures/blocks/core__quote__deprecated-2.serialized.html b/test/integration/fixtures/blocks/core__quote__deprecated-2.serialized.html index 08271ab418b33..024531d165d7e 100644 --- a/test/integration/fixtures/blocks/core__quote__deprecated-2.serialized.html +++ b/test/integration/fixtures/blocks/core__quote__deprecated-2.serialized.html @@ -1,3 +1,5 @@ -

Testing deprecated quote block...

...with a caption
+
+

Testing deprecated quote block...

+...with a caption
diff --git a/test/integration/fixtures/blocks/core__quote__style-1.html b/test/integration/fixtures/blocks/core__quote__style-1.html index 4bfd0ef80e5d4..6a56433a56267 100644 --- a/test/integration/fixtures/blocks/core__quote__style-1.html +++ b/test/integration/fixtures/blocks/core__quote__style-1.html @@ -1,3 +1,5 @@ - -

The editor will endeavour to create a new page and post building experience that makes writing rich posts effortless, and has “blocks” to make it easy what today might take shortcodes, custom HTML, or “mystery meat” embed discovery.

Matt Mullenweg, 2017
- + +
+

The editor will endeavour to create a new page and post building experience that makes writing rich posts effortless, and has “blocks” to make it easy what today might take shortcodes, custom HTML, or “mystery meat” embed discovery.

+Matt Mullenweg, 2017
+ diff --git a/test/integration/fixtures/blocks/core__quote__style-1.json b/test/integration/fixtures/blocks/core__quote__style-1.json index 90a8c88a23228..d262a2fefc6f3 100644 --- a/test/integration/fixtures/blocks/core__quote__style-1.json +++ b/test/integration/fixtures/blocks/core__quote__style-1.json @@ -3,9 +3,19 @@ "name": "core/quote", "isValid": true, "attributes": { - "value": "

The editor will endeavour to create a new page and post building experience that makes writing rich posts effortless, and has “blocks” to make it easy what today might take shortcodes, custom HTML, or “mystery meat” embed discovery.

", + "value": "", "citation": "Matt Mullenweg, 2017" }, - "innerBlocks": [] + "innerBlocks": [ + { + "name": "core/paragraph", + "isValid": true, + "attributes": { + "content": "The editor will endeavour to create a new page and post building experience that makes writing rich posts effortless, and has “blocks” to make it easy what today might take shortcodes, custom HTML, or “mystery meat” embed discovery.", + "dropCap": false + }, + "innerBlocks": [] + } + ] } ] diff --git a/test/integration/fixtures/blocks/core__quote__style-1.parsed.json b/test/integration/fixtures/blocks/core__quote__style-1.parsed.json index 5a071b57a7a5c..2491985cc6d87 100644 --- a/test/integration/fixtures/blocks/core__quote__style-1.parsed.json +++ b/test/integration/fixtures/blocks/core__quote__style-1.parsed.json @@ -2,10 +2,22 @@ { "blockName": "core/quote", "attrs": {}, - "innerBlocks": [], - "innerHTML": "\n

The editor will endeavour to create a new page and post building experience that makes writing rich posts effortless, and has “blocks” to make it easy what today might take shortcodes, custom HTML, or “mystery meat” embed discovery.

Matt Mullenweg, 2017
\n", + "innerBlocks": [ + { + "blockName": "core/paragraph", + "attrs": {}, + "innerBlocks": [], + "innerHTML": "\n

The editor will endeavour to create a new page and post building experience that makes writing rich posts effortless, and has “blocks” to make it easy what today might take shortcodes, custom HTML, or “mystery meat” embed discovery.

\n", + "innerContent": [ + "\n

The editor will endeavour to create a new page and post building experience that makes writing rich posts effortless, and has “blocks” to make it easy what today might take shortcodes, custom HTML, or “mystery meat” embed discovery.

\n" + ] + } + ], + "innerHTML": "\n
Matt Mullenweg, 2017
\n", "innerContent": [ - "\n

The editor will endeavour to create a new page and post building experience that makes writing rich posts effortless, and has “blocks” to make it easy what today might take shortcodes, custom HTML, or “mystery meat” embed discovery.

Matt Mullenweg, 2017
\n" + "\n
", + null, + "Matt Mullenweg, 2017
\n" ] } ] diff --git a/test/integration/fixtures/blocks/core__quote__style-1.serialized.html b/test/integration/fixtures/blocks/core__quote__style-1.serialized.html index 4268c4139854e..6a56433a56267 100644 --- a/test/integration/fixtures/blocks/core__quote__style-1.serialized.html +++ b/test/integration/fixtures/blocks/core__quote__style-1.serialized.html @@ -1,3 +1,5 @@ -

The editor will endeavour to create a new page and post building experience that makes writing rich posts effortless, and has “blocks” to make it easy what today might take shortcodes, custom HTML, or “mystery meat” embed discovery.

Matt Mullenweg, 2017
+
+

The editor will endeavour to create a new page and post building experience that makes writing rich posts effortless, and has “blocks” to make it easy what today might take shortcodes, custom HTML, or “mystery meat” embed discovery.

+Matt Mullenweg, 2017
diff --git a/test/integration/fixtures/blocks/core__quote__style-2.html b/test/integration/fixtures/blocks/core__quote__style-2.html index d4ecdca350df1..13c2762059ecf 100644 --- a/test/integration/fixtures/blocks/core__quote__style-2.html +++ b/test/integration/fixtures/blocks/core__quote__style-2.html @@ -1,3 +1,5 @@ - -

There is no greater agony than bearing an untold story inside you.

Maya Angelou
- + +
+

There is no greater agony than bearing an untold story inside you.

+Maya Angelou
+ diff --git a/test/integration/fixtures/blocks/core__quote__style-2.json b/test/integration/fixtures/blocks/core__quote__style-2.json index bc8901ab9225d..c7c699e4caf42 100644 --- a/test/integration/fixtures/blocks/core__quote__style-2.json +++ b/test/integration/fixtures/blocks/core__quote__style-2.json @@ -3,10 +3,20 @@ "name": "core/quote", "isValid": true, "attributes": { - "value": "

There is no greater agony than bearing an untold story inside you.

", + "value": "", "citation": "Maya Angelou", "className": "is-style-large" }, - "innerBlocks": [] + "innerBlocks": [ + { + "name": "core/paragraph", + "isValid": true, + "attributes": { + "content": "There is no greater agony than bearing an untold story inside you.", + "dropCap": false + }, + "innerBlocks": [] + } + ] } ] diff --git a/test/integration/fixtures/blocks/core__quote__style-2.parsed.json b/test/integration/fixtures/blocks/core__quote__style-2.parsed.json index fea7f9f380c46..e6eef0e2ba9ed 100644 --- a/test/integration/fixtures/blocks/core__quote__style-2.parsed.json +++ b/test/integration/fixtures/blocks/core__quote__style-2.parsed.json @@ -4,10 +4,22 @@ "attrs": { "className": "is-style-large" }, - "innerBlocks": [], - "innerHTML": "\n

There is no greater agony than bearing an untold story inside you.

Maya Angelou
\n", + "innerBlocks": [ + { + "blockName": "core/paragraph", + "attrs": {}, + "innerBlocks": [], + "innerHTML": "\n

There is no greater agony than bearing an untold story inside you.

\n", + "innerContent": [ + "\n

There is no greater agony than bearing an untold story inside you.

\n" + ] + } + ], + "innerHTML": "\n
Maya Angelou
\n", "innerContent": [ - "\n

There is no greater agony than bearing an untold story inside you.

Maya Angelou
\n" + "\n
", + null, + "Maya Angelou
\n" ] } ] diff --git a/test/integration/fixtures/blocks/core__quote__style-2.serialized.html b/test/integration/fixtures/blocks/core__quote__style-2.serialized.html index b257de24088e9..13c2762059ecf 100644 --- a/test/integration/fixtures/blocks/core__quote__style-2.serialized.html +++ b/test/integration/fixtures/blocks/core__quote__style-2.serialized.html @@ -1,3 +1,5 @@ -

There is no greater agony than bearing an untold story inside you.

Maya Angelou
+
+

There is no greater agony than bearing an untold story inside you.

+Maya Angelou
diff --git a/test/integration/fixtures/documents/markdown-out.html b/test/integration/fixtures/documents/markdown-out.html index 5e4ddca850da3..104996580b223 100644 --- a/test/integration/fixtures/documents/markdown-out.html +++ b/test/integration/fixtures/documents/markdown-out.html @@ -39,7 +39,13 @@

Quote

-

First

Second

+
+

First

+ + + +

Second

+