Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make it possible to undo prefix transforms #11497

Merged
merged 3 commits into from
Nov 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 47 additions & 10 deletions docs/block-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,18 +124,18 @@ Block styles can be used to provide alternative styles to block. It works by add
// Register block styles.
styles: [
// Mark style as default.
{
name: 'default',
label: __( 'Rounded' ),
isDefault: true
{
name: 'default',
label: __( 'Rounded' ),
isDefault: true
},
{
name: 'outline',
label: __( 'Outline' )
{
name: 'outline',
label: __( 'Outline' )
},
{
name: 'squared',
label: __( 'Squared' )
{
name: 'squared',
label: __( 'Squared' )
},
],
```
Expand Down Expand Up @@ -413,6 +413,43 @@ transforms: {
```
{% end %}

A prefix transform is a transform that will be applied if the user prefixes some text in e.g. the paragraph block with a given pattern and a trailing space.

{% codetabs %}
{% ES5 %}
```js
transforms: {
from: [
{
type: 'prefix',
prefix: '?',
transform: function( content ) {
return createBlock( 'my-plugin/question', {
content,
} );
},
},
]
}
```
{% ESNext %}
```js
transforms: {
from: [
{
type: 'prefix',
prefix: '?',
transform( content ) {
return createBlock( 'my-plugin/question', {
content,
} );
},
},
]
}
```
{% end %}


#### parent (optional)

Expand Down
3 changes: 1 addition & 2 deletions packages/block-library/src/code/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ export const settings = {
transforms: {
from: [
{
type: 'pattern',
trigger: 'enter',
type: 'enter',
ellatrix marked this conversation as resolved.
Show resolved Hide resolved
regExp: /^```$/,
transform: () => createBlock( 'core/code' ),
},
Expand Down
12 changes: 5 additions & 7 deletions packages/block-library/src/heading/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,18 +107,16 @@ export const settings = {
} );
},
},
{
type: 'pattern',
regExp: /^(#{2,6})\s/,
transform: ( { content, match } ) => {
const level = match[ 1 ].length;

...[ 2, 3, 4, 5, 6 ].map( ( level ) => ( {
type: 'prefix',
prefix: Array( level + 1 ).join( '#' ),
transform( content ) {
return createBlock( 'core/heading', {
level,
content,
} );
},
},
} ) ),
],
to: [
{
Expand Down
20 changes: 10 additions & 10 deletions packages/block-library/src/list/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,25 +110,25 @@ export const settings = {
} );
},
},
{
type: 'pattern',
regExp: /^[*-]\s/,
transform: ( { content } ) => {
...[ '*', '-' ].map( ( prefix ) => ( {
type: 'prefix',
prefix,
transform( content ) {
return createBlock( 'core/list', {
values: `<li>${ content }</li>`,
} );
},
},
{
type: 'pattern',
regExp: /^1[.)]\s/,
transform: ( { content } ) => {
} ) ),
...[ '1.', '1)' ].map( ( prefix ) => ( {
type: 'prefix',
prefix,
transform( content ) {
return createBlock( 'core/list', {
ordered: true,
values: `<li>${ content }</li>`,
} );
},
},
} ) ),
],
to: [
{
Expand Down
6 changes: 3 additions & 3 deletions packages/block-library/src/quote/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,9 @@ export const settings = {
} ),
},
{
type: 'pattern',
regExp: /^>\s/,
transform: ( { content } ) => {
type: 'prefix',
prefix: '>',
transform: ( content ) => {
return createBlock( 'core/quote', {
value: `<p>${ content }</p>`,
} );
Expand Down
3 changes: 1 addition & 2 deletions packages/block-library/src/separator/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ export const settings = {
transforms: {
from: [
{
type: 'pattern',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we schim the old API?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know. It was never official/documented.

trigger: 'enter',
type: 'enter',
regExp: /^-{3,}$/,
transform: () => createBlock( 'core/separator' ),
},
Expand Down
8 changes: 4 additions & 4 deletions packages/editor/src/components/rich-text/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,12 @@ export class RichText extends Component {
this.savedContent = value;
this.patterns = getPatterns( {
onReplace,
multilineTag: this.multilineTag,
onCreateUndoLevel: this.onCreateUndoLevel,
valueToFormat: this.valueToFormat,
onChange: this.onChange,
} );
this.enterPatterns = getBlockTransforms( 'from' ).filter( ( { type, trigger } ) =>
type === 'pattern' && trigger === 'enter'
);
this.enterPatterns = getBlockTransforms( 'from' )
.filter( ( { type } ) => type === 'enter' );

this.state = {};

Expand Down
71 changes: 41 additions & 30 deletions packages/editor/src/components/rich-text/patterns.js
Original file line number Diff line number Diff line change
@@ -1,69 +1,80 @@
/**
* External dependencies
*/
import { filter } from 'lodash';

/**
* WordPress dependencies
*/
import { getBlockTransforms, findTransform } from '@wordpress/blocks';
import { remove, applyFormat, getTextContent } from '@wordpress/rich-text';

export function getPatterns( { onReplace, multiline, valueToFormat } ) {
const patterns = filter( getBlockTransforms( 'from' ), ( { type, trigger } ) => {
return type === 'pattern' && trigger === undefined;
} );
import {
remove,
applyFormat,
getTextContent,
getSelectionStart,
slice,
} from '@wordpress/rich-text';

export function getPatterns( { onReplace, valueToFormat, onCreateUndoLevel, onChange } ) {
const prefixTransforms = getBlockTransforms( 'from' )
.filter( ( { type } ) => type === 'prefix' );

return [
( record ) => {
if ( ! onReplace ) {
return record;
}

const start = getSelectionStart( record );
const text = getTextContent( record );
const transformation = findTransform( patterns, ( item ) => {
return item.regExp.test( text );
const characterBefore = text.slice( start - 1, start );

if ( ! /\s/.test( characterBefore ) ) {
return record;
}

const trimmedTextBefore = text.slice( 0, start ).trim();
const transformation = findTransform( prefixTransforms, ( { prefix } ) => {
return trimmedTextBefore === prefix;
} );

if ( ! transformation ) {
return record;
}

const result = text.match( transformation.regExp );

const block = transformation.transform( {
content: valueToFormat( remove( record, 0, result[ 0 ].length ) ),
match: result,
} );
const content = valueToFormat( slice( record, start, text.length ) );
const block = transformation.transform( content );

onCreateUndoLevel();
onReplace( [ block ] );

return record;
},
( record ) => {
if ( multiline ) {
const BACKTICK = '`';
const start = getSelectionStart( record );
const text = getTextContent( record );
const characterBefore = text.slice( start - 1, start );

// Quick check the text for the necessary character.
if ( characterBefore !== BACKTICK ) {
return record;
}

const text = getTextContent( record );
const textBefore = text.slice( 0, start - 1 );
const indexBefore = textBefore.lastIndexOf( BACKTICK );

// Quick check the text for the necessary character.
if ( text.indexOf( '`' ) === -1 ) {
if ( indexBefore === -1 ) {
return record;
}

const match = text.match( /`([^`]+)`/ );
const startIndex = indexBefore;
const endIndex = start - 2;

if ( ! match ) {
if ( startIndex === endIndex ) {
return record;
}

const start = match.index;
const end = start + match[ 1 ].length;
onChange( record );

record = remove( record, start, start + 1 );
record = remove( record, end, end + 1 );
record = applyFormat( record, { type: 'code' }, start, end );
record = remove( record, startIndex, startIndex + 1 );
record = remove( record, endIndex, endIndex + 1 );
record = applyFormat( record, { type: 'code' }, startIndex, endIndex );

return record;
},
Expand Down
12 changes: 12 additions & 0 deletions test/e2e/specs/__snapshots__/rich-text.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,15 @@ exports[`RichText should handle change in tag name gracefully 1`] = `
<h3></h3>
<!-- /wp:heading -->"
`;

exports[`RichText should transform backtick to code 1`] = `
"<!-- wp:paragraph -->
<p>A <code>backtick</code></p>
<!-- /wp:paragraph -->"
`;

exports[`RichText should transform backtick to code 2`] = `
"<!-- wp:paragraph -->
<p>A \`backtick\`</p>
<!-- /wp:paragraph -->"
`;
7 changes: 7 additions & 0 deletions test/e2e/specs/blocks/__snapshots__/code.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Code can be created by three backticks and enter 1`] = `
"<!-- wp:code -->
<pre class=\\"wp-block-code\\"><code>&lt;?php</code></pre>
<!-- /wp:code -->"
`;
13 changes: 13 additions & 0 deletions test/e2e/specs/blocks/__snapshots__/heading.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Separator can be created by prefixing existing content with number signs and a space 1`] = `
"<!-- wp:heading {\\"level\\":4} -->
<h4>4</h4>
<!-- /wp:heading -->"
`;

exports[`Separator can be created by prefixing number sign and a space 1`] = `
"<!-- wp:heading {\\"level\\":3} -->
<h3>3</h3>
<!-- /wp:heading -->"
`;
6 changes: 6 additions & 0 deletions test/e2e/specs/blocks/__snapshots__/list.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ exports[`List can be created by using an asterisk at the start of a paragraph bl
<!-- /wp:list -->"
`;

exports[`List can undo asterisk transform 1`] = `
"<!-- wp:paragraph -->
<p>1.</p>
<!-- /wp:paragraph -->"
`;

exports[`List should create paragraph on split at end and merge back with content 1`] = `
"<!-- wp:list -->
<ul><li>one</li></ul>
Expand Down
7 changes: 7 additions & 0 deletions test/e2e/specs/blocks/__snapshots__/separator.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Separator can be created by three dashes and enter 1`] = `
"<!-- wp:separator -->
<hr class=\\"wp-block-separator\\"/>
<!-- /wp:separator -->"
`;
23 changes: 23 additions & 0 deletions test/e2e/specs/blocks/code.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Internal dependencies
*/
import {
clickBlockAppender,
getEditedPostContent,
newPost,
} from '../../support/utils';

describe( 'Code', () => {
beforeEach( async () => {
await newPost();
} );

it( 'can be created by three backticks and enter', async () => {
await clickBlockAppender();
await page.keyboard.type( '```' );
await page.keyboard.press( 'Enter' );
await page.keyboard.type( '<?php' );

expect( await getEditedPostContent() ).toMatchSnapshot();
} );
} );
Loading