diff --git a/blocks/api/raw-handling/special-comment-converter.js b/blocks/api/raw-handling/special-comment-converter.js index 2da2e32c803f41..8146d671ce6395 100644 --- a/blocks/api/raw-handling/special-comment-converter.js +++ b/blocks/api/raw-handling/special-comment-converter.js @@ -9,9 +9,9 @@ import { remove, replace } from '@wordpress/utils'; const { COMMENT_NODE } = window.Node; /** - * Looks for `` comments, as well as the `` - * variant and its `` companion, and replaces them with a custom - * element representing a future block. + * Looks for `` and `` comments, as well as the + * `` variant and its `` companion, + * and replaces them with a custom element representing a future block. * * The custom element is a way to bypass the rest of the `raw-handling` * transforms, which would eliminate other kinds of node with which to carry @@ -24,43 +24,39 @@ const { COMMENT_NODE } = window.Node; * @return {void} */ export default function( node ) { - if ( - node.nodeType !== COMMENT_NODE || - node.nodeValue.indexOf( 'more' ) !== 0 - ) { - // We don't specificially look for `noteaser`, meaning that if one is - // found on its own (and not adjacent to `more`), it will be lost. + if ( node.nodeType !== COMMENT_NODE ) { return; } - // Grab any custom text in the comment - const customText = node.nodeValue.slice( 4 ).trim(); - - // When a `` comment is found, we need to look for any - // `` sibling, but it may not be a direct sibling - // (whitespace typically lies in between) - let sibling = node; - let noTeaser = false; - while ( ( sibling = sibling.nextSibling ) ) { - if ( - sibling.nodeType === COMMENT_NODE && - sibling.nodeValue === 'noteaser' - ) { - noTeaser = true; - remove( sibling ); - break; - } + if ( node.nodeValue === 'nextpage' ) { + replace( node, createNextpage() ); + return; } - // Conjure up a custom More element - const more = createMore( customText, noTeaser ); + if ( node.nodeValue.indexOf( 'more' ) === 0 ) { + // Grab any custom text in the comment. + const customText = node.nodeValue.slice( 4 ).trim(); + + /* + * When a `` comment is found, we need to look for any + * `` sibling, but it may not be a direct sibling + * (whitespace typically lies in between) + */ + let sibling = node; + let noTeaser = false; + while ( ( sibling = sibling.nextSibling ) ) { + if ( + sibling.nodeType === COMMENT_NODE && + sibling.nodeValue === 'noteaser' + ) { + noTeaser = true; + remove( sibling ); + break; + } + } - // Append it to the top level for later conversion to blocks - let parent = node.parentNode; - while ( parent.nodeName !== 'BODY' ) { - parent = parent.parentNode; + replace( node, createMore( customText, noTeaser ) ); } - replace( node, more ); } function createMore( customText, noTeaser ) { @@ -75,3 +71,10 @@ function createMore( customText, noTeaser ) { } return node; } + +function createNextpage() { + const node = document.createElement( 'wp-block' ); + node.dataset.block = 'core/nextpage'; + + return node; +} diff --git a/blocks/api/raw-handling/test/special-comment-converter.js b/blocks/api/raw-handling/test/special-comment-converter.js index 422f61b30de9ee..602fd4611ef1aa 100644 --- a/blocks/api/raw-handling/test/special-comment-converter.js +++ b/blocks/api/raw-handling/test/special-comment-converter.js @@ -10,7 +10,7 @@ import specialCommentConverter from '../special-comment-converter'; import { deepFilterHTML } from '../utils'; describe( 'specialCommentConverter', () => { - it( 'should convert a single comment into a basic block', () => { + it( 'should convert a single "more" comment into a basic block', () => { equal( deepFilterHTML( '

', @@ -19,6 +19,12 @@ describe( 'specialCommentConverter', () => { '

' ); } ); + it( 'should convert a single "nextpage" comment into a basic block', () => { + equal( + deepFilterHTML( '

', [ specialCommentConverter ] ), + '

' + ); + } ); it( 'should convert two comments into a block', () => { equal( deepFilterHTML( @@ -79,5 +85,23 @@ describe( 'specialCommentConverter', () => {

Third paragraph

` ); } ); + it( 'should not break pagination order', () => { + const output = deepFilterHTML( + `

First page.

+

+

Second page

+

+

Third page

`, + [ specialCommentConverter ] + ); + equal( + output, + `

First page.

+

+

Second page

+

+

Third page

` + ); + } ); } ); } ); diff --git a/blocks/library/index.js b/blocks/library/index.js index ce1948234a5021..777e9aa0325a0f 100644 --- a/blocks/library/index.js +++ b/blocks/library/index.js @@ -23,6 +23,7 @@ import * as html from './html'; import * as latestPosts from './latest-posts'; import * as list from './list'; import * as more from './more'; +import * as nextpage from './nextpage'; import * as preformatted from './preformatted'; import * as pullquote from './pullquote'; import * as sharedBlock from './block'; @@ -60,6 +61,7 @@ export const registerCoreBlocks = () => { html, latestPosts, more, + nextpage, preformatted, pullquote, separator, diff --git a/blocks/library/nextpage/editor.scss b/blocks/library/nextpage/editor.scss new file mode 100644 index 00000000000000..cc54fec3ff397a --- /dev/null +++ b/blocks/library/nextpage/editor.scss @@ -0,0 +1,40 @@ +.editor-visual-editor__block[data-type="core/nextpage"] { + max-width: 100%; +} + +.wp-block-nextpage { + display: block; + text-align: center; + overflow: hidden; + white-space: nowrap; +} + +.wp-block-nextpage > span { + position: relative; + display: inline-block; + font-size: 12px; + text-transform: uppercase; + font-weight: 600; + font-family: $default-font; + color: $dark-gray-300; +} + +.wp-block-nextpage > span:before, +.wp-block-nextpage > span:after { + content: ''; + position: absolute; + top: 50%; + width: 100vw; + border-top: 3px dashed $light-gray-700; + margin-top: -2px; +} + +.wp-block-nextpage > span:before { + right: 100%; + margin-right: 20px; +} + +.wp-block-nextpage > span:after { + left: 100%; + margin-left: 20px; +} diff --git a/blocks/library/nextpage/index.js b/blocks/library/nextpage/index.js new file mode 100644 index 00000000000000..e67e276609f8a6 --- /dev/null +++ b/blocks/library/nextpage/index.js @@ -0,0 +1,61 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { RawHTML } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import './editor.scss'; +import { createBlock } from '../../api'; + +export const name = 'core/nextpage'; + +export const settings = { + title: __( 'Page break' ), + + description: __( 'This block allows you to set break points on your post. Visitors of your blog are then presented with content split into multiple pages.' ), + + icon: 'admin-page', + + category: 'layout', + + keywords: [ __( 'next page' ), __( 'pagination' ) ], + + supports: { + customClassName: false, + className: false, + html: false, + }, + + attributes: {}, + + transforms: { + from: [ + { + type: 'raw', + isMatch: ( node ) => node.dataset && node.dataset.block === 'core/nextpage', + transform() { + return createBlock( 'core/nextpage', {} ); + }, + }, + ], + }, + + edit() { + return ( +
+ { __( 'Page break' ) } +
+ ); + }, + + save() { + return ( + + { '' } + + ); + }, +}; diff --git a/blocks/library/nextpage/test/__snapshots__/index.js.snap b/blocks/library/nextpage/test/__snapshots__/index.js.snap new file mode 100644 index 00000000000000..9a324d23afcca1 --- /dev/null +++ b/blocks/library/nextpage/test/__snapshots__/index.js.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`core/nextpage block edit matches snapshot 1`] = ` +
+ + Page break + +
+`; diff --git a/blocks/library/nextpage/test/index.js b/blocks/library/nextpage/test/index.js new file mode 100644 index 00000000000000..3658f45050fecf --- /dev/null +++ b/blocks/library/nextpage/test/index.js @@ -0,0 +1,13 @@ +/** + * Internal dependencies + */ +import { name, settings } from '../'; +import { blockEditRender } from 'blocks/test/helpers'; + +describe( 'core/nextpage', () => { + test( 'block edit matches snapshot', () => { + const wrapper = blockEditRender( name, settings ); + + expect( wrapper ).toMatchSnapshot(); + } ); +} ); diff --git a/blocks/test/fixtures/core__nextpage.html b/blocks/test/fixtures/core__nextpage.html new file mode 100644 index 00000000000000..9bf78b8cbf7924 --- /dev/null +++ b/blocks/test/fixtures/core__nextpage.html @@ -0,0 +1,3 @@ + + + diff --git a/blocks/test/fixtures/core__nextpage.json b/blocks/test/fixtures/core__nextpage.json new file mode 100644 index 00000000000000..5ce9cb21fc6367 --- /dev/null +++ b/blocks/test/fixtures/core__nextpage.json @@ -0,0 +1,10 @@ +[ + { + "uid": "_uid_0", + "name": "core/nextpage", + "isValid": true, + "attributes": {}, + "innerBlocks": [], + "originalContent": "" + } +] diff --git a/blocks/test/fixtures/core__nextpage.parsed.json b/blocks/test/fixtures/core__nextpage.parsed.json new file mode 100644 index 00000000000000..0dde31a4bf41ad --- /dev/null +++ b/blocks/test/fixtures/core__nextpage.parsed.json @@ -0,0 +1,12 @@ +[ + { + "blockName": "core/nextpage", + "attrs": null, + "innerBlocks": [], + "innerHTML": "\n\n" + }, + { + "attrs": {}, + "innerHTML": "\n" + } +] diff --git a/blocks/test/fixtures/core__nextpage.serialized.html b/blocks/test/fixtures/core__nextpage.serialized.html new file mode 100644 index 00000000000000..beef64ebd56d36 --- /dev/null +++ b/blocks/test/fixtures/core__nextpage.serialized.html @@ -0,0 +1,3 @@ + + +