diff --git a/packages/block-editor/src/components/rich-text/format-edit.js b/packages/block-editor/src/components/rich-text/format-edit.js
index 7505ed1f81a3cc..29911206aba839 100644
--- a/packages/block-editor/src/components/rich-text/format-edit.js
+++ b/packages/block-editor/src/components/rich-text/format-edit.js
@@ -3,7 +3,7 @@
*/
import { withSelect } from '@wordpress/data';
import { Fragment } from '@wordpress/element';
-import { getActiveFormat } from '@wordpress/rich-text';
+import { getActiveFormat, getActiveObject } from '@wordpress/rich-text';
const FormatEdit = ( { formatTypes, onChange, value } ) => {
return (
@@ -15,13 +15,20 @@ const FormatEdit = ( { formatTypes, onChange, value } ) => {
const activeFormat = getActiveFormat( value, name );
const isActive = activeFormat !== undefined;
- const activeAttributes = isActive ? activeFormat.attributes || {} : {};
+ const activeObject = getActiveObject( value );
+ const isObjectActive = activeObject !== undefined;
return (
diff --git a/packages/block-editor/src/components/rich-text/index.js b/packages/block-editor/src/components/rich-text/index.js
index 5b91674b9a6733..1d714ba9844d39 100644
--- a/packages/block-editor/src/components/rich-text/index.js
+++ b/packages/block-editor/src/components/rich-text/index.js
@@ -177,10 +177,10 @@ export class RichText extends Component {
* @return {Object} The current record (value and selection).
*/
getRecord() {
- const { formats, text } = this.formatToValue( this.props.value );
+ const { formats, replacements, text } = this.formatToValue( this.props.value );
const { start, end, selectedFormat } = this.state;
- return { formats, text, start, end, selectedFormat };
+ return { formats, replacements, text, start, end, selectedFormat };
}
createRecord() {
@@ -394,13 +394,17 @@ export class RichText extends Component {
}
let { selectedFormat } = this.state;
- const { formats, text, start, end } = this.createRecord();
+ const { formats, replacements, text, start, end } = this.createRecord();
if ( this.formatPlaceholder ) {
- formats[ this.state.start ] = formats[ this.state.start ] || [];
- formats[ this.state.start ].push( this.formatPlaceholder );
- selectedFormat = formats[ this.state.start ].length;
- } else if ( selectedFormat ) {
+ selectedFormat = this.formatPlaceholder.length;
+
+ if ( selectedFormat > 0 ) {
+ formats[ this.state.start ] = this.formatPlaceholder;
+ } else {
+ delete formats[ this.state.start ];
+ }
+ } else if ( selectedFormat > 0 ) {
const formatsBefore = formats[ start - 1 ] || [];
const formatsAfter = formats[ start ] || [];
@@ -411,12 +415,13 @@ export class RichText extends Component {
}
source = source.slice( 0, selectedFormat );
+
formats[ this.state.start ] = source;
} else {
delete formats[ this.state.start ];
}
- const change = { formats, text, start, end, selectedFormat };
+ const change = { formats, replacements, text, start, end, selectedFormat };
this.onChange( change, {
withoutHistory: true,
@@ -936,7 +941,6 @@ export class RichText extends Component {
return unstableToDom( {
value,
multilineTag: this.multilineTag,
- multilineWrapperTags: this.multilineWrapperTags,
prepareEditableTree: this.props.prepareEditableTree,
} ).body.innerHTML;
}
@@ -975,7 +979,6 @@ export class RichText extends Component {
return children.fromDOM( unstableToDom( {
value,
multilineTag: this.multilineTag,
- multilineWrapperTags: this.multilineWrapperTags,
isEditableTree: false,
} ).body.childNodes );
}
@@ -984,7 +987,6 @@ export class RichText extends Component {
return toHTMLString( {
value,
multilineTag: this.multilineTag,
- multilineWrapperTags: this.multilineWrapperTags,
} );
}
diff --git a/packages/block-editor/src/components/rich-text/index.native.js b/packages/block-editor/src/components/rich-text/index.native.js
index 55bf4580e5e70d..db750a18d41f26 100644
--- a/packages/block-editor/src/components/rich-text/index.native.js
+++ b/packages/block-editor/src/components/rich-text/index.native.js
@@ -98,9 +98,9 @@ export class RichText extends Component {
const { formatPlaceholder, start, end } = this.state;
// Since we get the text selection from Aztec we need to be in sync with the HTML `value`
// Removing leading white spaces using `trim()` should make sure this is the case.
- const { formats, text } = this.formatToValue( this.props.value === undefined ? undefined : this.props.value.trimLeft() );
+ const { formats, replacements, text } = this.formatToValue( this.props.value === undefined ? undefined : this.props.value.trimLeft() );
- return { formats, formatPlaceholder, text, start, end };
+ return { formats, replacements, formatPlaceholder, text, start, end };
}
/*
@@ -156,13 +156,12 @@ export class RichText extends Component {
onSplit( before, after, ...blocks );
}
- valueToFormat( { formats, text } ) {
- const value = toHTMLString( {
- value: { formats, text },
- multilineTag: this.multilineTag,
- } );
+ valueToFormat( value ) {
// remove the outer root tags
- return this.removeRootTagsProduceByAztec( value );
+ return this.removeRootTagsProduceByAztec( toHTMLString( {
+ value,
+ multilineTag: this.multilineTag,
+ } ) );
}
getActiveFormatNames( record ) {
diff --git a/packages/format-library/src/image/index.js b/packages/format-library/src/image/index.js
index 2dca1c41506b61..ce62a8b6c5a759 100644
--- a/packages/format-library/src/image/index.js
+++ b/packages/format-library/src/image/index.js
@@ -40,7 +40,7 @@ export const image = {
}
static getDerivedStateFromProps( props, state ) {
- const { activeAttributes: { style } } = props;
+ const { activeObjectAttributes: { style } } = props;
if ( style === state.previousStyle ) {
return null;
@@ -79,8 +79,8 @@ export const image = {
}
render() {
- const { value, onChange, isActive, activeAttributes } = this.props;
- const { style } = activeAttributes;
+ const { value, onChange, isObjectActive, activeObjectAttributes } = this.props;
+ const { style } = activeObjectAttributes;
// Rerender PositionedAtSelection when the selection changes or when
// the width changes.
const key = value.start + style;
@@ -91,7 +91,7 @@ export const image = {
icon={ }
title={ __( 'Inline Image' ) }
onClick={ this.openModal }
- isActive={ isActive }
+ isActive={ isObjectActive }
/>
{ this.state.modal && }
- { isActive &&
+ { isObjectActive &&
{
- const newFormats = value.formats.slice( 0 );
+ const newReplacements = value.replacements.slice();
- newFormats[ value.start ] = [ {
+ newReplacements[ value.start ] = {
type: name,
- object: true,
attributes: {
- ...activeAttributes,
+ ...activeObjectAttributes,
style: `width: ${ this.state.width }px;`,
},
- } ];
+ };
onChange( {
...value,
- formats: newFormats,
+ replacements: newReplacements,
} );
event.preventDefault();
diff --git a/packages/rich-text/README.md b/packages/rich-text/README.md
index 0ac85d85b640d1..90fe67367ddc8c 100644
--- a/packages/rich-text/README.md
+++ b/packages/rich-text/README.md
@@ -61,6 +61,26 @@ called without any input, an empty value will be created. If
`multilineTag` will be separated by two newlines. The optional functions can
be used to filter out content.
+A value will have the following shape, which you are strongly encouraged not
+to modify without the use of helper functions:
+
+```js
+{
+ text: string,
+ formats: Array,
+ replacements: Array,
+ ?start: number,
+ ?end: number,
+}
+```
+
+As you can see, text and formatting are separated. `text` holds the text,
+including any replacement characters for objects and lines. `formats`,
+`objects` and `lines` are all sparse arrays of the same length as `text`. It
+holds information about the formatting at the relevant text indices. Finally
+`start` and `end` state which text indices are selected. They are only
+provided if a `Range` was given.
+
**Parameters**
- **$1** `[Object]`: Optional named arguments.
@@ -93,9 +113,23 @@ is no format at the selection.
`(Object|undefined)`: Active format object of the specified type, or undefined.
+### getActiveObject
+
+[src/index.js#L11-L11](src/index.js#L11-L11)
+
+Gets the active object, if there is any.
+
+**Parameters**
+
+- **value** `Object`: Value to inspect.
+
+**Returns**
+
+`?Object`: Active object, or undefined.
+
### getTextContent
-[src/index.js#L13-L13](src/index.js#L13-L13)
+[src/index.js#L14-L14](src/index.js#L14-L14)
Get the textual content of a Rich Text value. This is similar to
`Element.textContent`.
@@ -110,7 +144,7 @@ Get the textual content of a Rich Text value. This is similar to
### insert
-[src/index.js#L21-L21](src/index.js#L21-L21)
+[src/index.js#L22-L22](src/index.js#L22-L22)
Insert a Rich Text value, an HTML string, or a plain text string, into a
Rich Text value at the given `startIndex`. Any content between `startIndex`
@@ -130,7 +164,7 @@ none are provided.
### insertObject
-[src/index.js#L24-L24](src/index.js#L24-L24)
+[src/index.js#L25-L25](src/index.js#L25-L25)
Insert a format as an object into a Rich Text value at the given
`startIndex`. Any content between `startIndex` and `endIndex` will be
@@ -149,7 +183,7 @@ removed. Indices are retrieved from the selection if none are provided.
### isCollapsed
-[src/index.js#L14-L14](src/index.js#L14-L14)
+[src/index.js#L15-L15](src/index.js#L15-L15)
Check if the selection of a Rich Text value is collapsed or not. Collapsed
means that no characters are selected, but there is a caret present. If there
@@ -166,7 +200,7 @@ is no selection, `undefined` will be returned. This is similar to
### isEmpty
-[src/index.js#L15-L15](src/index.js#L15-L15)
+[src/index.js#L16-L16](src/index.js#L16-L16)
Check if a Rich Text value is Empty, meaning it contains no text or any
objects (such as images).
@@ -181,7 +215,7 @@ objects (such as images).
### join
-[src/index.js#L16-L16](src/index.js#L16-L16)
+[src/index.js#L17-L17](src/index.js#L17-L17)
Combine an array of Rich Text values into one, optionally separated by
`separator`, which can be a Rich Text value, HTML string, or plain text
@@ -198,7 +232,7 @@ string. This is similar to `Array.prototype.join`.
### registerFormatType
-[src/index.js#L17-L17](src/index.js#L17-L17)
+[src/index.js#L18-L18](src/index.js#L18-L18)
Registers a new format provided a unique name and an object defining its
behavior.
@@ -218,7 +252,7 @@ behavior.
### remove
-[src/index.js#L19-L19](src/index.js#L19-L19)
+[src/index.js#L20-L20](src/index.js#L20-L20)
Remove content from a Rich Text value between the given `startIndex` and
`endIndex`. Indices are retrieved from the selection if none are provided.
@@ -235,7 +269,7 @@ Remove content from a Rich Text value between the given `startIndex` and
### removeFormat
-[src/index.js#L18-L18](src/index.js#L18-L18)
+[src/index.js#L19-L19](src/index.js#L19-L19)
Remove any format object from a Rich Text value by type from the given
`startIndex` to the given `endIndex`. Indices are retrieved from the
@@ -254,7 +288,7 @@ selection if none are provided.
### replace
-[src/index.js#L20-L20](src/index.js#L20-L20)
+[src/index.js#L21-L21](src/index.js#L21-L21)
Search a Rich Text value and replace the match(es) with `replacement`. This
is similar to `String.prototype.replace`.
@@ -271,7 +305,7 @@ is similar to `String.prototype.replace`.
### slice
-[src/index.js#L25-L25](src/index.js#L25-L25)
+[src/index.js#L26-L26](src/index.js#L26-L26)
Slice a Rich Text value from `startIndex` to `endIndex`. Indices are
retrieved from the selection if none are provided. This is similar to
@@ -289,7 +323,7 @@ retrieved from the selection if none are provided. This is similar to
### split
-[src/index.js#L26-L26](src/index.js#L26-L26)
+[src/index.js#L27-L27](src/index.js#L27-L27)
Split a Rich Text value in two at the given `startIndex` and `endIndex`, or
split at the given separator. This is similar to `String.prototype.split`.
@@ -307,7 +341,7 @@ Indices are retrieved from the selection if none are provided.
### toggleFormat
-[src/index.js#L29-L29](src/index.js#L29-L29)
+[src/index.js#L30-L30](src/index.js#L30-L30)
Toggles a format object to a Rich Text value at the current selection.
@@ -322,7 +356,7 @@ Toggles a format object to a Rich Text value at the current selection.
### toHTMLString
-[src/index.js#L28-L28](src/index.js#L28-L28)
+[src/index.js#L29-L29](src/index.js#L29-L29)
Create an HTML string from a Rich Text value. If a `multilineTag` is
provided, text separated by a line separator will be wrapped in it.
@@ -332,7 +366,6 @@ provided, text separated by a line separator will be wrapped in it.
- **$1** `Object`: Named argements.
- **$1.value** `Object`: Rich text value.
- **$1.multilineTag** `[string]`: Multiline tag.
-- **$1.multilineWrapperTags** `[Array]`: Tags where lines can be found if nesting is possible.
**Returns**
@@ -340,7 +373,7 @@ provided, text separated by a line separator will be wrapped in it.
### unregisterFormatType
-[src/index.js#L31-L31](src/index.js#L31-L31)
+[src/index.js#L32-L32](src/index.js#L32-L32)
Unregisters a format.
diff --git a/packages/rich-text/src/apply-format.js b/packages/rich-text/src/apply-format.js
index 8134cd8d742a99..c9a59b96e6a656 100644
--- a/packages/rich-text/src/apply-format.js
+++ b/packages/rich-text/src/apply-format.js
@@ -23,12 +23,12 @@ import { normaliseFormats } from './normalise-formats';
* @return {Object} A new value with the format applied.
*/
export function applyFormat(
- { formats, text, start, end },
+ value,
format,
- startIndex = start,
- endIndex = end
+ startIndex = value.start,
+ endIndex = value.end
) {
- const newFormats = formats.slice( 0 );
+ const newFormats = value.formats.slice( 0 );
// The selection is collapsed.
if ( startIndex === endIndex ) {
@@ -52,14 +52,10 @@ export function applyFormat(
// with the format applied.
} else {
const previousFormat = newFormats[ startIndex - 1 ] || [];
- const hasType = find( previousFormat, { type: format.type } );
return {
- formats,
- text,
- start,
- end,
- formatPlaceholder: hasType ? undefined : format,
+ ...value,
+ formatPlaceholder: [ ...previousFormat, format ],
};
}
} else {
@@ -68,7 +64,7 @@ export function applyFormat(
}
}
- return normaliseFormats( { formats: newFormats, text, start, end } );
+ return normaliseFormats( { ...value, formats: newFormats } );
}
function applyFormats( formats, index, format ) {
diff --git a/packages/rich-text/src/apply-format.native.js b/packages/rich-text/src/apply-format.native.js
index 9c5a4749ae928b..ef641cbaa224d9 100644
--- a/packages/rich-text/src/apply-format.native.js
+++ b/packages/rich-text/src/apply-format.native.js
@@ -23,11 +23,13 @@ import { normaliseFormats } from './normalise-formats';
* @return {Object} A new value with the format applied.
*/
export function applyFormat(
- { formats: currentFormats, formatPlaceholder, text, start, end },
+ value,
formats,
- startIndex = start,
- endIndex = end
+ startIndex = value.start,
+ endIndex = value.end
) {
+ const { formats: currentFormats, formatPlaceholder, start } = value;
+
if ( ! Array.isArray( formats ) ) {
formats = [ formats ];
}
@@ -40,10 +42,8 @@ export function applyFormat(
// Follow the same logic as in getActiveFormat: placeholderFormats has priority over previousFormats
const activeFormats = ( placeholderFormats ? placeholderFormats : previousFormats ) || [];
return {
+ ...value,
formats: currentFormats,
- text,
- start,
- end,
formatPlaceholder: {
index: start,
formats: mergeFormats( activeFormats, formats ),
@@ -57,7 +57,7 @@ export function applyFormat(
applyFormats( newFormats, index, formats );
}
- return normaliseFormats( { formats: newFormats, text, start, end } );
+ return normaliseFormats( { ...value, formats: newFormats } );
}
function mergeFormats( formats1, formats2 ) {
diff --git a/packages/rich-text/src/change-list-type.js b/packages/rich-text/src/change-list-type.js
index 1dfc0406573636..e429b91c6cbca6 100644
--- a/packages/rich-text/src/change-list-type.js
+++ b/packages/rich-text/src/change-list-type.js
@@ -3,7 +3,6 @@
*/
import { LINE_SEPARATOR } from './special-characters';
-import { normaliseFormats } from './normalise-formats';
import { getLineIndex } from './get-line-index';
import { getParentLineIndex } from './get-parent-line-index';
@@ -20,12 +19,12 @@ import { getParentLineIndex } from './get-parent-line-index';
* @return {Object} The changed value.
*/
export function changeListType( value, newFormat ) {
- const { text, formats, start, end } = value;
+ const { text, replacements, start, end } = value;
const startingLineIndex = getLineIndex( value, start );
- const startLineFormats = formats[ startingLineIndex ] || [];
- const endLineFormats = formats[ getLineIndex( value, end ) ] || [];
+ const startLineFormats = replacements[ startingLineIndex ] || [];
+ const endLineFormats = replacements[ getLineIndex( value, end ) ] || [];
const startIndex = getParentLineIndex( value, startingLineIndex );
- const newFormats = formats.slice( 0 );
+ const newReplacements = replacements.slice();
const startCount = startLineFormats.length - 1;
const endCount = endLineFormats.length - 1;
@@ -36,16 +35,16 @@ export function changeListType( value, newFormat ) {
continue;
}
- if ( ( newFormats[ index ] || [] ).length <= startCount ) {
+ if ( ( newReplacements[ index ] || [] ).length <= startCount ) {
break;
}
- if ( ! newFormats[ index ] ) {
+ if ( ! newReplacements[ index ] ) {
continue;
}
changed = true;
- newFormats[ index ] = newFormats[ index ].map( ( format, i ) => {
+ newReplacements[ index ] = newReplacements[ index ].map( ( format, i ) => {
return i < startCount || i > endCount ? format : newFormat;
} );
}
@@ -54,10 +53,8 @@ export function changeListType( value, newFormat ) {
return value;
}
- return normaliseFormats( {
- text,
- formats: newFormats,
- start,
- end,
- } );
+ return {
+ ...value,
+ replacements: newReplacements,
+ };
}
diff --git a/packages/rich-text/src/concat.js b/packages/rich-text/src/concat.js
index 9f14091f9b1c87..07be12140db91b 100644
--- a/packages/rich-text/src/concat.js
+++ b/packages/rich-text/src/concat.js
@@ -3,6 +3,24 @@
*/
import { normaliseFormats } from './normalise-formats';
+import { create } from './create';
+
+/**
+ * Concats a pair of rich text values. Not that this mutates `a` and does NOT
+ * normalise formats!
+ *
+ * @param {Object} a Value to mutate.
+ * @param {Object} b Value to add read from.
+ *
+ * @return {Object} `a`, mutated.
+ */
+export function mergePair( a, b ) {
+ a.formats = a.formats.concat( b.formats );
+ a.replacements = a.replacements.concat( b.replacements );
+ a.text += b.text;
+
+ return a;
+}
/**
* Combine all Rich Text values into one. This is similar to
@@ -13,8 +31,5 @@ import { normaliseFormats } from './normalise-formats';
* @return {Object} A new value combining all given records.
*/
export function concat( ...values ) {
- return normaliseFormats( values.reduce( ( accumlator, { formats, text } ) => ( {
- text: accumlator.text + text,
- formats: accumlator.formats.concat( formats ),
- } ) ) );
+ return normaliseFormats( values.reduce( mergePair, create() ) );
}
diff --git a/packages/rich-text/src/create.js b/packages/rich-text/src/create.js
index d1c1e47d4df064..37bd1189193f2c 100644
--- a/packages/rich-text/src/create.js
+++ b/packages/rich-text/src/create.js
@@ -7,9 +7,9 @@ import { select } from '@wordpress/data';
* Internal dependencies
*/
-import { isEmpty } from './is-empty';
import { isFormatEqual } from './is-format-equal';
import { createElement } from './create-element';
+import { mergePair } from './concat';
import {
LINE_SEPARATOR,
OBJECT_REPLACEMENT_CHARACTER,
@@ -22,7 +22,11 @@ import {
const { TEXT_NODE, ELEMENT_NODE } = window.Node;
function createEmptyValue() {
- return { formats: [], text: '' };
+ return {
+ formats: [],
+ replacements: [],
+ text: '',
+ };
}
function simpleFindKey( object, value ) {
@@ -96,6 +100,26 @@ function toFormat( { type, attributes } ) {
* `multilineTag` will be separated by two newlines. The optional functions can
* be used to filter out content.
*
+ * A value will have the following shape, which you are strongly encouraged not
+ * to modify without the use of helper functions:
+ *
+ * ```js
+ * {
+ * text: string,
+ * formats: Array,
+ * replacements: Array,
+ * ?start: number,
+ * ?end: number,
+ * }
+ * ```
+ *
+ * As you can see, text and formatting are separated. `text` holds the text,
+ * including any replacement characters for objects and lines. `formats`,
+ * `objects` and `lines` are all sparse arrays of the same length as `text`. It
+ * holds information about the formatting at the relevant text indices. Finally
+ * `start` and `end` state which text indices are selected. They are only
+ * provided if a `Range` was given.
+ *
* @param {Object} [$1] Optional named arguments.
* @param {Element} [$1.element] Element to create value from.
* @param {string} [$1.text] Text to create value from.
@@ -120,6 +144,7 @@ export function create( {
if ( typeof text === 'string' && text.length > 0 ) {
return {
formats: Array( text.length ),
+ replacements: Array( text.length ),
text,
};
}
@@ -291,10 +316,11 @@ function createFromElement( {
const text = filterString( node.nodeValue );
range = filterRange( node, range, filterString );
accumulateSelection( accumulator, node, range, { text } );
- accumulator.text += text;
// Create a sparse array of the same length as `text`, in which
// formats can be added.
accumulator.formats.length += text.length;
+ accumulator.replacements.length += text.length;
+ accumulator.text += text;
continue;
}
@@ -312,8 +338,7 @@ function createFromElement( {
if ( type === 'br' ) {
accumulateSelection( accumulator, node, range, createEmptyValue() );
- accumulator.text += '\n';
- accumulator.formats.length += 1;
+ mergePair( accumulator, create( { text: '\n' } ) );
continue;
}
@@ -323,22 +348,10 @@ function createFromElement( {
type,
attributes: getAttributes( { element: node } ),
} );
-
- let format;
-
- if ( newFormat ) {
- // Reuse the last format if it's equal.
- if ( isFormatEqual( newFormat, lastFormat ) ) {
- format = lastFormat;
- } else {
- format = newFormat;
- }
- }
-
- let value;
+ const format = isFormatEqual( newFormat, lastFormat ) ? lastFormat : newFormat;
if ( multilineWrapperTags && multilineWrapperTags.indexOf( type ) !== -1 ) {
- value = createFromMultilineElement( {
+ const value = createFromMultilineElement( {
element: node,
range,
multilineTag,
@@ -346,64 +359,39 @@ function createFromElement( {
currentWrapperTags: [ ...currentWrapperTags, format ],
isEditableTree,
} );
- format = undefined;
- } else {
- value = createFromElement( {
- element: node,
- range,
- multilineTag,
- multilineWrapperTags,
- isEditableTree,
- } );
- }
-
- const text = value.text;
- const start = accumulator.text.length;
- accumulateSelection( accumulator, node, range, value );
-
- // Don't apply the element as formatting if it has no content.
- if ( isEmpty( value ) && format && ! format.attributes ) {
+ accumulateSelection( accumulator, node, range, value );
+ mergePair( accumulator, value );
continue;
}
- const { formats } = accumulator;
+ const value = createFromElement( {
+ element: node,
+ range,
+ multilineTag,
+ multilineWrapperTags,
+ isEditableTree,
+ } );
- if ( format && format.attributes && text.length === 0 ) {
- format.object = true;
- accumulator.text += OBJECT_REPLACEMENT_CHARACTER;
+ accumulateSelection( accumulator, node, range, value );
- if ( formats[ start ] ) {
- formats[ start ].unshift( format );
- } else {
- formats[ start ] = [ format ];
+ if ( ! format ) {
+ mergePair( accumulator, value );
+ } else if ( value.text.length === 0 ) {
+ if ( format.attributes ) {
+ mergePair( accumulator, {
+ formats: [ , ],
+ replacements: [ format ],
+ text: OBJECT_REPLACEMENT_CHARACTER,
+ } );
}
} else {
- accumulator.text += text;
- accumulator.formats.length += text.length;
-
- let i = value.formats.length;
-
- // Optimise for speed.
- while ( i-- ) {
- const formatIndex = start + i;
-
- if ( format ) {
- if ( formats[ formatIndex ] ) {
- formats[ formatIndex ].push( format );
- } else {
- formats[ formatIndex ] = [ format ];
- }
- }
-
- if ( value.formats[ i ] ) {
- if ( formats[ formatIndex ] ) {
- formats[ formatIndex ].push( ...value.formats[ i ] );
- } else {
- formats[ formatIndex ] = value.formats[ i ];
- }
- }
- }
+ mergePair( accumulator, {
+ ...value,
+ formats: Array.from( value.formats, ( formats ) =>
+ formats ? [ format, ...formats ] : [ format ]
+ ),
+ } );
}
}
@@ -459,17 +447,17 @@ function createFromMultilineElement( {
isEditableTree,
} );
- // Multiline value text should be separated by a double line break.
+ // Multiline value text should be separated by a line separator.
if ( index !== 0 || currentWrapperTags.length > 0 ) {
- const formats = currentWrapperTags.length > 0 ? [ currentWrapperTags ] : [ , ];
- accumulator.formats = accumulator.formats.concat( formats );
- accumulator.text += LINE_SEPARATOR;
+ mergePair( accumulator, {
+ formats: [ , ],
+ replacements: currentWrapperTags.length > 0 ? [ currentWrapperTags ] : [ , ],
+ text: LINE_SEPARATOR,
+ } );
}
accumulateSelection( accumulator, node, range, value );
-
- accumulator.formats = accumulator.formats.concat( value.formats );
- accumulator.text += value.text;
+ mergePair( accumulator, value );
}
return accumulator;
diff --git a/packages/rich-text/src/get-active-object.js b/packages/rich-text/src/get-active-object.js
new file mode 100644
index 00000000000000..e324521284597b
--- /dev/null
+++ b/packages/rich-text/src/get-active-object.js
@@ -0,0 +1,20 @@
+/**
+ * Internal dependencies
+ */
+
+import { OBJECT_REPLACEMENT_CHARACTER } from './special-characters';
+
+/**
+ * Gets the active object, if there is any.
+ *
+ * @param {Object} value Value to inspect.
+ *
+ * @return {?Object} Active object, or undefined.
+ */
+export function getActiveObject( { start, end, replacements, text } ) {
+ if ( start + 1 !== end || text[ start ] !== OBJECT_REPLACEMENT_CHARACTER ) {
+ return;
+ }
+
+ return replacements[ start ];
+}
diff --git a/packages/rich-text/src/get-last-child-index.js b/packages/rich-text/src/get-last-child-index.js
index 976051b10c0a3e..0fc4aeb32ff3ee 100644
--- a/packages/rich-text/src/get-last-child-index.js
+++ b/packages/rich-text/src/get-last-child-index.js
@@ -12,8 +12,8 @@ import { LINE_SEPARATOR } from './special-characters';
*
* @return {Array} The index of the last child.
*/
-export function getLastChildIndex( { text, formats }, lineIndex ) {
- const lineFormats = formats[ lineIndex ] || [];
+export function getLastChildIndex( { text, replacements }, lineIndex ) {
+ const lineFormats = replacements[ lineIndex ] || [];
// Use the given line index in case there are no next children.
let childIndex = lineIndex;
@@ -24,7 +24,7 @@ export function getLastChildIndex( { text, formats }, lineIndex ) {
continue;
}
- const formatsAtIndex = formats[ index ] || [];
+ const formatsAtIndex = replacements[ index ] || [];
// If the amout of formats is equal or more, store it, then return the
// last one if the amount of formats is less.
diff --git a/packages/rich-text/src/get-parent-line-index.js b/packages/rich-text/src/get-parent-line-index.js
index bd3f72de965196..1b0a0ecb5cf48c 100644
--- a/packages/rich-text/src/get-parent-line-index.js
+++ b/packages/rich-text/src/get-parent-line-index.js
@@ -14,8 +14,8 @@ import { LINE_SEPARATOR } from './special-characters';
*
* @return {Array} The parent list line index.
*/
-export function getParentLineIndex( { text, formats }, lineIndex ) {
- const startFormats = formats[ lineIndex ] || [];
+export function getParentLineIndex( { text, replacements }, lineIndex ) {
+ const startFormats = replacements[ lineIndex ] || [];
let index = lineIndex;
@@ -24,7 +24,7 @@ export function getParentLineIndex( { text, formats }, lineIndex ) {
continue;
}
- const formatsAtIndex = formats[ index ] || [];
+ const formatsAtIndex = replacements[ index ] || [];
if ( formatsAtIndex.length === startFormats.length - 1 ) {
return index;
diff --git a/packages/rich-text/src/indent-list-items.js b/packages/rich-text/src/indent-list-items.js
index 1a61bd7db15360..985d1062c76ed1 100644
--- a/packages/rich-text/src/indent-list-items.js
+++ b/packages/rich-text/src/indent-list-items.js
@@ -3,7 +3,6 @@
*/
import { LINE_SEPARATOR } from './special-characters';
-import { normaliseFormats } from './normalise-formats';
import { getLineIndex } from './get-line-index';
/**
@@ -14,8 +13,8 @@ import { getLineIndex } from './get-line-index';
*
* @return {boolean} The line index.
*/
-function getTargetLevelLineIndex( { text, formats }, lineIndex ) {
- const startFormats = formats[ lineIndex ] || [];
+function getTargetLevelLineIndex( { text, replacements }, lineIndex ) {
+ const startFormats = replacements[ lineIndex ] || [];
let index = lineIndex;
@@ -24,7 +23,7 @@ function getTargetLevelLineIndex( { text, formats }, lineIndex ) {
continue;
}
- const formatsAtIndex = formats[ index ] || [];
+ const formatsAtIndex = replacements[ index ] || [];
// Return the first line index that is one level higher. If the level is
// lower or equal, there is no result.
@@ -52,10 +51,10 @@ export function indentListItems( value, rootFormat ) {
return value;
}
- const { text, formats, start, end } = value;
+ const { text, replacements, end } = value;
const previousLineIndex = getLineIndex( value, lineIndex );
- const formatsAtLineIndex = formats[ lineIndex ] || [];
- const formatsAtPreviousLineIndex = formats[ previousLineIndex ] || [];
+ const formatsAtLineIndex = replacements[ lineIndex ] || [];
+ const formatsAtPreviousLineIndex = replacements[ previousLineIndex ] || [];
// The the indentation of the current line is greater than previous line,
// then the line cannot be furter indented.
@@ -63,7 +62,7 @@ export function indentListItems( value, rootFormat ) {
return value;
}
- const newFormats = formats.slice();
+ const newFormats = replacements.slice();
const targetLevelLineIndex = getTargetLevelLineIndex( value, lineIndex );
for ( let index = lineIndex; index < end; index++ ) {
@@ -74,12 +73,12 @@ export function indentListItems( value, rootFormat ) {
// Get the previous list, and if there's a child list, take over the
// formats. If not, duplicate the last level and create a new level.
if ( targetLevelLineIndex ) {
- const targetFormats = formats[ targetLevelLineIndex ] || [];
+ const targetFormats = replacements[ targetLevelLineIndex ] || [];
newFormats[ index ] = targetFormats.concat(
( newFormats[ index ] || [] ).slice( targetFormats.length - 1 )
);
} else {
- const targetFormats = formats[ previousLineIndex ] || [];
+ const targetFormats = replacements[ previousLineIndex ] || [];
const lastformat = targetFormats[ targetFormats.length - 1 ] || rootFormat;
newFormats[ index ] = targetFormats.concat(
@@ -89,10 +88,8 @@ export function indentListItems( value, rootFormat ) {
}
}
- return normaliseFormats( {
- text,
- formats: newFormats,
- start,
- end,
- } );
+ return {
+ ...value,
+ replacements: newFormats,
+ };
}
diff --git a/packages/rich-text/src/index.js b/packages/rich-text/src/index.js
index 423046079132bd..9d9f4620212876 100644
--- a/packages/rich-text/src/index.js
+++ b/packages/rich-text/src/index.js
@@ -8,6 +8,7 @@ export { charAt } from './char-at';
export { concat } from './concat';
export { create } from './create';
export { getActiveFormat } from './get-active-format';
+export { getActiveObject } from './get-active-object';
export { getSelectionEnd } from './get-selection-end';
export { getSelectionStart } from './get-selection-start';
export { getTextContent } from './get-text-content';
diff --git a/packages/rich-text/src/insert-line-separator.js b/packages/rich-text/src/insert-line-separator.js
index e273c9eea9ac48..77434a25ac012a 100644
--- a/packages/rich-text/src/insert-line-separator.js
+++ b/packages/rich-text/src/insert-line-separator.js
@@ -24,15 +24,16 @@ export function insertLineSeparator(
) {
const beforeText = getTextContent( value ).slice( 0, startIndex );
const previousLineSeparatorIndex = beforeText.lastIndexOf( LINE_SEPARATOR );
- const previousLineSeparatorFormats = value.formats[ previousLineSeparatorIndex ];
- let formats = [ , ];
+ const previousLineSeparatorFormats = value.replacements[ previousLineSeparatorIndex ];
+ let replacements = [ , ];
if ( previousLineSeparatorFormats ) {
- formats = [ previousLineSeparatorFormats ];
+ replacements = [ previousLineSeparatorFormats ];
}
const valueToInsert = {
- formats,
+ formats: [ , ],
+ replacements,
text: LINE_SEPARATOR,
};
diff --git a/packages/rich-text/src/insert-object.js b/packages/rich-text/src/insert-object.js
index fcdfc6f897c2dd..7495d6082cbcb1 100644
--- a/packages/rich-text/src/insert-object.js
+++ b/packages/rich-text/src/insert-object.js
@@ -25,11 +25,9 @@ export function insertObject(
endIndex
) {
const valueToInsert = {
+ formats: [ , ],
+ replacements: [ formatToInsert ],
text: OBJECT_REPLACEMENT_CHARACTER,
- formats: [ [ {
- ...formatToInsert,
- object: true,
- } ] ],
};
return insert( value, valueToInsert, startIndex, endIndex );
diff --git a/packages/rich-text/src/insert.js b/packages/rich-text/src/insert.js
index cf46305240fb70..4d2353eaba4cb9 100644
--- a/packages/rich-text/src/insert.js
+++ b/packages/rich-text/src/insert.js
@@ -19,11 +19,13 @@ import { normaliseFormats } from './normalise-formats';
* @return {Object} A new value with the value inserted.
*/
export function insert(
- { formats, text, start, end },
+ value,
valueToInsert,
- startIndex = start,
- endIndex = end
+ startIndex = value.start,
+ endIndex = value.end
) {
+ const { formats, replacements, text } = value;
+
if ( typeof valueToInsert === 'string' ) {
valueToInsert = create( { text: valueToInsert } );
}
@@ -32,6 +34,7 @@ export function insert(
return normaliseFormats( {
formats: formats.slice( 0, startIndex ).concat( valueToInsert.formats, formats.slice( endIndex ) ),
+ replacements: replacements.slice( 0, startIndex ).concat( valueToInsert.replacements, replacements.slice( endIndex ) ),
text: text.slice( 0, startIndex ) + valueToInsert.text + text.slice( endIndex ),
start: index,
end: index,
diff --git a/packages/rich-text/src/join.js b/packages/rich-text/src/join.js
index 7784b5962ca536..cabfc827560164 100644
--- a/packages/rich-text/src/join.js
+++ b/packages/rich-text/src/join.js
@@ -20,8 +20,9 @@ export function join( values, separator = '' ) {
separator = create( { text: separator } );
}
- return normaliseFormats( values.reduce( ( accumlator, { formats, text } ) => ( {
- text: accumlator.text + separator.text + text,
+ return normaliseFormats( values.reduce( ( accumlator, { formats, replacements, text } ) => ( {
formats: accumlator.formats.concat( separator.formats, formats ),
+ replacements: accumlator.replacements.concat( separator.replacements, replacements ),
+ text: accumlator.text + separator.text + text,
} ) ) );
}
diff --git a/packages/rich-text/src/normalise-formats.js b/packages/rich-text/src/normalise-formats.js
index 533df66933886a..72c04f818f9a4f 100644
--- a/packages/rich-text/src/normalise-formats.js
+++ b/packages/rich-text/src/normalise-formats.js
@@ -13,13 +13,13 @@ import { isFormatEqual } from './is-format-equal';
/**
* Normalises formats: ensures subsequent equal formats have the same reference.
*
- * @param {Object} value Value to normalise formats of.
+ * @param {Object} value Value to normalise formats of.
*
* @return {Object} New value with normalised formats.
*/
-export function normaliseFormats( { formats, text, start, end } ) {
+export function normaliseFormats( value ) {
const refs = [];
- const newFormats = formats.map( ( formatsAtIndex ) =>
+ const newFormats = value.formats.map( ( formatsAtIndex ) =>
formatsAtIndex.map( ( format ) => {
const equalRef = find( refs, ( ref ) =>
isFormatEqual( ref, format )
@@ -35,5 +35,5 @@ export function normaliseFormats( { formats, text, start, end } ) {
} )
);
- return { formats: newFormats, text, start, end };
+ return { ...value, formats: newFormats };
}
diff --git a/packages/rich-text/src/normalise-formats.native.js b/packages/rich-text/src/normalise-formats.native.js
deleted file mode 100644
index 2a75e343a2c125..00000000000000
--- a/packages/rich-text/src/normalise-formats.native.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * Internal dependencies
- */
-
-import { isFormatEqual } from './is-format-equal';
-
-/**
- * Normalises formats: ensures subsequent equal formats have the same reference.
- *
- * @param {Object} value Value to normalise formats of.
- *
- * @return {Object} New value with normalised formats.
- */
-export function normaliseFormats( { formats, formatPlaceholder, text, start, end } ) {
- const newFormats = formats.slice( 0 );
-
- newFormats.forEach( ( formatsAtIndex, index ) => {
- const lastFormatsAtIndex = newFormats[ index - 1 ];
-
- if ( lastFormatsAtIndex ) {
- const newFormatsAtIndex = formatsAtIndex.slice( 0 );
-
- newFormatsAtIndex.forEach( ( format, formatIndex ) => {
- const lastFormat = lastFormatsAtIndex[ formatIndex ];
-
- if ( isFormatEqual( format, lastFormat ) ) {
- newFormatsAtIndex[ formatIndex ] = lastFormat;
- }
- } );
-
- newFormats[ index ] = newFormatsAtIndex;
- }
- } );
-
- return { formats: newFormats, formatPlaceholder, text, start, end };
-}
diff --git a/packages/rich-text/src/outdent-list-items.js b/packages/rich-text/src/outdent-list-items.js
index 3a493caa9b03a8..19fac90515dfb2 100644
--- a/packages/rich-text/src/outdent-list-items.js
+++ b/packages/rich-text/src/outdent-list-items.js
@@ -3,7 +3,6 @@
*/
import { LINE_SEPARATOR } from './special-characters';
-import { normaliseFormats } from './normalise-formats';
import { getLineIndex } from './get-line-index';
import { getParentLineIndex } from './get-parent-line-index';
import { getLastChildIndex } from './get-last-child-index';
@@ -16,16 +15,16 @@ import { getLastChildIndex } from './get-last-child-index';
* @return {Object} The changed value.
*/
export function outdentListItems( value ) {
- const { text, formats, start, end } = value;
+ const { text, replacements, start, end } = value;
const startingLineIndex = getLineIndex( value, start );
// Return early if the starting line index cannot be further outdented.
- if ( formats[ startingLineIndex ] === undefined ) {
+ if ( replacements[ startingLineIndex ] === undefined ) {
return value;
}
- const newFormats = formats.slice( 0 );
- const parentFormats = formats[ getParentLineIndex( value, startingLineIndex ) ] || [];
+ const newFormats = replacements.slice( 0 );
+ const parentFormats = replacements[ getParentLineIndex( value, startingLineIndex ) ] || [];
const endingLineIndex = getLineIndex( value, end );
const lastChildIndex = getLastChildIndex( value, endingLineIndex );
@@ -51,10 +50,8 @@ export function outdentListItems( value ) {
}
}
- return normaliseFormats( {
- text,
- formats: newFormats,
- start,
- end,
- } );
+ return {
+ ...value,
+ replacements: newFormats,
+ };
}
diff --git a/packages/rich-text/src/remove-format.js b/packages/rich-text/src/remove-format.js
index be1c92ace7fd43..405cb6265e1e06 100644
--- a/packages/rich-text/src/remove-format.js
+++ b/packages/rich-text/src/remove-format.js
@@ -2,7 +2,7 @@
* External dependencies
*/
-import { find } from 'lodash';
+import { find, reject } from 'lodash';
/**
* Internal dependencies
@@ -23,28 +23,38 @@ import { normaliseFormats } from './normalise-formats';
* @return {Object} A new value with the format applied.
*/
export function removeFormat(
- { formats, text, start, end },
+ value,
formatType,
- startIndex = start,
- endIndex = end
+ startIndex = value.start,
+ endIndex = value.end
) {
- const newFormats = formats.slice( 0 );
+ const newFormats = value.formats.slice( 0 );
// If the selection is collapsed, expand start and end to the edges of the
// format.
if ( startIndex === endIndex ) {
const format = find( newFormats[ startIndex ], { type: formatType } );
- while ( find( newFormats[ startIndex ], format ) ) {
- filterFormats( newFormats, startIndex, formatType );
- startIndex--;
- }
-
- endIndex++;
+ if ( format ) {
+ while ( find( newFormats[ startIndex ], format ) ) {
+ filterFormats( newFormats, startIndex, formatType );
+ startIndex--;
+ }
- while ( find( newFormats[ endIndex ], format ) ) {
- filterFormats( newFormats, endIndex, formatType );
endIndex++;
+
+ while ( find( newFormats[ endIndex ], format ) ) {
+ filterFormats( newFormats, endIndex, formatType );
+ endIndex++;
+ }
+ } else {
+ return {
+ ...value,
+ formatPlaceholder: reject(
+ newFormats[ startIndex - 1 ] || [],
+ { type: formatType }
+ ),
+ };
}
} else {
for ( let i = startIndex; i < endIndex; i++ ) {
@@ -54,7 +64,7 @@ export function removeFormat(
}
}
- return normaliseFormats( { formats: newFormats, text, start, end } );
+ return normaliseFormats( { ...value, formats: newFormats } );
}
function filterFormats( formats, index, formatType ) {
diff --git a/packages/rich-text/src/remove-format.native.js b/packages/rich-text/src/remove-format.native.js
index b6213f813bb636..5c20260728b719 100644
--- a/packages/rich-text/src/remove-format.native.js
+++ b/packages/rich-text/src/remove-format.native.js
@@ -23,11 +23,12 @@ import { normaliseFormats } from './normalise-formats';
* @return {Object} A new value with the format applied.
*/
export function removeFormat(
- { formats, formatPlaceholder, text, start, end },
+ value,
formatType,
- startIndex = start,
- endIndex = end
+ startIndex = value.start,
+ endIndex = value.end
) {
+ const { formats, formatPlaceholder, start, end } = value;
const newFormats = formats.slice( 0 );
let newFormatPlaceholder = null;
@@ -55,7 +56,7 @@ export function removeFormat(
}
}
- return normaliseFormats( { formats: newFormats, formatPlaceholder: newFormatPlaceholder, text, start, end } );
+ return normaliseFormats( { ...value, formats: newFormats, formatPlaceholder: newFormatPlaceholder } );
}
function filterFormats( formats, index, formatType ) {
diff --git a/packages/rich-text/src/replace.js b/packages/rich-text/src/replace.js
index 110fc186bd6386..0cb26cb7431bd0 100644
--- a/packages/rich-text/src/replace.js
+++ b/packages/rich-text/src/replace.js
@@ -20,11 +20,12 @@ import { normaliseFormats } from './normalise-formats';
*
* @return {Object} A new value with replacements applied.
*/
-export function replace( { formats, text, start, end }, pattern, replacement ) {
+export function replace( { formats, replacements, text, start, end }, pattern, replacement ) {
text = text.replace( pattern, ( match, ...rest ) => {
const offset = rest[ rest.length - 2 ];
let newText = replacement;
let newFormats;
+ let newReplacements;
if ( typeof newText === 'function' ) {
newText = replacement( match, ...rest );
@@ -32,9 +33,11 @@ export function replace( { formats, text, start, end }, pattern, replacement ) {
if ( typeof newText === 'object' ) {
newFormats = newText.formats;
+ newReplacements = newText.replacements;
newText = newText.text;
} else {
newFormats = Array( newText.length );
+ newReplacements = Array( newText.length );
if ( formats[ offset ] ) {
newFormats = newFormats.fill( formats[ offset ] );
@@ -42,6 +45,7 @@ export function replace( { formats, text, start, end }, pattern, replacement ) {
}
formats = formats.slice( 0, offset ).concat( newFormats, formats.slice( offset + match.length ) );
+ replacements = replacements.slice( 0, offset ).concat( newReplacements, replacements.slice( offset + match.length ) );
if ( start ) {
start = end = offset + newText.length;
@@ -50,5 +54,5 @@ export function replace( { formats, text, start, end }, pattern, replacement ) {
return newText;
} );
- return normaliseFormats( { formats, text, start, end } );
+ return normaliseFormats( { formats, replacements, text, start, end } );
}
diff --git a/packages/rich-text/src/slice.js b/packages/rich-text/src/slice.js
index bb4313dd61309a..b535a445d45f5c 100644
--- a/packages/rich-text/src/slice.js
+++ b/packages/rich-text/src/slice.js
@@ -10,16 +10,19 @@
* @return {Object} A new extracted value.
*/
export function slice(
- { formats, text, start, end },
- startIndex = start,
- endIndex = end
+ value,
+ startIndex = value.start,
+ endIndex = value.end
) {
+ const { formats, replacements, text } = value;
+
if ( startIndex === undefined || endIndex === undefined ) {
- return { formats, text };
+ return { ...value };
}
return {
formats: formats.slice( startIndex, endIndex ),
+ replacements: replacements.slice( startIndex, endIndex ),
text: text.slice( startIndex, endIndex ),
};
}
diff --git a/packages/rich-text/src/split.js b/packages/rich-text/src/split.js
index a300c3ccbcca4a..f79a675b1e1f4f 100644
--- a/packages/rich-text/src/split.js
+++ b/packages/rich-text/src/split.js
@@ -15,7 +15,7 @@ import { replace } from './replace';
*
* @return {Array} An array of new values.
*/
-export function split( { formats, text, start, end }, string ) {
+export function split( { formats, replacements, text, start, end }, string ) {
if ( typeof string !== 'string' ) {
return splitAtSelection( ...arguments );
}
@@ -26,6 +26,7 @@ export function split( { formats, text, start, end }, string ) {
const startIndex = nextStart;
const value = {
formats: formats.slice( startIndex, startIndex + substring.length ),
+ replacements: replacements.slice( startIndex, startIndex + substring.length ),
text: substring,
};
@@ -50,16 +51,18 @@ export function split( { formats, text, start, end }, string ) {
}
function splitAtSelection(
- { formats, text, start, end },
+ { formats, replacements, text, start, end },
startIndex = start,
endIndex = end
) {
const before = {
formats: formats.slice( 0, startIndex ),
+ replacements: replacements.slice( 0, startIndex ),
text: text.slice( 0, startIndex ),
};
const after = {
formats: formats.slice( endIndex ),
+ replacements: replacements.slice( endIndex ),
text: text.slice( endIndex ),
start: 0,
end: 0,
diff --git a/packages/rich-text/src/test/__snapshots__/to-dom.js.snap b/packages/rich-text/src/test/__snapshots__/to-dom.js.snap
index a68cdab1c911eb..ae6c0db2d55750 100644
--- a/packages/rich-text/src/test/__snapshots__/to-dom.js.snap
+++ b/packages/rich-text/src/test/__snapshots__/to-dom.js.snap
@@ -36,6 +36,7 @@ exports[`recordToDom should create a value with formatting with attributes 1`] =
exports[`recordToDom should create a value with image object 1`] = `
+
@@ -45,7 +46,10 @@ exports[`recordToDom should create a value with image object 1`] = `
exports[`recordToDom should create a value with image object and formatting 1`] = `
-
+
+
@@ -57,7 +61,10 @@ exports[`recordToDom should create a value with image object and formatting 1`]
exports[`recordToDom should create a value with image object and text after 1`] = `
-
+
+
diff --git a/packages/rich-text/src/test/apply-format.js b/packages/rich-text/src/test/apply-format.js
index de4f7b69e5f5ef..b8cff3bc476202 100644
--- a/packages/rich-text/src/test/apply-format.js
+++ b/packages/rich-text/src/test/apply-format.js
@@ -61,7 +61,7 @@ describe( 'applyFormat', () => {
};
const expected = {
...record,
- formatPlaceholder: a2,
+ formatPlaceholder: [ a2 ],
};
const result = applyFormat( deepFreeze( record ), a2 );
diff --git a/packages/rich-text/src/test/change-list-type.js b/packages/rich-text/src/test/change-list-type.js
index 3817c66ba7977e..6294368c6427d2 100644
--- a/packages/rich-text/src/test/change-list-type.js
+++ b/packages/rich-text/src/test/change-list-type.js
@@ -17,7 +17,7 @@ describe( 'changeListType', () => {
it( 'should only change list type if list item is indented', () => {
const record = {
- formats: [ , ],
+ replacements: [ , ],
text: '1',
start: 1,
end: 1,
@@ -26,27 +26,25 @@ describe( 'changeListType', () => {
expect( result ).toEqual( record );
expect( result ).toBe( record );
- expect( getSparseArrayLength( result.formats ) ).toBe( 0 );
+ expect( getSparseArrayLength( result.replacements ) ).toBe( 0 );
} );
it( 'should change list type', () => {
const record = {
- formats: [ , [ ul ] ],
+ replacements: [ , [ ul ] ],
text: `1${ LINE_SEPARATOR }`,
start: 2,
end: 2,
};
const expected = {
- formats: [ , [ ol ] ],
- text: `1${ LINE_SEPARATOR }`,
- start: 2,
- end: 2,
+ ...record,
+ replacements: [ , [ ol ] ],
};
const result = changeListType( deepFreeze( record ), ol );
expect( result ).toEqual( expected );
expect( result ).not.toBe( record );
- expect( getSparseArrayLength( result.formats ) ).toBe( 1 );
+ expect( getSparseArrayLength( result.replacements ) ).toBe( 1 );
} );
it( 'should outdent with multiple lines selected', () => {
@@ -54,21 +52,19 @@ describe( 'changeListType', () => {
const text = `a${ LINE_SEPARATOR }1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }i${ LINE_SEPARATOR }3${ LINE_SEPARATOR }4${ LINE_SEPARATOR }b`;
const record = {
- formats: [ , [ ul ], , [ ul ], , [ ul, ul ], , [ ul ], , [ ul ], , , , [ ul ], , ],
+ replacements: [ , [ ul ], , [ ul ], , [ ul, ul ], , [ ul ], , [ ul ], , , , [ ul ], , ],
text,
start: 4,
end: 9,
};
const expected = {
- formats: [ , [ ol ], , [ ol ], , [ ol, ul ], , [ ol ], , [ ol ], , , , [ ul ], , ],
- text,
- start: 4,
- end: 9,
+ ...record,
+ replacements: [ , [ ol ], , [ ol ], , [ ol, ul ], , [ ol ], , [ ol ], , , , [ ul ], , ],
};
const result = changeListType( deepFreeze( record ), ol );
expect( result ).toEqual( expected );
expect( result ).not.toBe( record );
- expect( getSparseArrayLength( result.formats ) ).toBe( 6 );
+ expect( getSparseArrayLength( result.replacements ) ).toBe( 6 );
} );
} );
diff --git a/packages/rich-text/src/test/concat.js b/packages/rich-text/src/test/concat.js
index 9ac2aa2dc75569..ae8253e1a5461e 100644
--- a/packages/rich-text/src/test/concat.js
+++ b/packages/rich-text/src/test/concat.js
@@ -16,14 +16,17 @@ describe( 'concat', () => {
it( 'should merge records', () => {
const one = {
formats: [ , , [ em ] ],
+ replacements: [ , , , ],
text: 'one',
};
const two = {
formats: [ [ em ], , , ],
+ replacements: [ , , , ],
text: 'two',
};
const three = {
formats: [ , , [ em ], [ em ], , , ],
+ replacements: [ , , , , , , ],
text: 'onetwo',
};
diff --git a/packages/rich-text/src/test/create.js b/packages/rich-text/src/test/create.js
index 5128c55273d78a..b585d72ec66142 100644
--- a/packages/rich-text/src/test/create.js
+++ b/packages/rich-text/src/test/create.js
@@ -81,6 +81,7 @@ describe( 'create', () => {
expect( value ).toEqual( {
formats: [ [ em ], [ em ], [ em, strong ], [ em, strong ] ],
+ replacements: [ , , , , ],
text: 'test',
} );
diff --git a/packages/rich-text/src/test/get-active-object.js b/packages/rich-text/src/test/get-active-object.js
new file mode 100644
index 00000000000000..35d0f7637c7bc2
--- /dev/null
+++ b/packages/rich-text/src/test/get-active-object.js
@@ -0,0 +1,41 @@
+/**
+ * Internal dependencies
+ */
+
+import { getActiveObject } from '../get-active-object';
+import { OBJECT_REPLACEMENT_CHARACTER } from '../special-characters';
+
+describe( 'getActiveObject', () => {
+ it( 'should return object if selected', () => {
+ const record = {
+ replacements: [ { type: 'img' } ],
+ text: OBJECT_REPLACEMENT_CHARACTER,
+ start: 0,
+ end: 1,
+ };
+
+ expect( getActiveObject( record ) ).toEqual( { type: 'img' } );
+ } );
+
+ it( 'should return nothing if nothing is selected', () => {
+ const record = {
+ replacements: [ { type: 'img' } ],
+ text: OBJECT_REPLACEMENT_CHARACTER,
+ start: 0,
+ end: 0,
+ };
+
+ expect( getActiveObject( record ) ).toBe( undefined );
+ } );
+
+ it( 'should return nothing if te selection is not an object', () => {
+ const record = {
+ replacements: [ { type: 'em' } ],
+ text: 'a',
+ start: 0,
+ end: 1,
+ };
+
+ expect( getActiveObject( record ) ).toBe( undefined );
+ } );
+} );
diff --git a/packages/rich-text/src/test/get-last-child-index.js b/packages/rich-text/src/test/get-last-child-index.js
index 55c881d356555c..f59cec9eeeab1f 100644
--- a/packages/rich-text/src/test/get-last-child-index.js
+++ b/packages/rich-text/src/test/get-last-child-index.js
@@ -10,40 +10,40 @@ import deepFreeze from 'deep-freeze';
import { getLastChildIndex } from '../get-last-child-index';
import { LINE_SEPARATOR } from '../special-characters';
-describe( 'outdentListItems', () => {
+describe( 'getLastChildIndex', () => {
const ul = { type: 'ul' };
it( 'should return undefined if there is only one line', () => {
expect( getLastChildIndex( deepFreeze( {
- formats: [ , ],
+ replacements: [ , ],
text: '1',
} ), undefined ) ).toBe( undefined );
} );
it( 'should return the last line if no line is indented', () => {
expect( getLastChildIndex( deepFreeze( {
- formats: [ , ],
+ replacements: [ , ],
text: `1${ LINE_SEPARATOR }`,
} ), undefined ) ).toBe( 1 );
} );
it( 'should return the last child index', () => {
expect( getLastChildIndex( deepFreeze( {
- formats: [ , [ ul ], , [ ul ], , ],
+ replacements: [ , [ ul ], , [ ul ], , ],
text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`,
} ), undefined ) ).toBe( 3 );
} );
it( 'should return the last child index by sibling', () => {
expect( getLastChildIndex( deepFreeze( {
- formats: [ , [ ul ], , [ ul ], , ],
+ replacements: [ , [ ul ], , [ ul ], , ],
text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`,
} ), 1 ) ).toBe( 3 );
} );
it( 'should return the last child index (with further lower indented items)', () => {
expect( getLastChildIndex( deepFreeze( {
- formats: [ , [ ul ], , , , ],
+ replacements: [ , [ ul ], , , , ],
text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`,
} ), 1 ) ).toBe( 1 );
} );
diff --git a/packages/rich-text/src/test/get-parent-line-index.js b/packages/rich-text/src/test/get-parent-line-index.js
index 4e6a75ffd0a6e6..832ee4412dacc7 100644
--- a/packages/rich-text/src/test/get-parent-line-index.js
+++ b/packages/rich-text/src/test/get-parent-line-index.js
@@ -15,28 +15,28 @@ describe( 'getParentLineIndex', () => {
it( 'should return undefined if there is only one line', () => {
expect( getParentLineIndex( deepFreeze( {
- formats: [ , ],
+ replacements: [ , ],
text: '1',
} ), undefined ) ).toBe( undefined );
} );
it( 'should return undefined if the list is part of the first root list child', () => {
expect( getParentLineIndex( deepFreeze( {
- formats: [ , ],
+ replacements: [ , ],
text: `1${ LINE_SEPARATOR }2`,
} ), 2 ) ).toBe( undefined );
} );
it( 'should return the line index of the parent list (1)', () => {
expect( getParentLineIndex( deepFreeze( {
- formats: [ , , , [ ul ], , ],
+ replacements: [ , , , [ ul ], , ],
text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`,
} ), 3 ) ).toBe( 1 );
} );
it( 'should return the line index of the parent list (2)', () => {
expect( getParentLineIndex( deepFreeze( {
- formats: [ , [ ul ], , [ ul, ul ], , [ ul ], , ],
+ replacements: [ , [ ul ], , [ ul, ul ], , [ ul ], , ],
text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3${ LINE_SEPARATOR }4`,
} ), 5 ) ).toBe( undefined );
} );
diff --git a/packages/rich-text/src/test/helpers/index.js b/packages/rich-text/src/test/helpers/index.js
index 859e7e3acefc2e..16b09bb19b8326 100644
--- a/packages/rich-text/src/test/helpers/index.js
+++ b/packages/rich-text/src/test/helpers/index.js
@@ -4,7 +4,7 @@ export function getSparseArrayLength( array ) {
const em = { type: 'em' };
const strong = { type: 'strong' };
-const img = { type: 'img', attributes: { src: '' }, object: true };
+const img = { type: 'img', attributes: { src: '' } };
const a = { type: 'a', attributes: { href: '#' } };
const ul = { type: 'ul' };
const ol = { type: 'ol' };
@@ -25,6 +25,7 @@ export const spec = [
start: 0,
end: 0,
formats: [],
+ replacements: [],
text: '',
},
},
@@ -43,6 +44,7 @@ export const spec = [
start: 0,
end: 1,
formats: [ , ],
+ replacements: [ , ],
text: ' ',
},
},
@@ -61,6 +63,7 @@ export const spec = [
start: 5,
end: 5,
formats: [ , , , , , , , , , , ],
+ replacements: [ , , , , , , , , , , ],
text: 'test\u00a0 test',
},
},
@@ -79,6 +82,7 @@ export const spec = [
start: 0,
end: 0,
formats: [],
+ replacements: [],
text: '',
},
},
@@ -97,6 +101,7 @@ export const spec = [
start: 0,
end: 4,
formats: [ , , , , ],
+ replacements: [ , , , , ],
text: 'test',
},
},
@@ -115,6 +120,7 @@ export const spec = [
start: 0,
end: 2,
formats: [ , , ],
+ replacements: [ , , ],
text: '🍒',
},
},
@@ -133,6 +139,7 @@ export const spec = [
start: 0,
end: 2,
formats: [ [ em ], [ em ] ],
+ replacements: [ , , ],
text: '🍒',
},
},
@@ -151,6 +158,7 @@ export const spec = [
start: 0,
end: 4,
formats: [ [ em ], [ em ], [ em ], [ em ] ],
+ replacements: [ , , , , ],
text: 'test',
},
},
@@ -169,6 +177,7 @@ export const spec = [
start: 0,
end: 4,
formats: [ [ em, strong ], [ em, strong ], [ em, strong ], [ em, strong ] ],
+ replacements: [ , , , , ],
text: 'test',
},
},
@@ -187,6 +196,7 @@ export const spec = [
start: 0,
end: 2,
formats: [ [ em ], [ em ], [ em ], [ em ] ],
+ replacements: [ , , , , ],
text: 'test',
},
},
@@ -205,6 +215,7 @@ export const spec = [
start: 0,
end: 4,
formats: [ [ a ], [ a ], [ a ], [ a ] ],
+ replacements: [ , , , , ],
text: 'test',
},
},
@@ -217,12 +228,13 @@ export const spec = [
endOffset: 1,
endContainer: element,
} ),
- startPath: [ 1, 0 ],
- endPath: [ 1, 0 ],
+ startPath: [ 0, 0 ],
+ endPath: [ 0, 0 ],
record: {
start: 0,
end: 0,
- formats: [ [ img ] ],
+ formats: [ , ],
+ replacements: [ img ],
text: '\ufffc',
},
},
@@ -235,12 +247,13 @@ export const spec = [
endOffset: 1,
endContainer: element.querySelector( 'img' ),
} ),
- startPath: [ 0, 1, 0 ],
- endPath: [ 0, 1, 0 ],
+ startPath: [ 0, 0, 0 ],
+ endPath: [ 0, 2, 0 ],
record: {
start: 0,
end: 1,
- formats: [ [ em, img ] ],
+ formats: [ [ em ] ],
+ replacements: [ img ],
text: '\ufffc',
},
},
@@ -258,7 +271,8 @@ export const spec = [
record: {
start: 0,
end: 5,
- formats: [ , , [ em ], [ em ], [ em, img ] ],
+ formats: [ , , [ em ], [ em ], [ em ] ],
+ replacements: [ , , , , img ],
text: 'test\ufffc',
},
},
@@ -271,12 +285,13 @@ export const spec = [
endOffset: 2,
endContainer: element,
} ),
- startPath: [ 0, 1, 0 ],
+ startPath: [ 0, 0, 0 ],
endPath: [ 1, 2 ],
record: {
start: 0,
end: 5,
- formats: [ [ em, img ], [ em ], [ em ], , , ],
+ formats: [ [ em ], [ em ], [ em ], , , ],
+ replacements: [ img, , , , , ],
text: '\ufffctest',
},
},
@@ -295,6 +310,7 @@ export const spec = [
start: 0,
end: 0,
formats: [ , ],
+ replacements: [ , ],
text: '\n',
},
},
@@ -313,6 +329,7 @@ export const spec = [
start: 2,
end: 3,
formats: [ , , , , , ],
+ replacements: [ , , , , , ],
text: 'te\nst',
},
},
@@ -331,6 +348,7 @@ export const spec = [
start: 0,
end: 1,
formats: [ [ em ] ],
+ replacements: [ , ],
text: '\n',
},
},
@@ -347,6 +365,7 @@ export const spec = [
endPath: [ 4, 0 ],
record: {
formats: [ , , , , ],
+ replacements: [ , , , , ],
text: 'a\n\nb',
start: 2,
end: 3,
@@ -365,6 +384,7 @@ export const spec = [
endPath: [ 2, 0 ],
record: {
formats: [ , , , , ],
+ replacements: [ , , , , ],
text: 'a\n\nb',
start: 2,
end: 2,
@@ -386,6 +406,7 @@ export const spec = [
start: 0,
end: 0,
formats: [],
+ replacements: [],
text: '',
},
},
@@ -405,6 +426,7 @@ export const spec = [
start: 1,
end: 4,
formats: [ , , , , , , , ],
+ replacements: [ , , , , , , , ],
text: 'one\u2028two',
},
},
@@ -424,7 +446,8 @@ export const spec = [
record: {
start: 0,
end: 9,
- formats: [ , , , [ ul ], , [ ul ], , [ ul, ol ], , [ ul, ol ], , , , , , , , ],
+ formats: [ , , , , , , , , , , , , , , , , , ],
+ replacements: [ , , , [ ul ], , [ ul ], , [ ul, ol ], , [ ul, ol ], , , , , , , , ],
text: 'one\u2028a\u2028b\u20281\u20282\u2028three',
},
},
@@ -445,6 +468,7 @@ export const spec = [
start: 0,
end: 0,
formats: [],
+ replacements: [],
text: '',
},
},
@@ -464,7 +488,8 @@ export const spec = [
record: {
start: 1,
end: 1,
- formats: [ [ ul ] ],
+ formats: [ , ],
+ replacements: [ [ ul ] ],
text: '\u2028',
},
},
@@ -485,6 +510,7 @@ export const spec = [
start: 1,
end: 1,
formats: [ , , ],
+ replacements: [ , , ],
text: '\u2028\u2028',
},
},
@@ -504,6 +530,7 @@ export const spec = [
start: 4,
end: 4,
formats: [ , , , , ],
+ replacements: [ , , , , ],
text: 'one\u2028',
},
},
@@ -524,6 +551,7 @@ export const spec = [
start: 3,
end: 3,
formats: [ , , , ],
+ replacements: [ , , , ],
text: 'one',
},
},
@@ -534,6 +562,7 @@ export const spec = [
endPath: [],
record: {
formats: [ [ em ], [ em ], [ em ], [ em ], [ em ], [ em ], [ em ] ],
+ replacements: [ , , , , , , , ],
text: 'one\u2028two',
},
},
@@ -552,6 +581,7 @@ export const spec = [
start: 0,
end: 0,
formats: [],
+ replacements: [],
text: '',
},
},
@@ -570,6 +600,7 @@ export const spec = [
start: 0,
end: 4,
formats: [ [ strong ], [ strong ], [ strong ], [ strong ] ],
+ replacements: [ , , , , ],
text: 'test',
},
},
@@ -592,6 +623,7 @@ export const specWithRegistration = [
attributes: {},
unregisteredAttributes: {},
} ] ],
+ replacements: [ , ],
text: 'a',
},
},
@@ -613,6 +645,7 @@ export const specWithRegistration = [
class: 'test',
},
} ] ],
+ replacements: [ , ],
text: 'a',
},
},
@@ -634,6 +667,7 @@ export const specWithRegistration = [
class: 'custom-format',
},
} ] ],
+ replacements: [ , ],
text: 'a',
},
},
@@ -647,6 +681,7 @@ export const specWithRegistration = [
class: 'custom-format',
},
} ] ],
+ replacements: [ , ],
text: 'a',
},
},
@@ -663,6 +698,7 @@ export const specWithRegistration = [
html: 'a',
value: {
formats: [ , ],
+ replacements: [ , ],
text: 'a',
},
noToHTMLString: true,
@@ -685,6 +721,7 @@ export const specWithRegistration = [
attributes: {},
unregisteredAttributes: {},
} ] ],
+ replacements: [ , ],
text: 'a',
},
},
diff --git a/packages/rich-text/src/test/indent-list-items.js b/packages/rich-text/src/test/indent-list-items.js
index e7f631e5fa8f94..349174247cc422 100644
--- a/packages/rich-text/src/test/indent-list-items.js
+++ b/packages/rich-text/src/test/indent-list-items.js
@@ -17,7 +17,7 @@ describe( 'indentListItems', () => {
it( 'should not indent only item', () => {
const record = {
- formats: [ , ],
+ replacements: [ , ],
text: '1',
start: 1,
end: 1,
@@ -26,34 +26,32 @@ describe( 'indentListItems', () => {
expect( result ).toEqual( record );
expect( result ).toBe( record );
- expect( getSparseArrayLength( result.formats ) ).toBe( 0 );
+ expect( getSparseArrayLength( result.replacements ) ).toBe( 0 );
} );
it( 'should indent', () => {
// As we're testing list formats, the text should remain the same.
const text = `1${ LINE_SEPARATOR }`;
const record = {
- formats: [ , , ],
+ replacements: [ , , ],
text,
start: 2,
end: 2,
};
const expected = {
- formats: [ , [ ul ] ],
- text,
- start: 2,
- end: 2,
+ ...record,
+ replacements: [ , [ ul ] ],
};
const result = indentListItems( deepFreeze( record ), ul );
expect( result ).toEqual( expected );
expect( result ).not.toBe( record );
- expect( getSparseArrayLength( result.formats ) ).toBe( 1 );
+ expect( getSparseArrayLength( result.replacements ) ).toBe( 1 );
} );
it( 'should not indent without target list', () => {
const record = {
- formats: [ , [ ul ] ],
+ replacements: [ , [ ul ] ],
text: `1${ LINE_SEPARATOR }`,
start: 2,
end: 2,
@@ -62,80 +60,74 @@ describe( 'indentListItems', () => {
expect( result ).toEqual( record );
expect( result ).toBe( record );
- expect( getSparseArrayLength( result.formats ) ).toBe( 1 );
+ expect( getSparseArrayLength( result.replacements ) ).toBe( 1 );
} );
it( 'should indent and merge with previous list', () => {
// As we're testing list formats, the text should remain the same.
const text = `1${ LINE_SEPARATOR }${ LINE_SEPARATOR }`;
const record = {
- formats: [ , [ ol ], , ],
+ replacements: [ , [ ol ], , ],
text,
start: 3,
end: 3,
};
const expected = {
- formats: [ , [ ol ], [ ol ] ],
- text,
- start: 3,
- end: 3,
+ ...record,
+ replacements: [ , [ ol ], [ ol ] ],
};
const result = indentListItems( deepFreeze( record ), ul );
expect( result ).toEqual( expected );
expect( result ).not.toBe( record );
- expect( getSparseArrayLength( result.formats ) ).toBe( 2 );
+ expect( getSparseArrayLength( result.replacements ) ).toBe( 2 );
} );
it( 'should indent already indented item', () => {
// As we're testing list formats, the text should remain the same.
const text = `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`;
const record = {
- formats: [ , [ ul ], , [ ul ], , ],
+ replacements: [ , [ ul ], , [ ul ], , ],
text,
start: 5,
end: 5,
};
const expected = {
- formats: [ , [ ul ], , [ ul, ul ], , ],
- text,
- start: 5,
- end: 5,
+ ...record,
+ replacements: [ , [ ul ], , [ ul, ul ], , ],
};
const result = indentListItems( deepFreeze( record ), ul );
expect( result ).toEqual( expected );
expect( result ).not.toBe( record );
- expect( getSparseArrayLength( result.formats ) ).toBe( 2 );
+ expect( getSparseArrayLength( result.replacements ) ).toBe( 2 );
} );
it( 'should indent with multiple lines selected', () => {
// As we're testing list formats, the text should remain the same.
const text = `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`;
const record = {
- formats: [ , , , [ ul ], , ],
+ replacements: [ , , , [ ul ], , ],
text,
start: 2,
end: 5,
};
const expected = {
- formats: [ , [ ul ], , [ ul, ul ], , ],
- text,
- start: 2,
- end: 5,
+ ...record,
+ replacements: [ , [ ul ], , [ ul, ul ], , ],
};
const result = indentListItems( deepFreeze( record ), ul );
expect( result ).toEqual( expected );
expect( result ).not.toBe( record );
- expect( getSparseArrayLength( result.formats ) ).toBe( 2 );
+ expect( getSparseArrayLength( result.replacements ) ).toBe( 2 );
} );
it( 'should indent one level at a time', () => {
// As we're testing list formats, the text should remain the same.
const text = `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3${ LINE_SEPARATOR }4`;
const record = {
- formats: [ , [ ul ], , [ ul, ul ], , , , ],
+ replacements: [ , [ ul ], , [ ul, ul ], , , , ],
text,
start: 6,
end: 6,
@@ -144,34 +136,28 @@ describe( 'indentListItems', () => {
const result1 = indentListItems( deepFreeze( record ), ul );
expect( result1 ).not.toBe( record );
- expect( getSparseArrayLength( result1.formats ) ).toBe( 3 );
+ expect( getSparseArrayLength( result1.replacements ) ).toBe( 3 );
expect( result1 ).toEqual( {
- formats: [ , [ ul ], , [ ul, ul ], , [ ul ], , ],
- text,
- start: 6,
- end: 6,
+ ...record,
+ replacements: [ , [ ul ], , [ ul, ul ], , [ ul ], , ],
} );
const result2 = indentListItems( deepFreeze( result1 ), ul );
expect( result2 ).not.toBe( result1 );
- expect( getSparseArrayLength( result2.formats ) ).toBe( 3 );
+ expect( getSparseArrayLength( result2.replacements ) ).toBe( 3 );
expect( result2 ).toEqual( {
- formats: [ , [ ul ], , [ ul, ul ], , [ ul, ul ], , ],
- text,
- start: 6,
- end: 6,
+ ...record,
+ replacements: [ , [ ul ], , [ ul, ul ], , [ ul, ul ], , ],
} );
const result3 = indentListItems( deepFreeze( result2 ), ul );
expect( result3 ).not.toBe( result2 );
- expect( getSparseArrayLength( result3.formats ) ).toBe( 3 );
+ expect( getSparseArrayLength( result3.replacements ) ).toBe( 3 );
expect( result3 ).toEqual( {
- formats: [ , [ ul ], , [ ul, ul ], , [ ul, ul, ul ], , ],
- text,
- start: 6,
- end: 6,
+ ...record,
+ replacements: [ , [ ul ], , [ ul, ul ], , [ ul, ul, ul ], , ],
} );
} );
} );
diff --git a/packages/rich-text/src/test/insert-line-separator.js b/packages/rich-text/src/test/insert-line-separator.js
index 398b0a2b8834f3..497555cc4a01a0 100644
--- a/packages/rich-text/src/test/insert-line-separator.js
+++ b/packages/rich-text/src/test/insert-line-separator.js
@@ -17,12 +17,14 @@ describe( 'insertLineSeparator', () => {
it( 'should insert line separator at end', () => {
const value = {
formats: [ , ],
+ replacements: [ , ],
text: '1',
start: 1,
end: 1,
};
const expected = {
formats: [ , , ],
+ replacements: [ , , ],
text: `1${ LINE_SEPARATOR }`,
start: 2,
end: 2,
@@ -31,18 +33,20 @@ describe( 'insertLineSeparator', () => {
expect( result ).not.toBe( value );
expect( result ).toEqual( expected );
- expect( getSparseArrayLength( result.formats ) ).toBe( 0 );
+ expect( getSparseArrayLength( result.replacements ) ).toBe( 0 );
} );
it( 'should insert line separator at start', () => {
const value = {
formats: [ , ],
+ replacements: [ , ],
text: '1',
start: 0,
end: 0,
};
const expected = {
formats: [ , , ],
+ replacements: [ , , ],
text: `${ LINE_SEPARATOR }1`,
start: 1,
end: 1,
@@ -51,18 +55,20 @@ describe( 'insertLineSeparator', () => {
expect( result ).not.toBe( value );
expect( result ).toEqual( expected );
- expect( getSparseArrayLength( result.formats ) ).toBe( 0 );
+ expect( getSparseArrayLength( result.replacements ) ).toBe( 0 );
} );
it( 'should insert line separator with previous line separator formats', () => {
const value = {
- formats: [ , , , [ ol ], , ],
+ formats: [ , , , , , ],
+ replacements: [ , , , [ ol ], , ],
text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }a`,
start: 5,
end: 5,
};
const expected = {
- formats: [ , , , [ ol ], , [ ol ] ],
+ formats: [ , , , , , , ],
+ replacements: [ , , , [ ol ], , [ ol ] ],
text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }a${ LINE_SEPARATOR }`,
start: 6,
end: 6,
@@ -71,18 +77,20 @@ describe( 'insertLineSeparator', () => {
expect( result ).not.toBe( value );
expect( result ).toEqual( expected );
- expect( getSparseArrayLength( result.formats ) ).toBe( 2 );
+ expect( getSparseArrayLength( result.replacements ) ).toBe( 2 );
} );
it( 'should insert line separator without formats if previous line separator did not have any', () => {
const value = {
formats: [ , , , , , ],
+ replacements: [ , , , , , ],
text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }a`,
start: 5,
end: 5,
};
const expected = {
formats: [ , , , , , , ],
+ replacements: [ , , , , , , ],
text: `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }a${ LINE_SEPARATOR }`,
start: 6,
end: 6,
@@ -91,6 +99,6 @@ describe( 'insertLineSeparator', () => {
expect( result ).not.toBe( value );
expect( result ).toEqual( expected );
- expect( getSparseArrayLength( result.formats ) ).toBe( 0 );
+ expect( getSparseArrayLength( result.replacements ) ).toBe( 0 );
} );
} );
diff --git a/packages/rich-text/src/test/insert-object.js b/packages/rich-text/src/test/insert-object.js
index 15680372986a9d..7c2ba57806ad03 100644
--- a/packages/rich-text/src/test/insert-object.js
+++ b/packages/rich-text/src/test/insert-object.js
@@ -17,12 +17,14 @@ describe( 'insert', () => {
it( 'should delete and insert', () => {
const record = {
formats: [ , , , , [ em ], [ em ], [ em ], , , , , , , ],
+ replacements: [ , , , , , , , , , , , , , ],
text: 'one two three',
start: 6,
end: 6,
};
const expected = {
- formats: [ , , [ { ...obj, object: true } ], [ em ], , , , , , , ],
+ formats: [ , , , [ em ], , , , , , , ],
+ replacements: [ , , obj, , , , , , , , ],
text: `on${ OBJECT_REPLACEMENT_CHARACTER }o three`,
start: 3,
end: 3,
@@ -31,6 +33,7 @@ describe( 'insert', () => {
expect( result ).toEqual( expected );
expect( result ).not.toBe( record );
- expect( getSparseArrayLength( result.formats ) ).toBe( 2 );
+ expect( getSparseArrayLength( result.formats ) ).toBe( 1 );
+ expect( getSparseArrayLength( result.replacements ) ).toBe( 1 );
} );
} );
diff --git a/packages/rich-text/src/test/insert.js b/packages/rich-text/src/test/insert.js
index 64de9f44828a23..cae4cc5b85d5f5 100644
--- a/packages/rich-text/src/test/insert.js
+++ b/packages/rich-text/src/test/insert.js
@@ -17,16 +17,19 @@ describe( 'insert', () => {
it( 'should delete and insert', () => {
const record = {
formats: [ , , , , [ em ], [ em ], [ em ], , , , , , , ],
+ replacements: [],
text: 'one two three',
start: 6,
end: 6,
};
const toInsert = {
formats: [ [ strong ] ],
+ replacements: [],
text: 'a',
};
const expected = {
formats: [ , , [ strong ], [ em ], , , , , , , ],
+ replacements: [],
text: 'onao three',
start: 3,
end: 3,
@@ -41,16 +44,19 @@ describe( 'insert', () => {
it( 'should insert line break with selection', () => {
const record = {
formats: [ , , ],
+ replacements: [],
text: 'tt',
start: 1,
end: 1,
};
const toInsert = {
formats: [ , ],
+ replacements: [],
text: '\n',
};
const expected = {
formats: [ , , , ],
+ replacements: [],
text: 't\nt',
start: 2,
end: 2,
diff --git a/packages/rich-text/src/test/join.js b/packages/rich-text/src/test/join.js
index fb2f20b1b2784e..84801125cc2b0a 100644
--- a/packages/rich-text/src/test/join.js
+++ b/packages/rich-text/src/test/join.js
@@ -15,8 +15,9 @@ describe( 'join', () => {
const separators = [
' ',
{
- text: ' ',
formats: [ , ],
+ replacements: [ , ],
+ text: ' ',
},
];
@@ -24,14 +25,17 @@ describe( 'join', () => {
it( 'should join records with string separator', () => {
const one = {
formats: [ , , [ em ] ],
+ replacements: [ , , , ],
text: 'one',
};
const two = {
formats: [ [ em ], , , ],
+ replacements: [ , , , ],
text: 'two',
};
const three = {
formats: [ , , [ em ], , [ em ], , , ],
+ replacements: [ , , , , , , , ],
text: 'one two',
};
const result = join( [ deepFreeze( one ), deepFreeze( two ) ], separator );
diff --git a/packages/rich-text/src/test/outdent-list-items.js b/packages/rich-text/src/test/outdent-list-items.js
index c2bf8b30e4766b..e4325dfb61c904 100644
--- a/packages/rich-text/src/test/outdent-list-items.js
+++ b/packages/rich-text/src/test/outdent-list-items.js
@@ -16,7 +16,7 @@ describe( 'outdentListItems', () => {
it( 'should not outdent only item', () => {
const record = {
- formats: [ , ],
+ replacements: [ , ],
text: '1',
start: 1,
end: 1,
@@ -25,138 +25,126 @@ describe( 'outdentListItems', () => {
expect( result ).toEqual( record );
expect( result ).toBe( record );
- expect( getSparseArrayLength( result.formats ) ).toBe( 0 );
+ expect( getSparseArrayLength( result.replacements ) ).toBe( 0 );
} );
it( 'should indent', () => {
// As we're testing list formats, the text should remain the same.
const text = `1${ LINE_SEPARATOR }`;
const record = {
- formats: [ , [ ul ] ],
+ replacements: [ , [ ul ] ],
text,
start: 2,
end: 2,
};
const expected = {
- formats: [ , , ],
- text,
- start: 2,
- end: 2,
+ ...record,
+ replacements: [ , , ],
};
const result = outdentListItems( deepFreeze( record ) );
expect( result ).toEqual( expected );
expect( result ).not.toBe( record );
- expect( getSparseArrayLength( result.formats ) ).toBe( 0 );
+ expect( getSparseArrayLength( result.replacements ) ).toBe( 0 );
} );
it( 'should outdent two levels deep', () => {
// As we're testing list formats, the text should remain the same.
const text = `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`;
const record = {
- formats: [ , [ ul ], , [ ul, ul ], , ],
+ replacements: [ , [ ul ], , [ ul, ul ], , ],
text,
start: 5,
end: 5,
};
const expected = {
- formats: [ , [ ul ], , [ ul ], , ],
- text,
- start: 5,
- end: 5,
+ ...record,
+ replacements: [ , [ ul ], , [ ul ], , ],
};
const result = outdentListItems( deepFreeze( record ) );
expect( result ).toEqual( expected );
expect( result ).not.toBe( record );
- expect( getSparseArrayLength( result.formats ) ).toBe( 2 );
+ expect( getSparseArrayLength( result.replacements ) ).toBe( 2 );
} );
it( 'should outdent with multiple lines selected', () => {
// As we're testing list formats, the text should remain the same.
const text = `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`;
const record = {
- formats: [ , [ ul ], , [ ul, ul ], , ],
+ replacements: [ , [ ul ], , [ ul, ul ], , ],
text,
start: 2,
end: 5,
};
const expected = {
- formats: [ , , , [ ul ], , ],
- text,
- start: 2,
- end: 5,
+ ...record,
+ replacements: [ , , , [ ul ], , ],
};
const result = outdentListItems( deepFreeze( record ) );
expect( result ).toEqual( expected );
expect( result ).not.toBe( record );
- expect( getSparseArrayLength( result.formats ) ).toBe( 1 );
+ expect( getSparseArrayLength( result.replacements ) ).toBe( 1 );
} );
it( 'should outdent list item with children', () => {
// As we're testing list formats, the text should remain the same.
const text = `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3${ LINE_SEPARATOR }4`;
const record = {
- formats: [ , [ ul ], , [ ul, ul ], , [ ul, ul ], , ],
+ replacements: [ , [ ul ], , [ ul, ul ], , [ ul, ul ], , ],
text,
start: 2,
end: 2,
};
const expected = {
- formats: [ , , , [ ul ], , [ ul ], , ],
- text,
- start: 2,
- end: 2,
+ ...record,
+ replacements: [ , , , [ ul ], , [ ul ], , ],
};
const result = outdentListItems( deepFreeze( record ) );
expect( result ).toEqual( expected );
expect( result ).not.toBe( record );
- expect( getSparseArrayLength( result.formats ) ).toBe( 2 );
+ expect( getSparseArrayLength( result.replacements ) ).toBe( 2 );
} );
it( 'should outdent list based on parent list', () => {
// As we're testing list formats, the text should remain the same.
const text = `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3${ LINE_SEPARATOR }4`;
const record = {
- formats: [ , [ ul ], , [ ul, ul ], , [ ul ], , ],
+ replacements: [ , [ ul ], , [ ul, ul ], , [ ul ], , ],
text,
start: 6,
end: 6,
};
const expected = {
- formats: [ , [ ul ], , [ ul, ul ], , , , ],
- text,
- start: 6,
- end: 6,
+ ...record,
+ replacements: [ , [ ul ], , [ ul, ul ], , , , ],
};
const result = outdentListItems( deepFreeze( record ) );
expect( result ).toEqual( expected );
expect( result ).not.toBe( record );
- expect( getSparseArrayLength( result.formats ) ).toBe( 2 );
+ expect( getSparseArrayLength( result.replacements ) ).toBe( 2 );
} );
it( 'should outdent when a selected item is at level 0', () => {
// As we're testing list formats, the text should remain the same.
const text = `1${ LINE_SEPARATOR }2${ LINE_SEPARATOR }3`;
const record = {
- formats: [ , [ ul ], , , , ],
+ replacements: [ , [ ul ], , , , ],
text,
start: 2,
end: 5,
};
const expected = {
- formats: [ , , , , , ],
- text,
- start: 2,
- end: 5,
+ ...record,
+ replacements: [ , , , , , ],
};
const result = outdentListItems( deepFreeze( record ) );
expect( result ).toEqual( expected );
expect( result ).not.toBe( record );
- expect( getSparseArrayLength( result.formats ) ).toBe( 0 );
+ expect( getSparseArrayLength( result.replacements ) ).toBe( 0 );
} );
} );
diff --git a/packages/rich-text/src/test/replace.js b/packages/rich-text/src/test/replace.js
index f3c7d9aa923e9f..6cfd4dcc9e48b7 100644
--- a/packages/rich-text/src/test/replace.js
+++ b/packages/rich-text/src/test/replace.js
@@ -16,12 +16,14 @@ describe( 'replace', () => {
it( 'should replace string to string', () => {
const record = {
formats: [ , , , , [ em ], [ em ], [ em ], , , , , , , ],
+ replacements: [ , , , , , , , , , , , , , ],
text: 'one two three',
start: 6,
end: 6,
};
const expected = {
formats: [ , , , , [ em ], , , , , , , ],
+ replacements: [ , , , , , , , , , , , ],
text: 'one 2 three',
start: 5,
end: 5,
@@ -36,16 +38,19 @@ describe( 'replace', () => {
it( 'should replace string to record', () => {
const record = {
formats: [ , , , , [ em ], [ em ], [ em ], , , , , , , ],
+ replacements: [ , , , , , , , , , , , , , ],
text: 'one two three',
start: 6,
end: 6,
};
const replacement = {
formats: [ , ],
+ replacements: [ , ],
text: '2',
};
const expected = {
formats: [ , , , , , , , , , , , ],
+ replacements: [ , , , , , , , , , , , ],
text: 'one 2 three',
start: 5,
end: 5,
@@ -60,12 +65,14 @@ describe( 'replace', () => {
it( 'should replace string to function', () => {
const record = {
formats: [ , , , , , , , , , , , , ],
+ replacements: [ , , , , , , , , , , , , ],
text: 'abc12345#$*%',
start: 6,
end: 6,
};
const expected = {
formats: [ , , , , , , , , , , , , , , , , , , ],
+ replacements: [ , , , , , , , , , , , , , , , , , , ],
text: 'abc - 12345 - #$*%',
start: 18,
end: 18,
diff --git a/packages/rich-text/src/test/slice.js b/packages/rich-text/src/test/slice.js
index 9d40f7a6de0377..b181e5e9be8171 100644
--- a/packages/rich-text/src/test/slice.js
+++ b/packages/rich-text/src/test/slice.js
@@ -16,10 +16,12 @@ describe( 'slice', () => {
it( 'should slice', () => {
const record = {
formats: [ , , , , [ em ], [ em ], [ em ], , , , , , , ],
+ replacements: [ , , , , , , , , , , , , , ],
text: 'one two three',
};
const expected = {
formats: [ , [ em ], [ em ] ],
+ replacements: [ , , , ],
text: ' tw',
};
const result = slice( deepFreeze( record ), 3, 6 );
@@ -32,12 +34,14 @@ describe( 'slice', () => {
it( 'should slice record', () => {
const record = {
formats: [ , , , , [ em ], [ em ], [ em ], , , , , , , ],
+ replacements: [ , , , , , , , , , , , , , ],
text: 'one two three',
start: 3,
end: 6,
};
const expected = {
formats: [ , [ em ], [ em ] ],
+ replacements: [ , , , ],
text: ' tw',
};
const result = slice( deepFreeze( record ) );
diff --git a/packages/rich-text/src/test/split.js b/packages/rich-text/src/test/split.js
index 1cdfbae9630d23..8eef998e488d6e 100644
--- a/packages/rich-text/src/test/split.js
+++ b/packages/rich-text/src/test/split.js
@@ -18,17 +18,20 @@ describe( 'split', () => {
start: 5,
end: 10,
formats: [ , , , , [ em ], [ em ], [ em ], , , , , , , ],
+ replacements: [ , , , , , , , , , , , , , ],
text: 'one two three',
};
const expected = [
{
formats: [ , , , , [ em ], [ em ] ],
+ replacements: [ , , , , , , ],
text: 'one tw',
},
{
start: 0,
end: 0,
formats: [ [ em ], , , , , , , ],
+ replacements: [ , , , , , , , ],
text: 'o three',
},
];
@@ -45,6 +48,7 @@ describe( 'split', () => {
it( 'should split with selection', () => {
const record = {
formats: [ , , , , [ em ], [ em ], [ em ], , , , , , , ],
+ replacements: [ , , , , , , , , , , , , , ],
text: 'one two three',
start: 6,
end: 6,
@@ -52,10 +56,12 @@ describe( 'split', () => {
const expected = [
{
formats: [ , , , , [ em ], [ em ] ],
+ replacements: [ , , , , , , ],
text: 'one tw',
},
{
formats: [ [ em ], , , , , , , ],
+ replacements: [ , , , , , , , ],
text: 'o three',
start: 0,
end: 0,
@@ -74,6 +80,7 @@ describe( 'split', () => {
it( 'should split empty', () => {
const record = {
formats: [],
+ replacements: [],
text: '',
start: 0,
end: 0,
@@ -81,10 +88,12 @@ describe( 'split', () => {
const expected = [
{
formats: [],
+ replacements: [],
text: '',
},
{
formats: [],
+ replacements: [],
text: '',
start: 0,
end: 0,
@@ -103,6 +112,7 @@ describe( 'split', () => {
it( 'should split multiline', () => {
const record = {
formats: [ , , , , , , , , , , ],
+ replacements: [ , , , , , , , , , , ],
text: 'test\u2028\u2028test',
start: 5,
end: 5,
@@ -110,10 +120,12 @@ describe( 'split', () => {
const expected = [
{
formats: [ , , , , ],
+ replacements: [ , , , , ],
text: 'test',
},
{
formats: [ , , , , ],
+ replacements: [ , , , , ],
text: 'test',
start: 0,
end: 0,
@@ -134,33 +146,39 @@ describe( 'split', () => {
start: 6,
end: 16,
formats: [ , , , , [ em ], [ em ], [ em ], , , , , , , , , , , , , , , , , ],
+ replacements: [ , , , , , , , , , , , , , , , , , , , , , , , ],
text: 'one two three four five',
};
const expected = [
{
formats: [ , , , ],
+ replacements: [ , , , ],
text: 'one',
},
{
start: 2,
end: 3,
formats: [ [ em ], [ em ], [ em ] ],
+ replacements: [ , , , ],
text: 'two',
},
{
start: 0,
end: 5,
formats: [ , , , , , ],
+ replacements: [ , , , , , ],
text: 'three',
},
{
start: 0,
end: 2,
formats: [ , , , , ],
+ replacements: [ , , , , ],
text: 'four',
},
{
formats: [ , , , , ],
+ replacements: [ , , , , ],
text: 'five',
},
];
@@ -179,21 +197,25 @@ describe( 'split', () => {
start: 5,
end: 6,
formats: [ , , , , [ em ], [ em ], [ em ], , , , , , , ],
+ replacements: [ , , , , , , , , , , , , , ],
text: 'one two three',
};
const expected = [
{
formats: [ , , , ],
+ replacements: [ , , , ],
text: 'one',
},
{
start: 1,
end: 2,
formats: [ [ em ], [ em ], [ em ] ],
+ replacements: [ , , , ],
text: 'two',
},
{
formats: [ , , , , , ],
+ replacements: [ , , , , , ],
text: 'three',
},
];
diff --git a/packages/rich-text/src/test/to-dom.js b/packages/rich-text/src/test/to-dom.js
index 1df1e8e25b229a..8db8a52e1b4435 100644
--- a/packages/rich-text/src/test/to-dom.js
+++ b/packages/rich-text/src/test/to-dom.js
@@ -24,7 +24,6 @@ describe( 'recordToDom', () => {
spec.forEach( ( {
description,
multilineTag,
- multilineWrapperTags,
record,
startPath,
endPath,
@@ -33,7 +32,6 @@ describe( 'recordToDom', () => {
const { body, selection } = toDom( {
value: record,
multilineTag,
- multilineWrapperTags,
} );
expect( body ).toMatchSnapshot();
expect( selection ).toEqual( { startPath, endPath } );
diff --git a/packages/rich-text/src/to-dom.js b/packages/rich-text/src/to-dom.js
index b81c5184684440..9ebe8365a25bab 100644
--- a/packages/rich-text/src/to-dom.js
+++ b/packages/rich-text/src/to-dom.js
@@ -122,7 +122,6 @@ function prepareFormats( prepareEditableTree = [], value ) {
export function toDom( {
value,
multilineTag,
- multilineWrapperTags,
prepareEditableTree,
isEditableTree = true,
} ) {
@@ -135,7 +134,6 @@ export function toDom( {
formats: prepareFormats( prepareEditableTree, value ),
},
multilineTag,
- multilineWrapperTags,
createEmpty,
append,
getLastChild,
@@ -174,7 +172,6 @@ export function apply( {
value,
current,
multilineTag,
- multilineWrapperTags,
prepareEditableTree,
__unstableDomOnly,
} ) {
@@ -182,7 +179,6 @@ export function apply( {
const { body, selection } = toDom( {
value,
multilineTag,
- multilineWrapperTags,
prepareEditableTree,
} );
diff --git a/packages/rich-text/src/to-html-string.js b/packages/rich-text/src/to-html-string.js
index 0ba36e62510a35..bf6c60fda0442d 100644
--- a/packages/rich-text/src/to-html-string.js
+++ b/packages/rich-text/src/to-html-string.js
@@ -21,16 +21,13 @@ import { toTree } from './to-tree';
* @param {Object} $1 Named argements.
* @param {Object} $1.value Rich text value.
* @param {string} [$1.multilineTag] Multiline tag.
- * @param {Array} [$1.multilineWrapperTags] Tags where lines can be found if
- * nesting is possible.
*
* @return {string} HTML string.
*/
-export function toHTMLString( { value, multilineTag, multilineWrapperTags } ) {
+export function toHTMLString( { value, multilineTag } ) {
const tree = toTree( {
value,
multilineTag,
- multilineWrapperTags,
createEmpty,
append,
getLastChild,
diff --git a/packages/rich-text/src/to-tree.js b/packages/rich-text/src/to-tree.js
index c89bdc94a2d061..ef15fe7524b6ea 100644
--- a/packages/rich-text/src/to-tree.js
+++ b/packages/rich-text/src/to-tree.js
@@ -91,7 +91,6 @@ const padding = {
export function toTree( {
value,
multilineTag,
- multilineWrapperTags = [],
createEmpty,
append,
getLastChild,
@@ -104,7 +103,7 @@ export function toTree( {
onEndIndex,
isEditableTree,
} ) {
- const { formats, text, start, end } = value;
+ const { formats, replacements, text, start, end } = value;
const formatsLength = formats.length + 1;
const tree = createEmpty();
const multilineFormat = { type: multilineTag };
@@ -138,12 +137,8 @@ export function toTree( {
// Set multiline tags in queue for building the tree.
if ( multilineTag ) {
if ( character === LINE_SEPARATOR ) {
- characterFormats = lastSeparatorFormats = ( characterFormats || [] ).reduce( ( accumulator, format ) => {
- if ( character === LINE_SEPARATOR && multilineWrapperTags.indexOf( format.type ) !== -1 ) {
- accumulator.push( format );
- accumulator.push( multilineFormat );
- }
-
+ characterFormats = lastSeparatorFormats = ( replacements[ i ] || [] ).reduce( ( accumulator, format ) => {
+ accumulator.push( format, multilineFormat );
return accumulator;
}, [ multilineFormat ] );
} else {
@@ -196,11 +191,10 @@ export function toTree( {
return;
}
- const { type, attributes, unregisteredAttributes, object } = format;
+ const { type, attributes, unregisteredAttributes } = format;
const boundaryClass = (
isEditableTree &&
- ! object &&
character !== LINE_SEPARATOR &&
format === deepestActiveFormat
);
@@ -210,7 +204,6 @@ export function toTree( {
type,
attributes,
unregisteredAttributes,
- object,
boundaryClass,
} ) );
@@ -218,7 +211,7 @@ export function toTree( {
remove( pointer );
}
- pointer = append( format.object ? parent : newNode, '' );
+ pointer = append( newNode, '' );
} );
}
@@ -240,22 +233,27 @@ export function toTree( {
}
}
- if ( character !== OBJECT_REPLACEMENT_CHARACTER ) {
- if ( character === '\n' ) {
- pointer = append( getParent( pointer ), {
- type: 'br',
- attributes: isEditableTree ? {
- 'data-rich-text-line-break': 'true',
- } : undefined,
- object: true,
- } );
- // Ensure pointer is text node.
- pointer = append( getParent( pointer ), '' );
- } else if ( ! isText( pointer ) ) {
- pointer = append( getParent( pointer ), character );
- } else {
- appendText( pointer, character );
- }
+ if ( character === OBJECT_REPLACEMENT_CHARACTER ) {
+ pointer = append( getParent( pointer ), fromFormat( {
+ ...replacements[ i ],
+ object: true,
+ } ) );
+ // Ensure pointer is text node.
+ pointer = append( getParent( pointer ), '' );
+ } else if ( character === '\n' ) {
+ pointer = append( getParent( pointer ), {
+ type: 'br',
+ attributes: isEditableTree ? {
+ 'data-rich-text-line-break': 'true',
+ } : undefined,
+ object: true,
+ } );
+ // Ensure pointer is text node.
+ pointer = append( getParent( pointer ), '' );
+ } else if ( ! isText( pointer ) ) {
+ pointer = append( getParent( pointer ), character );
+ } else {
+ appendText( pointer, character );
}
if ( onStartIndex && start === i + 1 ) {
diff --git a/packages/rich-text/src/toggle-format.js b/packages/rich-text/src/toggle-format.js
index 6e7854dcaa6626..7545f5d30c9d6a 100644
--- a/packages/rich-text/src/toggle-format.js
+++ b/packages/rich-text/src/toggle-format.js
@@ -14,10 +14,7 @@ import { applyFormat } from './apply-format';
*
* @return {Object} A new value with the format applied or removed.
*/
-export function toggleFormat(
- value,
- format
-) {
+export function toggleFormat( value, format ) {
if ( getActiveFormat( value, format.type ) ) {
return removeFormat( value, format.type );
}