diff --git a/core-blocks/code/index.js b/core-blocks/code/index.js index 487cd5c9665195..720164aee372b0 100644 --- a/core-blocks/code/index.js +++ b/core-blocks/code/index.js @@ -23,9 +23,8 @@ export const settings = { attributes: { content: { type: 'string', - source: 'property', + source: 'text', selector: 'code', - property: 'textContent', }, }, diff --git a/core-blocks/heading/edit.js b/core-blocks/heading/edit.js index 05b4fc9df600ea..c13bb35bf959ec 100644 --- a/core-blocks/heading/edit.js +++ b/core-blocks/heading/edit.js @@ -1,7 +1,11 @@ /** - * WordPress dependencies + * External dependencies */ +import { range } from 'lodash'; +/** + * WordPress dependencies + */ import { __, sprintf } from '@wordpress/i18n'; import { Fragment } from '@wordpress/element'; import { PanelBody, Toolbar } from '@wordpress/components'; @@ -21,35 +25,29 @@ export default function HeadingEdit( { onReplace, className, } ) { - const { align, content, nodeName, placeholder } = attributes; + const { align, content, level, placeholder } = attributes; + const tagName = 'h' + level; + + function createLevelControl( targetLevel ) { + return { + icon: 'heading', + // translators: %s: heading level e.g: "1", "2", "3" + title: sprintf( __( 'Heading %d' ), targetLevel ), + isActive: targetLevel === level, + onClick: () => setAttributes( { level: targetLevel } ), + subscript: String( targetLevel ), + }; + } return ( - ( { - icon: 'heading', - // translators: %s: heading level e.g: "1", "2", "3" - title: sprintf( __( 'Heading %s' ), level ), - isActive: 'H' + level === nodeName, - onClick: () => setAttributes( { nodeName: 'H' + level } ), - subscript: level, - } ) ) } - /> +

{ __( 'Level' ) }

- ( { - icon: 'heading', - // translators: %s: heading level e.g: "1", "2", "3" - title: sprintf( __( 'Heading %s' ), level ), - isActive: 'H' + level === nodeName, - onClick: () => setAttributes( { nodeName: 'H' + level } ), - subscript: level, - } ) ) } - /> +

{ __( 'Text Alignment' ) }

setAttributes( { content: value } ) } onMerge={ mergeBlocks } diff --git a/core-blocks/heading/index.js b/core-blocks/heading/index.js index def9872def011d..db2b40a82eeade 100644 --- a/core-blocks/heading/index.js +++ b/core-blocks/heading/index.js @@ -1,9 +1,19 @@ +/** + * External dependencies + */ +import { omit } from 'lodash'; + /** * WordPress dependencies */ import { __ } from '@wordpress/i18n'; import { concatChildren } from '@wordpress/element'; -import { createBlock, getPhrasingContentSchema } from '@wordpress/blocks'; +import { + createBlock, + getPhrasingContentSchema, + getBlockAttributes, + getBlockType, +} from '@wordpress/blocks'; import { RichText } from '@wordpress/editor'; /** @@ -11,6 +21,40 @@ import { RichText } from '@wordpress/editor'; */ import edit from './edit'; +/** + * 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, +}; + +const schema = { + content: { + type: 'array', + source: 'children', + selector: 'h1,h2,h3,h4,h5,h6', + }, + level: { + type: 'number', + default: 2, + }, + align: { + type: 'string', + }, + placeholder: { + type: 'string', + }, +}; + export const name = 'core/heading'; export const settings = { @@ -24,31 +68,9 @@ export const settings = { keywords: [ __( 'title' ), __( 'subtitle' ) ], - supports: { - className: false, - anchor: true, - }, + supports, - attributes: { - content: { - type: 'array', - source: 'children', - selector: 'h1,h2,h3,h4,h5,h6', - }, - nodeName: { - type: 'string', - source: 'property', - selector: 'h1,h2,h3,h4,h5,h6', - property: 'nodeName', - default: 'H2', - }, - align: { - type: 'string', - }, - placeholder: { - type: 'string', - }, - }, + attributes: schema, transforms: { from: [ @@ -72,6 +94,15 @@ export const settings = { h5: { children: getPhrasingContentSchema() }, h6: { children: getPhrasingContentSchema() }, }, + transform( node ) { + return createBlock( 'core/heading', { + ...getBlockAttributes( + getBlockType( 'core/heading' ), + node.outerHTML + ), + level: getLevelFromHeadingNodeName( node.nodeName ), + } ); + }, }, { type: 'pattern', @@ -80,7 +111,7 @@ export const settings = { const level = match[ 1 ].length; return createBlock( 'core/heading', { - nodeName: `H${ level }`, + level, content, } ); }, @@ -99,6 +130,41 @@ export const settings = { ], }, + deprecated: [ + { + supports, + attributes: { + ...omit( schema, [ 'level' ] ), + nodeName: { + type: 'string', + source: 'property', + selector: 'h1,h2,h3,h4,h5,h6', + property: 'nodeName', + default: 'H2', + }, + }, + migrate( { attributes } ) { + const { nodeName, ...migratedAttributes } = attributes; + + return { + ...migratedAttributes, + level: getLevelFromHeadingNodeName( nodeName ), + }; + }, + save( { attributes } ) { + const { align, nodeName, content } = attributes; + + return ( + + ); + }, + }, + ], + merge( attributes, attributesToMerge ) { return { content: concatChildren( attributes.content, attributesToMerge.content ), @@ -108,11 +174,12 @@ export const settings = { edit, save( { attributes } ) { - const { align, nodeName, content } = attributes; + const { align, level, content } = attributes; + const tagName = 'h' + level; return ( diff --git a/core-blocks/heading/test/index.js b/core-blocks/heading/test/index.js index 955a5d952ec712..58a3ec1770347a 100644 --- a/core-blocks/heading/test/index.js +++ b/core-blocks/heading/test/index.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import { name, settings } from '../'; +import { name, settings, getLevelFromHeadingNodeName } from '../'; import { blockEditRender } from '../../test/helpers'; describe( 'core/heading', () => { @@ -11,3 +11,11 @@ describe( 'core/heading', () => { expect( wrapper ).toMatchSnapshot(); } ); } ); + +describe( 'getLevelFromHeadingNodeName()', () => { + it( 'should return a numeric value from nodeName', () => { + const level = getLevelFromHeadingNodeName( 'H4' ); + + expect( level ).toBe( 4 ); + } ); +} ); diff --git a/core-blocks/list/index.js b/core-blocks/list/index.js index 8c3924f87a15e8..29cb8145b956ce 100644 --- a/core-blocks/list/index.js +++ b/core-blocks/list/index.js @@ -1,14 +1,19 @@ /** * External dependencies */ -import { find, compact, get, initial, last, isEmpty } from 'lodash'; +import { find, compact, get, initial, last, isEmpty, omit } from 'lodash'; /** * WordPress dependencies */ import { Component, Fragment } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; -import { createBlock, getPhrasingContentSchema } from '@wordpress/blocks'; +import { + createBlock, + getPhrasingContentSchema, + getBlockAttributes, + getBlockType, +} from '@wordpress/blocks'; import { BlockControls, RichText, @@ -36,6 +41,23 @@ const listContentSchema = { }; } ); +const supports = { + className: false, +}; + +const schema = { + ordered: { + type: 'boolean', + default: false, + }, + values: { + type: 'array', + source: 'children', + selector: 'ol,ul', + default: [], + }, +}; + export const name = 'core/list'; export const settings = { @@ -45,25 +67,9 @@ export const settings = { category: 'common', keywords: [ __( 'bullet list' ), __( 'ordered list' ), __( 'numbered list' ) ], - attributes: { - nodeName: { - type: 'string', - source: 'property', - selector: 'ol,ul', - property: 'nodeName', - default: 'UL', - }, - values: { - type: 'array', - source: 'children', - selector: 'ol,ul', - default: [], - }, - }, + attributes: schema, - supports: { - className: false, - }, + supports, transforms: { from: [ @@ -75,7 +81,6 @@ export const settings = { const items = blockAttributes.map( ( { content } ) => content ); const hasItems = ! items.every( isEmpty ); return createBlock( 'core/list', { - nodeName: 'UL', values: hasItems ? items.map( ( content, index ) =>
  • { content }
  • ) : [], } ); }, @@ -90,7 +95,6 @@ export const settings = { } const hasItems = ! items.every( isEmpty ); return createBlock( 'core/list', { - nodeName: 'UL', values: hasItems ? items.map( ( content, index ) =>
  • { content }
  • ) : [], } ); }, @@ -102,13 +106,21 @@ export const settings = { ol: listContentSchema.ol, ul: listContentSchema.ul, }, + transform( node ) { + return createBlock( 'core/list', { + ...getBlockAttributes( + getBlockType( 'core/list' ), + node.outerHTML + ), + ordered: node.nodeName === 'OL', + } ); + }, }, { type: 'pattern', regExp: /^[*-]\s/, transform: ( { content } ) => { return createBlock( 'core/list', { - nodeName: 'UL', values: [
  • { content }
  • ], } ); }, @@ -118,7 +130,7 @@ export const settings = { regExp: /^1[.)]\s/, transform: ( { content } ) => { return createBlock( 'core/list', { - nodeName: 'OL', + ordered: true, values: [
  • { content }
  • ], } ); }, @@ -149,6 +161,40 @@ export const settings = { ], }, + deprecated: [ + { + supports, + attributes: { + ...omit( schema, [ 'ordered' ] ), + nodeName: { + type: 'string', + source: 'property', + selector: 'ol,ul', + property: 'nodeName', + default: 'UL', + }, + }, + migrate( { attributes } ) { + const { nodeName, ...migratedAttributes } = attributes; + + return { + ...migratedAttributes, + ordered: 'OL' === nodeName, + }; + }, + save( { attributes } ) { + const { nodeName, values } = attributes; + + return ( + + ); + }, + }, + ], + merge( attributes, attributesToMerge ) { const valuesToMerge = attributesToMerge.values || []; @@ -179,13 +225,6 @@ export const settings = { }; } - isListActive( listType ) { - const { internalListType } = this.state; - const { nodeName } = this.props.attributes; - - return listType === ( internalListType ? internalListType : nodeName ); - } - findInternalListType( { parents } ) { const list = find( parents, ( node ) => node.nodeName === 'UL' || node.nodeName === 'OL' ); return list ? list.nodeName : null; @@ -224,7 +263,7 @@ export const settings = { this.editor.execCommand( command ); } } else { - setAttributes( { nodeName: type } ); + setAttributes( { ordered: type === 'OL' } ); } }; } @@ -258,7 +297,8 @@ export const settings = { onReplace, className, } = this.props; - const { nodeName, values } = attributes; + const { ordered, values } = attributes; + const tagName = ordered ? 'ol' : 'ul'; return ( @@ -267,13 +307,13 @@ export const settings = { { icon: 'editor-ul', title: __( 'Convert to unordered list' ), - isActive: this.isListActive( 'UL' ), + isActive: ! ordered, onClick: this.createSetListType( 'UL', 'InsertUnorderedList' ), }, { icon: 'editor-ol', title: __( 'Convert to ordered list' ), - isActive: this.isListActive( 'OL' ), + isActive: ordered, onClick: this.createSetListType( 'OL', 'InsertOrderedList' ), }, { @@ -290,7 +330,7 @@ export const settings = { /> + ); }, }; diff --git a/core-blocks/test/fixtures/core__heading__h2-em.json b/core-blocks/test/fixtures/core__heading__h2-em.json index 213be79cfa972b..cac90a54f382e0 100644 --- a/core-blocks/test/fixtures/core__heading__h2-em.json +++ b/core-blocks/test/fixtures/core__heading__h2-em.json @@ -12,7 +12,7 @@ }, " Tool" ], - "nodeName": "H2" + "level": 2 }, "innerBlocks": [], "originalContent": "

    The Inserter Tool

    " diff --git a/core-blocks/test/fixtures/core__heading__h2.json b/core-blocks/test/fixtures/core__heading__h2.json index f07a75b91f5c6f..24d2e6292ee058 100644 --- a/core-blocks/test/fixtures/core__heading__h2.json +++ b/core-blocks/test/fixtures/core__heading__h2.json @@ -7,7 +7,7 @@ "content": [ "A picture is worth a thousand words, or so the saying goes" ], - "nodeName": "H2" + "level": 2 }, "innerBlocks": [], "originalContent": "

    A picture is worth a thousand words, or so the saying goes

    " diff --git a/core-blocks/test/fixtures/core__list__ul.json b/core-blocks/test/fixtures/core__list__ul.json index 4f86b13d9acd42..6c6c4fa879c389 100644 --- a/core-blocks/test/fixtures/core__list__ul.json +++ b/core-blocks/test/fixtures/core__list__ul.json @@ -4,7 +4,7 @@ "name": "core/list", "isValid": true, "attributes": { - "nodeName": "UL", + "ordered": false, "values": [ { "type": "li", diff --git a/editor/components/block-switcher/test/index.js b/editor/components/block-switcher/test/index.js index 16d6ee17207259..135337a09d2cd4 100644 --- a/editor/components/block-switcher/test/index.js +++ b/editor/components/block-switcher/test/index.js @@ -20,7 +20,7 @@ describe( 'BlockSwitcher', () => { const headingBlock1 = { attributes: { content: [ 'How are you?' ], - nodeName: 'H2', + level: 2, }, isValid: true, name: 'core/heading', @@ -31,7 +31,6 @@ describe( 'BlockSwitcher', () => { const textBlock = { attributes: { content: [ 'I am great!' ], - nodeName: 'P', }, isValid: true, name: 'core/text', @@ -42,7 +41,7 @@ describe( 'BlockSwitcher', () => { const headingBlock2 = { attributes: { content: [ 'I am the greatest!' ], - nodeName: 'H3', + level: 3, }, isValid: true, name: 'core/text', diff --git a/editor/components/document-outline/index.js b/editor/components/document-outline/index.js index 184f8873fbb62b..dadcf5f73a1713 100644 --- a/editor/components/document-outline/index.js +++ b/editor/components/document-outline/index.js @@ -33,28 +33,6 @@ const multipleH1Headings = [ { __( '(Multiple H1 headings are not recommended)' ) }, ]; -const getHeadingLevel = ( heading ) => { - switch ( heading.attributes.nodeName ) { - case 'h1': - case 'H1': - return 1; - case 'h2': - case 'H2': - return 2; - case 'h3': - case 'H3': - return 3; - case 'h4': - case 'H4': - return 4; - case 'h5': - case 'H5': - return 5; - case 'h6': - case 'H6': - return 6; - } -}; /** * Returns an array of heading blocks enhanced with the following properties: * path - An array of blocks that are ancestors of the heading starting from a top-level node. @@ -73,7 +51,7 @@ const computeOutlineHeadings = ( blocks = [], path = [] ) => { return { ...block, path, - level: getHeadingLevel( block ), + level: block.attributes.level, isEmpty: isEmptyHeading( block ), }; } diff --git a/editor/components/document-outline/test/index.js b/editor/components/document-outline/test/index.js index a0b922b3b1f04a..1dd6222612830d 100644 --- a/editor/components/document-outline/test/index.js +++ b/editor/components/document-outline/test/index.js @@ -22,15 +22,15 @@ describe( 'DocumentOutline', () => { const paragraph = createBlock( 'core/paragraph' ); const headingH1 = createBlock( 'core/heading', { content: 'Heading 1', - nodeName: 'H1', + level: 1, } ); const headingParent = createBlock( 'core/heading', { content: 'Heading parent', - nodeName: 'H2', + level: 2, } ); const headingChild = createBlock( 'core/heading', { content: 'Heading child', - nodeName: 'H3', + level: 3, } ); const nestedHeading = createBlock( 'core/columns', undefined, [ headingChild ] ); diff --git a/test/integration/fixtures/apple-out.html b/test/integration/fixtures/apple-out.html index 84bdfad50c7e1e..b2f2435d8188ee 100644 --- a/test/integration/fixtures/apple-out.html +++ b/test/integration/fixtures/apple-out.html @@ -22,7 +22,7 @@ - +
    1. One
    2. Two
    3. diff --git a/test/integration/fixtures/evernote-out.html b/test/integration/fixtures/evernote-out.html index 27e3063ccf7cca..2add7ec7a2f8fb 100644 --- a/test/integration/fixtures/evernote-out.html +++ b/test/integration/fixtures/evernote-out.html @@ -16,7 +16,7 @@ - +
      1. One
      2. Two diff --git a/test/integration/fixtures/google-docs-out.html b/test/integration/fixtures/google-docs-out.html index 1c54f0c4b23ecb..b0e18c5d654216 100644 --- a/test/integration/fixtures/google-docs-out.html +++ b/test/integration/fixtures/google-docs-out.html @@ -22,7 +22,7 @@

        This is a heading

        - +
        1. One
        2. Two
        3. diff --git a/test/integration/fixtures/markdown-out.html b/test/integration/fixtures/markdown-out.html index 5b674a8bfaf864..b665ba06b63f79 100644 --- a/test/integration/fixtures/markdown-out.html +++ b/test/integration/fixtures/markdown-out.html @@ -1,4 +1,4 @@ - +

          This is a heading with italic

          @@ -26,7 +26,7 @@

          Lists

          - +
          1. One
          2. Two
          3. diff --git a/test/integration/fixtures/ms-word-online-out.html b/test/integration/fixtures/ms-word-online-out.html index 6ef898504cb716..2208ea83d16a02 100644 --- a/test/integration/fixtures/ms-word-online-out.html +++ b/test/integration/fixtures/ms-word-online-out.html @@ -15,7 +15,7 @@ - +
            1. One 
            2. Two 
            3. diff --git a/test/integration/fixtures/ms-word-out.html b/test/integration/fixtures/ms-word-out.html index 4afcdc09b2ed80..54bc1e810e936a 100644 --- a/test/integration/fixtures/ms-word-out.html +++ b/test/integration/fixtures/ms-word-out.html @@ -8,7 +8,7 @@

              - +

              This is a heading level 1

              @@ -32,7 +32,7 @@

              This is a heading level 2

              - +
              1. One
              2. Two
              3. diff --git a/test/integration/fixtures/wordpress-out.html b/test/integration/fixtures/wordpress-out.html index 5bc8b8b8d4d7be..4595aa7cacf102 100644 --- a/test/integration/fixtures/wordpress-out.html +++ b/test/integration/fixtures/wordpress-out.html @@ -6,7 +6,7 @@

                Howdy

                This is a paragraph.

                - +

                More tag