diff --git a/packages/block-editor/src/components/rich-text/index.js b/packages/block-editor/src/components/rich-text/index.js index 21c004b225f6c5..423f096f3c6e45 100644 --- a/packages/block-editor/src/components/rich-text/index.js +++ b/packages/block-editor/src/components/rich-text/index.js @@ -14,11 +14,9 @@ import { createContext, } from '@wordpress/element'; import { useDispatch, useSelect } from '@wordpress/data'; -import { children as childrenSource } from '@wordpress/blocks'; import { useInstanceId, useMergeRefs } from '@wordpress/compose'; import { __unstableUseRichText as useRichText, - __unstableCreateElement, isEmpty, isCollapsed, removeFormat, @@ -168,19 +166,6 @@ function RichTextWrapper( } ); const hasFormats = ! adjustedAllowedFormats || adjustedAllowedFormats.length > 0; - let adjustedValue = originalValue; - let adjustedOnChange = originalOnChange; - - // Handle deprecated format. - if ( Array.isArray( originalValue ) ) { - adjustedValue = childrenSource.toHTML( originalValue ); - adjustedOnChange = ( newValue ) => - originalOnChange( - childrenSource.fromDOM( - __unstableCreateElement( document, newValue ).childNodes - ) - ); - } const onSelectionChange = useCallback( ( start, end ) => { @@ -256,9 +241,9 @@ function RichTextWrapper( onChange, ref: richTextRef, } = useRichText( { - value: adjustedValue, + value: originalValue, onChange( html, { __unstableFormats, __unstableText } ) { - adjustedOnChange( html ); + originalOnChange( html ); Object.values( changeHandlers ).forEach( ( changeHandler ) => { changeHandler( __unstableFormats, __unstableText ); } ); @@ -283,7 +268,7 @@ function RichTextWrapper( onChange, } ); - useMarkPersistent( { html: adjustedValue, value } ); + useMarkPersistent( { html: originalValue, value } ); const keyboardShortcuts = useRef( new Set() ); const inputEvents = useRef( new Set() ); @@ -447,11 +432,6 @@ ForwardedRichTextContainer.Content = ( { multiline, ...props } ) => { - // Handle deprecated `children` and `node` sources. - if ( Array.isArray( value ) ) { - value = childrenSource.toHTML( value ); - } - const MultilineTag = getMultilineTag( multiline ); if ( ! value && MultilineTag ) { diff --git a/packages/blocks/src/api/children.js b/packages/blocks/src/api/children.js deleted file mode 100644 index 40f279c02d7268..00000000000000 --- a/packages/blocks/src/api/children.js +++ /dev/null @@ -1,157 +0,0 @@ -/** - * External dependencies - */ -import { castArray } from 'lodash'; - -/** - * WordPress dependencies - */ -import { renderToString } from '@wordpress/element'; - -/** - * Internal dependencies - */ -import * as node from './node'; - -/** - * A representation of a block's rich text value. - * - * @typedef {WPBlockNode[]} WPBlockChildren - */ - -/** - * Given block children, returns a serialize-capable WordPress element. - * - * @param {WPBlockChildren} children Block children object to convert. - * - * @return {WPElement} A serialize-capable element. - */ -export function getSerializeCapableElement( children ) { - // The fact that block children are compatible with the element serializer is - // merely an implementation detail that currently serves to be true, but - // should not be mistaken as being a guarantee on the external API. The - // public API only offers guarantees to work with strings (toHTML) and DOM - // elements (fromDOM), and should provide utilities to manipulate the value - // rather than expect consumers to inspect or construct its shape (concat). - return children; -} - -/** - * Given block children, returns an array of block nodes. - * - * @param {WPBlockChildren} children Block children object to convert. - * - * @return {Array} An array of individual block nodes. - */ -function getChildrenArray( children ) { - // The fact that block children are compatible with the element serializer - // is merely an implementation detail that currently serves to be true, but - // should not be mistaken as being a guarantee on the external API. - return children; -} - -/** - * Given two or more block nodes, returns a new block node representing a - * concatenation of its values. - * - * @param {...WPBlockChildren} blockNodes Block nodes to concatenate. - * - * @return {WPBlockChildren} Concatenated block node. - */ -export function concat( ...blockNodes ) { - const result = []; - for ( let i = 0; i < blockNodes.length; i++ ) { - const blockNode = castArray( blockNodes[ i ] ); - for ( let j = 0; j < blockNode.length; j++ ) { - const child = blockNode[ j ]; - const canConcatToPreviousString = - typeof child === 'string' && - typeof result[ result.length - 1 ] === 'string'; - - if ( canConcatToPreviousString ) { - result[ result.length - 1 ] += child; - } else { - result.push( child ); - } - } - } - - return result; -} - -/** - * Given an iterable set of DOM nodes, returns equivalent block children. - * Ignores any non-element/text nodes included in set. - * - * @param {Iterable.} domNodes Iterable set of DOM nodes to convert. - * - * @return {WPBlockChildren} Block children equivalent to DOM nodes. - */ -export function fromDOM( domNodes ) { - const result = []; - for ( let i = 0; i < domNodes.length; i++ ) { - try { - result.push( node.fromDOM( domNodes[ i ] ) ); - } catch ( error ) { - // Simply ignore if DOM node could not be converted. - } - } - - return result; -} - -/** - * Given a block node, returns its HTML string representation. - * - * @param {WPBlockChildren} children Block node(s) to convert to string. - * - * @return {string} String HTML representation of block node. - */ -export function toHTML( children ) { - const element = getSerializeCapableElement( children ); - - return renderToString( element ); -} - -/** - * Given a selector, returns an hpq matcher generating a WPBlockChildren value - * matching the selector result. - * - * @param {string} selector DOM selector. - * - * @return {Function} hpq matcher. - */ -export function matcher( selector ) { - return ( domNode ) => { - let match = domNode; - - if ( selector ) { - match = domNode.querySelector( selector ); - } - - if ( match ) { - return fromDOM( match.childNodes ); - } - - return []; - }; -} - -/** - * Object of utility functions used in managing block attribute values of - * source `children`. - * - * @see https://github.com/WordPress/gutenberg/pull/10439 - * - * @deprecated since 4.0. The `children` source should not be used, and can be - * replaced by the `html` source. - * - * @private - */ -export default { - concat, - getChildrenArray, - fromDOM, - toHTML, - matcher, -}; diff --git a/packages/blocks/src/api/index.js b/packages/blocks/src/api/index.js index afa11f82c6b6ba..772e77eba7123d 100644 --- a/packages/blocks/src/api/index.js +++ b/packages/blocks/src/api/index.js @@ -156,8 +156,6 @@ export { doBlocksMatchTemplate, synchronizeBlocksWithTemplate, } from './templates'; -export { default as children } from './children'; -export { default as node } from './node'; export { __EXPERIMENTAL_STYLE_PROPERTY, __EXPERIMENTAL_ELEMENTS, diff --git a/packages/blocks/src/api/matchers.js b/packages/blocks/src/api/matchers.js index 7a6ac84891658a..f9dbf2ea1598d8 100644 --- a/packages/blocks/src/api/matchers.js +++ b/packages/blocks/src/api/matchers.js @@ -3,12 +3,6 @@ */ export { attr, prop, text, query } from 'hpq'; -/** - * Internal dependencies - */ -export { matcher as node } from './node'; -export { matcher as children } from './children'; - export function html( selector, multilineTag ) { return ( domNode ) => { let match = domNode; diff --git a/packages/blocks/src/api/node.js b/packages/blocks/src/api/node.js deleted file mode 100644 index 891034d3c3c279..00000000000000 --- a/packages/blocks/src/api/node.js +++ /dev/null @@ -1,132 +0,0 @@ -/** - * Internal dependencies - */ -import * as children from './children'; - -/** - * A representation of a single node within a block's rich text value. If - * representing a text node, the value is simply a string of the node value. - * As representing an element node, it is an object of: - * - * 1. `type` (string): Tag name. - * 2. `props` (object): Attributes and children array of WPBlockNode. - * - * @typedef {string|Object} WPBlockNode - */ - -/** - * Given a single node and a node type (e.g. `'br'`), returns true if the node - * corresponds to that type, false otherwise. - * - * @param {WPBlockNode} node Block node to test - * @param {string} type Node to type to test against. - * - * @return {boolean} Whether node is of intended type. - */ -function isNodeOfType( node, type ) { - return node && node.type === type; -} - -/** - * Given an object implementing the NamedNodeMap interface, returns a plain - * object equivalent value of name, value key-value pairs. - * - * @see https://dom.spec.whatwg.org/#interface-namednodemap - * - * @param {NamedNodeMap} nodeMap NamedNodeMap to convert to object. - * - * @return {Object} Object equivalent value of NamedNodeMap. - */ -export function getNamedNodeMapAsObject( nodeMap ) { - const result = {}; - for ( let i = 0; i < nodeMap.length; i++ ) { - const { name, value } = nodeMap[ i ]; - result[ name ] = value; - } - - return result; -} - -/** - * Given a DOM Element or Text node, returns an equivalent block node. Throws - * if passed any node type other than element or text. - * - * @throws {TypeError} If non-element/text node is passed. - * - * @param {Node} domNode DOM node to convert. - * - * @return {WPBlockNode} Block node equivalent to DOM node. - */ -export function fromDOM( domNode ) { - if ( domNode.nodeType === domNode.TEXT_NODE ) { - return domNode.nodeValue; - } - - if ( domNode.nodeType !== domNode.ELEMENT_NODE ) { - throw new TypeError( - 'A block node can only be created from a node of type text or ' + - 'element.' - ); - } - - return { - type: domNode.nodeName.toLowerCase(), - props: { - ...getNamedNodeMapAsObject( domNode.attributes ), - children: children.fromDOM( domNode.childNodes ), - }, - }; -} - -/** - * Given a block node, returns its HTML string representation. - * - * @param {WPBlockNode} node Block node to convert to string. - * - * @return {string} String HTML representation of block node. - */ -export function toHTML( node ) { - return children.toHTML( [ node ] ); -} - -/** - * Given a selector, returns an hpq matcher generating a WPBlockNode value - * matching the selector result. - * - * @param {string} selector DOM selector. - * - * @return {Function} hpq matcher. - */ -export function matcher( selector ) { - return ( domNode ) => { - let match = domNode; - - if ( selector ) { - match = domNode.querySelector( selector ); - } - - try { - return fromDOM( match ); - } catch ( error ) { - return null; - } - }; -} - -/** - * Object of utility functions used in managing block attribute values of - * source `node`. - * - * @see https://github.com/WordPress/gutenberg/pull/10439 - * - * @deprecated since 4.0. The `node` source should not be used, and can be - * replaced by the `html` source. - * - * @private - */ -export default { - isNodeOfType, - fromDOM, - toHTML, - matcher, -}; diff --git a/packages/blocks/src/api/parser/get-block-attributes.js b/packages/blocks/src/api/parser/get-block-attributes.js index 804e7f18ddd4ca..2022b6e9fd101a 100644 --- a/packages/blocks/src/api/parser/get-block-attributes.js +++ b/packages/blocks/src/api/parser/get-block-attributes.js @@ -13,7 +13,7 @@ import { applyFilters } from '@wordpress/hooks'; /** * Internal dependencies */ -import { attr, html, text, query, node, children, prop } from '../matchers'; +import { attr, html, text, query, prop } from '../matchers'; import { normalizeBlockType } from '../utils'; /** @@ -128,8 +128,6 @@ export function getBlockAttribute( case 'property': case 'html': case 'text': - case 'children': - case 'node': case 'query': case 'tag': value = parseWithAttributeSchema( innerHTML, attributeSchema ); @@ -202,10 +200,6 @@ export const matcherFromSource = memoize( ( sourceConfig ) => { return html( sourceConfig.selector, sourceConfig.multiline ); case 'text': return text( sourceConfig.selector ); - case 'children': - return children( sourceConfig.selector ); - case 'node': - return node( sourceConfig.selector ); case 'query': const subMatchers = mapValues( sourceConfig.query, diff --git a/packages/blocks/src/api/test/children.js b/packages/blocks/src/api/test/children.js deleted file mode 100644 index dbc066e585850c..00000000000000 --- a/packages/blocks/src/api/test/children.js +++ /dev/null @@ -1,136 +0,0 @@ -/** - * WordPress dependencies - */ -import { renderToString } from '@wordpress/element'; - -/** - * Internal dependencies - */ -import { - getSerializeCapableElement, - concat, - toHTML, - fromDOM, -} from '../children'; - -describe( 'getSerializeCapableElement', () => { - it( 'returns a serialize capable element', () => { - const blockNode = [ - 'This ', - { - type: 'strong', - props: { - class: 'is-extra-strong', - children: [ 'is' ], - }, - }, - ' a test', - ]; - - const element = getSerializeCapableElement( blockNode ); - - // Intentionally avoid introspecting the shape of the generated element - // since all that is cared about is that it can be serialized. - const html = renderToString( element ); - - expect( html ).toBe( - 'This is a test' - ); - } ); -} ); - -describe( 'concat', () => { - it( 'should combine two or more sets of block nodes', () => { - const result = concat( - { - type: 'strong', - props: { - children: [ 'Hello' ], - }, - }, - ' ', - { - type: 'em', - props: { - children: [ 'world' ], - }, - } - ); - - expect( result ).toEqual( [ - { - type: 'strong', - props: { - children: [ 'Hello' ], - }, - }, - ' ', - { - type: 'em', - props: { - children: [ 'world' ], - }, - }, - ] ); - } ); - - it( 'should merge adjacent strings', () => { - const result = concat( 'Hello', ' ', { - type: 'strong', - props: { - children: [ 'World' ], - }, - } ); - - expect( result ).toEqual( [ - 'Hello ', - { - type: 'strong', - props: { - children: [ 'World' ], - }, - }, - ] ); - } ); -} ); - -describe( 'toHTML', () => { - it( 'should convert a children array of block nodes to its equivalent html string', () => { - const children = [ - 'This is a ', - { - type: 'strong', - props: { - children: [ 'test' ], - }, - }, - '!', - ]; - - const html = toHTML( children ); - - expect( html ).toBe( 'This is a test!' ); - } ); -} ); - -describe( 'fromDOM', () => { - it( 'should return an equivalent block children', () => { - const node = document.createElement( 'div' ); - node.innerHTML = - 'This is a test'; - - const blockNode = fromDOM( node.childNodes ); - - expect( blockNode ).toEqual( [ - 'This ', - { - type: 'strong', - props: { - class: 'is-extra-strong', - children: [ 'is' ], - }, - }, - ' a test', - ] ); - } ); -} ); diff --git a/packages/blocks/src/api/test/matchers.js b/packages/blocks/src/api/test/matchers.js deleted file mode 100644 index 9f7fccefbe38e5..00000000000000 --- a/packages/blocks/src/api/test/matchers.js +++ /dev/null @@ -1,52 +0,0 @@ -/** - * External dependencies - */ -import { parse } from 'hpq'; - -/** - * WordPress dependencies - */ -import { renderToString } from '@wordpress/element'; - -/** - * Internal dependencies - */ -import * as sources from '../matchers'; - -describe( 'matchers', () => { - describe( 'children()', () => { - it( 'should return a source function', () => { - const source = sources.children(); - - expect( typeof source ).toBe( 'function' ); - } ); - - it( 'should return HTML equivalent WPElement of matched element', () => { - // Assumption here is that we can cleanly convert back and forth - // between a string and WPElement representation. - const html = - '

A delicious sundae dessert

'; - const match = parse( html, sources.children() ); - - expect( renderToString( match ) ).toBe( html ); - } ); - } ); - - describe( 'node()', () => { - it( 'should return a source function', () => { - const source = sources.node(); - - expect( typeof source ).toBe( 'function' ); - } ); - - it( 'should return HTML equivalent WPElement of matched element', () => { - // Assumption here is that we can cleanly convert back and forth - // between a string and WPElement representation. - const html = - '

A delicious sundae dessert

'; - const match = parse( html, sources.node() ); - - expect( renderToString( match ) ).toBe( `${ html }` ); - } ); - } ); -} ); diff --git a/packages/blocks/src/api/test/node.js b/packages/blocks/src/api/test/node.js deleted file mode 100644 index 8c627f95b3896d..00000000000000 --- a/packages/blocks/src/api/test/node.js +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Internal dependencies - */ -import { getNamedNodeMapAsObject, toHTML, fromDOM } from '../node'; - -describe( 'getNamedNodeMapAsObject', () => { - it( 'should return an object of node attributes', () => { - const node = document.createElement( 'img' ); - node.setAttribute( - 'src', - 'https://s.w.org/style/images/wporg-logo.svg' - ); - - const object = getNamedNodeMapAsObject( node.attributes ); - expect( object ).toEqual( { - src: 'https://s.w.org/style/images/wporg-logo.svg', - } ); - } ); -} ); - -describe( 'toHTML', () => { - it( 'should convert a block node to its equivalent html string', () => { - const blockNode = { - type: 'strong', - props: { - class: 'is-extra-strong', - children: [ 'This is a test' ], - }, - }; - - const html = toHTML( blockNode ); - - expect( html ).toBe( - 'This is a test' - ); - } ); -} ); - -describe( 'fromDOM', () => { - it( 'should return a text node as its string node value', () => { - const node = document.createTextNode( 'Hello world' ); - - const blockNode = fromDOM( node ); - - expect( blockNode ).toBe( 'Hello world' ); - } ); - - it( 'should throw an error on receiving non-element/text node', () => { - expect( () => { - fromDOM( document.createDocumentFragment() ); - } ).toThrow( TypeError ); - } ); - - it( 'should return an equivalent block node, including children', () => { - const node = document.createElement( 'strong' ); - node.setAttribute( 'class', 'is-extra-strong' ); - node.innerHTML = 'Hello world!'; - - const blockNode = fromDOM( node ); - - expect( blockNode ).toEqual( { - type: 'strong', - props: { - class: 'is-extra-strong', - children: [ - 'Hello ', - { - type: 'em', - props: { - children: [ 'world' ], - }, - }, - '!', - ], - }, - } ); - } ); -} ); diff --git a/packages/e2e-tests/plugins/deprecated-node-matcher.php b/packages/e2e-tests/plugins/deprecated-node-matcher.php deleted file mode 100644 index 7e0a6e3d2c5578..00000000000000 --- a/packages/e2e-tests/plugins/deprecated-node-matcher.php +++ /dev/null @@ -1,28 +0,0 @@ - p', - query: { - children: { - source: 'node', - }, - }, - }, - }, - category: 'text', - edit( { attributes, setAttributes } ) { - return el( - 'blockquote', - {}, - el( RichText, { - multiline: 'p', - value: toRichTextValue( attributes.value ), - onChange( nextValue ) { - setAttributes( { - value: fromRichTextValue( nextValue ), - } ); - }, - } ) - ); - }, - save( { attributes } ) { - return el( - 'blockquote', - {}, - el( RichText.Content, { - value: toRichTextValue( attributes.value ), - } ) - ); - }, - } ); -} )(); diff --git a/test/e2e/specs/editor/plugins/__snapshots__/Deprecated-Node-Matcher-should-insert-block-with-children-source-1-chromium.txt b/test/e2e/specs/editor/plugins/__snapshots__/Deprecated-Node-Matcher-should-insert-block-with-children-source-1-chromium.txt deleted file mode 100644 index 469b0e769f04bd..00000000000000 --- a/test/e2e/specs/editor/plugins/__snapshots__/Deprecated-Node-Matcher-should-insert-block-with-children-source-1-chromium.txt +++ /dev/null @@ -1,3 +0,0 @@ - -

test
a

- \ No newline at end of file diff --git a/test/e2e/specs/editor/plugins/__snapshots__/Deprecated-Node-Matcher-should-insert-block-with-node-source-1-chromium.txt b/test/e2e/specs/editor/plugins/__snapshots__/Deprecated-Node-Matcher-should-insert-block-with-node-source-1-chromium.txt deleted file mode 100644 index 4e5daa5abfffec..00000000000000 --- a/test/e2e/specs/editor/plugins/__snapshots__/Deprecated-Node-Matcher-should-insert-block-with-node-source-1-chromium.txt +++ /dev/null @@ -1,3 +0,0 @@ - -

test

- \ No newline at end of file diff --git a/test/e2e/specs/editor/plugins/deprecated-node-matcher.spec.js b/test/e2e/specs/editor/plugins/deprecated-node-matcher.spec.js deleted file mode 100644 index fd57954e9905da..00000000000000 --- a/test/e2e/specs/editor/plugins/deprecated-node-matcher.spec.js +++ /dev/null @@ -1,55 +0,0 @@ -/** - * WordPress dependencies - */ -/** - * WordPress dependencies - */ -const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); - -test.describe( 'Deprecated Node Matcher', () => { - test.beforeAll( async ( { requestUtils } ) => { - await requestUtils.activatePlugin( - 'gutenberg-test-deprecated-node-matcher' - ); - } ); - - test.beforeEach( async ( { admin } ) => { - await admin.createNewPost(); - } ); - - test.afterAll( async ( { requestUtils } ) => { - await requestUtils.deactivatePlugin( - 'gutenberg-test-deprecated-node-matcher' - ); - } ); - - test( 'should insert block with node source', async ( { - page, - editor, - } ) => { - // await insertBlock( 'Deprecated Node Matcher' ); - await editor.insertBlock( { name: 'core/deprecated-node-matcher' } ); - await page.keyboard.type( 'test' ); - await page.keyboard.press( 'Enter' ); - expect( await editor.getEditedPostContent() ).toMatchSnapshot(); - } ); - - test( 'should insert block with children source', async ( { - page, - editor, - pageUtils, - } ) => { - // await insertBlock( 'Deprecated Children Matcher' ); - await editor.insertBlock( { - name: 'core/deprecated-children-matcher', - } ); - await page.keyboard.type( 'test' ); - await page.keyboard.press( 'Enter' ); - await page.keyboard.type( 'a' ); - await page.keyboard.down( 'Shift' ); - await page.keyboard.press( 'ArrowLeft' ); - await page.keyboard.up( 'Shift' ); - await pageUtils.pressKeyWithModifier( 'primary', 'b' ); - expect( await editor.getEditedPostContent() ).toMatchSnapshot(); - } ); -} );