diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js
index a42e86fa94037..6013bc2d79d07 100644
--- a/packages/block-library/src/gallery/edit.js
+++ b/packages/block-library/src/gallery/edit.js
@@ -2,7 +2,7 @@
* External dependencies
*/
import classnames from 'classnames';
-import { filter, pick, map, get } from 'lodash';
+import { filter, map } from 'lodash';
/**
* WordPress dependencies
@@ -31,6 +31,7 @@ import { __, sprintf } from '@wordpress/i18n';
*/
import GalleryImage from './gallery-image';
import icon from './icon';
+import { defaultColumnsNumber, pickRelevantMediaFiles } from './shared';
const MAX_COLUMNS = 8;
const linkOptions = [
@@ -40,16 +41,6 @@ const linkOptions = [
];
const ALLOWED_MEDIA_TYPES = [ 'image' ];
-export function defaultColumnsNumber( attributes ) {
- return Math.min( 3, attributes.images.length );
-}
-
-export const pickRelevantMediaFiles = ( image ) => {
- const imageProps = pick( image, [ 'alt', 'id', 'link', 'caption' ] );
- imageProps.url = get( image, [ 'sizes', 'large', 'url' ] ) || get( image, [ 'media_details', 'sizes', 'large', 'source_url' ] ) || image.url;
- return imageProps;
-};
-
class GalleryEdit extends Component {
constructor() {
super( ...arguments );
diff --git a/packages/block-library/src/gallery/index.js b/packages/block-library/src/gallery/index.js
index 7f8aaa79bb3f4..d6ea28fe051c3 100644
--- a/packages/block-library/src/gallery/index.js
+++ b/packages/block-library/src/gallery/index.js
@@ -1,38 +1,28 @@
/**
* External dependencies
*/
-import { filter, every, map, some } from 'lodash';
+import { map, some } from 'lodash';
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
-import { createBlock } from '@wordpress/blocks';
import { RichText } from '@wordpress/block-editor';
-import { mediaUpload } from '@wordpress/editor';
-import { createBlobURL } from '@wordpress/blob';
/**
* Internal dependencies
*/
-import { default as edit, defaultColumnsNumber, pickRelevantMediaFiles } from './edit';
+import edit from './edit';
import icon from './icon';
import metadata from './block.json';
+import save from './save';
+import transforms from './transforms';
+import { defaultColumnsNumber } from './shared';
const { name, attributes: blockAttributes } = metadata;
export { metadata, name };
-const parseShortcodeIds = ( ids ) => {
- if ( ! ids ) {
- return [];
- }
-
- return ids.split( ',' ).map( ( id ) => (
- parseInt( id, 10 )
- ) );
-};
-
export const settings = {
title: __( 'Gallery' ),
description: __( 'Display multiple images in a rich gallery.' ),
@@ -41,138 +31,9 @@ export const settings = {
supports: {
align: true,
},
-
- transforms: {
- from: [
- {
- type: 'block',
- isMultiBlock: true,
- blocks: [ 'core/image' ],
- transform: ( attributes ) => {
- // Init the align attribute from the first item which may be either the placeholder or an image.
- let { align } = attributes[ 0 ];
- // Loop through all the images and check if they have the same align.
- align = every( attributes, [ 'align', align ] ) ? align : undefined;
-
- const validImages = filter( attributes, ( { id, url } ) => id && url );
-
- return createBlock( 'core/gallery', {
- images: validImages.map( ( { id, url, alt, caption } ) => ( { id, url, alt, caption } ) ),
- ids: validImages.map( ( { id } ) => id ),
- align,
- } );
- },
- },
- {
- type: 'shortcode',
- tag: 'gallery',
- attributes: {
- images: {
- type: 'array',
- shortcode: ( { named: { ids } } ) => {
- return parseShortcodeIds( ids ).map( ( id ) => ( {
- id,
- } ) );
- },
- },
- ids: {
- type: 'array',
- shortcode: ( { named: { ids } } ) => {
- return parseShortcodeIds( ids );
- },
- },
- columns: {
- type: 'number',
- shortcode: ( { named: { columns = '3' } } ) => {
- return parseInt( columns, 10 );
- },
- },
- linkTo: {
- type: 'string',
- shortcode: ( { named: { link = 'attachment' } } ) => {
- return link === 'file' ? 'media' : link;
- },
- },
- },
- },
- {
- // When created by drag and dropping multiple files on an insertion point
- type: 'files',
- isMatch( files ) {
- return files.length !== 1 && every( files, ( file ) => file.type.indexOf( 'image/' ) === 0 );
- },
- transform( files, onChange ) {
- const block = createBlock( 'core/gallery', {
- images: files.map( ( file ) => pickRelevantMediaFiles( {
- url: createBlobURL( file ),
- } ) ),
- } );
- mediaUpload( {
- filesList: files,
- onFileChange: ( images ) => {
- const imagesAttr = images.map(
- pickRelevantMediaFiles
- );
- onChange( block.clientId, {
- ids: map( imagesAttr, 'id' ),
- images: imagesAttr,
- } );
- },
- allowedTypes: [ 'image' ],
- } );
- return block;
- },
- },
- ],
- to: [
- {
- type: 'block',
- blocks: [ 'core/image' ],
- transform: ( { images, align } ) => {
- if ( images.length > 0 ) {
- return images.map( ( { id, url, alt, caption } ) => createBlock( 'core/image', { id, url, alt, caption, align } ) );
- }
- return createBlock( 'core/image', { align } );
- },
- },
- ],
- },
-
+ transforms,
edit,
-
- save( { attributes } ) {
- const { images, columns = defaultColumnsNumber( attributes ), imageCrop, linkTo } = attributes;
- return (
-
- { images.map( ( image ) => {
- let href;
-
- switch ( linkTo ) {
- case 'media':
- href = image.url;
- break;
- case 'attachment':
- href = image.link;
- break;
- }
-
- const img = ;
-
- return (
- -
-
-
- );
- } ) }
-
- );
- },
-
+ save,
deprecated: [
{
attributes: blockAttributes,
diff --git a/packages/block-library/src/gallery/save.js b/packages/block-library/src/gallery/save.js
new file mode 100644
index 0000000000000..49ff711aa6d63
--- /dev/null
+++ b/packages/block-library/src/gallery/save.js
@@ -0,0 +1,42 @@
+/**
+ * WordPress dependencies
+ */
+import { RichText } from '@wordpress/block-editor';
+
+/**
+ * Internal dependencies
+ */
+import { defaultColumnsNumber } from './shared';
+
+export default function save( { attributes } ) {
+ const { images, columns = defaultColumnsNumber( attributes ), imageCrop, linkTo } = attributes;
+ return (
+
+ { images.map( ( image ) => {
+ let href;
+
+ switch ( linkTo ) {
+ case 'media':
+ href = image.url;
+ break;
+ case 'attachment':
+ href = image.link;
+ break;
+ }
+
+ const img = ;
+
+ return (
+ -
+
+
+ );
+ } ) }
+
+ );
+}
diff --git a/packages/block-library/src/gallery/shared.js b/packages/block-library/src/gallery/shared.js
new file mode 100644
index 0000000000000..15affe5c62039
--- /dev/null
+++ b/packages/block-library/src/gallery/shared.js
@@ -0,0 +1,14 @@
+/**
+ * External dependencies
+ */
+import { get, pick } from 'lodash';
+
+export function defaultColumnsNumber( attributes ) {
+ return Math.min( 3, attributes.images.length );
+}
+
+export const pickRelevantMediaFiles = ( image ) => {
+ const imageProps = pick( image, [ 'alt', 'id', 'link', 'caption' ] );
+ imageProps.url = get( image, [ 'sizes', 'large', 'url' ] ) || get( image, [ 'media_details', 'sizes', 'large', 'source_url' ] ) || image.url;
+ return imageProps;
+};
diff --git a/packages/block-library/src/gallery/transforms.js b/packages/block-library/src/gallery/transforms.js
new file mode 100644
index 0000000000000..af8d5d164c10e
--- /dev/null
+++ b/packages/block-library/src/gallery/transforms.js
@@ -0,0 +1,135 @@
+/**
+ * External dependencies
+ */
+import { filter, every, map } from 'lodash';
+
+/**
+ * WordPress dependencies
+ */
+import { createBlock } from '@wordpress/blocks';
+import { mediaUpload } from '@wordpress/editor';
+import { createBlobURL } from '@wordpress/blob';
+
+/**
+ * Internal dependencies
+ */
+import { pickRelevantMediaFiles } from './shared';
+
+const parseShortcodeIds = ( ids ) => {
+ if ( ! ids ) {
+ return [];
+ }
+
+ return ids.split( ',' ).map( ( id ) => (
+ parseInt( id, 10 )
+ ) );
+};
+
+const transforms = {
+ from: [
+ {
+ type: 'block',
+ isMultiBlock: true,
+ blocks: [ 'core/image' ],
+ transform: ( attributes ) => {
+ // Init the align attribute from the first item which may be either the placeholder or an image.
+ let { align } = attributes[ 0 ];
+ // Loop through all the images and check if they have the same align.
+ align = every( attributes, [ 'align', align ] ) ? align : undefined;
+
+ const validImages = filter( attributes, ( { id, url } ) => id && url );
+
+ return createBlock( 'core/gallery', {
+ images: validImages.map( ( { id, url, alt, caption } ) => ( {
+ id,
+ url,
+ alt,
+ caption,
+ } ) ),
+ ids: validImages.map( ( { id } ) => id ),
+ align,
+ } );
+ },
+ },
+ {
+ type: 'shortcode',
+ tag: 'gallery',
+ attributes: {
+ images: {
+ type: 'array',
+ shortcode: ( { named: { ids } } ) => {
+ return parseShortcodeIds( ids ).map( ( id ) => ( {
+ id,
+ } ) );
+ },
+ },
+ ids: {
+ type: 'array',
+ shortcode: ( { named: { ids } } ) => {
+ return parseShortcodeIds( ids );
+ },
+ },
+ columns: {
+ type: 'number',
+ shortcode: ( { named: { columns = '3' } } ) => {
+ return parseInt( columns, 10 );
+ },
+ },
+ linkTo: {
+ type: 'string',
+ shortcode: ( { named: { link = 'attachment' } } ) => {
+ return link === 'file' ? 'media' : link;
+ },
+ },
+ },
+ },
+ {
+ // When created by drag and dropping multiple files on an insertion point
+ type: 'files',
+ isMatch( files ) {
+ return files.length !== 1 && every( files, ( file ) => file.type.indexOf( 'image/' ) === 0 );
+ },
+ transform( files, onChange ) {
+ const block = createBlock( 'core/gallery', {
+ images: files.map( ( file ) => pickRelevantMediaFiles( {
+ url: createBlobURL( file ),
+ } ) ),
+ } );
+ mediaUpload( {
+ filesList: files,
+ onFileChange: ( images ) => {
+ const imagesAttr = images.map(
+ pickRelevantMediaFiles,
+ );
+ onChange( block.clientId, {
+ ids: map( imagesAttr, 'id' ),
+ images: imagesAttr,
+ } );
+ },
+ allowedTypes: [ 'image' ],
+ } );
+ return block;
+ },
+ },
+ ],
+ to: [
+ {
+ type: 'block',
+ blocks: [ 'core/image' ],
+ transform: ( { images, align } ) => {
+ if ( images.length > 0 ) {
+ return images.map( ( { id, url, alt, caption } ) => createBlock( 'core/image', {
+ id,
+ url,
+ alt,
+ caption,
+ align,
+ } ) );
+ }
+ return createBlock( 'core/image', { align } );
+ },
+ },
+ ],
+};
+
+export default transforms;
diff --git a/packages/block-library/src/heading/index.js b/packages/block-library/src/heading/index.js
index 4cbe792e8ec8e..4dd2f16e086ce 100644
--- a/packages/block-library/src/heading/index.js
+++ b/packages/block-library/src/heading/index.js
@@ -7,11 +7,6 @@ import { omit } from 'lodash';
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
-import {
- createBlock,
- getPhrasingContentSchema,
- getBlockAttributes,
-} from '@wordpress/blocks';
import { RichText } from '@wordpress/block-editor';
/**
@@ -20,22 +15,14 @@ import { RichText } from '@wordpress/block-editor';
import edit from './edit';
import icon from './icon';
import metadata from './block.json';
+import save from './save';
+import transforms from './transforms';
+import { getLevelFromHeadingNodeName } from './shared';
const { name, attributes: schema } = metadata;
export { metadata, name };
-/**
- * Given a node name string for a heading node, returns its numeric level.
- *
- * @param {string} nodeName Heading node name.
- *
- * @return {number} Heading level.
- */
-export function getLevelFromHeadingNodeName( nodeName ) {
- return Number( nodeName.substr( 1 ) );
-}
-
const supports = {
className: false,
anchor: true,
@@ -43,71 +30,11 @@ const supports = {
export const settings = {
title: __( 'Heading' ),
-
description: __( 'Introduce new sections and organize content to help visitors (and search engines) understand the structure of your content.' ),
-
icon,
-
keywords: [ __( 'title' ), __( 'subtitle' ) ],
-
supports,
-
- transforms: {
- from: [
- {
- type: 'block',
- blocks: [ 'core/paragraph' ],
- transform: ( { content } ) => {
- return createBlock( 'core/heading', {
- content,
- } );
- },
- },
- {
- type: 'raw',
- selector: 'h1,h2,h3,h4,h5,h6',
- schema: {
- h1: { children: getPhrasingContentSchema() },
- h2: { children: getPhrasingContentSchema() },
- h3: { children: getPhrasingContentSchema() },
- h4: { children: getPhrasingContentSchema() },
- h5: { children: getPhrasingContentSchema() },
- h6: { children: getPhrasingContentSchema() },
- },
- transform( node ) {
- return createBlock( 'core/heading', {
- ...getBlockAttributes(
- 'core/heading',
- node.outerHTML
- ),
- level: getLevelFromHeadingNodeName( node.nodeName ),
- } );
- },
- },
- ...[ 2, 3, 4, 5, 6 ].map( ( level ) => ( {
- type: 'prefix',
- prefix: Array( level + 1 ).join( '#' ),
- transform( content ) {
- return createBlock( 'core/heading', {
- level,
- content,
- } );
- },
- } ) ),
- ],
- to: [
- {
- type: 'block',
- blocks: [ 'core/paragraph' ],
- transform: ( { content } ) => {
- return createBlock( 'core/paragraph', {
- content,
- } );
- },
- },
- ],
- },
-
+ transforms,
deprecated: [
{
supports,
@@ -142,25 +69,11 @@ export const settings = {
},
},
],
-
merge( attributes, attributesToMerge ) {
return {
content: ( attributes.content || '' ) + ( attributesToMerge.content || '' ),
};
},
-
edit,
-
- save( { attributes } ) {
- const { align, level, content } = attributes;
- const tagName = 'h' + level;
-
- return (
-
- );
- },
+ save,
};
diff --git a/packages/block-library/src/heading/save.js b/packages/block-library/src/heading/save.js
new file mode 100644
index 0000000000000..522013158ee99
--- /dev/null
+++ b/packages/block-library/src/heading/save.js
@@ -0,0 +1,17 @@
+/**
+ * WordPress dependencies
+ */
+import { RichText } from '@wordpress/block-editor';
+
+export default function save( { attributes } ) {
+ const { align, level, content } = attributes;
+ const tagName = 'h' + level;
+
+ return (
+
+ );
+}
diff --git a/packages/block-library/src/heading/shared.js b/packages/block-library/src/heading/shared.js
new file mode 100644
index 0000000000000..604eaa9adba8f
--- /dev/null
+++ b/packages/block-library/src/heading/shared.js
@@ -0,0 +1,10 @@
+/**
+ * Given a node name string for a heading node, returns its numeric level.
+ *
+ * @param {string} nodeName Heading node name.
+ *
+ * @return {number} Heading level.
+ */
+export function getLevelFromHeadingNodeName( nodeName ) {
+ return Number( nodeName.substr( 1 ) );
+}
diff --git a/packages/block-library/src/heading/test/index.js b/packages/block-library/src/heading/test/shared.js
similarity index 80%
rename from packages/block-library/src/heading/test/index.js
rename to packages/block-library/src/heading/test/shared.js
index ffa9d2538674d..e601a3d98b3d7 100644
--- a/packages/block-library/src/heading/test/index.js
+++ b/packages/block-library/src/heading/test/shared.js
@@ -1,7 +1,7 @@
/**
* Internal dependencies
*/
-import { getLevelFromHeadingNodeName } from '../';
+import { getLevelFromHeadingNodeName } from '../shared';
describe( 'getLevelFromHeadingNodeName()', () => {
it( 'should return a numeric value from nodeName', () => {
diff --git a/packages/block-library/src/heading/transforms.js b/packages/block-library/src/heading/transforms.js
new file mode 100644
index 0000000000000..b043018a400ca
--- /dev/null
+++ b/packages/block-library/src/heading/transforms.js
@@ -0,0 +1,71 @@
+/**
+ * WordPress dependencies
+ */
+import {
+ createBlock,
+ getPhrasingContentSchema,
+ getBlockAttributes,
+} from '@wordpress/blocks';
+
+/**
+ * Internal dependencies
+ */
+import { getLevelFromHeadingNodeName } from './shared';
+
+const transforms = {
+ from: [
+ {
+ type: 'block',
+ blocks: [ 'core/paragraph' ],
+ transform: ( { content } ) => {
+ return createBlock( 'core/heading', {
+ content,
+ } );
+ },
+ },
+ {
+ type: 'raw',
+ selector: 'h1,h2,h3,h4,h5,h6',
+ schema: {
+ h1: { children: getPhrasingContentSchema() },
+ h2: { children: getPhrasingContentSchema() },
+ h3: { children: getPhrasingContentSchema() },
+ h4: { children: getPhrasingContentSchema() },
+ h5: { children: getPhrasingContentSchema() },
+ h6: { children: getPhrasingContentSchema() },
+ },
+ transform( node ) {
+ return createBlock( 'core/heading', {
+ ...getBlockAttributes(
+ 'core/heading',
+ node.outerHTML
+ ),
+ level: getLevelFromHeadingNodeName( node.nodeName ),
+ } );
+ },
+ },
+ ...[ 2, 3, 4, 5, 6 ].map( ( level ) => ( {
+ type: 'prefix',
+ prefix: Array( level + 1 ).join( '#' ),
+ transform( content ) {
+ return createBlock( 'core/heading', {
+ level,
+ content,
+ } );
+ },
+ } ) ),
+ ],
+ to: [
+ {
+ type: 'block',
+ blocks: [ 'core/paragraph' ],
+ transform: ( { content } ) => {
+ return createBlock( 'core/paragraph', {
+ content,
+ } );
+ },
+ },
+ ],
+};
+
+export default transforms;
diff --git a/packages/block-library/src/html/index.js b/packages/block-library/src/html/index.js
index 603199158a292..bcfec8fb79f84 100644
--- a/packages/block-library/src/html/index.js
+++ b/packages/block-library/src/html/index.js
@@ -1,9 +1,7 @@
/**
* WordPress dependencies
*/
-import { RawHTML } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
-import { getPhrasingContentSchema } from '@wordpress/blocks';
/**
* Internal dependencies
@@ -11,6 +9,8 @@ import { getPhrasingContentSchema } from '@wordpress/blocks';
import edit from './edit';
import icon from './icon';
import metadata from './block.json';
+import save from './save';
+import transforms from './transforms';
const { name } = metadata;
@@ -18,44 +18,15 @@ export { metadata, name };
export const settings = {
title: __( 'Custom HTML' ),
-
description: __( 'Add custom HTML code and preview it as you edit.' ),
-
icon,
-
keywords: [ __( 'embed' ) ],
-
supports: {
customClassName: false,
className: false,
html: false,
},
-
- transforms: {
- from: [
- {
- type: 'raw',
- isMatch: ( node ) => node.nodeName === 'FIGURE' && !! node.querySelector( 'iframe' ),
- schema: {
- figure: {
- require: [ 'iframe' ],
- children: {
- iframe: {
- attributes: [ 'src', 'allowfullscreen', 'height', 'width' ],
- },
- figcaption: {
- children: getPhrasingContentSchema(),
- },
- },
- },
- },
- },
- ],
- },
-
+ transforms,
edit,
-
- save( { attributes } ) {
- return { attributes.content };
- },
+ save,
};
diff --git a/packages/block-library/src/html/save.js b/packages/block-library/src/html/save.js
new file mode 100644
index 0000000000000..08d72be511bb2
--- /dev/null
+++ b/packages/block-library/src/html/save.js
@@ -0,0 +1,8 @@
+/**
+ * WordPress dependencies
+ */
+import { RawHTML } from '@wordpress/element';
+
+export default function save( { attributes } ) {
+ return { attributes.content };
+}
diff --git a/packages/block-library/src/html/transforms.js b/packages/block-library/src/html/transforms.js
new file mode 100644
index 0000000000000..a54c17ef8f6de
--- /dev/null
+++ b/packages/block-library/src/html/transforms.js
@@ -0,0 +1,28 @@
+/**
+ * WordPress dependencies
+ */
+import { getPhrasingContentSchema } from '@wordpress/blocks';
+
+const transforms = {
+ from: [
+ {
+ type: 'raw',
+ isMatch: ( node ) => node.nodeName === 'FIGURE' && !! node.querySelector( 'iframe' ),
+ schema: {
+ figure: {
+ require: [ 'iframe' ],
+ children: {
+ iframe: {
+ attributes: [ 'src', 'allowfullscreen', 'height', 'width' ],
+ },
+ figcaption: {
+ children: getPhrasingContentSchema(),
+ },
+ },
+ },
+ },
+ },
+ ],
+};
+
+export default transforms;
diff --git a/packages/block-library/src/image/index.js b/packages/block-library/src/image/index.js
index a61d51e0b4aba..cf8eb321c4700 100644
--- a/packages/block-library/src/image/index.js
+++ b/packages/block-library/src/image/index.js
@@ -6,14 +6,7 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
-import { createBlobURL } from '@wordpress/blob';
-import {
- createBlock,
- getBlockAttributes,
- getPhrasingContentSchema,
-} from '@wordpress/blocks';
import { RichText } from '@wordpress/block-editor';
-import { Fragment } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
/**
@@ -22,247 +15,30 @@ import { __ } from '@wordpress/i18n';
import edit from './edit';
import icon from './icon';
import metadata from './block.json';
+import save from './save';
+import transforms from './transforms';
const { name, attributes: blockAttributes } = metadata;
export { metadata, name };
-const imageSchema = {
- img: {
- attributes: [ 'src', 'alt' ],
- classes: [ 'alignleft', 'aligncenter', 'alignright', 'alignnone', /^wp-image-\d+$/ ],
- },
-};
-
-const schema = {
- figure: {
- require: [ 'img' ],
- children: {
- ...imageSchema,
- a: {
- attributes: [ 'href', 'rel', 'target' ],
- children: imageSchema,
- },
- figcaption: {
- children: getPhrasingContentSchema(),
- },
- },
- },
-};
-
-function getFirstAnchorAttributeFormHTML( html, attributeName ) {
- const { body } = document.implementation.createHTMLDocument( '' );
-
- body.innerHTML = html;
-
- const { firstElementChild } = body;
-
- if (
- firstElementChild &&
- firstElementChild.nodeName === 'A'
- ) {
- return firstElementChild.getAttribute( attributeName ) || undefined;
- }
-}
-
-export function stripFirstImage( attributes, { shortcode } ) {
- const { body } = document.implementation.createHTMLDocument( '' );
-
- body.innerHTML = shortcode.content;
-
- let nodeToRemove = body.querySelector( 'img' );
-
- // if an image has parents, find the topmost node to remove
- while ( nodeToRemove && nodeToRemove.parentNode && nodeToRemove.parentNode !== body ) {
- nodeToRemove = nodeToRemove.parentNode;
- }
-
- if ( nodeToRemove ) {
- nodeToRemove.parentNode.removeChild( nodeToRemove );
- }
-
- return body.innerHTML.trim();
-}
-
export const settings = {
title: __( 'Image' ),
-
description: __( 'Insert an image to make a visual statement.' ),
-
icon,
-
keywords: [
'img', // "img" is not translated as it is intended to reflect the HTML tag.
__( 'photo' ),
],
-
- transforms: {
- from: [
- {
- type: 'raw',
- isMatch: ( node ) => node.nodeName === 'FIGURE' && !! node.querySelector( 'img' ),
- schema,
- transform: ( node ) => {
- // Search both figure and image classes. Alignment could be
- // set on either. ID is set on the image.
- const className = node.className + ' ' + node.querySelector( 'img' ).className;
- const alignMatches = /(?:^|\s)align(left|center|right)(?:$|\s)/.exec( className );
- const align = alignMatches ? alignMatches[ 1 ] : undefined;
- const idMatches = /(?:^|\s)wp-image-(\d+)(?:$|\s)/.exec( className );
- const id = idMatches ? Number( idMatches[ 1 ] ) : undefined;
- const anchorElement = node.querySelector( 'a' );
- const linkDestination = anchorElement && anchorElement.href ? 'custom' : undefined;
- const href = anchorElement && anchorElement.href ? anchorElement.href : undefined;
- const rel = anchorElement && anchorElement.rel ? anchorElement.rel : undefined;
- const linkClass = anchorElement && anchorElement.className ? anchorElement.className : undefined;
- const attributes = getBlockAttributes( 'core/image', node.outerHTML, { align, id, linkDestination, href, rel, linkClass } );
- return createBlock( 'core/image', attributes );
- },
- },
- {
- type: 'files',
- isMatch( files ) {
- return files.length === 1 && files[ 0 ].type.indexOf( 'image/' ) === 0;
- },
- transform( files ) {
- const file = files[ 0 ];
- // We don't need to upload the media directly here
- // It's already done as part of the `componentDidMount`
- // int the image block
- const block = createBlock( 'core/image', {
- url: createBlobURL( file ),
- } );
-
- return block;
- },
- },
- {
- type: 'shortcode',
- tag: 'caption',
- attributes: {
- url: {
- type: 'string',
- source: 'attribute',
- attribute: 'src',
- selector: 'img',
- },
- alt: {
- type: 'string',
- source: 'attribute',
- attribute: 'alt',
- selector: 'img',
- },
- caption: {
- shortcode: stripFirstImage,
- },
- href: {
- shortcode: ( attributes, { shortcode } ) => {
- return getFirstAnchorAttributeFormHTML( shortcode.content, 'href' );
- },
- },
- rel: {
- shortcode: ( attributes, { shortcode } ) => {
- return getFirstAnchorAttributeFormHTML( shortcode.content, 'rel' );
- },
- },
- linkClass: {
- shortcode: ( attributes, { shortcode } ) => {
- return getFirstAnchorAttributeFormHTML( shortcode.content, 'class' );
- },
- },
- id: {
- type: 'number',
- shortcode: ( { named: { id } } ) => {
- if ( ! id ) {
- return;
- }
-
- return parseInt( id.replace( 'attachment_', '' ), 10 );
- },
- },
- align: {
- type: 'string',
- shortcode: ( { named: { align = 'alignnone' } } ) => {
- return align.replace( 'align', '' );
- },
- },
- },
- },
- ],
- },
-
+ transforms,
getEditWrapperProps( attributes ) {
const { align, width } = attributes;
if ( 'left' === align || 'center' === align || 'right' === align || 'wide' === align || 'full' === align ) {
return { 'data-align': align, 'data-resized': !! width };
}
},
-
edit,
-
- save( { attributes } ) {
- const {
- url,
- alt,
- caption,
- align,
- href,
- rel,
- linkClass,
- width,
- height,
- id,
- linkTarget,
- } = attributes;
-
- const classes = classnames( {
- [ `align${ align }` ]: align,
- 'is-resized': width || height,
- } );
-
- const image = (
-
- );
-
- const figure = (
-
- { href ? (
-
- { image }
-
- ) : image }
- { ! RichText.isEmpty( caption ) && }
-
- );
-
- if ( 'left' === align || 'right' === align || 'center' === align ) {
- return (
-
-
-
- );
- }
-
- return (
-
- );
- },
-
+ save,
deprecated: [
{
attributes: blockAttributes,
diff --git a/packages/block-library/src/image/save.js b/packages/block-library/src/image/save.js
new file mode 100644
index 0000000000000..032759c34c158
--- /dev/null
+++ b/packages/block-library/src/image/save.js
@@ -0,0 +1,73 @@
+/**
+ * External dependencies
+ */
+import classnames from 'classnames';
+
+/**
+ * WordPress dependencies
+ */
+import { RichText } from '@wordpress/block-editor';
+import { Fragment } from '@wordpress/element';
+
+export default function save( { attributes } ) {
+ const {
+ url,
+ alt,
+ caption,
+ align,
+ href,
+ rel,
+ linkClass,
+ width,
+ height,
+ id,
+ linkTarget,
+ } = attributes;
+
+ const classes = classnames( {
+ [ `align${ align }` ]: align,
+ 'is-resized': width || height,
+ } );
+
+ const image = (
+
+ );
+
+ const figure = (
+
+ { href ? (
+
+ { image }
+
+ ) : image }
+ { ! RichText.isEmpty( caption ) && }
+
+ );
+
+ if ( 'left' === align || 'right' === align || 'center' === align ) {
+ return (
+
+
+
+ );
+ }
+
+ return (
+
+ );
+}
diff --git a/packages/block-library/src/image/test/index.js b/packages/block-library/src/image/test/transforms.js
similarity index 97%
rename from packages/block-library/src/image/test/index.js
rename to packages/block-library/src/image/test/transforms.js
index 5b21dcefdf6eb..14f2f8dc42580 100644
--- a/packages/block-library/src/image/test/index.js
+++ b/packages/block-library/src/image/test/transforms.js
@@ -1,7 +1,7 @@
/**
* Internal dependencies
*/
-import { stripFirstImage } from '../';
+import { stripFirstImage } from '../transforms';
describe( 'stripFirstImage', () => {
test( 'should do nothing if no image is present', () => {
diff --git a/packages/block-library/src/image/transforms.js b/packages/block-library/src/image/transforms.js
new file mode 100644
index 0000000000000..2af42cc2244e9
--- /dev/null
+++ b/packages/block-library/src/image/transforms.js
@@ -0,0 +1,161 @@
+/**
+ * WordPress dependencies
+ */
+import { createBlobURL } from '@wordpress/blob';
+import {
+ createBlock,
+ getBlockAttributes,
+ getPhrasingContentSchema,
+} from '@wordpress/blocks';
+
+export function stripFirstImage( attributes, { shortcode } ) {
+ const { body } = document.implementation.createHTMLDocument( '' );
+
+ body.innerHTML = shortcode.content;
+
+ let nodeToRemove = body.querySelector( 'img' );
+
+ // if an image has parents, find the topmost node to remove
+ while ( nodeToRemove && nodeToRemove.parentNode && nodeToRemove.parentNode !== body ) {
+ nodeToRemove = nodeToRemove.parentNode;
+ }
+
+ if ( nodeToRemove ) {
+ nodeToRemove.parentNode.removeChild( nodeToRemove );
+ }
+
+ return body.innerHTML.trim();
+}
+
+function getFirstAnchorAttributeFormHTML( html, attributeName ) {
+ const { body } = document.implementation.createHTMLDocument( '' );
+
+ body.innerHTML = html;
+
+ const { firstElementChild } = body;
+
+ if (
+ firstElementChild &&
+ firstElementChild.nodeName === 'A'
+ ) {
+ return firstElementChild.getAttribute( attributeName ) || undefined;
+ }
+}
+
+const imageSchema = {
+ img: {
+ attributes: [ 'src', 'alt' ],
+ classes: [ 'alignleft', 'aligncenter', 'alignright', 'alignnone', /^wp-image-\d+$/ ],
+ },
+};
+
+const schema = {
+ figure: {
+ require: [ 'img' ],
+ children: {
+ ...imageSchema,
+ a: {
+ attributes: [ 'href', 'rel', 'target' ],
+ children: imageSchema,
+ },
+ figcaption: {
+ children: getPhrasingContentSchema(),
+ },
+ },
+ },
+};
+
+const transforms = {
+ from: [
+ {
+ type: 'raw',
+ isMatch: ( node ) => node.nodeName === 'FIGURE' && !! node.querySelector( 'img' ),
+ schema,
+ transform: ( node ) => {
+ // Search both figure and image classes. Alignment could be
+ // set on either. ID is set on the image.
+ const className = node.className + ' ' + node.querySelector( 'img' ).className;
+ const alignMatches = /(?:^|\s)align(left|center|right)(?:$|\s)/.exec( className );
+ const align = alignMatches ? alignMatches[ 1 ] : undefined;
+ const idMatches = /(?:^|\s)wp-image-(\d+)(?:$|\s)/.exec( className );
+ const id = idMatches ? Number( idMatches[ 1 ] ) : undefined;
+ const anchorElement = node.querySelector( 'a' );
+ const linkDestination = anchorElement && anchorElement.href ? 'custom' : undefined;
+ const href = anchorElement && anchorElement.href ? anchorElement.href : undefined;
+ const rel = anchorElement && anchorElement.rel ? anchorElement.rel : undefined;
+ const linkClass = anchorElement && anchorElement.className ? anchorElement.className : undefined;
+ const attributes = getBlockAttributes( 'core/image', node.outerHTML, { align, id, linkDestination, href, rel, linkClass } );
+ return createBlock( 'core/image', attributes );
+ },
+ },
+ {
+ type: 'files',
+ isMatch( files ) {
+ return files.length === 1 && files[ 0 ].type.indexOf( 'image/' ) === 0;
+ },
+ transform( files ) {
+ const file = files[ 0 ];
+ // We don't need to upload the media directly here
+ // It's already done as part of the `componentDidMount`
+ // int the image block
+ return createBlock( 'core/image', {
+ url: createBlobURL( file ),
+ } );
+ },
+ },
+ {
+ type: 'shortcode',
+ tag: 'caption',
+ attributes: {
+ url: {
+ type: 'string',
+ source: 'attribute',
+ attribute: 'src',
+ selector: 'img',
+ },
+ alt: {
+ type: 'string',
+ source: 'attribute',
+ attribute: 'alt',
+ selector: 'img',
+ },
+ caption: {
+ shortcode: stripFirstImage,
+ },
+ href: {
+ shortcode: ( attributes, { shortcode } ) => {
+ return getFirstAnchorAttributeFormHTML( shortcode.content, 'href' );
+ },
+ },
+ rel: {
+ shortcode: ( attributes, { shortcode } ) => {
+ return getFirstAnchorAttributeFormHTML( shortcode.content, 'rel' );
+ },
+ },
+ linkClass: {
+ shortcode: ( attributes, { shortcode } ) => {
+ return getFirstAnchorAttributeFormHTML( shortcode.content, 'class' );
+ },
+ },
+ id: {
+ type: 'number',
+ shortcode: ( { named: { id } } ) => {
+ if ( ! id ) {
+ return;
+ }
+
+ return parseInt( id.replace( 'attachment_', '' ), 10 );
+ },
+ },
+ align: {
+ type: 'string',
+ shortcode: ( { named: { align = 'alignnone' } } ) => {
+ return align.replace( 'align', '' );
+ },
+ },
+ },
+ },
+ ],
+};
+
+export default transforms;
diff --git a/packages/block-library/src/latest-comments/index.js b/packages/block-library/src/latest-comments/index.js
index 002ee39c6f49f..ba3214750be62 100644
--- a/packages/block-library/src/latest-comments/index.js
+++ b/packages/block-library/src/latest-comments/index.js
@@ -13,19 +13,13 @@ export const name = 'core/latest-comments';
export const settings = {
title: __( 'Latest Comments' ),
-
description: __( 'Display a list of your most recent comments.' ),
-
icon,
-
category: 'widgets',
-
keywords: [ __( 'recent comments' ) ],
-
supports: {
align: true,
html: false,
},
-
edit,
};
diff --git a/packages/block-library/src/latest-posts/index.js b/packages/block-library/src/latest-posts/index.js
index 6532a934759f4..a8cdf38168036 100644
--- a/packages/block-library/src/latest-posts/index.js
+++ b/packages/block-library/src/latest-posts/index.js
@@ -13,19 +13,13 @@ export const name = 'core/latest-posts';
export const settings = {
title: __( 'Latest Posts' ),
-
description: __( 'Display a list of your most recent posts.' ),
-
icon,
-
category: 'widgets',
-
keywords: [ __( 'recent posts' ) ],
-
supports: {
align: true,
html: false,
},
-
edit,
};
diff --git a/packages/block-library/src/legacy-widget/index.js b/packages/block-library/src/legacy-widget/index.js
index 0339aaba8f1fc..51d00539b7327 100644
--- a/packages/block-library/src/legacy-widget/index.js
+++ b/packages/block-library/src/legacy-widget/index.js
@@ -13,16 +13,11 @@ export const name = 'core/legacy-widget';
export const settings = {
title: __( 'Legacy Widget (Experimental)' ),
-
description: __( 'Display a legacy widget.' ),
-
icon,
-
category: 'widgets',
-
supports: {
html: false,
},
-
edit,
};
diff --git a/packages/block-library/src/list/index.js b/packages/block-library/src/list/index.js
index 0ff8478b3f53f..dcc1098e71b13 100644
--- a/packages/block-library/src/list/index.js
+++ b/packages/block-library/src/list/index.js
@@ -7,13 +7,7 @@ import { omit } from 'lodash';
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
-import {
- createBlock,
- getPhrasingContentSchema,
- getBlockAttributes,
-} from '@wordpress/blocks';
import { RichText } from '@wordpress/block-editor';
-import { replace, join, split, create, toHTMLString, __UNSTABLE_LINE_SEPARATOR } from '@wordpress/rich-text';
/**
* Internal dependencies
@@ -21,28 +15,13 @@ import { replace, join, split, create, toHTMLString, __UNSTABLE_LINE_SEPARATOR }
import edit from './edit';
import icon from './icon';
import metadata from './block.json';
+import save from './save';
+import transforms from './transforms';
const { name, attributes: schema } = metadata;
export { metadata, name };
-const listContentSchema = {
- ...getPhrasingContentSchema(),
- ul: {},
- ol: { attributes: [ 'type' ] },
-};
-
-// Recursion is needed.
-// Possible: ul > li > ul.
-// Impossible: ul > ul.
-[ 'ul', 'ol' ].forEach( ( tag ) => {
- listContentSchema[ tag ].children = {
- li: {
- children: listContentSchema,
- },
- };
-} );
-
const supports = {
className: false,
};
@@ -52,118 +31,8 @@ export const settings = {
description: __( 'Create a bulleted or numbered list.' ),
icon,
keywords: [ __( 'bullet list' ), __( 'ordered list' ), __( 'numbered list' ) ],
-
supports,
-
- transforms: {
- from: [
- {
- type: 'block',
- isMultiBlock: true,
- blocks: [ 'core/paragraph' ],
- transform: ( blockAttributes ) => {
- return createBlock( 'core/list', {
- values: toHTMLString( {
- value: join( blockAttributes.map( ( { content } ) => {
- const value = create( { html: content } );
-
- if ( blockAttributes.length > 1 ) {
- return value;
- }
-
- // When converting only one block, transform
- // every line to a list item.
- return replace( value, /\n/g, __UNSTABLE_LINE_SEPARATOR );
- } ), __UNSTABLE_LINE_SEPARATOR ),
- multilineTag: 'li',
- } ),
- } );
- },
- },
- {
- type: 'block',
- blocks: [ 'core/quote' ],
- transform: ( { value } ) => {
- return createBlock( 'core/list', {
- values: toHTMLString( {
- value: create( { html: value, multilineTag: 'p' } ),
- multilineTag: 'li',
- } ),
- } );
- },
- },
- {
- type: 'raw',
- selector: 'ol,ul',
- schema: {
- ol: listContentSchema.ol,
- ul: listContentSchema.ul,
- },
- transform( node ) {
- return createBlock( 'core/list', {
- ...getBlockAttributes(
- 'core/list',
- node.outerHTML
- ),
- ordered: node.nodeName === 'OL',
- } );
- },
- },
- ...[ '*', '-' ].map( ( prefix ) => ( {
- type: 'prefix',
- prefix,
- transform( content ) {
- return createBlock( 'core/list', {
- values: `${ content }`,
- } );
- },
- } ) ),
- ...[ '1.', '1)' ].map( ( prefix ) => ( {
- type: 'prefix',
- prefix,
- transform( content ) {
- return createBlock( 'core/list', {
- ordered: true,
- values: `${ content }`,
- } );
- },
- } ) ),
- ],
- to: [
- {
- type: 'block',
- blocks: [ 'core/paragraph' ],
- transform: ( { values } ) =>
- split( create( {
- html: values,
- multilineTag: 'li',
- multilineWrapperTags: [ 'ul', 'ol' ],
- } ), __UNSTABLE_LINE_SEPARATOR )
- .map( ( piece ) =>
- createBlock( 'core/paragraph', {
- content: toHTMLString( { value: piece } ),
- } )
- ),
- },
- {
- type: 'block',
- blocks: [ 'core/quote' ],
- transform: ( { values } ) => {
- return createBlock( 'core/quote', {
- value: toHTMLString( {
- value: create( {
- html: values,
- multilineTag: 'li',
- multilineWrapperTags: [ 'ul', 'ol' ],
- } ),
- multilineTag: 'p',
- } ),
- } );
- },
- },
- ],
- },
-
+ transforms,
deprecated: [
{
supports,
@@ -197,7 +66,6 @@ export const settings = {
},
},
],
-
merge( attributes, attributesToMerge ) {
const { values } = attributesToMerge;
@@ -210,15 +78,6 @@ export const settings = {
values: attributes.values + values,
};
},
-
edit,
-
- save( { attributes } ) {
- const { ordered, values } = attributes;
- const tagName = ordered ? 'ol' : 'ul';
-
- return (
-
- );
- },
+ save,
};
diff --git a/packages/block-library/src/list/save.js b/packages/block-library/src/list/save.js
new file mode 100644
index 0000000000000..9b0ff55b44cd5
--- /dev/null
+++ b/packages/block-library/src/list/save.js
@@ -0,0 +1,13 @@
+/**
+ * WordPress dependencies
+ */
+import { RichText } from '@wordpress/block-editor';
+
+export default function save( { attributes } ) {
+ const { ordered, values } = attributes;
+ const tagName = ordered ? 'ol' : 'ul';
+
+ return (
+
+ );
+}
diff --git a/packages/block-library/src/list/transforms.js b/packages/block-library/src/list/transforms.js
new file mode 100644
index 0000000000000..baf09b1b945c6
--- /dev/null
+++ b/packages/block-library/src/list/transforms.js
@@ -0,0 +1,144 @@
+/**
+ * WordPress dependencies
+ */
+import {
+ createBlock,
+ getBlockAttributes,
+ getPhrasingContentSchema,
+} from '@wordpress/blocks';
+import {
+ __UNSTABLE_LINE_SEPARATOR,
+ create,
+ join,
+ replace,
+ split,
+ toHTMLString,
+} from '@wordpress/rich-text';
+
+const listContentSchema = {
+ ...getPhrasingContentSchema(),
+ ul: {},
+ ol: { attributes: [ 'type' ] },
+};
+
+// Recursion is needed.
+// Possible: ul > li > ul.
+// Impossible: ul > ul.
+[ 'ul', 'ol' ].forEach( ( tag ) => {
+ listContentSchema[ tag ].children = {
+ li: {
+ children: listContentSchema,
+ },
+ };
+} );
+
+const transforms = {
+ from: [
+ {
+ type: 'block',
+ isMultiBlock: true,
+ blocks: [ 'core/paragraph' ],
+ transform: ( blockAttributes ) => {
+ return createBlock( 'core/list', {
+ values: toHTMLString( {
+ value: join( blockAttributes.map( ( { content } ) => {
+ const value = create( { html: content } );
+
+ if ( blockAttributes.length > 1 ) {
+ return value;
+ }
+
+ // When converting only one block, transform
+ // every line to a list item.
+ return replace( value, /\n/g, __UNSTABLE_LINE_SEPARATOR );
+ } ), __UNSTABLE_LINE_SEPARATOR ),
+ multilineTag: 'li',
+ } ),
+ } );
+ },
+ },
+ {
+ type: 'block',
+ blocks: [ 'core/quote' ],
+ transform: ( { value } ) => {
+ return createBlock( 'core/list', {
+ values: toHTMLString( {
+ value: create( { html: value, multilineTag: 'p' } ),
+ multilineTag: 'li',
+ } ),
+ } );
+ },
+ },
+ {
+ type: 'raw',
+ selector: 'ol,ul',
+ schema: {
+ ol: listContentSchema.ol,
+ ul: listContentSchema.ul,
+ },
+ transform( node ) {
+ return createBlock( 'core/list', {
+ ...getBlockAttributes(
+ 'core/list',
+ node.outerHTML
+ ),
+ ordered: node.nodeName === 'OL',
+ } );
+ },
+ },
+ ...[ '*', '-' ].map( ( prefix ) => ( {
+ type: 'prefix',
+ prefix,
+ transform( content ) {
+ return createBlock( 'core/list', {
+ values: `${ content }`,
+ } );
+ },
+ } ) ),
+ ...[ '1.', '1)' ].map( ( prefix ) => ( {
+ type: 'prefix',
+ prefix,
+ transform( content ) {
+ return createBlock( 'core/list', {
+ ordered: true,
+ values: `${ content }`,
+ } );
+ },
+ } ) ),
+ ],
+ to: [
+ {
+ type: 'block',
+ blocks: [ 'core/paragraph' ],
+ transform: ( { values } ) =>
+ split( create( {
+ html: values,
+ multilineTag: 'li',
+ multilineWrapperTags: [ 'ul', 'ol' ],
+ } ), __UNSTABLE_LINE_SEPARATOR )
+ .map( ( piece ) =>
+ createBlock( 'core/paragraph', {
+ content: toHTMLString( { value: piece } ),
+ } )
+ ),
+ },
+ {
+ type: 'block',
+ blocks: [ 'core/quote' ],
+ transform: ( { values } ) => {
+ return createBlock( 'core/quote', {
+ value: toHTMLString( {
+ value: create( {
+ html: values,
+ multilineTag: 'li',
+ multilineWrapperTags: [ 'ul', 'ol' ],
+ } ),
+ multilineTag: 'p',
+ } ),
+ } );
+ },
+ },
+ ],
+};
+
+export default transforms;