Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions lib/client-assets.php
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ function gutenberg_register_scripts_and_styles() {
'lodash',
'wp-polyfill',
'wp-data',
'wp-deprecated',
'wp-escape-html',
),
filemtime( gutenberg_dir_path() . 'build/rich-text/index.js' ),
Expand Down
33 changes: 25 additions & 8 deletions packages/block-library/src/list/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
BlockControls,
RichText,
} from '@wordpress/editor';
import { replace, join, split, create, toHTMLString } from '@wordpress/rich-text';
import { replace, join, split, create, toHTMLString, LINE_SEPARATOR } from '@wordpress/rich-text';
import { G, Path, SVG } from '@wordpress/components';

const listContentSchema = {
Expand Down Expand Up @@ -75,9 +75,12 @@ export const settings = {
blocks: [ 'core/paragraph' ],
transform: ( blockAttributes ) => {
return createBlock( 'core/list', {
values: toHTMLString( join( blockAttributes.map( ( { content } ) =>
replace( create( { html: content } ), /\n/g, '\u2028' )
), '\u2028' ), 'li' ),
values: toHTMLString( {
value: join( blockAttributes.map( ( { content } ) =>
replace( create( { html: content } ), /\n/g, LINE_SEPARATOR )
), LINE_SEPARATOR ),
multilineTag: 'li',
} ),
} );
},
},
Expand All @@ -86,7 +89,10 @@ export const settings = {
blocks: [ 'core/quote' ],
transform: ( { value } ) => {
return createBlock( 'core/list', {
values: toHTMLString( create( { html: value, multilineTag: 'p' } ), 'li' ),
values: toHTMLString( {
value: create( { html: value, multilineTag: 'p' } ),
multilineTag: 'li',
} ),
} );
},
},
Expand Down Expand Up @@ -132,10 +138,14 @@ export const settings = {
type: 'block',
blocks: [ 'core/paragraph' ],
transform: ( { values } ) =>
split( create( { html: values, multilineTag: 'li' } ), '\u2028' )
split( create( {
html: values,
multilineTag: 'li',
multilineWrapperTags: [ 'ul', 'ol' ],
} ), LINE_SEPARATOR )
.map( ( piece ) =>
createBlock( 'core/paragraph', {
content: toHTMLString( piece ),
content: toHTMLString( { value: piece } ),
} )
),
},
Expand All @@ -144,7 +154,14 @@ export const settings = {
blocks: [ 'core/quote' ],
transform: ( { values } ) => {
return createBlock( 'core/quote', {
value: toHTMLString( create( { html: values, multilineTag: 'li' } ), 'p' ),
value: toHTMLString( {
value: create( {
html: values,
multilineTag: 'li',
multilineWrapperTags: [ 'ul', 'ol' ],
} ),
multilineTag: 'p',
} ),
} );
},
},
Expand Down
18 changes: 12 additions & 6 deletions packages/block-library/src/quote/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,12 @@ export const settings = {
blocks: [ 'core/paragraph' ],
transform: ( attributes ) => {
return createBlock( 'core/quote', {
value: toHTMLString( join( attributes.map( ( { content } ) =>
create( { html: content } )
), '\u2028' ), 'p' ),
value: toHTMLString( {
value: join( attributes.map( ( { content } ) =>
create( { html: content } )
), '\u2028' ),
multilineTag: 'p',
} ),
} );
},
},
Expand Down Expand Up @@ -113,7 +116,7 @@ export const settings = {
...split( create( { html: value, multilineTag: 'p' } ), '\u2028' )
.map( ( piece ) =>
createBlock( 'core/paragraph', {
content: toHTMLString( piece ),
content: toHTMLString( { value: piece } ),
} )
)
);
Expand Down Expand Up @@ -153,12 +156,15 @@ export const settings = {

return [
createBlock( 'core/heading', {
content: toHTMLString( pieces[ 0 ] ),
content: toHTMLString( { value: pieces[ 0 ] } ),
} ),
createBlock( 'core/quote', {
...attrs,
citation,
value: toHTMLString( quotePieces.length ? join( pieces.slice( 1 ), '\u2028' ) : create(), 'p' ),
value: toHTMLString( {
value: quotePieces.length ? join( pieces.slice( 1 ), '\u2028' ) : create(),
multilineTag: 'p',
} ),
} ),
];
},
Expand Down
107 changes: 85 additions & 22 deletions packages/editor/src/components/rich-text/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,15 @@ import {
toHTMLString,
getTextContent,
insert,
insertLineSeparator,
isEmptyLine,
unstableToDom,
getSelectionStart,
getSelectionEnd,
charAt,
LINE_SEPARATOR,
remove,
isCollapsed,
} from '@wordpress/rich-text';
import { decodeEntities } from '@wordpress/html-entities';

Expand Down Expand Up @@ -77,6 +84,10 @@ export class RichText extends Component {
this.multilineTag = multiline === true ? 'p' : multiline;
}

if ( this.multilineTag === 'li' ) {
this.multilineWrapperTags = [ 'ul', 'ol' ];
}

this.onInit = this.onInit.bind( this );
this.getSettings = this.getSettings.bind( this );
this.onSetup = this.onSetup.bind( this );
Expand Down Expand Up @@ -240,6 +251,7 @@ export class RichText extends Component {
element: this.editableRef,
range,
multilineTag: this.multilineTag,
multilineWrapperTags: this.multilineWrapperTags,
removeNode: ( node ) => node.getAttribute( 'data-mce-bogus' ) === 'all',
unwrapNode: ( node ) => !! node.getAttribute( 'data-mce-bogus' ),
removeAttribute: ( attribute ) => attribute.indexOf( 'data-mce-' ) === 0,
Expand All @@ -248,7 +260,17 @@ export class RichText extends Component {
}

applyRecord( record ) {
apply( record, this.editableRef, this.multilineTag );
apply( {
value: record,
current: this.editableRef,
multilineTag: this.multilineTag,
multilineWrapperTags: this.multilineWrapperTags,
createLinePadding( doc ) {
const element = doc.createElement( 'br' );
element.setAttribute( 'data-mce-bogus', '1' );
return element;
},
} );
}

isEmpty() {
Expand Down Expand Up @@ -497,10 +519,8 @@ export class RichText extends Component {
const { keyCode } = event;
const isReverse = keyCode === BACKSPACE;

const { isCollapsed } = getSelection();

// Only process delete if the key press occurs at uncollapsed edge.
if ( ! isCollapsed ) {
if ( ! getSelection().isCollapsed ) {
return;
}

Expand Down Expand Up @@ -588,32 +608,68 @@ export class RichText extends Component {
onKeyDown( event ) {
const { keyCode } = event;

const isDelete = keyCode === DELETE || keyCode === BACKSPACE;
if ( isDelete ) {
this.onDeleteKeyDown( event );
}

const isHorizontalNavigation = keyCode === LEFT || keyCode === RIGHT;
if ( isHorizontalNavigation ) {
this.onHorizontalNavigationKeyDown( event );
}

if ( keyCode === DELETE || keyCode === BACKSPACE ) {
if ( this.multilineTag ) {
const value = this.createRecord();
const start = getSelectionStart( value );
const end = getSelectionEnd( value );

let newValue;

if ( keyCode === BACKSPACE ) {
if ( charAt( value, start - 1 ) === LINE_SEPARATOR ) {
newValue = remove(
value,
// Only remove the line if the selection is
// collapsed.
isCollapsed( value ) ? start - 1 : start,
end
);
}
} else if ( charAt( value, end ) === LINE_SEPARATOR ) {
newValue = remove(
value,
start,
// Only remove the line if the selection is collapsed.
isCollapsed( value ) ? end + 1 : end,
);
}

if ( newValue ) {
this.onChange( newValue );

event.preventDefault();
// It's important that we stop other handlers (e.g. ones
// registered by TinyMCE) from also handling this event.
event.stopImmediatePropagation();
}
}

this.onDeleteKeyDown( event );
}

// If we click shift+Enter on inline RichTexts, we avoid creating two contenteditables
// We also split the content and call the onSplit prop if provided.
if ( keyCode === ENTER ) {
event.preventDefault();
// It's important that we stop other handlers (e.g. ones registered
// by TinyMCE) from also handling this event.
event.stopImmediatePropagation();

const record = this.createRecord();

if ( this.props.onReplace ) {
const text = getTextContent( this.getRecord() );
const text = getTextContent( record );
const transformation = findTransform( this.enterPatterns, ( item ) => {
return item.regExp.test( text );
} );

if ( transformation ) {
// Calling onReplace() will destroy the editor, so it's
// important that we stop other handlers (e.g. ones
// registered by TinyMCE) from also handling this event.
event.stopImmediatePropagation();
this.props.onReplace( [
transformation.transform( { content: text } ),
] );
Expand All @@ -622,16 +678,12 @@ export class RichText extends Component {
}

if ( this.multilineTag ) {
const record = this.getRecord();

if ( this.props.onSplit && isEmptyLine( record ) ) {
this.props.onSplit( ...split( record ).map( this.valueToFormat ) );
} else {
// Character is used to separate lines in multiline values.
this.onChange( insert( record, '\u2028' ) );
this.onChange( insertLineSeparator( record ) );
}
} else if ( event.shiftKey || ! this.props.onSplit ) {
const record = this.getRecord();
const text = getTextContent( record );
const length = text.length;
let toInsert = '\n';
Expand All @@ -646,7 +698,7 @@ export class RichText extends Component {
toInsert = '\n\n';
}

this.onChange( insert( this.getRecord(), toInsert ) );
this.onChange( insert( record, toInsert ) );
} else {
this.splitContent();
}
Expand Down Expand Up @@ -810,13 +862,15 @@ export class RichText extends Component {
return create( {
html: children.toHTML( value ),
multilineTag: this.multilineTag,
multilineWrapperTags: this.multilineWrapperTags,
} );
}

if ( this.props.format === 'string' ) {
return create( {
html: value,
multilineTag: this.multilineTag,
multilineWrapperTags: this.multilineWrapperTags,
} );
}

Expand All @@ -832,11 +886,19 @@ export class RichText extends Component {
valueToFormat( { formats, text } ) {
// Handle deprecated `children` and `node` sources.
if ( this.usedDeprecatedChildrenSource ) {
return children.fromDOM( unstableToDom( { formats, text }, this.multilineTag ).body.childNodes );
return children.fromDOM( unstableToDom( {
value: { formats, text },
multilineTag: this.multilineTag,
multilineWrapperTags: this.multilineWrapperTags,
} ).body.childNodes );
}

if ( this.props.format === 'string' ) {
return toHTMLString( { formats, text }, this.multilineTag );
return toHTMLString( {
value: { formats, text },
multilineTag: this.multilineTag,
multilineWrapperTags: this.multilineWrapperTags,
} );
}

return { formats, text };
Expand Down Expand Up @@ -909,6 +971,7 @@ export class RichText extends Component {
onPaste={ this.onPaste }
onInput={ this.onInput }
multilineTag={ this.multilineTag }
multilineWrapperTags={ this.multilineWrapperTags }
setRef={ this.setRef }
/>
{ isPlaceholderVisible &&
Expand Down
5 changes: 4 additions & 1 deletion packages/editor/src/components/rich-text/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,10 @@ export class RichText extends Component {
}

valueToFormat( { formats, text } ) {
const value = toHTMLString( { formats, text }, this.multilineTag );
const value = toHTMLString( {
value: { formats, text },
multilineTag: this.multilineTag,
} );
// remove the outer root tags
return this.removeRootTagsProduceByAztec( value );
}
Expand Down
7 changes: 6 additions & 1 deletion packages/editor/src/components/rich-text/tinymce.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ export default class TinyMCE extends Component {
onPaste,
onInput,
multilineTag,
multilineWrapperTags,
} = this.props;

/*
Expand All @@ -239,7 +240,11 @@ export default class TinyMCE extends Component {
} else if ( Array.isArray( defaultValue ) ) {
initialHTML = children.toHTML( defaultValue );
} else if ( typeof defaultValue !== 'string' ) {
initialHTML = toHTMLString( defaultValue, multilineTag );
initialHTML = toHTMLString( {
value: defaultValue,
multilineTag,
multilineWrapperTags,
} );
}

return createElement( tagName, {
Expand Down
Loading